SECCON 2017 Online CTF
今年も会社のチームで参加しました。 時間いっぱいの参加はできませんでしたが、 今年は昨年よりpwn以外の問題が増え、とっつきやすくなった感じです。 最近はどのCTFも軒並み難易度が高く、参加しても1番簡単な問題が1問解けるかどうかというくらいだったので、今回のような手ごろな問題を解いて達成感を得られるのはとてもありがたいです。 達成感、重要ですよね。
以下、軽くWrite up。
Run me! (Programming 100)
import sys sys.setrecursionlimit(99999) def f(n): return n if n < 2 else f(n-2) + f(n-1) print "SECCON{" + str(f(11011))[:32] + "}"
再起でフィボナッチ数列を求めていますが、再起が深すぎて実行するとプログラムが止まります。なので、再起なしで、フィボナッチ数列を求めてやれば答えが出ます。
n={1:1,2:1} for i in range(3,11012): n[i]=n[i-1]+n[i-2] print("SECCON{" + str(n[11011])[:32] + "}")
この問題はすぐに解けました。再起の上限の設定なんてあるんだなーと。
Vigenere3d (Crypto 100)
$ python Vigenere3d.py SECCON{************} POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9
昨年のSECCONでも出てきたヴィジュネル暗号の3D版です。昨年と解き方は同じだろうということで、暗号処理の中身はあまり気にせず、頭の「SECCON{」を暗号し、出力の先頭と一致する鍵を探します。
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}" def _l(idx, s): return s[idx:] + s[:idx] def crypto(p, k1, k2): t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))] c = t[s.find(p)][s.find(k1)][s.find(k2)] return c key = [] cp = [['S','P'], ['E','O'], ['C','R'], ['C','4'], ['O','d'], ['N','n'], ['{','y']] for c in cp: keys = [] for i in s: for j in s: if crypto(c[0], i, j) == c[1]: keys.append([i,j]) key.append(keys[0]) print key
鍵は2つあり、14文字の鍵とその逆順を使います。1文字ごとの2つの鍵の組み合わせを総当たりしています。 この処理で鍵の前半7文字とその逆順の前半7文字(つまり後半7文字)の組み合わせが出てきます。 ここで、それぞれの鍵は変数sのパターン分66通り出てくるのですが、実行してみると、66通りのどの鍵を使っても出力は同じになることが分かります。 そのため、1文字目はすべて「A」となる鍵を持ってきています。 これで、14文字の鍵が全てわかりますので、その鍵で復号して暗号文に一致する文字を探します。
flag = '' i = 0 tmp = [] for g in reversed(key): tmp.append([g[1], g[0]]) key = (key + tmp) * 3 cstr = 'POR4dnyTLHBfwbxAAZhe}}ocZR3Cxcftw9' for p in cstr: for k in s: if crypto(k, key[i][0], key[i][1]) == p: flag += k i += 1 print flag
換字のテーブルの構造はほとんど考えず、ただ総当たりでやりました。鍵が66通りどれでやっても結果が同じことに気づくのに時間がかかりました。
Powerful_Shell (Binary 300)
難読化されたPowershellを実行する問題。 まず、ps1ファイルを実行できるよう、管理者権限のPowershellコンソールで「Set-ExecutionPolicy RemoteSigned」を実行します。
ファイルの中身を見ると、「$ECCON」という変数に色々入れて最後に実行しているっぽいので、ラスト1文を消して「echo $ECCON」にすると、難読化を解除したスクリプトが見えます。
最初に耐解析的なセクションがあり、イベントログの件数を確認し、少なすぎればサンドボックスと判定します。この処理におそらく管理者権限が必要で、管理者権限のあるコンソールでなければ処理が停止します。
管理者権限のコンソールでスクリプトを実行してみます。
背景が黒くなり「SECCON」ロゴが出てきます。耐解析のセクションを抜けると鍵盤が出てきて、入力に応じて音がでます。 出力する音を決めているのは「$keytone」という変数なので、ここをechoとかで見てみる(難読化解除後の16~20行目をコピペしてコンソールに張り付けてから、「echo $keytone」)。
Name Value ---- ----- j 493.891672853823 s 293.669745699181 y 415.31173722644 w 277.187329377222 u 466.171663254114 g 392.002080523246 e 311.132257498162 t 370.000694323673 h 440.007458245659 f 349.234151046506 d 329.633144283996 a 261.63 k 523.26
91行目の「$secret」変数の値と一致するkeyが正解。
「$secret=@(440,440,493,440,440,493,440,493,523,493,440,493,440,349)」
「hhjhhjhjkjhjhf」を入力すると「さくらさくら」が流れて、次のステージに行けます。 (ロゴといい、すごい凝ってる) パスワードを求められるので、さらに100行目以降の難読化を解除していきます。
色々やっているっぽいけど、とりあえず、「$plain」変数をechoします。 すると、asciiが10進になっているようなものが出てくるので、これを文字列に変換。 また、意味の分からない難読化されたスクリプトが出てきます。
${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;}; ${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;}; ${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]"; ${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]); ${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}
ここは本当に意味が分からなくて、しばらく悩みましたが、結局、一番最後についている「|&${;}」がスクリプトを実行している箇所だろうと考え、ここを削除し、「${;}」をechoすると、また10進数をcharに変換しているようだったので、これをascii化。
'$ECCON=Read-Host -Prompt \'Enter the password\'\r\nIf($ECCON -eq \'P0wEr$H311\'){\r\n\tWrite-Host \'Good Job!\';\r\n\tWrite-Host "SECCON{$ECCON}"\r\n\x0c'
でフラグにたどり着きました。
Powershellはあまり詳しくないのですが、思っていたよりかなり柔軟な難読化ができるんだなあ、という印象です。
その他
後は、Log search (Web 100) や SqlSRF (Web 400) に挑んではいましたが、答えにたどり着けず。Log search はElastic SearchのQuery DSLをインジェクションするのかと思って色々試していましたが、「違うじゃん」と分かったところで、諦めました。回答はもう少し単純だったようで、Elastic Searchももっと触れておかないとなと感じました。SqlSRF みたいな問題はいつも、割と好きで解きたいと思いつついつも解けない問題です。
後はCode Blueで坂井弘亮氏が話していたSOPの問題もありましたが、手を付けられませんでした。
今回もpwn系も少し解けるようになりたいなー、とCTFのたびに思っています。