Off by one overflow
Reading time: 7 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
基本信息
仅仅访问 1B 溢出允许攻击者修改下一个块的 size
字段。这允许篡改哪些块实际上被释放,从而可能生成一个包含另一个合法块的块。该利用方式类似于 double free 或重叠块。
有两种类型的 off by one 漏洞:
- 任意字节:这种类型允许用任何值覆盖该字节
- 空字节(off-by-null):这种类型仅允许用 0x00 覆盖该字节
- 这种漏洞的一个常见示例可以在以下代码中看到,其中
strlen
和strcpy
的行为不一致,这允许在下一个块的开头设置一个 0x00 字节。 - 这可以通过 House of Einherjar 进行利用。
- 如果使用 Tcache,这可以被利用为 double free 情况。
Off-by-null
c
// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/
int main(void)
{
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
}
在其他检查中,现在每当一个块被释放时,都会将前一个大小与元数据块中配置的大小进行比较,这使得从版本2.28开始,这种攻击相当复杂。
代码示例:
- https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c
- 由于使用了Tcaches,这种攻击不再有效。
- 此外,如果您尝试使用更大的块进行滥用(因此不涉及tcaches),您将收到错误:
malloc(): invalid next size (unsorted)
目标
- 使一个块包含在另一个块内,因此对第二个块的写入访问允许覆盖包含的块
要求
- 通过一个溢出修改大小元数据的信息
一般的越界攻击
- 分配三个块
A
、B
和C
(假设大小为0x20),以及另一个块以防止与顶块合并。 - 释放
C
(插入到0x20 Tcache空闲列表中)。 - 使用块
A
溢出到B
。利用越界修改B
的size
字段从0x21变为0x41。 - 现在我们有
B
包含空闲块C
- 释放
B
并分配一个0x40的块(它将再次放置在这里) - 我们可以修改
C
的fd
指针,它仍然是空闲的(Tcache中毒)
越界空指针攻击
- 3个内存块(a、b、c)依次保留。然后释放中间的一个。第一个块包含一个越界溢出漏洞,攻击者利用它写入0x00(如果前一个字节是0x10,它将使中间块指示它比实际小0x10)。
- 然后,在中间释放的块(b)中分配两个更小的块,但是,由于
b + b->size
从未更新 c 块,因为指向的地址小于它应该的值。 - 然后,b1和c被释放。由于
c - c->prev_size
仍然指向 b(现在是 b1),两者合并为一个块。然而,b2仍然在 b1 和 c 之间。 - 最后,执行新的 malloc,回收这个内存区域,实际上将包含 b2,允许新 malloc 的所有者控制 b2 的内容。
这张图片完美地解释了攻击:
其他示例与参考
- https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
- Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
- 由于
strlen
考虑下一个块的size
字段而导致的越界。 - 正在使用 Tcache,因此一般的越界攻击可以通过 Tcache 中毒获得任意写入原语。
- Asis CTF 2016 b00ks
- 可以利用越界泄漏堆中的地址,因为字符串末尾的字节0x00被下一个字段覆盖。
- 通过滥用越界写入获得任意写入,指针指向另一个地方,在那里将构建一个带有假指针的假结构。然后,可以跟随该结构的指针以获得任意写入。
- libc 地址被泄漏,因为如果使用 mmap 扩展堆,则 mmap 分配的内存与 libc 之间有固定的偏移量。
- 最后,滥用任意写入将写入 __free_hook 的地址,使用一个 gadget。
- plaidctf 2015 plaiddb
- 在读取用户输入行的
getline
函数中存在一个 NULL 越界漏洞。此函数用于读取内容的“密钥”,而不是内容。 - 在写作中创建了5个初始块:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- 块防御 (0x400) 以避免与顶块合并
- 然后释放块1、5和3,因此:
-
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- 然后滥用块3 (0x1f8),越界空指针被滥用,将 prev_size 写入 `0x4e0`。
- 注意最初分配的块1、2、5和3的大小加上这4个块的头部等于 `0x4e0`:`hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- 然后,释放块4,生成一个消耗所有块直到开头的块:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]