172 lines
4.7 KiB
Lua
172 lines
4.7 KiB
Lua
local io = require "io"
|
|
local nmap = require "nmap"
|
|
local shortport = require "shortport"
|
|
local stdnse = require "stdnse"
|
|
local string = require "string"
|
|
local table = require "table"
|
|
|
|
description = [[
|
|
Guesses Oracle instance/SID names against the TNS-listener.
|
|
|
|
If the <code>oraclesids</code> script argument is not used to specify an
|
|
alternate file, the default <code>oracle-sids</code> file will be used.
|
|
License to use the <code>oracle-sids</code> file was granted by its
|
|
author, Alexander Kornbrust (http://seclists.org/nmap-dev/2009/q4/645).
|
|
]]
|
|
|
|
---
|
|
-- @args oraclesids A file containing SIDs to try.
|
|
--
|
|
-- @usage
|
|
-- nmap --script=oracle-sid-brute --script-args=oraclesids=/path/to/sidfile -p 1521-1560 <host>
|
|
-- nmap --script=oracle-sid-brute -p 1521-1560 <host>
|
|
--
|
|
-- @output
|
|
-- PORT STATE SERVICE REASON
|
|
-- 1521/tcp open oracle syn-ack
|
|
-- | oracle-sid-brute:
|
|
-- | orcl
|
|
-- | prod
|
|
-- |_ devel
|
|
|
|
-- Version 0.3
|
|
|
|
-- Created 12/10/2009 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
|
|
-- Revised 12/11/2009 - v0.2 - Added tns_type, split packet creation to header & data
|
|
-- Revised 12/14/2009 - v0.3 - Fixed ugly file_exist kludge
|
|
|
|
author = "Patrik Karlsson"
|
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
|
categories = {"intrusive", "brute"}
|
|
|
|
|
|
portrule = shortport.port_or_service(1521, 'oracle-tns')
|
|
|
|
-- A table containing the different TNS types ... not complete :)
|
|
local tns_type = {CONNECT=1, REFUSE=4, REDIRECT=5, RESEND=11}
|
|
|
|
--- Creates a TNS header
|
|
-- A lot of values are still hardcoded ...
|
|
--
|
|
-- @param packetType string containing the type of TNS packet
|
|
-- @param packetLength number defining the length of the DATA segment of the packet
|
|
--
|
|
-- @return string with the raw TNS header
|
|
--
|
|
local function create_tns_header(packetType, packetLength)
|
|
|
|
local request = string.pack( ">I2 I2 BB I2",
|
|
packetLength + 34, -- Packet Length
|
|
0, -- Packet Checksum
|
|
tns_type[packetType], -- Packet Type
|
|
0, -- Reserved Byte
|
|
0 -- Header Checksum
|
|
)
|
|
|
|
return request
|
|
|
|
end
|
|
|
|
--- Creates a TNS connect packet
|
|
--
|
|
-- @param host_ip string containing the IP of the remote host
|
|
-- @param port_no number containing the remote port of the Oracle instance
|
|
-- @param sid string containing the SID against which to attempt to connect
|
|
--
|
|
-- @return string containing the raw TNS packet
|
|
--
|
|
local function create_connect_packet( host_ip, port_no, sid )
|
|
|
|
local connect_data = string.format(
|
|
"(DESCRIPTION=(CONNECT_DATA=(SID=%s)(CID=(PROGRAM=)(HOST=__jdbc__)(USER=)))\z
|
|
(ADDRESS=(PROTOCOL=tcp)(HOST=%s)(PORT=%d)))", sid, host_ip, port_no)
|
|
|
|
local data = string.pack(">I2 I2 I2 I2 I2 I2 I2 I2 I2 I2 I4 BB",
|
|
308, -- Version
|
|
300, -- Version (Compatibility)
|
|
0, -- Service Options
|
|
2048, -- Session Data Unit Size
|
|
32767, -- Maximum Transmission Data Unit Size
|
|
20376, -- NT Protocol Characteristics
|
|
0, -- Line Turnaround Value
|
|
1, -- Value of 1 in Hardware
|
|
connect_data:len(), -- Length of connect data
|
|
34, -- Offset to connect data
|
|
0, -- Maximum Receivable Connect Data
|
|
1, -- Connect Flags 0
|
|
1 -- Connect Flags 1
|
|
)
|
|
.. connect_data
|
|
|
|
|
|
local header = create_tns_header("CONNECT", connect_data:len() )
|
|
|
|
return header .. data
|
|
|
|
end
|
|
|
|
--- Process a TNS response and extracts Length, Checksum and Type
|
|
--
|
|
-- @param packet string as a raw TNS response
|
|
-- @return table with Length, Checksum and Type set
|
|
--
|
|
local function process_tns_packet( packet )
|
|
|
|
local tnspacket = {}
|
|
|
|
-- just pull out the bare minimum to be able to match
|
|
tnspacket.Length, tnspacket.Checksum, tnspacket.Type = string.unpack(">I2I2B", packet)
|
|
|
|
return tnspacket
|
|
|
|
end
|
|
|
|
action = function(host, port)
|
|
|
|
local found_sids = {}
|
|
local socket = nmap.new_socket()
|
|
local catch = function() socket:close() end
|
|
local try = nmap.new_try(catch)
|
|
local request, response, tns_packet
|
|
local sidfile
|
|
|
|
socket:set_timeout(5000)
|
|
|
|
-- open the sid file specified by the user or fallback to the default oracle-sids file
|
|
local sidfilename = nmap.registry.args.oraclesids or nmap.fetchfile("nselib/data/oracle-sids")
|
|
|
|
sidfile = io.open(sidfilename)
|
|
|
|
if not sidfile then
|
|
return
|
|
end
|
|
|
|
-- read sids line-by-line from the sidfile
|
|
for sid in sidfile:lines() do
|
|
|
|
-- check for comments
|
|
if not sid:match("#!comment:") then
|
|
|
|
try(socket:connect(host, port))
|
|
request = create_connect_packet( host.ip, port.number, sid )
|
|
try(socket:send(request))
|
|
response = try(socket:receive_bytes(1))
|
|
tns_packet = process_tns_packet(response)
|
|
|
|
-- If we get anything other than REFUSE consider it as a valid SID
|
|
if tns_packet.Type ~= tns_type.REFUSE then
|
|
table.insert(found_sids, sid)
|
|
end
|
|
|
|
try(socket:close())
|
|
|
|
end
|
|
|
|
end
|
|
|
|
sidfile:close()
|
|
|
|
return stdnse.format_output(true, found_sids)
|
|
|
|
end
|