女子小学生バイナリアンのCTFにっき。

CTF diaries by an elementary schoolgirl who is addicted to binary analysis.

SECCON 2014 CTF online quals write-up

古い記事があったので投稿。。。
プログラムの多くは時間の流れとともに失われていました。。。。。(ぅд;`)

前回のSECCON 2014 CTF オンライン予選に続いて、英語のオンライン予選にも、とあるチームのバイナリ担当として参加してきました!

とりあえずまた、解いた問題のwrite-upを書こうかと思いますー。


・Binary 100 Shuffle

バイナリを読むまでもないんですが、0x0804854Bから0x080486AFまでの間で

スタックに表示可能範囲のバイト値を積んでいっています。

この後の処理でその文字列をシャッフルするので、この段階で読んでしまえばいいわけです。

16進数を読み込んで適当にスクリプトで表示。

import sys

ques = [ 0x53, 0x45, 0x43, 0x43, 0x4f, 0x4e, 0x7b, 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x45, 0x43, 0x43, 0x4f, 0x4e, 0x20, 0x32, 0x30, 0x31, 0x34, 0x20, 0x43, 0x54, 0x46, 0x21, 0x7d, 0x00 ]

for c in ques:
    sys.stdout.write(chr(c))
SECCON{Welcome to the SECCON 2014 CTF!}



・Binary 100 Reverseit

Reverse、ということで、

バイト列を前後反転させたり、ビット反転させたり、エンディアン変換してみたりしていました。

そうしたら、少し考えている間にチームの方が解いてくれました!

1バイトごとに、上位4bitと下位4bitを入れ替えるんだとか。

よくすぐに気付いたなーって感動。



・Crypt 100 Easy Cipher

2進数、8進数、10進数、16進数で構成された数列が問題文。

とりあえず全部文字型に変換して表示したくなりますよね!

桁数、0から始まるか、数字のみで構成されるのかA-Fが含まれるのか、

で識別できるので、それぞれ文字型に変換します。

以下、毎度の適当スクリプト

import sys

ques = '87 101 108 1100011 0157 6d 0145 040 116 0157 100000 0164 104 1100101 32 0123 69 67 0103 1001111 1001110 040 062 060 49 064 100000 0157 110 6c 0151 1101110 101 040 0103 1010100 70 101110 0124 1101000 101 100000 1010011 1000101 67 0103 4f 4e 100000 105 1110011 040 116 1101000 0145 040 1100010 0151 103 103 0145 1110011 0164 100000 1101000 0141 99 6b 1100101 0162 32 0143 111 1101110 1110100 101 0163 0164 040 0151 0156 040 74 0141 1110000 1100001 0156 056 4f 0157 0160 115 44 040 0171 1101111 117 100000 1110111 0141 0156 1110100 32 0164 6f 32 6b 1101110 1101111 1110111 100000 0164 1101000 0145 040 0146 6c 97 1100111 2c 100000 0144 111 110 100111 116 100000 1111001 6f 117 63 0110 1100101 0162 0145 100000 1111001 111 117 100000 97 114 0145 46 1010011 0105 0103 67 79 1001110 123 87 110011 110001 67 110000 1001101 32 55 060 100000 110111 0110 110011 32 53 51 0103 0103 060 0116 040 5a 0117 73 0101 7d 1001000 0141 1110110 1100101 100000 102 0165 0156 33'

for i in ques.split(' '):
    if len(i) > 4:
        sys.stdout.write(chr(int(i, 2)))
    elif len(i) > 2:
        if str(i)[0] == '0':
            sys.stdout.write(chr(int(i, 8)))
        else:
            sys.stdout.write(chr(int(i)))
    else:
        if str(i).isdigit() == True:
            sys.stdout.write(chr(int(i)))
        else:
            sys.stdout.write(chr(int(i, 16)))
Welcome to the SECCON 2014 online CTF.The SECCON is the biggest hacker contest in Japan.Oops, you want to know the flag, don't you?Here you are.SECCON{W31C0M 70 7H3 53CC0N ZOIA}Have fun!
SECCON{W31C0M 70 7H3 53CC0N ZOIA}

・Binary 200 Let's disassemble

ncで接続すると、バイナリ列が問題として渡されます。

アセンブルした結果を送ると、次の問題に進めるっぽいです。

何度か試してみたところ、x86じゃない模様。

SECCON・・・また変なアーキテクチャかー。と思いつついろいろなアーキテクチャを試してみると、

Z80であることが判明。ぜっぱち。。。

Z80の命令セットなんて知らないので、

8080/Z80 Instruction Set

スクレイピングして機械語アセンブリの対応表を作ることに。

また、byte、word、address、indexなどの可変部分がある場合は、正規表現でマッチすることに。

これらの対応表と正規表現リストを使って、問題に対して自動で応答するスクリプトを書きました。

以下、適当スクリプトです。

# 今回本当に本当に適当なので注意!!そのうちリファクタリングする! ←しない

問題が2つ。

1つめは、参考にしたWebサイトが非常にbuggyだったこと。10箇所以上誤りがありました。

2つめは、インデックスレジスタの扱い方が不明だったこと。

どちらも

ODA - The Online Disassembler

で解決しました。

ミスった問題を都度、手動でODAに投げ、結果を確認して修正していきました。

100ラウンド分問題を解くとFLAGが。地味に長かったー。

# インデックスレジスタオペランド中の増分については、

# 0x00~0x7Fまでの範囲はそのまま、0x80~0xFFまでの範囲は-128~-1に対応していました。

# 他のオペランドと違い、10進数で表記するので注意が必要でした。

SECCON{I love Z80. How about you?}
うん、ちょっとだけZ80、好きになれたかも。


・Crypt 200 Decrypt it (Easy)

解いていたチームの方から、バイナリっぽいとのことで依頼が。

実行ファイルrndで暗号化しているようなので、rndを読んで復号するプログラムを書きました。

srand(time(0))が呼ばれているけれど、ファイルの作成日時から狙い撃ちできるので、問題なしです!

# 一応前後30秒の範囲でブルートフォースするつもりでした。

以下、適当プログラム。

復号すると、下のようなPNGファイルになります。

ここまででバイナリ屋さんとしての仕事は果たせたようなので、

チームの方にお戻ししました!

* *


全体を通して、とても楽しめたと思います。

個人的には、前半バイナリ問題がない時間が長かったので、

バイナリ問題がもうちょっと早い段階から出ていて、もう一問くらいあると嬉しかったですねー。


チームの順位は惜しくも全国出場を逃した感じだったので、

英語のオンライン予選と地方大会で楽しもうと思います!



それでは、また〜。

SECCON 2014 CTF オンライン予選 write-up

SECCON 2014 CTFのオンライン予選にとあるチームのバイナリ担当として参加してきました!

とりあえず、解いた問題のwrite-upを書こうかと思いますー。



・バイナリ100 x86アセンブラを読もう

タイトル通りで読むだけの問題でした。ざっと読んだら、適当にPythonのコードにして実行して、

はい、おしまい♪

#!/usr/bin/env python

#-*- coding:utf-8 -*-

def test01361000(arg1):
    ebp4 = 0 
    ebp8 = 1 

    while ebp8 <= arg1:
        ebp4 += ebp8
        ebp8 += 1

    return ebp4 - 2 

def main():
    arg1 = 255 
    ret = test01361000(arg1)
    print "FLAG{%d}" % ret 

main()
FLAG{32638}



・プログラミング100 重ねてみよう

gifファイルだったので、とりあえず画像に分解しようと思ってプレビュー.appで開いていたら、

チームの人が

http://gif-explode.com/

を使って分解してアップロードしてくれてました!

あとは重ねるスクリプトを書くだけ。

白黒画像なのでなにも考えずに既存のコマンドを使えて、簡単でした。

以下、適当スクリプトです。

#!/bin/sh

convert -average 1.png 2.png result.png
for i in `seq 3 49`
do
    convert -average $i.png result.png result.png
    convert result.png -threshold 10000 result.png
done

できた画像

f:id:harukakka_r9:20140722140934p:plain

QRコードリーダーで読み取って、終わりっ

ちょっと欠けてて読めない場合もあるって話を聞いたけど、どうなんだろ?

FLAG{Many dot makes a QR code}



・バイナリ300 ダンプを追え!

dump.binはdata、encrypt.nmはどうやらnmコマンドの実行結果を記録したものみたい。

dump.binをバイナリエディタで読んでみると、V850の文字列が。

検索すると、NECマイコンのようです。

とりあえずIDA Proでは開けなそうだった(←実はいけたらしいです...泣)ので、

binutilsNEC V850向けにコンパイル

# v850-nec-elf-objdump -D -b binary -mv850 dump.bin

とかやって、encrypt.nmを見ながら逆アセしたものを読んでいく。

命令セットリファレンスはこれ。 → http://www17.tok2.com/home/taro/U10243JJ7V0UM00.pdf

00001546 T _proc → FLAGをごにょごにょ
000015a0 T _main → メモリダンプをとってる

00001546 T _procのなかみを少し真面目に読んでいくと、

5692番地(dump上では0x23c)からの16バイトがFLAGをprocessしたものらしい。

XORなので、アルゴリズムを読んでPythonに直して実行すればOK。

以下、適当スクリプトです。

# r12レジスタの中身は追うのが面倒だったのでブルートフォースしました。

import sys

# key = '63 17 86 d8 34 f9 06 8c 9b 80 9d 96 d7 da df 92'.split()
key = '99 23 134 216 52 249 6 140 155 128 157 150 215 218 223 146'.split()

r14 = 16
for r12 in range(255):
    print str(r12) + ':'
    r13 = 0
    while r13 < r14:
        try:
            ret = int(key[r13]) ^ r12
        except:
            continue
        r13 += 1
        r12 += r12
        r12 += 17
        sys.stdout.write(chr(ret))
        r12 &= 255
    print ''
FLAG{Victory850}
(r12=37のとき表示)

#でコメントアウトした部分が競技中のミス。

16進数値をそのまま10進数値みたいに書いちゃった...。

スクリプトを書き上げた時点で終了10分前。

時間ギリギリだったのでミスに気付けずに、FLAGは取れず。

終わってすぐ気付いたときの悔しさといったら...!

ブルートフォースのためにひどい例外処理をしたのも一因なので、

やっぱりめんどうくさがらずにちゃんと読めばよかったですねー。

あんまりにもあんまりなミスなので、次は絶対に繰り返しません!

* *


全体を通して、とても楽しめたと思います。

個人的には、前半バイナリ問題がない時間が長かったので、

バイナリ問題がもうちょっと早い段階から出ていて、もう一問くらいあると嬉しかったですねー。


チームの順位は惜しくも全国出場を逃した感じだったので、

英語のオンライン予選と地方大会で楽しもうと思います!



それでは、また〜。