|
1 |
| -# zero to hero - 500 |
| 1 | +# zero to hero |
| 2 | +**Category:** Binary Exploitation |
2 | 3 |
|
3 |
| -## Description |
| 4 | +**Points:** 500 |
| 5 | + |
| 6 | +**Description:** |
4 | 7 | Now you're really cooking. Can you pwn [this]() service?. Connect with `nc 2019shell1.picoctf.com 49928`. [libc.so.6]() [ld-2.29.so]()
|
5 | 8 |
|
6 |
| -## Analysis |
7 |
| -The binary uses glibc version 2.29, which patches the double free vulnerability. |
| 9 | +---------- |
8 | 10 |
|
9 |
| -## Solution |
10 | 11 | We are given the libc base address, so no leaks are needed. All we have to do is get a write.
|
11 | 12 |
|
12 |
| -### House of Poortho |
| 13 | +The issue is that the binary uses libc 2.29, which patches the double free vulnerability (or does it? :o). |
13 | 14 |
|
14 |
| -The vulnerability is that read() overwrites the first byte of the next chunk header with a null byte. If the next chunk has a size header with least significant byte not equal to 0x00, the size of the next chunk changes. |
| 15 | +Googling common exploits in libc 2.29 didn't help because they involved the use of unsorted bin and/or fastbin, and the checks on chunk size and slot count restricted allocations to tcache. |
15 | 16 |
|
16 |
| -``` |
17 |
| - +-------------------+------------------+ |
18 |
| -current | ... | 0x51 | |
19 |
| - +--------------------------------------+ |
20 |
| - | ... | |
21 |
| - +-------------------+------------------+ |
22 |
| - next | ... | 0x171 | |
23 |
| - +--------------------------------------+ |
24 |
| - | ... | |
25 |
| - +--------------------------------------+ |
26 |
| -``` |
27 |
| -*Before null byte overflow* |
| 17 | +The vulnerability is that read() overwrites the first byte of the next chunk header with a null byte. By asking for a chunk divisible by 0x8 but not 0x10 and triggering the vuln, the size of the next chunk changes. When the next chunk is freed again, it will be placed into a separate tcache bin, and the double free patch only checks for chunks within the same list. |
| 18 | + |
| 19 | +Everything is self-explanatory from here. Once we get double free, we overwrite `__free_hook` with the win function. |
| 20 | + |
| 21 | +------------ |
| 22 | + |
| 23 | +I was under the assumption that chunk headers were 16 bytes long, and chunk size was at offset 8, so the null byte overrun wouldn't do anything. It turns out that this was false. When the previous chunk is in use, the chunk header is actually 8 bytes. |
28 | 24 |
|
29 | 25 | ```
|
30 |
| - +-------------------+------------------+ |
31 |
| -current | ... | 0x51 | |
32 |
| - +--------------------------------------+ |
33 |
| - | AAAAAAAA | |
34 |
| - +-------------------+------------------+ |
35 |
| - next | AAAAAAAA | 0x100 | |
36 |
| - +--------------------------------------+ |
37 |
| - | ... | |
38 |
| - +--------------------------------------+ |
| 26 | + +-------------------+------------------+ |
| 27 | +-0x010 | data in previous chunk | |
| 28 | + +-------------------+------------------+ |
| 29 | + 0x000 | prev data/padding | 0x171 | |
| 30 | + +--------------------------------------+ |
| 31 | + | ... | |
| 32 | + +--------------------------------------+ |
| 33 | ++0x170 | next chunk | |
| 34 | + +--------------------------------------+ |
39 | 35 | ```
|
40 |
| -*After null byte overflow* |
41 | 36 |
|
42 |
| -Assuming that we have freed the next chunk already, when it is freed again, it will be placed into a separate tcache bin, bypassing the double free patch (which only checks for chunks within the same bin). From here, we can control the `fd` pointer of the tcache chunk, doing a standard [tcache poisoning](https://github.com/shellphish/how2heap/blob/master/glibc_2.26/tcache_poisoning.c) to overwrite `__free_hook` with the win function. |
| 37 | +Then what about the size of the previous chunk that the heap manager uses to find the previous chunk header during forward consolidation? |
| 38 | + |
| 39 | +This only applies when the previous-in-use flag is 0. |
| 40 | +Since the heap manager owns the previous chunk, it can store the size of the previous chunk at the end of the chunk data when the previous chunk is freed. |
| 41 | +In short, the chunk header is applicable only when the previous-in-use flag is 0. |
43 | 42 |
|
44 |
| -Using a single null byte overflow to bypass the new double free protections in glibc 2.29 is a novel exploit. As common with binary exploitation techniques, naming rights go to the person the challenge author. Thus, we would like to refer to this as the House of Poortho, in honor of the problem creator. |
| 43 | +``` |
| 44 | + +-------------------+------------------+ |
| 45 | +-0x010 | data in previous chunk | |
| 46 | + +-------------------+------------------+ |
| 47 | + 0x000 | prev chunk size | 0x170 | |
| 48 | + +--------------------------------------+ |
| 49 | + | ... | |
| 50 | + +--------------------------------------+ |
| 51 | ++0x170 | next chunk | |
| 52 | + +--------------------------------------+ |
| 53 | +``` |
0 commit comments