Off by one overflow
基本信息
仅具有1字节溢出的访问权限允许攻击者修改下一个块的size
字段。这允许篡改实际上被释放的块,可能生成包含另一个合法块的块。利用类似于双重释放或重叠块。
有两种类型的off by one漏洞:
任意字节:这种类型允许用任何值覆盖该字节
空字节(off-by-null):这种类型只允许用0x00覆盖该字节
这种漏洞的一个常见示例可以在以下代码中看到,其中
strlen
和strcpy
的行为不一致,这允许在下一个块的开头设置一个0x00字节。这可以利用House of Einherjar。
如果使用Tcache,这可以被利用为双重释放情况。
在其他检查之外,现在每当一个块被释放时,都会将前一个大小与元数据块中配置的大小进行比较,从2.28版本开始,这使得这种攻击变得相当复杂。
代码示例:
由于使用了 Tcaches,此攻击不再起作用。
此外,如果尝试使用更大的块来滥用它(以便不涉及 tcaches),则会出现错误:
malloc(): invalid next size (unsorted)
目标
使一个块被包含在另一个块内,因此对第二个块的写访问允许覆盖包含的块
要求
利用 off-by-one 溢出来修改大小元数据信息
一般的 off-by-one 攻击
分配三个块
A
、B
和C
(假设大小为 0x20),另外再分配一个块以防止与顶部块合并。释放
C
(插入到 0x20 Tcache 空闲列表中)。使用块
A
对B
进行溢出。滥用 off-by-one 将B
的size
字段从 0x21 修改为 0x41。现在我们有
B
包含了空闲块C
释放
B
并分配一个 0x40 块(它将再次放置在这里)我们可以修改仍然空闲的
C
的fd
指针(Tcache 污染)
Off-by-null 攻击
依次保留三个内存块(a、b、c)。然后释放中间的块。第一个块包含一个 off by one 溢出漏洞,攻击者利用它使用 0x00(如果前一个字节是 0x10,则会使中间块指示它比实际小 0x10)。
然后,在中间释放的块(b)中分配了另外两个较小的块,但是由于
b + b->size
从未更新 c 块,因为指向的地址比应该的小。然后,b1 和 c 被释放。由于
c - c->prev_size
仍然指向 b(现在是 b1),两者被合并为一个块。但是,b2 仍然在 b1 和 c 之间。最后,执行新的 malloc 以重新获取这块内存区域,实际上将包含 b2,从而允许新 malloc 的所有者控制 b2 的内容。
这张图片完美解释了这次攻击:
其他示例和参考资料
由于
strlen
考虑到下一个块的size
字段,发生 off-by-one。正在使用 Tcache,因此一般的 off-by-one 攻击可用于通过 Tcache 污染获得任意写入原语。
可以滥用 off by one 来从堆中泄漏地址,因为字符串末尾的字节 0x00 被下一个字段覆盖。
通过滥用 off by one 写入来获得任意写入,使指针指向将构建具有虚假指针的虚假结构的另一个位置成为可能。然后,可以跟随此结构的指针以获得任意写入。
泄漏 libc 地址是因为如果使用 mmap 扩展堆,则由 mmap 分配的内存与 libc 有固定的偏移量。
最后,滥用任意写入将写入到 __free_hook 地址的一个单个小工具。
在
getline
函数中存在一个 NULL off by one 漏洞,用于读取用户输入行。此函数用于读取内容的“键”,而不是内容。在 writeup 中创建了 5 个初始块:
chunk1(0x200)
chunk2(0x50)
chunk5(0x68)
chunk3(0x1f8)
chunk4(0xf0)
chunk defense(0x400)以避免与顶部块合并
然后释放了 chunk 1、5 和 3,因此:
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
Last updated