1. kusano_k

    Posted

    kusano_k
Changes in title
+SECCON CTF 2019 write-up
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,485 @@
+https://www.seccon.jp/2019/akihabara/#ctf
+
+superflipは1,265点で10位。最初のほうは調子が良かったが……。
+
+![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/1915316c-9dae-4dd9-4cdd-993dd44cd596.png)
+
+国内と国際があるけれど、順位表が違うだけで問題は同じ。
+
+## 問題の形式
+
+各大問ごとに攻撃点と防御点がある。
+
+攻撃点は良くあるJeopardy形式と同じ。問題のファイルやサーバーの中からフラグを探して投稿すると点が入る。点数は全部同じで1本100点。
+
+防御点は、各問題で指定されたURLに、チームごと5分ごとに変わるディフェンスキーワードが書かれていれば、5分ごとに「20/書かれているチーム数」の点数が入る。本来はサーバーの制御を奪ったら、他の参加者からサーバーを守れという意味での防御点だろうけど、まあ、その方式でやるのは無理があるだろうから、形式は問題によって様々。
+
+## 壱
+
+各チーム(IPアドレスの上位12ビット)ごとにポートが指定される。指定されたポートにTCPで繋ぐと、「トークン」を聞かれ、トークンを答えるとフラグとともにUDPで指定されたポートに同じトークンを投稿しろと言われる。
+
+```
+Attack Flag: SECCON{P13453 +4K3 C4R3} - OK, Please send UDP packet with token in payload to game port, first port is 21854, time limit is 20 second
+```
+
+`SECCON{P13453 +4K3 C4R3}`
+
+UDPで投稿すると別のポートにトークンを投げろと言われ、合計10回で、トークンが防御点用のファイルに書き込まれる。つまり、トークンをディフェンスキーワードにして、5分に1回以上これをやれば防御点が獲得できる。
+
+何が難しいんだ?と言われそうだけど、問題文に不穏な一文がある。
+
+> Caution: If your service process goes to wrong state, we will not restart till all team's score goes to no count or any trouble is found.
+
+この問題は接続ごとにサーバープログラムが起動するわけではなく、起動しっぱなし。タイムリミットを過ぎても10回繰り返した後でないと、TCPで待ち受ける初期状態に戻らない。UDPで投げるトークンが一致していない場合も同様にUDPモードのまま。スクリプトを書いていたりしてサーバーから送られてきたデータを読み捨ててしまったら終わり。まあ、プログラムを解析するとポートは1,000通りしかないから総当たりができるし、スクリプトを書いていたらトークンはスクリプトに残っていると思うのだけど。
+
+コンテスト中の通信は全て記録しておけということだろうか。そうしているチームもあるらしい。
+
+もう1個難しいのが、UDPの接続終了後に0.09秒のウエイトがあり、上記の制限時間は徐々に短くなっていって最後は1秒になる。余裕が0.1秒しかない。そもそも、UDPの通信のプログラムなんて書いたことがなくて、`recvfrom` に小さな値を指定したらエラーになったりして良く分からなかったけれど、次のプログラムで制限1秒になった後も10回に1回くらいは成功するようになった。この問題の状況では運営サーバーで試せないし、そもそも1日目の帰宅後だったので、ローカルで試行錯誤した。
+
+```solve.py
+import time
+import re
+from socket import *
+import select
+import sys
+
+#target = "127.0.0.1"
+target = "10.1.1.1"
+
+#index = 22 # 127.0.0.1
+index = (192<<16|168<<8|41)%50
+
+token = sys.argv[1]
+print "Token: %s"%repr(token)
+
+def tcp():
+ s = socket(AF_INET, SOCK_STREAM)
+ print "port", index*1000+10000
+ s.connect((target, index*1000+10000))
+
+ r = ""
+ while len(r)==0 or r[-1]!=":":
+ r += s.recv(1)
+ print r
+
+ s.send(token)
+
+ r = ""
+ while len(r)<6 or r[-6:]!="second":
+ r += s.recv(1)
+ print r
+ s.close()
+
+ return int(re.search(r"port is (\d+),", r).group(1))
+
+port = tcp()
+print port
+
+def udp():
+ s = socket(AF_INET, SOCK_DGRAM)
+ #s.bind(("127.0.0.1", port+1))
+ s.bind(("192.168.41.5", port+1))
+
+ while not select.select([s], [], [], 0)[0]:
+ s.sendto(token, (target, port))
+ pass
+ r, _addr = s.recvfrom(0x20)
+ print r
+ s.close()
+
+ m = re.search(r"port is (\d+)", r)
+ if m:
+ return int(m.group(1))
+ else:
+ return 0
+
+for _ in range(10):
+ port = udp()
+```
+
+後はスコアサーバーからのディフェンスキーワードの取得とプログラムの実行を10秒に1回繰り返した。
+
+```attack.sh
+while true
+do
+ date
+ token=$(curl -sS -b "PHPSESSID=3838679e25c9df2babe71a6fc9dde5f88218e37c" http://score-dom.seccon/flagwords/ | grep '<th>superflip' | egrep -o '[0-9a-f]{32,32}')
+ python -u solve.py $token
+ sleep 10
+done
+```
+
+これを書いたのが1日目帰宅後で、2日目は順調に防御点を稼いでいたけれど、14時くらいに止まっていた。UDPの各ポートにトークンを投げまくっても回復しなかった。懇親会で聞いたら、問題サーバーのプロセスが落ちたチームがあって、再起動はしなかったと言われた。同じスクリプトを動かしっぱなしなのだから状況が変わることも無さそうなのに……。
+
+![20191223_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/803b3ecb-9945-992f-efa1-3e0ab32d7b32.jpeg)
+
+同じくらいの時間に止まっているチームは他にもいる。他のチームのIPアドレスからの接続を弾くのはファイアウォールではなくプログラムに実装されているので、何か脆弱性があれば他のチームから落とされることもありえそう。とはいえ、それなら攻撃を実行した1チーム以外は皆止まりそうなものだが……。謎。
+
+SECCONはこれまで会場内の物理サーバーで運営していたが、時代の波に乗ってクラウド化したらしい。Pingで遅延が30ミリ秒くらいだったからけっこう際どい……と作問者に言ってみたら、乱数のポート番号を推測して応答が返る前にタイミングを合わせて送れば良いと返された。なるほど。`srand(0), srand(rand())`と乱数を初期化しているのはミスではなかったのか。
+
+## 弐
+
+画像認識サーバーに画像を投げろという問題。画像を投稿すると、
+
+```
+Statistics for each color: 1480/12000
+Recognition rate = 1.825% (73/4000)
+```
+
+というような結果が返ってくる。「Statistics for each color」って何だろう。画像サイズは640x400と指定されているから分母は画素数でもないし。認識率の高い画像を得るのが目標。50%、60%、70%ごとに攻撃点用のフラグが返ってくる。45%以上で最大の認識率の画像を投稿しているチームが防御点を得られる。次の画像を投稿するまで3秒待たないといけない。「最大で1時間に1,200枚しか試せないよ」と問題文にも書かれていた。
+
+4時間ごとに認識パラメタと認識率の最大値がリセットされる。ただし正解画像は変わらない。今これを書いていて気が付いたけれど、「正解画像」があるんだな。てっきり機械学習の物体識別のように、画像が犬の確率とか、猫の確率とかが計算されて、隠されている何かの確率が認識率だと思っていた。
+
+「まずは色々試してみないとね」と白一色とか赤一色とか共に黒一色の画像を投稿したら、1個目のフラグが降ってきた。
+<img width="320" alt="black2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/b6309653-8b21-6109-4e52-900148399034.png">
+
+```
+Statistics for each color: 9164/12000
+Recognition rate = 50.125% (2005/4000)
+
+SECCON{S6BhhlE2v457zeyOzA2lBZQn8HwyMxZb} (2019-12-21 12:03:59)
+```
+
+`#101010`で塗りつぶした画像を投稿したら全てのフラグが手に入ってしまった。えぇ……。最初の4時間だったから「認識パラメタ」が甘いのか?
+
+<img width="320" alt="black2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/e36f02f1-9766-03ff-e6c1-20882f519bd5.png">
+
+```
+Statistics for each color: 10491/12000
+Recognition rate = 73.25% (2930/4000)
+
+SECCON{BaEkG068DzXENTu1fMtHo5Y1LwB4JaFa} (2019-12-21 12:20:59)
+SECCON{GMUHjEGSgVcyt3psECE5x8jRprAMl2Kg} (2019-12-21 12:20:59)
+SECCON{S6BhhlE2v457zeyOzA2lBZQn8HwyMxZb} (2019-12-21 12:03:59)
+```
+
+`SECCON{BaEkG068DzXENTu1fMtHo5Y1LwB4JaFa}`
+`SECCON{GMUHjEGSgVcyt3psECE5x8jRprAMl2Kg}`
+`SECCON{S6BhhlE2v457zeyOzA2lBZQn8HwyMxZb}`
+
+ディープラーニングとか良く分からないし、そもそもディープラーニングの画像生成って微分ができるのが前提のところ各画像の認識率しか手に入らないし、ハイパーパラメタのチューニングライブラリも画素数の次元はやってくれないだろうなぁで防御点は諦めていた。正解画像とかとの単なる距離とかならエリアごとに徐々に色を変えていくとかやってみても良かったかもしれない。
+
+## 参
+
+色々なアーキテクチャでexploitを書けという問題だったかな。手を付けていない。
+
+## 四
+
+懇親会でチーム紹介があって、特に話すことが無いチームには司会者が「どの問題が面白かった?」と聞いていた。「4問目」と答えていたチームが多かった。
+
+予選の[follow-me](https://qiita.com/kusano_k/items/6ad4c50dbfffb96e0fca#follow-me-225-pt-86-solves)と同じように、Intel Pinを使って条件分岐ごとにアドレスをジャンプしたかどうかを記録したログから、同じログになるような入力を求める問題。攻撃フラグは全4問。
+
+ある程度解析したら手元で実行して、問題のトレース結果と見比べ、辻褄を合わせる感じで進めると楽。トレース結果が同じになれば良いのであって、同一の入力にする必要は無い。
+
+### box1
+
+数字と、各英字で処理が分かれている。`000000000012ce0010a0000b`で通った。12や10はループの回数。
+
+```
+[*] API /attack/1/submit with input = 000000000012ce0010a0000b
+{'message': 'Good! Submit this flag :)', 'flag': 'SECCON{Good! Go on next :hugging-face: oUedlavRDOMzUhzu}', 'error': False}
+```
+
+`SECCON{Good! Go on next :hugging-face: oUedlavRDOMzUhzu}`
+
+### box2
+
+入力データを暗号化だか復号だかしている。面倒。あと、プログラムを解析してみると、未初期化メモリを使っている。まあ、Cのコード上は未初期化でも実際に実行したときに値が決定的に決まっていれば良いのだけど、スタックのアドレスが書かれていた。ASLRで実行ごとに変わるぞ。どうするんだこれ……と思ったところで暗号化(復号?)の結果の値を一切見ていない事に気が付いた。それなら何でも良いな。
+
+`0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0`が通った。
+
+```
+[*] API /attack/2/submit with input = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0
+{'message': 'Good! Submit this flag :)', 'flag': 'SECCON{Brilliant! You know crypto function depends on input length :relaxed: gVtDHSPrBkoHdxiw}', 'error': False}
+```
+
+暗号アルゴリズムは値に処理が依存しないほうが望ましいということを分からせるための問題か?
+
+[単純電力解析 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%8D%98%E7%B4%94%E9%9B%BB%E5%8A%9B%E8%A7%A3%E6%9E%90)
+
+`SECCON{Brilliant! You know crypto function depends on input length :relaxed: gVtDHSPrBkoHdxiw}`
+
+### box3
+
+x86の(一部の命令の)エミュレーター。最初に各オペランドに対応したサイズ256個の関数テーブルを作っている。ビルドし直すのが面倒で手元に動かすときに予選のものをそのまま使っていたら、予選のものは関数呼び出しに対応していなかった。決勝のものは関数の呼び出し先がコード中にあるのではなく、メモリから読んでいる場合は、アドレスを出力してくれる。手元でプログラムを動かして関数テーブルを作ったところでダンプして見比べれば、どのオペランドがどの順で並んでいるかはすぐに分かる。あとは各オペランドでのフラグの変化などを読めば良い。とはいえ、分量が多くてなかなかに面倒。
+
+```
+mov reg imm32
+mov reg imm32
+
+cmp r/m32 r32
+jg rel8 (taken)
+add r/m32 r32
+jmp rel8
+
+cmp r/m32 r32
+jg rel8 (taken)
+add r/m32 r32
+jmp rel8
+
+cmp r/m32 r32
+jg rel8 (taken)
+add r/m32 r32
+jmp rel8
+
+cmp r/m32 r32
+jg rel8 (taken)
+add r/m32 r32
+jmp rel8
+
+cmp r/m32 r32
+jg rel8 (taken)
+add r/m32 r32
+jmp rel8
+
+cmp r/m32 r32
+jg rel8 (not taken)
+
+hlt
+```
+
+という感じだったので、これで。
+
+```
+$ objdump -D -M intel -mi386 -b binary code
+
+code: file format binary
+
+
+Disassembly of section .data:
+
+00000000 <.data>:
+ 0: b8 00 00 00 00 mov eax,0x0
+ 5: b9 04 00 00 00 mov ecx,0x4
+ a: 39 c8 cmp eax,ecx
+ c: 7f 05 jg 0x13
+ e: 01 ff add edi,edi
+ 10: 40 inc eax
+ 11: eb f7 jmp 0xa
+ 13: f4 hlt
+```
+
+この問題のプログラムの入力はx86の入力そのものなので、アセンブラの書き方が分からないときには、いちいちプログラムに食わせなくても逆アセンブルしてみれば良い。`add r/m32`でレジスタとメモリをどうやって切り替えるのかとか知らなかった。次の1バイトの上位2ビットが`11`(`0xc0`)ならば、残りの6ビットを3ビットずつ使ってオペランド2個のレジスタを指定する。
+
+```
+[*] API /attack/3/submit with input = ? ? 9ネ?@?E
+{'message': 'Good! Submit this flag :)', 'flag': 'SECCON{Cool! You know how CPU emulator works :sunglass: SogtZbFVCnyPrmMA}', 'error': False}
+```
+
+`SECCON{Cool! You know how CPU emulator works :sunglass: SogtZbFVCnyPrmMA}`
+
+### box4
+
+バイナリはbox3と同じ。入力だけが違う。
+
+```
+push imm32
+push imm32
+push imm32
+push imm32
+pop reg
+
+pop reg
+dec reg (>0)
+mov r/m32 r32
+add r/m32 r32
+dec reg (>0)
+jnz rel8 (taken)
+add r/m32 r32
+dec reg (=0)
+jnz rel8 (not taken)
+cmp r/m32 r32
+jz rel8 (not taken)
+jmp rel32
+
+pop reg
+dec reg (>0)
+mov r/m32 r32
+add r/m32 r32
+dec reg (=0)
+jnz rel8 (not taken)
+cmp r/m32 r32
+jz rel8 (not taken)
+jmp rel32
+
+pop reg
+dec reg (>0)
+mov r/m32 r32
+add r/m32 r32
+dec reg (>0)
+jnz rel8 (taken)
+add r/m32 r32
+dec reg (>0)
+jnz rel8 (taken)
+add r/m32 r32
+dec reg (=0)
+jnz rel8 (not taken)
+cmp r/m32 r32
+jz rel8 (taken)
+
+hlt
+```
+
+このエミュレータは`add`ではフラグが変化しないから適当で良いのだが、`dec`はフラグが変化する(=トレース結果が変わる)のできちんと合わせないといけない。
+
+```
+ 0: 68 03 00 00 00 push 0x3
+ 5: 68 01 00 00 00 push 0x1
+ a: 68 02 00 00 00 push 0x2
+ f: 68 03 7c 00 00 push 0x7c03
+ 14: 59 pop ecx
+ 15: 58 pop eax
+ 16: 49 dec ecx
+ 17: 89 c0 mov eax,eax
+ 19: 01 ff add edi,edi
+ 1b: 48 dec eax
+ 1c: 75 fb jne 0x19
+ 1e: 39 cd cmp ebp,ecx
+ 20: 74 05 je 0x27
+ 22: e9 ee ff ff ff jmp 0x15
+ 27: f4 hlt
+```
+
+外側のループは3回回るので、最初は`push 0x7c03`を`push 0x03`にして`cmp ebp,ecx`の部分で値が0になっている`eax`と比較していた。これだと`dec`の条件を満たさなくてダメだった。`ebp`は`0x7c00`で初期化されている。
+
+まあ、考えてみれば、律儀にループにする必要も無かったかもしれない。ジャンプで条件を満たしても満たさなくても次の命令に飛ばせば良い。
+
+```
+[*] API /attack/4/submit with input = h h h h| YXI佳Hu・ヘt鴃
+{'message': 'Good! Submit this flag :)', 'flag': 'SECCON{Good job! You are emperor of x86-64 :pray: tAXnPJEpyLoLKsQR}', 'error': False}
+```
+
+フラグの中身を今読んだ。x86だと思っていたけどx64だったのか。まあ、通ったから良いか。
+
+`SECCON{Good job! You are emperor of x86-64 :pray: tAXnPJEpyLoLKsQR}`
+
+### 防御点
+
+1時間ごとにbox1を元にした問題が出題される。最初に解いた1チームディフェンスキーワードが書き込まれる(1時間そのチームに点数が入る)。
+
+国内で準優勝したkimiyukiさんはこれを自動化して点数を稼いでいたらしい。一応1日目に別の時間の問題を持って帰って中を見てみたけど、バイナリ自体も変わっていた。トレース結果が変わるくらいなら頑張ろうと思ったけど、これはつらい。
+
+## 六
+
+Jeopardy。小問が(たしか)5個。防御点は無し。大問の問題ページをメモってくるのを忘れたので、小問の順番は適当。
+
+### mimura
+
+コンテスト開始前に謎の電子部品が配られた。
+
+![20191223.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/74878c26-2a4e-e428-6af9-6cbfa8e69860.jpeg)
+
+「記念品かな? ラッキー」と思っていたけど、問題だったわ。問題文には
+
+> It's a hardware challenge.
+
+としか書かれていなかったがこれでしょう。手つかず。
+
+### Bad Mouse
+
+たぶん上の写真の左下のやつ。指してみたけどエラーで認識されなかった。
+
+こちらはIntel HEX形式のファームウエアが与えられた。冒頭に
+
+```
+=>?@aBcDAUiHkJKLMNQPOaS\UVWXY`kemgoiAqcdEywLyN{P]Mopqrstuvwxyz{|
+}~OHrQCLEFGHiN[U]W_YqXSTUVWXYZ[\]^_`}fElGnIpmqklk}QxSzU|w~wxuA}D
+?FAHEFCDAMIPKRMTQROPMYU\W^Y`Ua[\[mc`ibsdcughIjKlK}p@rBstwzY@kBeD
+CE?@CBERgGaHOJKLINQYS[UYQYWXyakemgoiAgcdelwqys{uM}opw~KwUvO{?F{|
+IDQIcJUMQLGHgP]T_VaXsYSTSeg`ibkd}e_`cbedcuihkjklmt?yA{C}UEwxuz}E
+?GAE}ECDAFIQKSMQIQOPqYc\e^g`y^[\UeshsjulEmghejmuowqumustS|I@KBMD
+_E?@?QSLUNWPiQKLORqXCZ}\[]WXQaodofqhAicdqlyqKr}uytopOxE|G~I@[A{|
+[DQHSJULgMGHIJ[T~]OXQRSTuYoZ_\Yk]`_`gb{dEu?hojklMu?xAzC|UzwxYz[|
+yMa@cBCDELWQYS[Um]OPoXe\g^i`{a[\[mohqjslEmghGp}t?vAxSystvFxHWI[|
+]~?@B
+```
+
+という文字列があり、ある程度規則的に値が増えているけれどそうでないところもあり、ここにマウスの動きをエンコードしているのかな?と、ファームウエアを読んでみた。
+
+AVR形式なので、AVR形式をダンプできるようにビルドしたobjdumpならば、
+
+```
+$ objdump -D -m avr:25 -b binary firm.bin
+```
+
+で逆アセンブルできる。AVRの解説をしているサイトを読みながら処理を追ってみたけれど良く分からず。終了1時間前くらいに「Ghidraが対応しているんじゃない?」と思って試してみたら対応していた。まだ難しいがもう少し早く気が付いていれば何とかなったかもしれん。
+
+### factortheflag
+
+```
+I hid the SECCON{} flag in a big prime number.
+1401111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111112220791111111111111111
+1111111111111111111111111111122207911223089031988903088023088023088920012001200
+2319889030879222080230880230890319887911122318879211992120012999912120013000013
+0000131008920012001199121200120022089200130000119912119911121200120011992119912
+1199121199121199121200130101000012001199121200120930009200130000119921199111121
+2001200119921199121199121199121199121200130010208012002318879112120929999112120
+9299991212103188892001200119912230890318889199121199121200130000131007911112119
+9212092091991211992119912120013010111188791222079112129999121199121199121200130
+0001200119911121200120012091992119921299992120013010099991112119911112129999121
+1991211991212001300001200120012001209199223198889199212001209199213010099991112
+1199212001299991212001300001300001300001200120012001299991111212091991212001209
+1992130100999911121199122308903198890308802308802308892001200119922308903198879
+2121031988903088011992130100999911121199111111111111111111111111111111111111111
+2220791111111111111111111111111111111111111111111112220791111111111111111111111
+```
+
+「SECCONで素数の性質とかをガチで使った問題が出るか……? :thinking: 」と思って、メモ帳に貼り付けてメモ帳の幅を変えると何か周期が見える。色々試すと幅92文字が一番良い感じ。開始位置をちょっとズラして、
+
+```
+140
+1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111112220791111111111111111111111111111111111111111111112220791122
+3089031988903088023088023088920012001200231988903087922208023088023089031988791112231887921199212
+0012999912120013000013000013100892001200119912120012002208920013000011991211991112120012001199211
+9912119912119912119912120013010100001200119912120012093000920013000011992119911112120012001199211
+9912119912119912119912120013001020801200231887911212092999911212092999912121031888920012001199122
+3089031888919912119912120013000013100791111211992120920919912119921199121200130101111887912220791
+1212999912119912119912120013000012001199111212001200120919921199212999921200130100999911121199111
+1212999912119912119912120013000012001200120012091992231988891992120012091992130100999911121199212
+0012999912120013000013000013000012001200120012999911112120919912120012091992130100999911121199122
+3089031988903088023088023088920012001199223089031988792121031988903088011992130100999911121199111
+1111111111111111111111111111111111112220791111111111111111111111111111111111111111111112220791111
+111111111111111111
+```
+
+スクショをペイントに貼り付けてバケツツール。
+
+![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25276/59bb7eb8-c866-f1fc-6f6e-00e2455bfb21.png)
+
+最後の2文字が読めなかったが、524287はメルセンヌ素数。で、`mP`だった。
+
+`SECCON{524287mP}`
+
+### QR Decoder
+
+ウェブサーバーのURLとバイナリファイルが与えられる。バイナリファイルを見ると、`zbarimg`というプログラムを実行して結果を`QR-Code:Hello, world!`と比較している。`Hello, world!`をQRコードにしてサーバーに投稿したら1個目のフラグゲット。
+
+```
+The decoded string is: Hello, world!
+Congratulations!
+The first flag is SECCON{8182 means decimal ASCII code of Q and R}.
+Next, read ./flag2.txt in the server.
+```
+
+`SECCON{8182 means decimal ASCII code of Q and R}`
+
+素直に http://10.1.5.1:8182/cgi-bin/flag2.txt を開いたら2個目のフラグが読めた。終わり。
+
+`SECCON{U R QR C0DE H4CK3R}`
+
+### syzbot panic
+
+syzbotに関する問題で、さらに小問が5問あって繋げて1個のフラグにする。2問目以降は「これこれこういう(たぶんsyzbot自体やLinuxの)コミットのSHA-1の先頭10文字は?」という形式。1問目は、
+
+> (Q1) What is FQDN (in all lower characters) of a website that manages the state of bugs syzbot has found?
+
+で、まずこれが分からん。フラグの全体の長さが与えられているから計算すると23文字になるはず。`syzkaller.appspot.com`(21文字)じゃないのか?
+
+この日本語のページが読めるかどうかで大きく差が付いて国際大会としては良くないと思うんだよなぁ……。結局解けていないからこのページに書かれているコミットに正解があるのかは知らないけど。
+
+[The SYZBOT CTF](http://i-love.sakura.ne.jp/The_SYZBOT_CTF.html)
+
+
+