2014年10月24日金曜日

Hack.lu 2014 CTF

単独で参加しました。結果はダメダメです☆(ゝω・)v
(終了間際、EDに合流しましたが何の役にも立てませんでした。死にたい。)

今回、バイナリ系は全く解けませんでした。。。
Web問はそこそこ解けたので、以下そのwriteupです。

Encrypted(Web50)

何の変哲も無いログインフォームが与えられました。
適当にa:aでログインすると下記のURLに飛びました。
https://wildwildweb.fluxfingers.net:1411/dologin.php?dhrel=FRYRPG+%60anzr%60+SEBZ+%60hfref%60+JURER+%60anzr%60+%3D+%27n%27+NAQ+%60cnffjbeq%60+%3D+ZQ5%28%27n%27%29
rot13っぽかったので、デコードすると下記のsql文になりました。
SELECT `name` FROM `users` WHERE `name` = 'a' AND `password` = MD5('a')
とりあえずadminでログインすればいいんじゃね?っと考え、下記のURLにアクセスしたらflagが出てきました。
https://wildwildweb.fluxfingers.net:1411/dologin.php?dhrel=FRYRPG%20%60anzr%60%20SEBZ%20%60hfref%60%20JURER%20%60anzr%60%20%3D%20%27nqzva%27
※dhrel=urlencode(rot13(SELECT `name` FROM `users` WHERE `name` = 'admin'))
flag{nobody_needs_server_side_validation}

Next Global Backdoor(Web150)

phpのソースコードとそれを設置しているページが与えられました。
<body bgcolor="black">
<center><img src="img.png"></center>
<?php @$GLOBALS=$GLOBALS{next}=next($GLOBALS{'GLOBALS'})[$GLOBALS['next']['next']=next($GLOBALS)['GLOBALS']][$next['GLOBALS']=next($GLOBALS[GLOBALS]['GLOBALS'])[$next['next']]][$next['GLOBALS']=next($next['GLOBALS'])][$GLOBALS[next]['next']($GLOBALS['next']{'GLOBALS'})]=next(neXt(${'next'}['next']));
?>
ぱっと見、意味不明ですがタイトルからして任意のコードを実行出来るような気がしました。
とりあえずソースコードを整形しました。
<body bgcolor="black">
<center><img src="img.png"></center>
<?php
    @$GLOBALS =
    $GLOBALS['next'] =
        next($GLOBALS['GLOBALS'])
            [$GLOBALS['next']['next'] = next($GLOBALS)['GLOBALS']]
            [$next['GLOBALS'] = next($GLOBALS[GLOBALS]['GLOBALS'])[$next['next']]]
            [$next['GLOBALS'] = next($next['GLOBALS'])]
            [$GLOBALS['next']['next']($GLOBALS['next']['GLOBALS'])] =
                next(next($['next']['next']));
?>
$GLOBALS['next']['next']に関数名、$GLOBALS['next']['GLOBALS']に引数を与えればいいみたいです。
$a = $b = $c とした場合、$cから評価されるのでnext($GLOBALS['GLOBALS'])[~から処理を読み解き、
次のようになれば任意の関数が実行されることが解りました。
(next(next($['next']['next']))は普通にエラーですが@が付いてるので無視されます)
array(5) {
  ["_GET"]=>
  array(0) {
  }
  ["_POST"]=>
  array(0) {
  }
  ["_COOKIE"]=>
  array(1) {
    ["GLOBALS"]=>
    string(8) "readfile"
  }
  ["_FILES"]=>
  array(1) {
    ["readfile"]=>
    array(2) {
      [0]=>
      int(0)
      [1]=>
      string(11) "/etc/passwd"
    }
  }
  ["GLOBALS"]=>
  *RECURSION*
}
/etc/passwdには大したものが無かったので、とりあえずreadfile('/flag.txt')したらFLAGが出てきました。
flag{backdoor_business_is_hard,_fella}

Objection(Web150)

謎のソースコードが与えられました。
const net = require \net
const BufferStream = require \bufferstream

admin_password = (require \fs).readFileSync \admin_password, \utf8


server = net.createServer (con) ->
  console.log 'client connected'
  con.write 'hello!\n'
  client_context =
    is_admin: false
    token: (require \fs).readFileSync \secret_token, \utf8
    login: ([password], cb) ->
      if password == admin_password
        cb "Authentication successful"
        @is_admin = true
      else
        cb "Authentication failed"
    get_token: ([], cb) ->
      if not @is_admin then return cb "You are not authorized to perform this action."
      cb "The current token is #{@token}"
  in_stream = new BufferStream {encoding:\utf8, size:\flexible}
  con.pipe in_stream
  <- in_stream.split \\n
  it .= toString \utf8
  console.log "got line: #{it}"
  [funcname, ...args] = it.split ' '
  if typeof client_context[funcname] != \function
    return con.write "error: unknown function #funcname\n"
  client_context[funcname] args, ->
    con.write "#it\n"

server.listen 1408, ->
  console.log 'server bound'
色々ぐぐってみるとCoffeeScriptだということが解りました。
CoffeeScriptはJavaScriptに変換して実行するものらしいです。
故に、JavaScriptに備わっている__defineGetter__が使えます。
__defineGetter__は第二引数を省略するとプロパティはNullを返します。
これにより、コンソール上で「__defineGetter__ is_admin」を実行し、
is_adminを参照するとNullを返すようにして、get_tokenを実行するとFLAGが出てきました。
flag{real_cowboys_dont_use_object_create_null}

ImageUpload(Web200)

画像アップローダーが与えられました。

画像のexif情報も合わせて保存されるようです。
Manufacturerに下記の値を入れることでModelに「5.5.40-0ubuntu0.14.04.1」が入りました。
☆(ゝω・)vキャピ',version())#

あとは普通にsqliし、アカウント情報を手に入れてログインしたらFLAGが出てきました。
flag{1_5h07_7h3_5h3r1ff}

Dalton's Corporate Security Safe for Business(Web200)

JavaScript製のCAPTCHA入力ページが与えられました。
普通に入力してると「Too slow」とか言われるので自動化しました。(ソースコード
まじめにJavaScript解析するのはつらいので、正規表現でゴリ押ししました。
10回CAPTCHAを送信するとログインページのURLが出現し、素早くアクセスするとFLAG出てきました。
fef9565c97c3a62fe10d2a0084a9e8179d72f4a05084997cb80e900d1a77a42e3

Killy The Bit(Web200)

phpのソースコードの断片とそれを設置しているページが与えられました。
下記の条件を突破し、sqliしないといけないようです。
!preg_match('/sleep|benchmark|and|or|\||&/i',$_GET['name'])
最初は
"SELECT name,email FROM user where name='".$_GET['name']."'"
でエラーになり、
"SELECT name,email FROM user where name sounds like '".$_GET['name']."'"
で正しく実行されるsqliを考えていたのですが全くひらめかず、
「blind? we will kill you :)」をシカトしてblind sqliでadminのパスワードを抜きました。
FLAGの形式、使用文字は他の問題のFLAGを元に推測しました。「$」は勘で見つけました。
(orの部分は手動で対応しました)
flag{Killy_The_Bit_Is_Wanted_for_9000_$$_FoR_FlipPing_Bits}

Hidden in ρlaιn sιght(Crypto150)

nodejsのソースコードとそれ動かしているサービスが与えられました。
問題文によると/files/testuser/flag.txtにFLAGがあるようです。
サービスの内容はファイルアップローダーで、/files/testuser/flag.txtにアクセスするためには
HMAC-SHA256値を推測する必要があるようです。
一見、hmac値は乱数が入るようですが、よく見るとHMAC_SECRETの一部がΕ(U+0395)になっています。

つまり、HMAC_SECRETに値はセットされず、sha256(testuser/flag.txt)を求めればいいだけです。
flag{unicode_stego_is_best_stego}

その他

Web400つらかったです。ずっとCSP~wって言ってました。
writeup