週末に物見遊山でSECCON 2013 北海道大会に参加してきました。
もともとセキュリティは壊す方には興味があるものの守りとかしらないという殴る一方のドS仕様な人間なのですが、今年の頭に社内で開かれたセキュリティコンテストなるものへ参加するチームに誘われ、優秀な同期が次々と問題をとくのを眺めながら「ほー」とか「へー」といってる間に勝利し、持つべきものは優秀な友達だなとおもっていたところ、彼らがSECCONに参加するというのでまた甘い汁が吸えると思って釣られて参加してきました。
で、なんで北海道という話になると思うのですが理由は単純で
1.横浜大会にでても勝てなそう(対策の時間&レベル的に)
2.どうせなら行ったことない地域に行ってうまいものが食べたい
3.Ruby会議ではRuby札幌の方々にお世話になったので札幌がいいんじゃないか
という真面目な参加計画を立てている同期の横で煩悩と自分の都合で行き先を決めたのが私です(キリッ
で、結果を先に言うと4位という中途半端な順位で尻尾を巻いて逃げ帰ってきました。
優勝チームの皆様おめでとうございます!
参加者の皆様お疲れ様でした!!
あとハイパー余談なのですが参加者の方ならわかる小ネタ2つおいておきますね!
Dr.にゃんぱすー ‐ ニコニコ動画:GINZA
※この記事はこの動画とともに記載されているため変なテンションになっております。
チームのとしては練習問題を含む4問を回答しましたが、そのうち私が2問を解いて人権を得たので、人権を得た人間の勤めとしてWriteupを書きたいと思います。
熱いメッセージ
プログラミングの問題は確かこんなタイトルだったと思う。
PLMAM1なる謎の言語で書かれた以下のプログラムを実行した結果がどうなるか答えろという問題。
s=0 & (k=0 | k=-3)[ output(8+k); k:=k-3; s:=0; ] s=0 & c < 2 [ output(12); c:=c+1; s:=0; ] s=0 & c = 2 [ output(15); s:=2; ] s=2 [ output(27); output(0); s:=3] s=3 [ output(19-a); s:=4; ] s=4 & a=0; [ a:=14; s:=3; ] a=14 [ output(3); output(3); a:=1; ] a<13 [ output(15); a:=a+1; ] b=0 [ output(14); b:=100; ]
いきなり答えを書いてもいいんだけど私が正解に至ったまでの道のりをだらだらと書いておく。
PLMAM1ってなんだよ・・・って思ってぐぐってみると「第2回 科学の甲子園」のためだけに作られた専用言語ということがわかる。
実行環境が拾えるのかと思ったがそうでもないらしい。
記事からわかったのはPLMAM1は先頭に条件式、後ろに処理を書くということでひとまずRubyのスクリプトに落としこむ。
変数は0で初期化されていると仮定して実装。
a, b, c, k, s = 0, 0, 0, 0, 0 if (s == 0 && (k == 0 || k == -3)) puts(8+k) k -= 3 s = 0 end if s == 0 && c < 2 puts(12) c += 1 s = 0 end if s == 0 && c == 2 puts(15) s = 2 end if s == 2 puts(27) puts(0) s = 3 end if s == 3 puts(19-a) s = 4 end if s == 4 && a == 0 a = 14 s = 3 end if a == 14 puts(3) puts(3) a = 1 end if a < 13 puts(15) a += 1 end if b == 0 puts(14) b = 100 end
実行してみると
% ruby message.rb 8 12 15 14
一応これを入れてみても通らなかったのでやはり言語仕様が必要だということで検索を続けることに。
ググッた結果をよく見ると実技マニュアルが公開されているので「これだ!」って思ってアクセスするとそのページが無いと言われる(いまぐぐってみたら普通に存在していた)が、Google先生のキャッシュが残っているのでそれを利用。
だいたい想定していた仕様と同じだったのだが、output関数は数字に応じた文字を出力するらしいのでそのように処理を変更。
a, b, c, k, s = 0, 0, 0, 0, 0 words = [" ", *"A".."Z", ",", ".", "!", "?", "'"] if (s == 0 && (k == 0 || k == -3)) print(words[8+k]) k -= 3 s = 0 end if s == 0 && c < 2 print(words[12]) c += 1 s = 0 end if s == 0 && c == 2 print(words[15]) s = 2 end if s == 2 print(words[27]) print(words[0]) s = 3 end if s == 3 print(words[19-a]) s = 4 end if s == 4 && a == 0 a = 14 s = 3 end if a == 14 print(words[3]) print(words[3]) a = 1 end if a < 13 print(words[15]) a += 1 end if b == 0 print(words[14]) b = 100 end
実行してみると
% ruby message.rb HLON
変な文字だなと思って入力してみたけどこれも不正解。
というわけで他の処理が動いてないのがおかしいということで引き続き実技マニュアルを確認していると、上から条件に合う処理が実行され、実行されると先頭に戻り上から順にまた条件に合う処理を行い、最終的にすべての条件に合わなくなったところで処理が終了すると書かれていたのその通りに再々実装。
a, b, c, k, s = 0, 0, 0, 0, 0 words = [" ", *"A".."Z", ",", ".", "!", "?", "'"] loop{ if (s == 0 && (k == 0 || k == -3)) print(words[8+k]) k -= 3 s = 0 redo end if s == 0 && c < 2 print(words[12]) c += 1 s = 0 redo end if s == 0 && c == 2 print(words[15]) s = 2 redo end if s == 2 print(words[27]) print(words[0]) s = 3 redo end if s == 3 print(words[19-a]) s = 4 redo end if s == 4 && a == 0 a = 14 s = 3 redo end if a == 14 print(words[3]) print(words[3]) a = 1 redo end if a < 13 print(words[15]) a += 1 redo end if b == 0 print(words[14]) b = 100 redo end break } puts
実行してみると
% ruby message.rb HELLO, SECCOOOOOOOOOOOON
というわけで答えは"HELLO, SECCOOOOOOOOOOOON"で正解。
ここまでで多分30分ぐらいだった。
デコードせよ
QRコードが与えられていてそれをデコードする問題。
普通にQRコードをデコードするツールに食わせても"VlZOQlIwa2d"というテキストデータが得られる。しかしBase64でもデコードできないので12文字でできる暗号化ってなんだと思いながらわからなくなって放置。
しばらくして他のチームが続々と解いていくので「普通に考えれば解けるはずだと思うんだけどなー」と思ってMacのプレビューで開いたら16枚のGIFになっていることにようやく気づく。
あとは16枚を1つずつ切り出して順番にQRコードをデコードしていくと以下の文字が得られる。
VlZOQlIwa2dUazhnVlU1QlNra0tWVmRCUjBrZ1RrOGdWVkpCU2trS1ZVNUJSMGtnVGs4Z1ZVMUJUVWtLVlU1QlIwa2dUazhnUjBWT1Mwa0tWRWhGSUVaTVFVY2dTVk1nVlU1QlIwbE9UMHBWVFU5T1ZFRkpVMDlWQ2c9PQo=
どうみてもBase64です。
というわけで速攻でデコード。
% echo "VlZOQlIwa2dUazhnVlU1QlNra0tWVmRCUjBrZ1RrOGdWVkpCU2trS1ZVNUJSMGtnVGs4Z1ZVMUJUVWtLVlU1QlIwa2dUazhnUjBWT1Mwa0tWRWhGSUVaTVFVY2dTVk1nVlU1QlIwbE9UMHBWVFU5T1ZFRkpVMDlWQ2c9PQo=" | base64 -D VVNBR0kgTk8gVU5BSkkKVVdBR0kgTk8gVVJBSkkKVU5BR0kgTk8gVU1BTUkKVU5BR0kgTk8gR0VOS0kKVEhFIEZMQUcgSVMgVU5BR0lOT0pVTU9OVEFJU09VCg==
え、またBase64?!
といわけでもう一度デコード。
% echo "VlZOQlIwa2dUazhnVlU1QlNra0tWVmRCUjBrZ1RrOGdWVkpCU2trS1ZVNUJSMGtnVGs4Z1ZVMUJUVWtLVlU1QlIwa2dUazhnUjBWT1Mwa0tWRWhGSUVaTVFVY2dTVk1nVlU1QlIwbE9UMHBWVFU5T1ZFRkpVMDlWQ2c9PQo=" | base64 -D | base64 -D USAGI NO UNAJI UWAGI NO URAJI UNAGI NO UMAMI UNAGI NO GENKI THE FLAG IS UNAGINOJUMONTAISOU
そんなわけでFLAGは"UNAGINOJUMONTAISOU"で正解だった。
結局時間内に解けた問題はこの2問だけ。
終わった後に解説を聞いてホテルに帰ってフォレンジックの問題をやったら解けた。
他の参加者の方でフォレンジックの問題を解いた人のWriteupを見たけどどうやら答えは”TORATORATORA”であってたらしい。
解法だけ聞けば解けたってあたり発想が足りなかっただけで悔しいなー。
でも、うちのチームが使ったツールだとJPGが2枚しか出てこなかったので結局解法を聞かなければ解けなかったと思う。(3枚目はバイナリから自力でJPGを切り出した。Writeupで4枚目があったと聞いてびっくり。)
やっぱり負けるのは悔しいというわけでもう少し腕を磨いてオンライン予選に参加したいと思います。