本日SECCON2016 京都大会 「サイバー甲子園」というものがあり、行って優勝してきました。
登録
Twitterでnkpoidがリンクを貼っていたのを見て、一緒に出ることにする。
チーム名を”elf”に決め、リーダーを(ランダムで)僕に決定した。
申請の時に英語、数学、理科、社会、保険体育の学校での成績や得意分野、特技、将来の夢を入力させられたのが謎だった。
抽選通過から本番まで
抽選の結果参加できることになったらしい。追加で国語の成績を聞かれたり、交通費申請をしたりした。京都での実施だったため、大阪在住である僕にとってはありがたみが薄かった。
CTFはセキュリティ・キャンプで初めてやって以来だった(当時は普通に何もできなかった)ので、SECCONはCTFではないという話を各所で耳にしつつも対策しなきゃいけないなあと焦ってはいたが、結局忙しくて何もできなかった。
せめて言えばスシローに行った時に待ち時間で去年のwriteupを2つくらい見ておいたことくらいかな。
当日
前日は学校の遠足で嵐山に行っていたため、2日連続の京都ということで微妙な気持ちになっていた。(家から遠くもないけど近くもないので微妙に疲労感が貯まる)
東京からやってきたnkpoidと京都駅で会ってやっと当日気分になってきた。一緒にラーメンを食べて会場に向かった。
案内されたルートを無視して小路を通り逆側から向かった結果校門を間違え、到着が数分遅れてしまった。(申し訳ありませんでした。)
(あと、印鑑を持ってきたものの朱肉を忘れてしまった。(ISUCONでの反省が活きていない))
適当にアナウンスを聞き競技開始。
競技(writeup)
やっとwriteupです。自分が関わった問題のみ。残りはnkpoidが書いてくれるはずや。
[Sample 10] TRY FIRST
問題に書かれているフラグを投げるだけ。
[Crypto 100] very easy
stringsするだけ。very easy。
[Crypto 200] decode the flag
flag.encryptedというファイルと”53CC0NZOl6″というパスワードを渡され、opensslコマンドで暗号化したものですと言われる。
というわけで以下のようなシェルスクリプトを書いて総当り。
array=(aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb base64 bf bf-cbc bf-cfb bf-ecb bf-ofb cast cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb des des-cbc des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb des-ede-ofb des-ede3 des-ede3-cbcdes-ede3-cfbdes-ede3-ofb des-ofb des3 desx rc2 rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb rc4 rc4-40 seed seed-cbc seed-cfb seed-ecb seed-ofb) for i in "${array[@]}" do echo $i openssl $i -d -in flag.encrypted -k 53CC0NZOl6 echo -e "\n---\n" done
結果から正常にFLAGとして出てきたものを回答。
[Network 200] sample
pcapが渡されるのでWiresharkで開く。最初見た時、単にpingしあってるだけに見えてさっぱりわからなかった。nkpoidに見てもらい、「TTLが毎度異なっているのが怪しそう、ASCIIかと思ったけど違う。ずらすのかな、後は任せる」的なことを言われたので再度引き受ける。
確かに、レスポンスを返す側は常に一定のttlで返しているのに対し、リクエストを送る側は61, 61, 61, 80, 66, 64,…と変わっていっている。
というわけで、この数字をずらしてASCIIコードを出してみるPythonプログラムを書く。(例 2ずらし: 63, 63, 63, 82, 68, 66,…)
ttls = [61, 61, 61, 80, 66, 64, 64, 76, 75, 120, 77, 102, 107, 100, 70, 112, 75, 108, 68, 108, 108, 97, 122] for i in range(0, 10): str = '' for j in ttls: str += chr(j+i) print str
すると4文字ずらしくらいでflagが出てきた。
今見て気づいたのですがこのコードは非常に頭が悪くて、逆方向へのずらしが考慮できていない。(例 -1ずらし: 60, 60, 60, 79, 65, 63,…)
まあ、運が良かったですね。
[Programming 100] x2.txt
「2倍した」みたいな感じのヒントワードとともにx2.txtというファイルが渡される。これは罠で、テキストファイルではない。
とりあえずvim->:%!xxdでバイナリ表示してみる。
9240 d0c2 ecca 40c2 40e0 cadc 5c40 9240 d0c2 ecca 40c2 dc40 c2e0 e0d8 ca5c 40a6 8a86 869e 9cf6 d8e6 d0d2 cce8 bede e4be e4e6 d0d2 cce8 fa42 0a
nkpoidに「2倍したって言われてこれ見せられてどう思います?」って聞いて「半分にしてみては」と言われる。それはそう。
各バイトを10進にして半分にし、それらをHexに戻してつなげ、ASCIIコードで出してみるPythonプログラムを書く。
s = '9240 d0c2 ecca 40c2 40e0 cadc 5c40 9240 d0c2 ecca 40c2 dc40 c2e0 e0d8 ca5c 40a6 8a86 869e 9cf6 d8e6 d0d2 cce8 bede e4be e4e6 d0d2 cce8 fa42 0a00' result = '' array = s.split(' ') for i in array: first = int(i[0]+i[1], 16) hex1 = hex(first/2).lstrip('0x') if len(hex1) == 1: hex1 = '0' + hex1 result += hex(first/2).lstrip('0x') # -- second = int(i[2]+i[3], 16) hex2 = hex(second/2).lstrip('0x') if len(hex2) == 1: hex2 = '0' + hex2 result += hex(second/2).lstrip('0x') print result print result.decode('hex')
Pythonのhexコマンドは0xABみたいな感じに’0x’をつけてくるので、lstripでそれを削除。また、12->0xCみたいに、15以下だと1文字で返ってくるので、その場合は先端に0を足す。
そんな感じで結合したHexをASCIIコードとして10進に変えるとflagが出てくる。めでたしめでたし。
[Programming 200] decode the trapezoid QR code
ねじれたQRコードの画像を渡される。Illustratorで逆方向にねじってQRコードを読んだらフラグがあった。Programmingとは。
(ちゃんとProgrammingで解いている人もいて感心した)
[Programming 100] sum primes
12345番目から3万なんとか番目(忘れた)の素数の和を出せという問題。
エラトステネスのふるいを使ってPythonプログラムを書いてみたものの正解できず、nkpoidに頼んでも、nkpoidも不正解。その後、運営から「解答が間違っていたので修正します」との報告が入る。(オイオイ…)
そして数十分後(オイオイ…)、修正されたと言われ、nkpoidが提出して正解。
[Trivia 100] acronym
どんなんやったっけな。忘れた。3秒くらいで終わったことだけ覚えている。
[Trivia 100] blacked out PDF
一部が黒塗りになっているPDFが与えられた。「オッこれスシローで過去問で見たぞ」と思ったのですが、まんまそのままだった。
文字の上から黒塗りにされているだけなので、辺り一帯のテキストをコピーすれば、黒塗りの下の文字もコピーされる。それだけ。
[Trivia 200] blacked out PDF again
同じようなPDFの、パスワードがかかっている版。表示は見られるが、テキストをコピーしようとするとパスワードを求められる。
どうせ下にはテキストがあるんだからどうにかして見られるのだろうなと思ったけど、わからなかったので、パスワード総当りしてみることにした。
qpdfというツールがあるらしいので、brew install qpdf
でインストール。
以下のような総当りシェルスクリプトを書いた。
alphabet=(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) for i in "${alphabet[@]}" do qpdf --decrypt --password=$i owabi2.protected.pdf after.pdf && exit; done
もしqpdfのdecryptが成功すれば、パスワードを外した版であるafter.pdfが生成され終了、失敗すればエラーが出るという仕組み。
実行してみる。
…エラーしか出ない。パスワードは1字ではないということか。
alphabet=(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) for i in "${alphabet[@]}" do for j in "${alphabet[@]}" do qpdf --decrypt --password=$i$j owabi2.protected.pdf after.pdf && exit; done done
実行してみる。無事パスワードなしPDFが生成された。前述の通りテキストをコピーしてFLAGを抽出。
今見返してみると大文字アルファベットや数字や記号入りのパスワードを考慮していない…(頭が悪くて恥ずかしい)
偶然パスワードが小文字アルファベット2字だったから良かったですね。運が良かった。
競技まとめ
使ったソフトやツール
特筆すべきものはこんな感じかな?
- Wireshark: pcapを読む
- qpdf(brew): コマンドラインからパスワードつきPDFを開く(別の最適解があれば誰か教えて欲しい)
- Illustrator: 画像の変形(GIMPでいいと思います)
- stringsコマンド: わからんかったらとりあえずこれ叩いた
プログラミングが必要となった時は、総当りなどでコマンドを叩くのがメインのものはシェルスクリプト、そうでなければPythonを使った。
どちらもよく書くけど最近書いてないものだったので、結構ググり時間を消費してしまった。
感想
- 途中の妨害タイムで、アンケートで答えた学校での成績や特技、将来の夢を晒されたのが(同意はしていましたが)やはりつらかった。解法で詰まっていて考えている時に将来の夢について聞かれてマイクを出されたため、適当な解答をしたのですが、めっちゃ態度悪い人みたいになってしまったかもしれず申し訳ない。
- 表彰直前は「トイレに行きたい」以外のことを考えていなかったため、一言頼まれた時に何を言うか全く考えておらず、特技の「貧弱な語彙力」を発揮することとなってしまった。
- 表彰の時にバックで僕の将来の夢が朗読されるのめちゃくちゃ恥ずかしいのでやめて欲しい… (tsunくんみたいに「アラブ人」と書いておけばよかった)
- いざwriteupとして文字起こししてみると大したことしてなくて恥ずかしい。クソコードなのは、焦る中動けばいいやと思って書いたものなので甘く見てください。
- 僕はほぼ経験がない割に結構できて、楽しかった。問題が簡単だったのと、聡明なチームメイトのnkpoidのおかげですね。
- nkpoidとうまく役割分担できてよかった。僕は特に得意分野があるわけでもなく、お互いその場のノリで「これやります」って言って解く感じでしたが、うまくいってよかった。
- バイナリはstrings以外何も知らない状態で行ったので、very easy以外だいたいnkpoidに任せることになってしまった。ありがとう。強くなりたい。
- 1週間前に
某所のクソドライバのせいでMacの環境を破壊したためmacOSを再インストールしており、その影響でWiresharkやバイナリエディタが入っていない状態だった。Wiresharkはその場で落とし、バイナリエディタはvim->:%!xxdで代用した。 - ネットワークが恵まれていなかったため、苦労した。競技用のサーバーにアクセスする用の有線LANとインターネット利用向けのWi-Fiを使わせてもらっていたが、有線LAN接続中はWi-Fiに繋がっていてもインターネットにアクセスできなかったため、競技用サーバーにアクセスする必要のない時は有線LANを外すようにしていたが、頻繁に切り替えることとなり面倒だった。
以上です。
交通費もらえて(近所だけど)京都に行けたし、楽しかったし、優勝して東京行けることになったので嬉しいです。ありがとうございました!