summaryrefslogtreecommitdiffstats
path: root/scripts/oracle-tns-version.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/oracle-tns-version.nse')
-rw-r--r--scripts/oracle-tns-version.nse104
1 files changed, 104 insertions, 0 deletions
diff --git a/scripts/oracle-tns-version.nse b/scripts/oracle-tns-version.nse
new file mode 100644
index 0000000..72fae6d
--- /dev/null
+++ b/scripts/oracle-tns-version.nse
@@ -0,0 +1,104 @@
+description = [[
+Decodes the VSNNUM version number from an Oracle TNS listener.
+]]
+
+local shortport = require "shortport"
+local nmap = require "nmap"
+local comm = require "comm"
+local stdnse = require "stdnse"
+local string = require "string"
+local U = require "lpeg-utility"
+
+author = "Daniel Miller"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"version", "safe"}
+
+portrule = function (host, port)
+ return (
+ -- -sV has an actual version for this, no need to send more probes and decode.
+ not (port.version and port.version.version and port.version.version ~= "")
+ -- Otherwise, normal checking for port numbers etc.
+ and shortport.version_port_or_service({1521,1522,1523}, "oracle-tns")(host, port)
+ )
+end
+
+-- Lifted from nmap-service-probes
+-- TODO: Figure out if we can send a better probe than this. We might need to
+-- send ADDRESS, CID, etc.
+local oracle_tns_probe = "\0Z\0\0\x01\0\0\0\x016\x01,\0\0\x08\0\x7F\xFF\x7F\x08\0\0\0\x01\0 \0:\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x004\xE6\0\0\0\x01\0\0\0\0\0\0\0\0(CONNECT_DATA=(COMMAND=version))"
+
+local ERR_CODES = {
+ ["1189"] = "unauthorized",
+ ["1194"] = "insecure transport",
+ ["12154"] = "unknown identifier",
+ ["12504"] = "requires service name",
+ ["12505"] = "unknown sid",
+ ["12514"] = "unknown service name",
+}
+
+local function decode_vsnnum (vsnnum)
+ vsnnum = tonumber(vsnnum)
+ return string.format("%d.%d.%d.%d.%d",
+ vsnnum >> 24,
+ vsnnum >> 20 & 0xF,
+ vsnnum >> 12 & 0xFF,
+ vsnnum >> 8 & 0xF,
+ vsnnum & 0xFF
+ )
+end
+
+do
+ local test_data = {
+ ["135290880"] = "8.1.6.0.0",
+ ["153092352"] = "9.2.0.1.0",
+ ["169869568"] = "10.2.0.1.0",
+ ["185599488"] = "11.1.0.6.0",
+ ["202375680"] = "12.1.0.2.0",
+ ["301989888"] = "18.0.0.0.0",
+ ["318767104"] = "19.0.0.0.0",
+ ["352321536"] = "21.0.0.0.0",
+ }
+ for n, v in pairs(test_data) do
+ local ver = decode_vsnnum(n)
+ assert(ver == v, ("%s == %s"):format(ver, v))
+ end
+end
+
+action = function (host, port)
+ local response
+ -- Did the service engine already do the hard work?
+ if port.version and port.version.service_fp then
+ -- Probes sent, replies received, but no match.
+ response = U.get_response(port.version.service_fp, "oracle-tns")
+ end
+
+ if not response then
+ -- Have to send the probe ourselves
+ local status
+ status, response = comm.exchange(host, port, oracle_tns_probe)
+ if not status then
+ stdnse.debug1("Couldn't get a response: %s", response)
+ return nil
+ end
+ end
+
+ local vsnnum = response and response:match("%(VSNNUM=(%d+)%)", 12)
+ port.version = port.version or {}
+ if vsnnum then
+ local version = decode_vsnnum(vsnnum)
+ port.version.product = "Oracle TNS listener"
+ port.version.version = version
+ local cpes = port.version.cpe or {}
+ cpes[#cpes+1] = "cpe:/a:oracle:database_server:" .. version
+ port.version.cpe = cpes
+ end
+
+ local errno = response and response:match("%(ERR=(%d+)%)", 12)
+ if errno then
+ port.version.extrainfo = ERR_CODES[errno] or ("error: "..errno)
+ end
+
+ if vsnnum or errno then
+ nmap.set_port_version(host, port, "hardmatched")
+ end
+end