どうも wasamusume で旗を全力で振っている、みむらです。
そういえば前回の SECCON CTF って
香川でしたっけか。
前回は強行スケジュールでしたが、今回はホテルでゆっくりと。
そんなわけで、 wasamusume として SECCON 北陸大会に参加してきました。
一緒に参加したあたがわさんも記事を公開されていますので、こちらもどうぞ。:
SECCON 2013 北陸大会参加 あたがわの日記
2013/12/10 03:20 追記:
また、公式ウェブサイトにてスコアが公開されたようですので、
記事の最後に掲載しました。
今回も長くなりそうですんでこの辺で分割しておきます。
(続きは「続きを読む」より)
参加するまで
今回はいつもの かーみーさんが諸事情で来られず。
(いつも迷惑掛けていてすんません、すんません。。)
でもどうせなら誰かを呼んで、わいわい楽しくやろうと思いまして
同じ大学の hyt さんに声を掛けました。
数回しか会ったことなかったことに加えて、大会開催の数週間前に聞いたのですが、
大丈夫ですとのことでしたので、ぜひ!ということに。
(どうもありがとうございました。そしてその行動力、見習いたいです・・w)
11月は2つ出かける用事があり、
まず福岡に遊びに行って、その次の週に SECCON ということで
交通費だけでお財布事情も非常によろしくなくなることが判明していましたので、
初めて旅行会社のパックを利用して申し込みました。
結果としては非常に安く、かつよい宿&よい交通機関が手配され、
今まで自分が予約取ってごにょごにょやるよりは、遙かによかったです。
次回も是非利用したいと思いました。
・・・ちなみに、福岡へは ANA さんの旅作を。
富山へは JTB さんのパックを利用しました
参加前日 – 富山まで
一人あたり往復で6枚の切符を持って、越後湯沢経由で富山へ。
お風呂入るためだけに越後行く親方かっこいい
— ふま・インティライミ (@yh_Mar) 2013, 11月 30
越後湯沢で温泉入りたかった!
東京周辺もこのようにイルミネーションがきらびやかな時期になっていて
なかなかにリアルが充実していない私にはちょいと…
それと、 LANケーブルが足りないってんで、
こういうイルミネーションきらめく中、大丸東京店へ行きましたが
あいにくそういう物の取り扱いはないそうで。 注意です。
富山
ホテルは、風呂があってお風呂がついて食事が充実していること ということで
アパホテル<富山駅前>に。
一部で、アパ大好きな人とか思われているようですが、そこまでではないです。
他のホテルが良ければそっちを使います。
部屋について機材の確認含めて展開していたところ、
なんか廊下から聞き覚えのある笑い声が。
会場近くなので、まさかねーと思っていたのですが
風呂場で実行委員の一人と遭遇。
朝食時にも、Wさんと遭遇しまして(ぁ
たぶんあの笑い声は間違いない・・と思ってはいるのですがどうだったんだろう。。
CTF
ホテルから会場のビルが見えましたので特に迷うことは無く。
CTF には “wasamusume” として
私(@mimura1133)
あたがわさん (@ipv4)
hyt さん
の3人で参加しました。
WiMAX 回線を契約して持ち込みましたが、
部屋の騒音対策のためか、CTF 大会開催中は映画館にあるようなドアがしまりまして、
2.5 Ghz 帯が・・・!!!
ということで、一緒に持ち込んでいた NTT docomo Xi 回線に切り替えました。
大会中は終始和やかに進みまして、
ノリノリで問題を解いていきました。 (Write-up は記事の最後に)
最後の方、「この一問が解けないと、全国が!!!」と互いに煽りながら解いていきまして
なんだかんだ気づいてみれば相当の点数で優勝していました。
これで全国に突撃できそうです!
終了後
終始雑談をしていました。
私としては、某大学の K 先生と話が出来たことが一番大きかったです。
(一緒に話をしてみたいなとなんとなく思っていまして・・w)
その中で出たこととして、
どうも私は「鉄ちゃん」の定義に当てはまるらしいのですが、どうも納得いきませんなぁ(笑)
今までの鉄ちゃんらしい行動といえば、
新幹線の車内チャイムを聞くためだけに福岡で1日追加で宿泊して
博多~鹿児島中央間を往復で乗ってみるとか
(これを聴く目的なら新幹線往復切符余裕です・・!)
大阪環状線の接近・通過メロディを聴くと「うぉー!!」となったりします。
あとはシンコペーションや Verde Rayo V2, JR-SH3-1 あたりを聞くと目が覚めますし(ぁ
Gota del Vient や遊園地のある駅, 南風の行方 も好きです
(またこの記事も、くるりさんの「赤い電車」を聞きながら書いていたりします)
音楽として聞いていて楽しいので、
これは鉄ちゃんではないんじゃないかなとおもうわけですよ・・!
(あくまでも、一人の音楽を楽しんでいる人としてカウントをですね)
・・・悪あがきはこの辺にして。
今回の SECCON で全国へ行けることになりまして、
3月にまた楽しんでこれたらいいなと思っています。
最後に。
東京から来たチームとか関西からきた怖いチームがいて「北陸大会とは何だったんだ…」という感じだったので、初参加の私たちのチームは「1人1問解いて楽しんで帰る」ということを目標に頑張ってきました。
すんませんすんません。
・・・・でもうちは怖くないとおもいます・・よ・・きっとね!!
Write-up
今回の大会では、10問の問題が最終的に出題され、
うちのチームではそのうち9問解きました。
そのうち、私が解いたのは
「司令部からの暗号文を解読してください(フォレンジックス500)」
「パスワードを答えなさい(バイナリ100)」
「パスワードを得よ(バイナリ200)」
「熱いメッセージ?(プログラミング100)」
の4問になります。
また、
「この中にファイルあるはずなんだけど…(ネットワーク300)」
「スロットマシーン(Web 300)」
「出身地チャート(エラーコードを探せ!) (Web 100)」
に関しては、チームメンバのあたがわさんが write-up を公開していますので、
そちらを参照してください
(SECCON 2013 北陸大会参加 あたがわの日記)
司令部からの暗号文を解読してください(フォレンジックス 500)
ディスクイメージが渡されるので、 FTK Imager で開く。
Message.txt に “VRZGNWSOHPMY” とあって、他に画像が2枚 (!ank.jpg, !ero.jpg) ある。
“unallocated space” にも似たようなファイルが置いてあり、こいつを取り出す。
絵が !ank.jpg と同じ物なのに、 !ank.jpg が 23kb で こちらが 124kb ってことで
やけにファイルサイズが大きいので Bz で眺めてみると、3枚分のデータがあることがわかる。
それぞれを切り出すとこのような感じに。
そしてまたこれらをよく見てみると、 “Rotor position” と書かれた文字列が入っていることがわかる。
3枚の画像からそれぞれ取り出すと、
Rotor position 1:J
Rotor position 2:P
Rotor position 3:N
となり、なんとなく「エニグマ」っぽい感じがしていたので
(大学の講義でエニグマ暗号にも触れていたのでなんとなく)
エニグマをシミュレーションするものを探して、
http://enigmaco.de/enigma/enigma.html
このウェブサイトで、上3つのダイヤルを J,P,N の位置に合わせて
Message.txt にあった “VRZGNWSOHPMY” を入力すると
“TORATORATORA”
(ワレ奇襲ニ成功セリ!)
ということで、得点を得ることが出来ました。
パスワードを答えなさい(バイナリ100)
Windows の exe ファイルが降ってくる。
早速 IDA Pro に投げ込んで解析。
まず最初にこの辺を見ると、
cmp [ebp+argc],2 jz short loc_4010AA
ってことなので、引数を1つ取ることがわかります。
(自身の実行イメージへのパスが1つめに格納されるため、引数を1つ取ると 1+1 で 2となる)
sub_401000 に入力した文字列を渡してごにょごにょして、
その結果を基に “Invalid key” と出すか、
”key=hogehoge” と出すかが決まるようなので、 sub_401000 を見に行きます。
この辺を見ると、入力した文字列を sub_401100 に渡しているようなので sub_401100 へ。
こうなっているので、ぱっと見た感じストリーム暗号っぽい。(1文字づつ処理をしていく)
でもって [ebp+var_C] がカウンタで、何文字目かを表している。
後はこれをまじめに読んでいくと、
1. movzx ecx,byte ptr [eax] で、arg_4 の var_C 文字目の文字を ecx に取り出す。
2. DE -> ED -> BE –> EF の順番で入力文字に xor を掛ける (1文字目は DE, 2文字目は ED.. のように)3. byte_40B040 にある変換表を元に変換を行う
4. BA -> DC -> AB – > 1E -> C0 -> ED の順番で入力文字に xor を掛ける
5. byte_40B140 にある変換表を元に変換を行う
6. mov [edx], al で eax(al) に格納された文字を var_1C の var_C 文字目に格納する。
という流れが読めます。
あとはそこから、sub_40102A に戻ってきて (0x401000 の先。 call sub_401100 の次の命令)
その先のコードで byte_40B000 と比較していることが読めます。
また比較するデータ量は 12バイト分しかありません。
ここまで来れば、プログラムに起こして解かせます。
また、そこまで時間も掛からなそうですので総当たりで。
static void Main(string[] args) { byte[] table1 = { 0xC6, 0x1, 0x0F, 0x2F, 0x87, 0x26, 0x94, 0x0CF, 0x80, 0x18, 0x43, 0xC0, 0x0B3, 0x92, 0x0E7, 0x0A4, 0x39, 0x72, 0x0B, 0x85, 0x23, 0x95, 0x0B9, 0x0E2, 0x1D, 0x69, 0x70, 0x0EC, 0x2A, 0x34, 0x0FA, 0x4B, 0x4D, 0x0F0, 0x42, 0x0F7, 0x4A, 0x0, 0x0C9, 0x36, 0x5A, 0x8E, 0x5, 0x0D, 0x0AE, 0x0D2, 0x0A3, 0x66, 0x98, 0x0DB, 0x0B4, 0x6E, 0x9A, 0x8, 0x3E, 0x0EE, 0x96, 0x81, 0x55, 0x6, 0x0AC, 0x0F9, 0x6B, 0x88, 0x24, 0x0F4, 0x0E8, 0x63, 0x7D, 0x0DF, 0x89, 0x0F3, 0x0A5, 0x8D, 0x90, 0x74, 0x97, 0x0FD, 0x0AA, 0x99, 0x0B1, 0x83, 0x59, 0x0F5, 0x0D6, 0x9D, 0x7E, 0x5B, 0x8A, 0x0E3, 0x6C, 0x6F, 0x67, 0x82, 0x78, 0x7F, 0x0B7, 0x3A, 0x0B0, 0x5D, 0x0D0, 0x76, 0x0DA, 0x44, 0x29, 0x5E, 0x0C3, 0x3F, 0x0DC, 0x0BB, 0x75, 0x0A6, 0x58, 0x65, 0x0A1, 0x2B, 0x0E1, 0x0A0, 0x79, 0x7C, 0x77, 0x0B6, 0x14, 0x0CE, 0x0A8, 0x4F, 0x52, 0x31, 0x0A, 0x9B, 0x35, 0x0F1, 0x0A2, 0x60, 0x27, 0x84, 0x4C, 0x86, 0x9F, 0x93, 0x19, 0x1C, 0x0FB, 0x8F, 0x28, 0x8B, 0x0FC, 0x0CC, 0x0CA, 0x0F8, 0x46, 0x0EA, 0x0EF, 0x0AF, 0x10, 0x0D9, 0x56, 0x7B, 0x0B8, 0x0E9, 0x1B, 0x0E, 0x0C5, 0x71, 0x0BF, 0x3B, 0x0E4, 0x4, 0x2D, 0x9, 0x53, 0x2, 0x2C, 0x0DE, 0x62, 0x11, 0x0D8, 0x51, 0x48, 0x57, 0x7, 0x25, 0x12, 0x9C, 0x8C, 0x0FF, 0x7A, 0x1E, 0x0A7, 0x0FE, 0x0E6, 0x0BE, 0x0B5, 0x3, 0x17, 0x3C, 0x0E5, 0x0AB, 0x0BC, 0x0CB, 0x1F, 0x0C4, 0x68, 0x0C2, 0x30, 0x54, 0x0BA, 0x22, 0x0B2, 0x0CD, 0x6D, 0x49, 0x6A, 0x0AD, 0x0A9, 0x0C, 0x0DD, 0x0D7, 0x0BD, 0x37, 0x0C7, 0x0F2, 0x0ED, 0x38, 0x40, 0x13, 0x16, 0x61, 0x33, 0x73, 0x4E, 0x1A, 0x5C, 0x41, 0x2E, 0x15, 0x0C8, 0x91, 0x0EB, 0x3D, 0x45, 0x0E0, 0x0F6, 0x50, 0x0C1, 0x0D1, 0x9E, 0x32, 0x0D5, 0x47, 0x0D3, 0x5F, 0x64, 0x0D4, 0x21, 0x20 }; byte[] table2 = { 0x73, 0x0B5, 0x0C4, 0x0BC, 0x6C, 0x0E0, 0x0FB, 0x15, 0x1F, 0x26, 0x6, 0x0E1, 0x4, 0x7B, 0x3B, 0x3E, 0x8, 0x0F9, 0x84, 0x9E, 0x5A, 0x0DF, 0x34, 0x8C, 0x3D, 0x8A, 0x47, 0x0D9, 0x64, 0x0E9, 0x0F3, 0x0F1, 0x13, 0x69, 0x0D2, 0x50, 0x0C1, 0x1A, 0x0B3, 0x0AF, 0x30, 0x39, 0x83, 0x74, 0x0C9, 0x70, 0x18, 0x95, 0x61, 0x0CD, 0x4F, 0x49, 0x16, 0x0E3, 0x6F, 0x24, 0x0D8, 0x0A, 0x1E, 0x0C8, 0x0C5, 0x4E, 0x0A8, 0x0BA, 0x46, 0x0C, 0x0FF, 0x0C7, 0x1D, 0x85, 0x3F, 0x0E6, 0x0F, 0x19, 0x0C3, 0x0D, 0x0D7, 0x0A9, 0x0C6, 0x5E, 0x2B, 0x0B0, 0x62, 0x0D4, 0x0EA, 0x0BD, 0x76, 0x97, 0x71, 0x8F, 0x31, 0x0A4, 0x4D, 0x92, 0x4C, 0x7D, 0x7C, 0x4B, 0x0EE, 0x72, 0x9A, 0x0EB, 0x17, 0x53, 0x0FD, 0x0B, 0x0AB, 0x2A, 0x88, 0x0BE, 0x99, 0x54, 0x0D1, 0x68, 0x11, 0x8E, 0x0B9, 0x2E, 0x0A2, 0x0EF, 0x91, 0x0E2, 0x5B, 0x0D3, 0x0AE, 0x42, 0x0D6, 0x0CC, 0x3, 0x32, 0x9C, 0x87, 0x0DE, 0x20, 0x0AD, 0x9B, 0x9F, 0x0DA, 0x7A, 0x59, 0x0A5, 0x58, 0x0B4, 0x43, 0x0A1, 0x0EC, 0x56, 0x12, 0x0DD, 0x0F4, 0x67, 0x2C, 0x0E, 0x23, 0x7E, 0x6B, 0x0B6, 0x4A, 0x3A, 0x25, 0x0F2, 0x3C, 0x81, 0x51, 0x41, 0x78, 0x60, 0x1, 0x98, 0x0FE, 0x5F, 0x27, 0x1B, 0x44, 0x89, 0x2D, 0x0A3, 0x21, 0x79, 0x0AC, 0x0A6, 0x82, 0x9D, 0x0FC, 0x0F6, 0x0C0, 0x0B2, 0x0, 0x8B, 0x29, 0x6E, 0x0E5, 0x35, 0x0ED, 0x0D5, 0x55, 0x9, 0x8D, 0x75, 0x0F8, 0x0E7, 0x77, 0x0F0, 0x0F5, 0x0E4, 0x38, 0x0BF, 0x0B8, 0x48, 0x0A0, 0x28, 0x33, 0x65, 0x45, 0x2, 0x36, 0x22, 0x0CA, 0x0F7, 0x0CE, 0x7F, 0x1C, 0x66, 0x0CB, 0x5, 0x80, 0x93, 0x0DC, 0x63, 0x10, 0x7, 0x0B7, 0x0D0, 0x0B1, 0x14, 0x0E8, 0x0CF, 0x6A, 0x37, 0x2F, 0x0A7, 0x94, 0x0AA, 0x57, 0x40, 0x0BB, 0x6D, 0x90, 0x86, 0x52, 0x5D, 0x0FA, 0x96, 0x0DB, 0x0C2, 0x5C }; byte[] xortable1 = { 0xDE, 0xED, 0xBE, 0xEF }; byte[] xortable2 = { 0xBA, 0xDC, 0xAB, 0x1E, 0xC0, 0xED }; byte[] answer = { 0x9A, 0x2B, 0x88, 0x0F, 0x12, 0x62, 0x28, 0x60, 0x86, 0x3C, 0x13, 0xA2 }; Console.WriteLine( new string( answer.Select((a, i) => (char)Enumerable.Range(' ', '~').First(c => { c = table1[xortable1[i % 4] ^ c]; c = table2[xortable2[i % 6] ^ c]; return c == a; })).ToArray() ) ); Console.WriteLine("\nDone."); }
変換表を取ってきて配列にして、あとはごにょごにょっと。
実行するとすぐ求まるかと思います。
ということで “sUbstItUtIOn” が答え。
パスワードを得よ(バイナリ200)
ディスクイメージが渡されて A.HRB のパスワードを求めてね! という問題。
IDA Pro で読むと、こういう感じで出てくるので、
あとは、読む。
ってことで “HaRIbOteOS” が答え。
熱いメッセージ?(プログラミング100)
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
香川大会でも出まして、そのときには解けなかったので今回こそは!と。
仕様は以下の pdf を読むとよくわかります。
http://rikai.jst.go.jp/koushien/tournament/img/2013/jitsugi03_jitsugi_manual.pdf
static void output(int i) { if (i == 0) Console.Write(" "); else if (i < 27) Console.Write((char)('A' + (i - 1))); else if (i == 27) Console.Write(","); } static void Main(string[] args) { int s = 0; int k = 0; int c = 0; int a = 0; int b = 0; while(true) { if (s == 0 && (k == 0 || k == -3)) { output(k + 8); k = k - 3; s = 0; continue; } if (s == 0 && c < 2) { output(12); c++; s = 0; continue; } if (s == 0 && c == 2) { output(15); s = 2; continue; } if (s == 2) { output(27); output(0); s = 3; continue; } if (s == 3) { output(19 - a); s = 4; continue; } if (s == 4 && a == 0) { a = 14; s = 3; continue; } if (a == 14) { output(3); output(3); a = 1; continue; } if (a < 13) { output(15); a++; continue; } if (b == 0) { output(14); b = 100; continue; } break; } Console.WriteLine(); }
後はこのような感じで、素直に C# に起こします。
ということで “HELLO, SECCOOOOOOOOOOOON” が答え。
Write-up について
今回は前回までの大会傾向を見ておくとある程度解けそうな問題が多かった気がします。
また、やはり解くときには なんだかんだ C# で書いてしまう今日この頃です。
今回あげた Write-up の一部は、
後で解き直してわかった簡潔な方法に基づいているものがあったりします。
今週末には名古屋・大阪でも SECCON がありますが、
参加される方は是非とも楽しんできてください。
後日談
賞状が届きました!
2013/12/10 03:22 追記:
SECCON 公式ブログにも試合結果が公開されました:
SECCON北陸(富山)大会の試合結果 – SECCON 2013 blog
(上に飛び抜けている青色の線が、 wasamusume のグラフです)
今までの努力の積み重ね・・というところでしょうか。解いていて楽しかったです!