SECUINSIDE CTF 2012 参加記

SECUINSIDE CTF 2012に参加しました。
今回は、友人が泊まりで遊びにきてたので、友人が寝てる間とかにちまちま一人で参戦。w


解いた問題数でのランキング

スコアによるランキング

得点順位 解答数順位 チーム 解いた問題数 スコア
3位 6位 sutegoma2 10問 5040
ランク外 38位 自分とこ 4問 950
ランク外 75位 Tachikoma 1問

今回のCTFでは、開催中は問題の得点が公表されない形式でした。
問題の得点は、あらかじめ決められた得点が必ず獲得できるというわけではなく、
多くのチームが解答した問題については、得点が低く計算されるという、少し面白い方式でした。
みんなが解ける問題なら得点は低くていいよね、的な。


問題ファイルはこちらで公開されているようです。


それでは、Writeupの後、感想と考察。


Writeup

zombie(500)


問題文:
http://61.42.25.27/c/a8241dc330c0353ccd8db73244c8bd30/

SQLインジェクションの問題。
PHPのソースが見れるようになっている。
次のように、スペースや一部キーワードが制限されている。

if(eregi("load|union| |\t|/|char|ascii|hex|<|>|infor|\.|challenge2|challenge3|challenge4",$dd)) exit("Access Denied");

$q=mysql_query("select * from challenge1 order by $dd desc");

スペースやタブが使えないので、改行で区切ることにした。
charが使えないので、substringとordでごそごそ。
しかし、ORDER BY の後に WHERE句が置けない。
結局、スマートな解答は結局思いつかず、次のような感じのSQLでBFした。

(CASE
ORD(SUBSTRING(password,0,1))
WHEN
50
THEN
password
ELSE
score
END)

BFに使ったVB.NETのコード

ASCII文字約100種として、FLAGの文字数が11文字。
1100回なら、だいじょぶだよね・・・?
みんながスコア更新しまくるので、適当なスコアを投げながらBFしたのだけど、
システムの問題か、ひたすらサーバが落ちまくってた。
BFしてもあんまり意味ないよって発言がIRCで見えてたけど、
BFなしの、ちゃんとした解き方が気になるなぁ。


FLAG: 0ldzombieee



21:16 (aozx) who brute-forcing target score.php
21:16 (aozx) 61.197.xxx.xxx <-
それは私です。w

beast(500)


問題文:
http://61.42.25.27/c/f79de6418b66ab6d2717cf2b2cfb37ea/

SQLインジェクションの問題。
PHPのソースが見れるようになっている。
これまたキーワードや文字数が、次のように制限されている。

if(strlen($_POST[phone])>=20) exit("Access Denied");
if(eregi("admin",$_POST[id])) exit("Access Denied");
if(eregi("load|admin|0x|#|hex|char|ascii|ord|from|select|union|infor|challenge",$_POST[phone])) exit("Access Denied");

@mysql_query("insert into challenge4 values('$_POST[id]',$_POST[phone],'guest')");

guest を admin にできれば、OK。
最初、シングルクオーテーションを入れるとうまくいかなくて、
なんでだろーと思ってたけど、多分、conn.phpmysql_real_escape_stringされてるんだと予想。
だとすると、idでインジェクションすることは無理。
となると、制限の多いphoneでインジェクションするしかない。


3000+3とか、length(id)とかはちゃんと動く。
"1111,id) -- - " も動く。lvがidになった。
adminは入れれないので、idをnimdaにして、"1,reverse(id))-- -"したら通った。


FLAG: 57483f303a55fed3b40a11519abf38f4

yhsj(500)


問題文:
http://61.42.25.29/ca91991084ceda1d22c5f2c8efc52c9e/

SQLインジェクションの問題。
PHPのソースが見れるようになっている。
(あれー、msg.phpsがまだ公開されてない....)


テーブルは、次のような構成。


talk (
 id string
 pw string
 ip string
)

talk_msg (
 ck
 mfrom => $_SESSION[id]: talk.id
 mto: talk.id
 msg
 tm
)

この問題では、tmというUNIX時間を使ってインジェクションしていった。
これまたcharとかは制限されてるけど、ordは使えるので、ord+substring。
talk.id="admin"のpwを知りたいので、次のSQLでBF(またw)。

60*(SELECT CASE ORD(SUBSTRING((SELECT pw FROM talk WHERE LENGTH(id)=5 AND ORD(SUBSTRING(id,1,1))=97 AND ORD(SUBSTRING(id,2,1))=100 AND ORD(SUBSTRING(id,3,1))=109 AND ORD(SUBSTRING(id,4,1))=105 AND ORD(SUBSTRING(id,5,1))=110 LIMIT 0,1),1,1)) WHEN 50 THEN 1 ELSE 2 END)

これで、投稿日時が1分ずれるようになるので、pwを1文字ずつ求めていく。
pwは、"zombie_{パスワード}"のMD5ハッシュなので、
32文字×36文字種=1152回。まぁ、だいじょぶだよね。
BFに使ったVB.NETのコード:


求めたハッシュは、72b302bf297a228a75730123efef7c41。
Backtrackに入ってる辞書でBF。あれ、解けない。
適当に総当たりで攻撃。あれ、解けない。
なんでやー!と思いながら、online hash crackに放り込むと、


"banana"


と表示された。は?w
zombie_{パスワード}
になるはずだから、これじゃ解けない。ちょっと待て。w


とかやってたら、IRCで運営側がこの問題のfixを始めた。
fix後は、adminのパスワードが正しいものに変更され、updateを制限ワードに入れてた。
オイ。変更したの誰だよ。w


追記:
このwriteupを見るに、updateじゃなくて単純にinsertしただけっていう可能性も?
凄く面白い解き方だなぁ。


気を取り直して、もう一度。
今度は、0f38a34e843e84f44ac699ec800cfd52が得られた。
辞書で攻撃してみると、"zombie_rainbow"がヒット。
後は、adminでログインして、フラッグをゲット。


FLAG: f290e59906916ad37852c398cac83433

iu


問題文:
Hints:
1. hex
2. [-3:]
3. inverse.

Challenge text:

        • -

the message was decoded:
11111011 11101111 10001110 10000110 00011000 01100001
10000110 00011000 01011000 10100010 11100011 01011010
10111010 00001000 01101101 11001000 00010000 00010010
00010011 10101110 00111110 11111011 10111010 01011110
01100100

        • -

追加ヒント:
http://61.42.25.27/slamdunkhero/desc.txt

One more hint:

\\"inverse\\"

more hints:

1. you have 25 bytes, you work on 22 bytes and 3 bytes separately.
2. flag format = e(22bytes) + e(3bytes)
3. which means d(e(22bytes)) + d(e(3bytes)) must be the same with the binary words. (have you checked this before? ;)
4. it\\\'s base64, there is a possibility that d(x) == d(y)
5. we know you\\\'re confused!


今回のサービス問題かな?
22バイトと3バイトに分けて、base64エンコードすると、答えが出る。


22bytes: +++OhhhhhhhYouNaughtyBASE64++w==
3bytes: ul5k

ただし、これでは通らない。
追加ヒントにあるように、必ずしも d(x) == d(y) になるとは限らない。
確かに、22バイト×8ビット=176ビットとなり、
176 mod 6 = 2 なので、2ビット余る。


linuxbase64コマンドだと、勝手に0をパディングして処理してしまう。
今回だと、余った2ビットは11なので、110000 として処理されてしまう。
出てきたキーワードからも、wじゃなくて+だろうという予想はつく。
実際、+は111110なので、それっぽい。
よって、答えは"+++OhhhhhhhYouNaughtyBASE64+++==ul5k"となる。


ちなみに、ずっと "+++OhhhhhhhYouNaughtyBASE64+++ul5k" で試してて、
何がダメなんだろう、inverseってあるから3バイトをinverseすればいいのかなとか
めっちゃ試行錯誤してた↓↓↓。ダメじゃーん。


10111010 01011110 01100100 ul5k
01000101 10100001 10011011 RaGb
01100100 01011110 10111010 ZF16
00100110 01111010 01011101 Jnpd
11011001 10000101 10100010 2YWi
10100010 10000101 11011001 ooXZ


FLAG: +++OhhhhhhhYouNaughtyBASE64+++==ul5k

感想

WEB系について

phpのソースが提示されている分、難易度は易しめなのかなー?とも感じました。
とはいえ、提示されていても結構大変に感じた....

その他

終了時間をちゃんと把握していなかったのと、途中で意識が飛んでしまったことで、
最後に解禁された5問はほとんど手つかず。無念。
Exploit系は全く手が出なかった。。
Web上からExploitっていうのが、初めてすぎて。勉強不足。
もっと、舐めるようにアセンブラを読めるようになりたい。
スタックの積み下ろしとか追うのが、ホントできない。深刻な問題。

Google Document

今回、一人参加だったけども Google Document の SpreadSheet を使ってみた。
既に使ってるよ!というチームは多そうだけど。


  • 問題ごとにシートを作成(SpreadSheet自体じゃないよ)
  • 問題に関連する情報をメモ
  • 問題で試した内容を記録

こうすることで、次のような利点があると思う。

  • 関連情報の集約化により、調べる手間が減る
  • 他の人がどういうアプローチをしているのかが分かるので、発想の枝分かれができる
  • 他の人が既に試した失敗手法を繰り返さない
  • (多分)勉強になる

複数人でやるときには、もってこいだなと思った。
情報共有が加速するのと、問題ごとの情報整理がシートごとに勝手に行われるので、非常に良い。
Writeupも、シート見ながら書き起こせる。
変更がリアルタイムで見れるので、オフライン・オンライン問わず、イイ感じ。

さいごに

参加者の方々、お疲れ様でした!
素敵なCTFをありがとう! > SECUINSIDE の中の人たち
sutegoma2、ベスト3 おめでとう!!!