SECCON CTF 2019 QUALS writeup
SECCON CTF 2019 QUALS
yharima で参加.今回は6人で参加.
自分にあまり人権はなかったが,メンバーが頑張ってくれて 1954pts で 45位.決勝は厳しそう.
pwn 担当なのでいつも通り pwn ばっかり手を出してたけど爆死しました.
ソース: https://github.com/yuta1024/ctf_log/tree/master/SECCON_CTF_2019_QUALS

Beeeeeeeeeer
最初は pwn がなかったので適当に手を出した.
実行するとわけわからん感じだけど,中身をみるとやたら長い base64 エンコードされたものがある.
echo <やたらながい> |base64 -d|gunzip|bash 圧縮されてるし解凍して bash に詳してるし怪しい.
この部分を取り出すと for 文が回ってたりするがまた長い base64 がある.
ただ今度は暗号化されてるようで echo <やたらながい> |base64 -d|openssl aes-256-cbc -d -pass pass:$(echo -n $n|md5sum |cut -c2,3,5,12) -md md5 2>/dev/null |bash; となっている.
$n は上のほうでランダムに決定されていて取りうる範囲は 1 - 10 なので適当に1から10ためしてみると3で復号できる.
また難読化されたものがでるが,末尾が SECCON{$S1$n$_____};echo -e '\033[?7h';となっていてフラグっぽい.
$n は 3 として $S1 は? と思ったけどメンバーがすでに解析終わっていたようで hogefuga らしい.
あとは $_____ だけどどうすれば…とおもっていたらメンバーが順番に echo していけば読めると教えてくれたので読んでいくとどうやら bash らしい.
というわけで bash といれてみると,以下のようになった.
$ S1=hogefuga n=3 bash beer3
Enter the password
bash
Good Job!
}
どゆこと…?でも Good Job だからあってるんだよなあとおもって strace にかける,
$ S1=hogefuga n=3 strace bash beer3
(snip)
write(1, "Good Job!\n", 10Good Job!
) = 10
write(1, "\n", 1
) = 1
write(1, "\33[?7l "..., 1024 4
write(1, " ", 5 ) = 5
write(1, "SECCON{hogefuga3bash}\n", 22SECCON{hogefuga3bash}
) = 22
write(1, "\33[?7h\n", 6
) = 6
read(255, "", 8192) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
exit_group(0) = ?
+++ exited with 0 +++
フラグでとるやん!制御文字でクリアでもされているのか?という話に.
というわけで SECCON{hogefuga3bash} が答え.
Sum
実行すると数字を与えて最後に 0 を入れると加算結果を表示してくれる.
1 1 1 1 0 みたいなのはいいけど 1 1 1 1 1 0 みたいにするとセグフォで落ちる.
=> 0x40077a <sum+35>: mov QWORD PTR [rax],0x0
このときに rax は 0x0で入力を他の数字にかえてみる.(1 1 1 1 1 1).
=> 0x40077a <sum+35>: mov QWORD PTR [rax],0x0
どうも6個目の入力のアドレス先に 0 を代入してるらしい.さらに読み進めていくとここに加算された結果を足しこんでいくようだ.
ということは任意のアドレスを書き換えることができる.ひとまず書き換えが1回だけでは何も出来ないので main が何回も実行されるようにしたい.
6個以上入力を食わすと exit されるので exit の got を上書きして main に飛ぶようにする.
注意しないといけないのは6個の合計値が加算されるので,書き換えたい先のアドレス分の値は引いておかないといけない.
ここまできたら libc のアドレスを leak して one_gadget のアドレスを求めたら exit の got を上書きして飛ばしてあげれば良い.
ただ,libc を leak する方法で迷走した.GOT を上書きしてなんとかしたいが,都合よく libc のアドレスを leak できそうな引数をとってるものがない.
setup をみると setvbuf で 0x601060(stdout) が指定されていてちょっと使えそうなきがしたのでまず exit => main から exit => _start にして setup が何度も呼ばれるようにする.
そして setvbuf を puts に書き換えて実行してみるもどうもそれっぽい値がでない.
ここから迷走したが最終的には 0x601060 にさらに puts@got のアドレスを書き込んでやると libc が leak できたのであとは one_gadget に飛ばした.他にいい方法がありそうな気もする.
https://github.com/yuta1024/ctf_log/blob/master/SECCON_CTF_2019_QUALS/sum/sum.py
$ python sum.py
[+] Opening connection to sum.chal.seccon.jp on port 10001: Done
[+] libc_base addr = 0x7fee79528000
[*] Switching to interactive mode
$ ls
bin
boot
dev
etc
flag.txt
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
start.sh
sum
sys
tmp
usr
var
$ cat flag.txt
SECCON{ret_call_call_ret??_ret_ret_ret........shell!}
まとめ
2問しかも1つは半分くらいメンバーも手を出していたので人権1.5だった.
pwn 難しすぎなのと heap から逃げてたけどいい加減向き合うことにします. one は解けないといけない問題であった‥.
決勝でれたらいいな….
嘆き
lazy
無限に時間を溶かした上に解けなかった問題.
ID/PASS は BOF して抜いてバイナリを拾ってくるまでは簡単.
さらに BOF があるので ROP し放題なわけだが libc をダウンロードできない.
無理やり ROP してダウンロードしてみるも 4MB くらいで EOF が返ってくる.
中の関数などを使って直接フラグを表示させる方法も試行したが,おそらくシェルをとってその上で同じディレクトリにある cat コマンドを使わないとだめな雰囲気を感じた.
以下のようにフラグファイルが見えて他のファイルが読めたので心がつらかった.
$ python lazy.py [+] Opening connection to lazy.chal.seccon.jp on port 33333: Done [+] Receiving all data: Done (193B) [*] Closed connection to lazy.chal.seccon.jp port 33333 run.sh lazy ld.so cat .profile libc.so.6 810a0afb2c69f8864ee65f0bdca999d7_FLAG .bashrc q .bash_logout run.sh Sending 68 bytes#!/bin/sh export HOME="/home/lazy" ./ld.so --library-path . ./lazy $ python lazy.py [+] Opening connection to lazy.chal.seccon.jp on port 33333: Done [+] Receiving all data: Done (52B) [*] Closed connection to lazy.chal.seccon.jp port 33333 810a0afb2c69f8864ee65f0bdca999d7_FLAG No such file!
もっと勉強します….
追記
繰り上げで国内決勝に出れることになりました! :tada: