チーム Harekaze で Pwn2Win CTF 2017 に参加しました。最終的にチームで 988 点を獲得し、順位は得点 207 チーム中 40 位でした。うち、私は 7 問を解いて 988 点を入れました。
以下、解いた問題の write-up です。
achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf
という 1.09 MB ほどのサイズのファイルが与えられました。file
に投げてどのようなファイルか確認しましょう。
$ file ./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf
./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
stripped かつ statically linked な x86_64 の ELF のようです。実行してみましょう。
$ ./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf
Flag: hoge
Wrong!
フラグの入力を求められました。Wrong!
の位置を調べておいて、バイナリ中で参照されている部分を探してみましょう。
$ 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.
>>> with open('./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf', 'rb') as f:
... print hex(f.read().index('Wrong!'))
...
0xb2e91
$ objdump -d -M intel ./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf
...
4851f6: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18]
4851fb: 48 8b 4c 24 10 mov rcx,QWORD PTR [rsp+0x10]
485200: 48 89 0c 24 mov QWORD PTR [rsp],rcx
485204: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
485209: e8 b2 f7 ff ff call 0x4849c0
48520e: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18]
485213: 48 8b 4c 24 10 mov rcx,QWORD PTR [rsp+0x10]
485218: 48 83 f8 1e cmp rax,0x1e
48521c: 0f 84 9d 00 00 00 je 0x4852bf
485222: 48 8d 05 68 dc 02 00 lea rax,[rip+0x2dc68] # 0x4b2e91 ("Wrong!")
485229: 48 89 84 24 80 00 00 mov QWORD PTR [rsp+0x80],rax
485230: 00
485231: 48 c7 84 24 88 00 00 mov QWORD PTR [rsp+0x88],0x6
485238: 00 06 00 00 00
48523d: 48 c7 84 24 90 00 00 mov QWORD PTR [rsp+0x90],0x0
485244: 00 00 00 00 00
485249: 48 c7 84 24 98 00 00 mov QWORD PTR [rsp+0x98],0x0
485250: 00 00 00 00 00
485255: 48 8d 05 64 00 01 00 lea rax,[rip+0x10064] # 0x4952c0
48525c: 48 89 04 24 mov QWORD PTR [rsp],rax
485260: 48 8d 84 24 80 00 00 lea rax,[rsp+0x80]
485267: 00
485268: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
48526d: e8 fe 66 f8 ff call 0x40b970
...
gdb で 0x485218
にブレークポイントを設定して実行し、hoge
を入力すると rax の値は 4
になっていました。また、hogege
を入力すると rax の値は 6
になっていました。どうやらフラグの文字数は 30 文字のようです。
入力した文字数が 30 文字だった場合の処理を見ていきましょう。
4852bf: 48 89 0c 24 mov QWORD PTR [rsp],rcx
4852c3: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
4852c8: e8 13 f9 ff ff call 0x484be0
4852cd: 0f b6 44 24 10 movzx eax,BYTE PTR [rsp+0x10]
4852d2: 84 c0 test al,al
4852d4: 74 7a je 0x485350
4852d6: 48 8d 05 ff fd 02 00 lea rax,[rip+0x2fdff] # 0x4b50dc ("Achievement Unlocked!")
4852dd: 48 89 44 24 60 mov QWORD PTR [rsp+0x60],rax
4852e2: 48 c7 44 24 68 15 00 mov QWORD PTR [rsp+0x68],0x15
4852e9: 00 00
4852eb: 48 c7 44 24 70 00 00 mov QWORD PTR [rsp+0x70],0x0
4852f2: 00 00
4852f4: 48 c7 44 24 78 00 00 mov QWORD PTR [rsp+0x78],0x0
4852fb: 00 00
4852fd: 48 8d 05 bc ff 00 00 lea rax,[rip+0xffbc] # 0x4952c0
485304: 48 89 04 24 mov QWORD PTR [rsp],rax
485308: 48 8d 44 24 60 lea rax,[rsp+0x60]
48530d: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
485312: e8 59 66 f8 ff call 0x40b970
485317: 48 8b 44 24 10 mov rax,QWORD PTR [rsp+0x10]
48531c: 48 8b 4c 24 18 mov rcx,QWORD PTR [rsp+0x18]
485321: 48 89 44 24 70 mov QWORD PTR [rsp+0x70],rax
485326: 48 89 4c 24 78 mov QWORD PTR [rsp+0x78],rcx
48532b: 48 8d 44 24 70 lea rax,[rsp+0x70]
485330: 48 89 04 24 mov QWORD PTR [rsp],rax
485334: 48 c7 44 24 08 01 00 mov QWORD PTR [rsp+0x8],0x1
48533b: 00 00
48533d: 48 c7 44 24 10 01 00 mov QWORD PTR [rsp+0x10],0x1
485344: 00 00
485346: e8 65 81 ff ff call 0x47d4b0
48534b: e9 5f ff ff ff jmp 0x4852af
485350: 48 8d 05 3a db 02 00 lea rax,[rip+0x2db3a] # 0x4b2e91 ("Wrong!")
485357: 48 89 44 24 40 mov QWORD PTR [rsp+0x40],rax
48535c: 48 c7 44 24 48 06 00 mov QWORD PTR [rsp+0x48],0x6
485363: 00 00
485365: 48 c7 44 24 50 00 00 mov QWORD PTR [rsp+0x50],0x0
48536c: 00 00
48536e: 48 c7 44 24 58 00 00 mov QWORD PTR [rsp+0x58],0x0
485375: 00 00
485377: 48 8d 05 42 ff 00 00 lea rax,[rip+0xff42] # 0x4952c0
48537e: 48 89 04 24 mov QWORD PTR [rsp],rax
485382: 48 8d 44 24 40 lea rax,[rsp+0x40]
485387: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
48538c: e8 df 65 f8 ff call 0x40b970
...
0x484be0
を呼んだ結果が 0 であれば Wrong!
を、そうでなければ Achievement Unlocked!
を出力しています。0x484be0
を見ていきましょう。
484be0: 64 48 8b 0c 25 f8 ff mov rcx,QWORD PTR fs:0xfffffffffffffff8
484be7: ff ff
484be9: 48 8d 84 24 e0 fe ff lea rax,[rsp-0x120]
484bf0: ff
484bf1: 48 3b 41 10 cmp rax,QWORD PTR [rcx+0x10]
484bf5: 0f 86 9d 04 00 00 jbe 0x485098
484bfb: 48 81 ec a0 01 00 00 sub rsp,0x1a0
484c02: 48 89 ac 24 98 01 00 mov QWORD PTR [rsp+0x198],rbp
484c09: 00
484c0a: 48 8d ac 24 98 01 00 lea rbp,[rsp+0x198]
484c11: 00
484c12: 48 8d 05 e7 fb 00 00 lea rax,[rip+0xfbe7] # 0x494800
484c19: 48 89 04 24 mov QWORD PTR [rsp],rax
484c1d: 48 c7 44 24 08 00 00 mov QWORD PTR [rsp+0x8],0x0
484c24: 00 00
484c26: e8 f5 e7 f7 ff call 0x403420
...
484d30: 48 8b 6d 00 mov rbp,QWORD PTR [rbp+0x0]
484d34: 31 c9 xor ecx,ecx
484d36: ba 01 00 00 00 mov edx,0x1
484d3b: 48 89 4c 24 40 mov QWORD PTR [rsp+0x40],rcx
484d40: 88 54 24 35 mov BYTE PTR [rsp+0x35],dl
484d44: 48 8b 9c 24 b0 01 00 mov rbx,QWORD PTR [rsp+0x1b0]
484d4b: 00
484d4c: 48 39 d9 cmp rcx,rbx
484d4f: 0f 8d 2c 03 00 00 jge 0x485081
484d55: 48 8b b4 24 a8 01 00 mov rsi,QWORD PTR [rsp+0x1a8]
484d5c: 00
484d5d: 0f b6 3c 0e movzx edi,BYTE PTR [rsi+rcx*1]
484d61: 40 88 7c 24 37 mov BYTE PTR [rsp+0x37],dil
484d66: 48 8b bc 24 50 01 00 mov rdi,QWORD PTR [rsp+0x150]
484d6d: 00
484d6e: 48 89 7c 24 08 mov QWORD PTR [rsp+0x8],rdi
484d73: 48 8d 3d 86 fa 00 00 lea rdi,[rip+0xfa86] # 0x494800
484d7a: 48 89 3c 24 mov QWORD PTR [rsp],rdi
484d7e: 4c 8d 44 24 37 lea r8,[rsp+0x37]
484d83: 4c 89 44 24 10 mov QWORD PTR [rsp+0x10],r8
484d88: e8 43 e9 f7 ff call 0x4036d0
484d8d: 31 c0 xor eax,eax
484d8f: 48 89 44 24 38 mov QWORD PTR [rsp+0x38],rax
484d94: 48 83 f8 08 cmp rax,0x8
484d98: 7d 50 jge 0x484dea
484d9a: 48 8b 4c 24 40 mov rcx,QWORD PTR [rsp+0x40]
484d9f: 48 8d 14 c8 lea rdx,[rax+rcx*8]
484da3: 48 81 fa f0 00 00 00 cmp rdx,0xf0
484daa: 0f 83 ca 02 00 00 jae 0x48507a
484db0: 48 8d 54 14 58 lea rdx,[rsp+rdx*1+0x58]
484db5: 48 89 54 24 10 mov QWORD PTR [rsp+0x10],rdx
484dba: 48 8d 15 3f fa 00 00 lea rdx,[rip+0xfa3f] # 0x494800
484dc1: 48 89 14 24 mov QWORD PTR [rsp],rdx
484dc5: 48 8b 9c 24 48 01 00 mov rbx,QWORD PTR [rsp+0x148]
484dcc: 00
484dcd: 48 89 5c 24 08 mov QWORD PTR [rsp+0x8],rbx
484dd2: e8 f9 e8 f7 ff call 0x4036d0
484dd7: 48 8b 44 24 38 mov rax,QWORD PTR [rsp+0x38]
484ddc: 48 ff c0 inc rax
484ddf: 48 89 44 24 38 mov QWORD PTR [rsp+0x38],rax
484de4: 48 83 f8 08 cmp rax,0x8
484de8: 7c b0 jl 0x484d9a
484dea: c6 44 24 36 00 mov BYTE PTR [rsp+0x36],0x0
484def: 48 8b 84 24 90 01 00 mov rax,QWORD PTR [rsp+0x190]
484df6: 00
484df7: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
484dfc: 48 8d 05 fd f9 00 00 lea rax,[rip+0xf9fd] # 0x494800
484e03: 48 89 04 24 mov QWORD PTR [rsp],rax
484e07: 48 8d 4c 24 36 lea rcx,[rsp+0x36]
484e0c: 48 89 4c 24 10 mov QWORD PTR [rsp+0x10],rcx
484e11: e8 5a f8 f7 ff call 0x404670
484e16: 0f b6 44 24 36 movzx eax,BYTE PTR [rsp+0x36]
484e1b: 48 8b 4c 24 40 mov rcx,QWORD PTR [rsp+0x40]
484e20: 48 85 c9 test rcx,rcx
484e23: 75 1c jne 0x484e41
484e25: 48 3d d0 00 00 00 cmp rax,0xd0
484e2b: 74 14 je 0x484e41
484e2d: 31 c0 xor eax,eax
484e2f: 48 ff c1 inc rcx
484e32: 89 c2 mov edx,eax
484e34: 48 8b 84 24 48 01 00 mov rax,QWORD PTR [rsp+0x148]
484e3b: 00
484e3c: e9 fa fe ff ff jmp 0x484d3b
484e41: 48 83 f9 01 cmp rcx,0x1
484e45: 75 0a jne 0x484e51
484e47: 48 83 f8 71 cmp rax,0x71
484e4b: 74 04 je 0x484e51
484e4d: 31 c0 xor eax,eax
484e4f: eb de jmp 0x484e2f
484e51: 48 83 f9 02 cmp rcx,0x2
484e55: 75 0c jne 0x484e63
484e57: 48 3d e6 00 00 00 cmp rax,0xe6
484e5d: 74 04 je 0x484e63
484e5f: 31 c0 xor eax,eax
484e61: eb cc jmp 0x484e2f
484e63: 48 83 f9 03 cmp rcx,0x3
484e67: 75 0a jne 0x484e73
484e69: 48 83 f8 32 cmp rax,0x32
484e6d: 74 04 je 0x484e73
484e6f: 31 c0 xor eax,eax
484e71: eb bc jmp 0x484e2f
...
入力した文字列を何かしてから、ループのカウンターが 1 であれば何かされた文字と 0x71
と比較、2 であれば 0xe6
と比較、3 であれば 0x32
と比較 … ということを繰り返しています。
以下のようなスクリプトを key.py
として保存して実行してみます。
plaintext = 'A' * 30
encrypted = ''
def xor(s, t):
return ''.join(chr(ord(c) ^ ord(d)) for c, d in zip(s, t))
class MyBreakpoint(gdb.Breakpoint):
def stop(self):
global encrypted
encrypted += chr(gdb.parse_and_eval('$rax'))
return False
with open('input', 'w') as f:
f.write(plaintext)
MyBreakpoint('*0x484e41')
gdb.execute('r < input')
print repr(xor(plaintext, encrypted))
gdb.execute('q')
$ gdb -n -x key.py ./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf
Reading symbols from ./achievementunlocked_088a2d785c35acaed6cdf64afff1ecceb649690d9a4175ae6e6a7645bd1f3bbf...(no debugging symbols found)...done.
Breakpoint 1 at 0x484e41
Flag: Wrong!
[Inferior 1 (process 4256) exited normally]
'%\xa0\x1fMhry\x90\x90\xf5:\x81\xfc6-\x06\xf7|\xe6\x83F/\x9e@\x05\xb1\xb0\xea-'
plaintext = 'A' * 30
を plaintext = 'B' * 30
に変えてみても同じ結果が得られました。どうやら xor を使っているようです。
比較されている値を集めて xor してみましょう。
def xor(s, t):
return ''.join(chr(ord(c) ^ ord(d)) for c, d in zip(s, t))
print xor('\x71\xe6\x32\x0f\x3a\x09\x2e\xf8\xa1\xb6\x52\xde\xcd\x65\x72\x52\x9f\x4f\xb9\xf4\x72\x76\xc1\x34\x35\xee\xf7\xda\x50', '%\xa0\x1fMhry\x90\x90\xf5:\x81\xfc6-\x06\xf7|\xe6\x83F/\x9e@\x05\xb1\xb0\xea-')
$ python solve.py
TF-BR{Wh1Ch_1S_Th3_w4Y_t0_G0}
最初の 1 文字が消えてしまっていますがフラグが得られました。
CTF-BR{Wh1Ch_1S_Th3_w4Y_t0_G0}
問題サーバの接続情報が与えられました。接続してみましょう。
$ nc 200.136.213.143 9999
Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
1
You can query the flag, but the characters are private (indistinguishable).
Differential privacy mechanism: Laplace
Sensitivity: ||125 - 45|| = 80
Epsilon: 6.5
Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
2
[59, 95, 79, 45, 77, 88, 134, 36, 93, 95, 127, 85, 97, 122, 101, 104, 118, 111, 106, 109, 93, 97, 86, 115, 118, 101, 111, 112, 95, 101, 97, 112, 115, 106, 125, 85, 117]
Hello, chose an option:
[1] Info
[2] Query the flag (in ASCII)
[3] Quit
3
何度か接続し直してみましょう。
[59, 107, 97, 46, 61, 77, 172, 77, 96, 97, 96, 99, 107, 109, 127, 124, 88, 146, 119, 101, 117, 98, 95, 106, 100, 105, 130, 139, 114, 95, 89, 118, 90, 105, 106, 105, 102]
[62, 83, 49, 23, 35, 60, 143, 43, 78, 149, 124, 79, 88, 103, 141, 113, 98, 74, 106, 125, 146, 94, 123, 109, 86, 104, 105, 106, 118, 82, 115, 124, 58, 98, 110, 89, 126]
[73, 91, 92, 37, 55, 137, 116, 71, 93, 91, 80, 71, 100, 135, 79, 120, 71, 87, 98, 77, 120, 110, 117, 100, 132, 82, 93, 121, 105, 88, 111, 80, 114, 111, 99, 98, 116]
[72, 64, 56, 43, 50, 79, 122, 61, 109, 91, 119, 89, 87, 93, 110, 109, 110, 112, 97, 73, 119, 95, 96, 134, 121, 93, 99, 116, 81, 84, 70, 111, 109, 90, 116, 107, 102]
[87, 49, 92, 35, 87, 89, 124, 44, 88, 88, 74, 95, 101, 135, 141, 138, 102, 98, 96, 109, 140, 101, 134, 102, 101, 94, 93, 100, 97, 111, 102, 124, 93, 104, 103, 95, 139]
毎回返ってくる結果が変わっています。これを集めて中央値を調べてみましょう。
import numpy as np
from pwn import *
res = []
for _ in range(500):
s = remote('200.136.213.143', 9999)
s.recvuntil('[3] Quit\n')
s.sendline('2')
res.append(eval(s.recvline()))
s.sendline('3')
s.close()
print ''.join(chr(int(np.median([a[i] for a in res]))) for i in range(len(res[0])))
$ python solve.py
...
BUE-BR{I`bm_juss_filueriog`the_noise~
それっぽい文字列が出てきました。意味が通るように少し直してみるとフラグが得られました。
CTF-BR{I_am_just_filtering_the_noise}
Now prove you were a good kid and show you learned the most basic lesson in CTFs!!
という問題文が与えられました。
CTF の紹介ページを眺めていると、ルールページの下部に以下のような文章が表示されていました。
For the first time, these tiny letters on the bottom of the screen are not a prank. \o/ if you got to this point, means that you probably read all our informations and instructions. And for that, we will award your team with extra points in the competition, after all, reading is FUNDAMENTAL for a competition like this. Use the flag “CTF-BR{RTFM_1s_4_g00d_3xpr3ss10n_v3.0}” on the challenge “Bonus” during the day of the event and guarantee your extra score! ;)
CTF-BR{RTFM_1s_4_g00d_3xpr3ss10n_v3.0}
大変に長い問題文が与えられました。ぼーっと眺めていると最終行に以下のような文章がありました。
Answer with ‘CTF-BR{mission_accepted}’ if you wish to help us!
CTF-BR{mission_accepted}
以下のようなソースコードが与えられました。
#include <stdio.h>
#include <limits.h>
#include <string.h>
typedef struct
{
char flag[SHRT_MAX+1];
char in[SHRT_MAX+1];
char sub[SHRT_MAX+1];
int n;
} player;
player p1;
void main()
{
FILE *fp = fopen("/home/hidden-program/flag","r");
memset(p1.flag,0,sizeof(p1.flag));
fscanf(fp,"%[^\n]",p1.flag);
fclose(fp);
while(1)
{
printf("Insert a short integer: ");
fflush(stdout);
scanf(" %d", &p1.n);
if(p1.n>SHRT_MAX)
printf("Invalid number\n\n");
else break;
}
p1.n = (short)abs((short)p1.n);
printf("Insert a string: ");
fflush(stdout);
scanf("%10000s",p1.in);
printf("Insert another string: ");
fflush(stdout);
scanf("%10000s",p1.sub);
if(strcmp(&p1.in[p1.n],p1.sub)==0) printf("Congratulations!! YOU WIN!!\n");
else
printf("\tYou lost!!!\n\
In the string %s the substring in the position %d is %s\n\
Try again...\n", p1.in, p1.n, &p1.in[p1.n]);
fflush(stdout);
}
Insert a short integer
で -32768
を入力するとフラグが得られました。
$ nc 200.136.213.126 1988
Insert a short integer: -32768
Insert a string: hoge
Insert another string: fuga
You lost!!!
In the string hoge the substring in the position -32768 is CTF-BR{Th1s_1S_4_50_5Imp13_C_exp1017_}
Try again...
CTF-BR{Th1s_1S_4_50_5Imp13_C_exp1017_}
与えられたソースコードを実行するとフラグが得られました。
CTF-BR{Congrats!_you_know_how_to_sum!}
Message.txt
というテキストファイルと StrangeCircuit.jpg
という画像が与えられました。
with open('Message.txt') as f:
s = f.read().replace('\n\n', '').splitlines()[1:]
for i, line in enumerate(s):
s[i] = [int(x) for x in line.replace(' ', '')]
res = [''] * 8
for i, line in enumerate(filter(lambda line: line[0] == 1, s)):
res[i % 8] += str(line[1] ^ 1) + str(line[2]) + str(line[3]) + str(line[4] ^ 1) + str(line[5] ^ 1) + str(line[6] ^ 1) + str(line[7]) + str(line[8])
print '\n'.join(res).replace('1', '#').replace('0', ' ')
$ python solve.py
###### ###### ##### ##### #### ## # ## ###### ## ###### ##### ## # # #### # # ###### # # #### ##### # # ##### ##
# ## # # # # # # # # # # # # ## # # # ## # # # # # ## # # # # # ## ## # #
# ## # #### # # # # # # # # # # # ## # # # # # # # # # # ## # # # # # # # # # # #
# ## ##### #### ##### #### # # # # # # # ## ##### # # # # # # # ## ## # # #### ##### # # # #### #
# ## # # # ## # # # # # ###### ## # ###### # ## # # # # ## # # ## # # # # #
###### ## # # # # # # ###### ## ###### # # ## # # # # # #### # # ###### ###### ###### # # # # # # #
# ##### # # ## # # ##### #### # # #### # # #### # # ##### ##### ##
フラグが得られました。
CTF-BR{LOCATE_AND_KILL_REMS}