Stack Canaries
Last updated
Last updated
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
StackGuard 在 EIP (扩展指令指针) 之前插入一个特殊值,称为 canary,具体为 0x000aff0d
(表示空值、换行符、EOF、回车)以防止缓冲区溢出。然而,像 recv()
、memcpy()
、read()
和 bcopy()
这样的函数仍然易受攻击,并且它不保护 EBP (基指针)。
StackShield 采用比 StackGuard 更复杂的方法,通过维护一个 全局返回栈,存储所有返回地址 (EIPs)。这种设置确保任何溢出不会造成伤害,因为它允许比较存储的和实际的返回地址以检测溢出发生。此外,StackShield 可以检查返回地址与边界值,以检测 EIP 是否指向预期数据空间之外。然而,这种保护可以通过 Return-to-libc、ROP(返回导向编程)或 ret2ret 等技术绕过,这表明 StackShield 也不保护局部变量。
-fstack-protector
:该机制在 EBP 之前放置一个 canary,并重新组织局部变量以将缓冲区放置在更高的内存地址,防止它们覆盖其他变量。它还安全地复制传递到局部变量上方的堆栈参数,并使用这些副本作为参数。然而,它不保护少于 8 个元素的数组或用户结构中的缓冲区。
canary 是从 /dev/urandom
派生的随机数或默认值 0xff0a0000
。它存储在 TLS (线程局部存储) 中,允许跨线程共享内存空间具有线程特定的全局或静态变量。这些变量最初从父进程复制,子进程可以在不影响父进程或兄弟进程的情况下更改其数据。然而,如果 fork()
在不创建新 canary 的情况下使用,所有进程(父进程和子进程)共享相同的 canary,使其易受攻击。在 i386 架构中,canary 存储在 gs:0x14
,在 x86_64 中,存储在 fs:0x28
。
这种本地保护识别具有易受攻击缓冲区的函数,并在这些函数的开始处注入代码以放置 canary,在结束时验证其完整性。
当 Web 服务器使用 fork()
时,它允许通过逐字节猜测 canary 字节进行暴力攻击。然而,在 fork()
后使用 execve()
会覆盖内存空间,从而消除攻击。vfork()
允许子进程在尝试写入之前执行而不进行复制,此时会创建一个副本,提供了一种不同的进程创建和内存处理方法。
在 x64
二进制文件中,canary cookie 是一个 0x8
字节的 qword。前七个字节是随机的,最后一个字节是 空字节。
在 x86
二进制文件中,canary cookie 是一个 0x4
字节的 dword。前三个字节是随机的,最后一个字节是 空字节。
两个 canary 的最低有效字节是空字节,因为它将是来自较低地址的堆栈中的第一个,因此 读取字符串的函数将在读取之前停止。
泄露 canary 然后用其自身的值覆盖它(例如,缓冲区溢出)。
如果 canary 在子进程中被 fork,可能可以逐字节 暴力破解 它:
如果二进制文件中存在一些有趣的 泄露或任意读取漏洞,可能可以泄露它:
覆盖堆栈存储指针
易受堆栈溢出影响的堆栈可能 包含可以被覆盖的字符串或函数地址,以利用该漏洞而无需到达堆栈 canary。检查:
Pointer Redirecting修改主 canary 和线程 canary
在受 canary 保护的线程函数中 缓冲区溢出 可以用来 修改线程的主 canary。因此,缓解措施是无效的,因为检查使用的是两个相同的 canary(尽管已被修改)。
此外,在受 canary 保护的线程函数中 缓冲区溢出 可以用来 修改存储在 TLS 中的主 canary。这是因为,可能通过线程的 堆栈中的 bof 到达存储 TLS 的内存位置(因此,canary)。 因此,缓解措施是无效的,因为检查使用的是两个相同的 canary(尽管已被修改)。 此攻击在以下写作中进行:http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
还可以查看 https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 的演示,其中提到通常 TLS 是通过 mmap
存储的,当 线程 的 堆栈 被创建时,它也是通过 mmap
生成的,这可能允许如前所述的溢出。
修改 __stack_chk_fail
的 GOT 条目
如果二进制文件具有部分 RELRO,则可以使用任意写入来修改 __stack_chk_fail
的 GOT 条目,使其成为一个不会在 canary 被修改时阻止程序的虚拟函数。
此攻击在以下写作中进行:https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)