off-by-one

单字节缓冲区溢出

Maybe in:

  • 使用循环语句向堆块中写入数据时,循环的次数设置错误
  • 字符串操作不合适

off-by-one是可以基于各种缓冲区的,比如堆、栈、bss段等,在堆上比较常见

详见:堆中的 Off-By-One - CTF Wiki


利用手法:

  1. 控制溢出字节:修改大小造成块结构之间出现重叠,从而泄漏其它块数据,或是覆盖其它块数据
  2. 溢出NULL字节:使得pre_inuse被清,这样前块会被认为是free块
    1. 这时可以用unlink方法
    2. prev_size域启用,可以伪造prev_size,从而造成块之间发生重叠,此方法的关键在于unlink的时候没有检查按照prev_size找到的块大小是否与prev_size一致
    • 新版本已经加入针对2.2的check,在2.28以及以前版本没有该check

ctfshow 142

修改free_got表

no pie

远程:ubuntu18.04

思路:
利用off-by-one控制堆块(改写堆块大小)
进而
劫持got表,got表是可写的!

根据题目,堆内存的读写依赖于堆块之间的指针链接
有edit() add() delete() show() 函数

通过off-by-one改写堆块大小,我们可以

  • 根据我们想要的指针链接方式重新释放(改变了tcachebin的大小)、申请堆块
  • 覆盖下一个堆块的内容

因为show()函数是根据堆块指针打印内容的
我们可以覆盖下一个堆块时修改存储指针的内存区域为free_got表地址,打印泄露出free()函数地址

  1. 可以计算出系统调用地址sys_addr
  2. 改变了heapContent指针指向,指向了free_got表!!

而edit()函数也依赖于堆块指针
我们便可以修改free的got表!!
sys_addr写入free的got表 => 调用free = 调用sys_addr

接下来,
我们可以找个堆块,”free”掉指向heapContent的指针
这个”free”其实是sys,heapContent指针指向字符串参数’/bin/sh\x00’
(只需写入heapContent的内容为’/bin/sh\x00’即可)

1
2
3
4
typedef struct {
size_t size;
size_t* heapContent;
}MyHeap;

off-by-one
http://example.com/2025/03/27/off-by-one/
作者
yvyvSunlight
发布于
2025年3月27日
许可协议