diff options
Diffstat (limited to '')
-rw-r--r-- | scripts/rmi-vuln-classloader.nse | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/scripts/rmi-vuln-classloader.nse b/scripts/rmi-vuln-classloader.nse new file mode 100644 index 0000000..968eea2 --- /dev/null +++ b/scripts/rmi-vuln-classloader.nse @@ -0,0 +1,115 @@ +local rmi = require "rmi" +local shortport = require "shortport" +local string = require "string" +local stdnse = require "stdnse" +local vulns = require "vulns" + +description = [[ +Tests whether Java rmiregistry allows class loading. The default +configuration of rmiregistry allows loading classes from remote URLs, +which can lead to remote code execution. The vendor (Oracle/Sun) +classifies this as a design feature. + + +Based on original Metasploit module by mihi. + +References: +* https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb +]]; + +--- +-- @usage +-- nmap --script=rmi-vuln-classloader -p 1099 <target> +-- +-- @output +-- PORT STATE SERVICE +-- 1099/tcp open rmiregistry +-- | rmi-vuln-classloader: +-- | VULNERABLE: +-- | RMI registry default configuration remote code execution vulnerability +-- | State: VULNERABLE +-- | Description: +-- | Default configuration of RMI registry allows loading classes from remote URLs which can lead to remote code executeion. +-- | +-- | References: +-- |_ https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb + +author = "Aleksandar Nikolic"; +license = "Same as Nmap--See https://nmap.org/book/man-legal.html"; +categories = { + "intrusive", + "vuln" +}; + + +portrule = shortport.port_or_service({1098, 1099, 1090, 8901, 8902, 8903}, {"java-rmi", "rmiregistry"}) + +action = function (host, port) + local registry = rmi.Registry:new(host, port); + registry:_handshake(); + local rmiArgs = rmi.Arguments:new(); + local argsRaw = "75" .. --TC_ARRAY + "72" .. -- TC_CLASSDESC + "0018" .. -- string len + "5B4C6A6176612E726D692E7365727665722E4F626A49443B" .. -- class name "[Ljava.rmi.server.ObjID;" + "871300B8D02C647E" .. -- serial id + "02" .. -- FLAGS (serializable) + "0000" .. -- FIELD COUNT + "70787000000000" .. --TC_NULL TC_BLOCKEND TC_NULL + "77080000000000000000" .. -- TC_BLOCKDATA + "73" .. -- TC_OBJECT + "72" .. -- TC_CLASSDESC + "0005" .. -- string len + "64756D6D79" .. -- class name "dummy" + "A16544BA26F9C2F4" .. -- serial id + "02" .. -- FLAGS (serializable) + "0000" .. -- FIELD COUNT + "74" .. -- TC_STRING + "0010" .. -- string len + "66696C653A2E2F64756D6D792E6A6172" .. -- annotation "file:./dummy.jar" + "78" .. -- TC_ENDBLOCKDATA + "70" .. -- TC_NULL + "7701000A"; -- TC_BLOCKDATA + local rmi_vuln = { + title = "RMI registry default configuration remote code execution vulnerability", + + description = [[ +Default configuration of RMI registry allows loading classes from remote URLs which can lead to remote code execution. +]], + references = { + 'https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb', + }, + exploit_results = {}, + }; + + local report = vulns.Report:new(SCRIPT_NAME, host, port); + rmi_vuln.state = vulns.STATE.NOT_VULN; + + rmiArgs:addRaw(stdnse.fromhex( argsRaw)); + + -- reference: java/rmi/dgc/DGCImpl_Stub.java and java/rmi/dgc/DGCImpl_Skel.java + -- we are calling DGC's (its objectId is 2) method with opnum 0 + -- DCG's hashcode is f6b6898d8bf28643 hex or -669196253586618813 dec + local status, j_array = registry.out:writeMethodCall(registry.out, 2, "f6b6898d8bf28643", 0, rmiArgs); + local status, retByte = registry.out.dis:readByte(); + if not status then + return false, "No return data received from server"; + end + + if 0x51 ~= retByte then + -- 0x51 : Returndata + return false, "No return data received from server"; + end + -- Need to make sure we get a good chunk of data. It's going to be a java + -- stack trace. But if we don't get enough, I guess we can check with + -- whatever we get. + registry.out.dis:canRead(256) + local data = registry.out.dis.bReader.readBuffer; + + if string.find(data, "RMI class loader disabled") == nil then + rmi_vuln.state = vulns.STATE.VULN; + return report:make_output(rmi_vuln); + end + + return report:make_output(rmi_vuln); +end; |