diff --git a/CHANGELOG b/CHANGELOG index 2e791e2b0..e2004304b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added rmi-vuln-classloader which scans for machines vulnerable to + remote class loading. [Aleksandar Nikolic] + o [NSE] Rewrote mysql-brute to use brute library [Aleksandar Nikolic] o Fixed the greppable output of hosts that time-out (when --host-timeout was diff --git a/nselib/rmi.lua b/nselib/rmi.lua index 9205349aa..a6e9d8d2e 100644 --- a/nselib/rmi.lua +++ b/nselib/rmi.lua @@ -52,6 +52,7 @@ _ENV = stdnse.module("rmi", stdnse.seeall) -- Some lazy shortcuts local function dbg(str,...) + local arg={...} stdnse.print_debug(3,"RMI:"..str, table.unpack(arg)) end -- Convenience function to both print an error message and return @@ -60,6 +61,7 @@ end -- return doh("Foo should be gazonk but was %s", foo) -- end local function doh(str,...) + local arg={...} stdnse.print_debug("RMI-ERR:"..tostring(str), table.unpack(arg)) return false, str end @@ -103,6 +105,7 @@ BufferedWriter = { end, -- Convenience function, wraps bin pack = function(self, fmt, ... ) + local arg={...} self.writeBuffer = self.writeBuffer .. bin.pack( fmt, table.unpack(arg)) end, @@ -294,6 +297,7 @@ JavaDOS = { return self:pack('>P', text) end, pack = function(self, ...) + local arg={...} return self.bWriter:pack(table.unpack(arg)) end, write = function(self, data) @@ -1478,6 +1482,9 @@ Arguments = { self.dos:writeByte(TC.TC_STRING) self.dos:writeUTF(str) end, + addRaw = function(self, str) + self.dos:write(str) + end, getData = function(self) local _, res = self.dos:flush() return res diff --git a/scripts/rmi-vuln-classloader.nse b/scripts/rmi-vuln-classloader.nse new file mode 100644 index 000000000..7874f57a2 --- /dev/null +++ b/scripts/rmi-vuln-classloader.nse @@ -0,0 +1,115 @@ +local shortport = require "shortport" +local stdnse = require "stdnse" +local vulns = require "vulns" +local rmi = require "rmi" + +description = [[ +Checks if rmiregistry allows class loading. + +The default configuration of rmiregistry allows loading classes from remote +URLs which can lead to remote code execution. This is considered as "by +design". + +Based on original Metasploit module by mihi. + +References: +* http://dev.metasploit.com/redmine/projects/framework/repository/entry/modules/exploits/multi/misc/java_rmi_server.rb +]]; + +--- +-- @usage +-- nmap nmap --script=rmi-vuln-classloader -p 1099 +-- +-- @output +-- PORT STATE SERVICE +-- 1099/tcp open rmiregistry +-- | rmi-vuln: +-- | 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: +-- |_ http://dev.metasploit.com/redmine/projects/framework/repository/entry/modules/exploits/multi/misc/java_rmi_server.rb + +author = "Aleksandar Nikolic"; +license = "Same as Nmap--See http://nmap.org/book/man-legal.html"; +categories = { + "intrusive", + "vuln" +}; + + + +portrule = shortport.port_or_service({ + 1099 + }, { + "rmiregistry" + }); + +action = function (host, port) + local registry = rmi.Registry:new(host.ip, port.number); + 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 executeion. + ]], + references = { + 'http://dev.metasploit.com/redmine/projects/framework/repository/entry/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(bin.pack("H", argsRaw)); + + -- reference: java/rmi/dgc/DGCImpl_Stub.java and java/rmi/dgc/DGCImpl_Skel.java + -- we are calling DGC's (it's 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 + 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;