summaryrefslogtreecommitdiffstats
path: root/scripts/oracle-sid-brute.nse
blob: d559b54752d77a69335b4308cbd26a4051f37a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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