栈溢出从复现到挖掘-CVE-2018-16333漏洞复现详解
字数 1882 2025-08-29 22:41:24

CVE-2018-16333漏洞分析与利用教程

1. 漏洞概述

CVE-2018-16333是一个基于栈溢出的漏洞,存在于某IoT设备的web服务中。漏洞成因是web服务在处理POST请求时,对ssid参数直接复制到栈上的局部变量中,且没有进行长度限制,导致栈溢出。

2. 漏洞定位

漏洞位于form_fast_setting_wifi_set函数中,关键问题点:

  • 程序获取ssid参数后,未经检查直接使用strcpy函数复制到栈变量
  • 存在两个连续的strcpy操作,增加了利用复杂度

3. 漏洞分析

3.1 漏洞代码分析

IDA反汇编显示的关键伪代码:

char s[64];          // [sp+200h] [bp-7Ch] BYREF
char dest[64];       // [sp+1C0h] [bp-BCh] BYREF
char *src;           // [sp+260h] [bp-1Ch]

3.2 栈布局分析

通过pwndbg调试获取的栈结构:

  • char s偏移量:0x7C (从栈帧基址FP向低地址方向偏移124字节)
  • src指针偏移量:0x1C (从栈帧基址FP向低地址方向偏移28字节)
  • dest偏移量:0xBC (从栈帧基址FP向低地址方向偏移188字节)

3.3 关键偏移量计算

  • src距离返回地址:0x20 (32字节)
  • char ssrc的偏移量:0x60 (96字节)
  • dest到返回地址的距离:0xC0 (192字节)

4. 利用难点

由于存在两个strcpy操作:

  1. 第一次strcpy(s, src)会覆盖src指针
  2. 第二次strcpy(dest, src)使用被覆盖的src指针

因此需要精心构造payload,确保:

  1. 第一次溢出后src指向一个可读地址
  2. 第二次strcpy不会导致程序崩溃
  3. 最终能控制程序执行流

5. 利用过程

5.1 利用链设计

  1. 第一次strcpy(s, src):

    • 目标:覆盖src指针,使其指向可控地址
    • 填充长度:96字节(char ssrc的距离)
    • 最后4字节:写入一个可读地址
  2. 第二次strcpy(dest, src):

    • 通过被篡改的src指针,向dest写入ROP链
    • 需要覆盖返回地址,距离为32字节
    • 实际填充:24字节(32-4-4,减去可读地址和返回地址本身)

5.2 关键地址获取

  1. libc基址计算

    • 通过内存映射获取libc基址:0x3fdd1cd4
    • 使用IDA打开libc.so.0,计算函数偏移量
  2. 关键函数地址

    • system函数偏移量:0x5A270
    • puts函数偏移量:0x35CD4
  3. Gadget查找

    • gadget1: pop {r3, pc} (地址: 0x00018298)
      • 功能:从栈顶弹出两个值,分别存入r3和pc
      • 用途:控制r3寄存器的值并跳转
    • gadget2: mov r0, sp ; blx r3 (地址: 0x00040cb8)
      • 功能:将栈指针sp的值赋给r0,然后跳转到r3
      • 用途:传递参数并触发system()

5.3 ARM调用约定

  • 第一个参数通过r0传递
  • 函数地址通常通过blx r3跳转(r3存储目标地址)
  • 关键寄存器:
    • r0:传递函数第一个参数
    • r3:暂存函数地址
    • pc:程序计数器,控制执行流

5.4 Payload构造

完整payload结构:

  1. 前96字节:填充数据
  2. 可读地址(4字节)
  3. 24字节填充("bbbb")
  4. ROP链:
    • pop_r3地址(libc_base + 0x18298)
    • system函数地址(libc_base + 0x5A270)
    • mov_r0_ret_r3地址(libc_base + 0x40cb8)
  5. 要执行的命令字符串

6. 调试验证

调试关键点:

  1. 在第一个strcpy函数前打断点(0x67070)
  2. 在第二个strcpy函数前打断点(0x67080)
  3. 观察寄存器状态:
    • R0:函数第一个参数
    • R11(FP):当前栈帧基址
    • SP:当前栈顶
    • PC:下一条指令地址

验证栈空间:

  • 从R0(0x408001e8)到0x40800248应被"aaaa"覆盖
  • 0x40800248地址应指向libc可读地址
  • ROP链应正确布置在栈帧基址开始的位置

7. 利用脚本注意事项

  1. 请求需要重复发送两次(程序可能不稳定)
    response = requests.post(url, cookies=cookie, data=data)
    response = requests.post(url, cookies=cookie, data=data)
    
  2. ARM架构为小端序,注意字节顺序
  3. 每个寄存器占用4字节,注意对齐

8. 总结

本漏洞利用的关键技术点:

  1. 精确计算栈偏移量
  2. 处理两次strcpy的相互影响
  3. ARM架构下的ROP链构造
  4. 寄存器控制和参数传递
  5. 利用strcpy实现内存写操作

通过精心构造的payload,最终可以实现任意命令执行,完成RCE(远程代码执行)。

CVE-2018-16333漏洞分析与利用教程 1. 漏洞概述 CVE-2018-16333是一个基于栈溢出的漏洞,存在于某IoT设备的web服务中。漏洞成因是web服务在处理POST请求时,对ssid参数直接复制到栈上的局部变量中,且没有进行长度限制,导致栈溢出。 2. 漏洞定位 漏洞位于 form_fast_setting_wifi_set 函数中,关键问题点: 程序获取ssid参数后,未经检查直接使用 strcpy 函数复制到栈变量 存在两个连续的 strcpy 操作,增加了利用复杂度 3. 漏洞分析 3.1 漏洞代码分析 IDA反汇编显示的关键伪代码: 3.2 栈布局分析 通过pwndbg调试获取的栈结构: char s 偏移量:0x7C (从栈帧基址FP向低地址方向偏移124字节) src 指针偏移量:0x1C (从栈帧基址FP向低地址方向偏移28字节) dest 偏移量:0xBC (从栈帧基址FP向低地址方向偏移188字节) 3.3 关键偏移量计算 src 距离返回地址:0x20 (32字节) char s 到 src 的偏移量:0x60 (96字节) dest 到返回地址的距离:0xC0 (192字节) 4. 利用难点 由于存在两个 strcpy 操作: 第一次 strcpy(s, src) 会覆盖 src 指针 第二次 strcpy(dest, src) 使用被覆盖的 src 指针 因此需要精心构造payload,确保: 第一次溢出后 src 指向一个可读地址 第二次 strcpy 不会导致程序崩溃 最终能控制程序执行流 5. 利用过程 5.1 利用链设计 第一次strcpy(s, src) : 目标:覆盖 src 指针,使其指向可控地址 填充长度:96字节( char s 到 src 的距离) 最后4字节:写入一个可读地址 第二次strcpy(dest, src) : 通过被篡改的 src 指针,向 dest 写入ROP链 需要覆盖返回地址,距离为32字节 实际填充:24字节(32-4-4,减去可读地址和返回地址本身) 5.2 关键地址获取 libc基址计算 : 通过内存映射获取libc基址:0x3fdd1cd4 使用IDA打开libc.so.0,计算函数偏移量 关键函数地址 : system 函数偏移量:0x5A270 puts 函数偏移量:0x35CD4 Gadget查找 : gadget1 : pop {r3, pc} (地址: 0x00018298) 功能:从栈顶弹出两个值,分别存入r3和pc 用途:控制r3寄存器的值并跳转 gadget2 : mov r0, sp ; blx r3 (地址: 0x00040cb8) 功能:将栈指针sp的值赋给r0,然后跳转到r3 用途:传递参数并触发system() 5.3 ARM调用约定 第一个参数通过r0传递 函数地址通常通过 blx r3 跳转(r3存储目标地址) 关键寄存器: r0:传递函数第一个参数 r3:暂存函数地址 pc:程序计数器,控制执行流 5.4 Payload构造 完整payload结构: 前96字节:填充数据 可读地址(4字节) 24字节填充("bbbb") ROP链: pop_ r3地址(libc_ base + 0x18298) system函数地址(libc_ base + 0x5A270) mov_ r0_ ret_ r3地址(libc_ base + 0x40cb8) 要执行的命令字符串 6. 调试验证 调试关键点: 在第一个 strcpy 函数前打断点(0x67070) 在第二个 strcpy 函数前打断点(0x67080) 观察寄存器状态: R0:函数第一个参数 R11(FP):当前栈帧基址 SP:当前栈顶 PC:下一条指令地址 验证栈空间: 从R0(0x408001e8)到0x40800248应被"aaaa"覆盖 0x40800248地址应指向libc可读地址 ROP链应正确布置在栈帧基址开始的位置 7. 利用脚本注意事项 请求需要重复发送两次(程序可能不稳定) ARM架构为小端序,注意字节顺序 每个寄存器占用4字节,注意对齐 8. 总结 本漏洞利用的关键技术点: 精确计算栈偏移量 处理两次 strcpy 的相互影响 ARM架构下的ROP链构造 寄存器控制和参数传递 利用 strcpy 实现内存写操作 通过精心构造的payload,最终可以实现任意命令执行,完成RCE(远程代码执行)。