forked from rituallyunclean/NSE_1
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbroadcast-sybase-asa-discover.nse
188 lines (159 loc) · 4.94 KB
/
broadcast-sybase-asa-discover.nse
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
local bin = require "bin"
local bit = require "bit"
local nmap = require "nmap"
local os = require "os"
local stdnse = require "stdnse"
local table = require "table"
description = [[
Discovers Sybase Anywhere servers on the LAN by sending broadcast discovery messages.
]]
---
-- @usage
-- nmap --script broadcast-sybase-asa-discover
--
-- @output
-- Pre-scan script results:
-- | broadcast-sybase-asa-discover:
-- | ip=192.168.0.1; name=mysqlanywhere1; port=2638
-- |_ ip=192.168.0.2; name=mysqlanywhere2; port=49152
--
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = { "broadcast", "safe" }
prerule = function() return ( nmap.address_family() == "inet") end
--
-- The following code is a bit overkill and is ment to go into a library once
-- more scripts that make use of it are developed.
--
Ping = {
-- The PING request class
Request = {
-- Creates a new Ping request
new = function(self)
local o = {}
setmetatable(o, self)
self.__index = self
return o
end,
-- returns the ping request as a string
__tostring = function(self)
return bin.pack("HAH", "1b00003d0000000012", "CONNECTIONLESS_TDS",
"000000010000040005000500000102000003010104080000000000000000070204b1")
end
},
-- The Ping Response class
Response = {
-- Creates a new response
-- @param data string containing the raw data as received over the socket
-- @return o instance of Response
new = function(self, data)
local o = { data = data }
setmetatable(o, self)
self.__index = self
o:parse()
if ( o.dbinstance ) then
return o
end
end,
-- Parses the raw response and populates the
-- <code>dbinstance.name</code> and <code>dbinstance.port</code> fields
parse = function(self)
-- do a very basic length check
local pos, len = bin.unpack(">I", self.data)
len = bit.band(len, 0x0000FFFF)
if ( len ~= #self.data ) then
stdnse.print_debug(2, "The packet length was reported as %d, expected %d", len, #self.data)
return
end
local connectionless_tds
pos, connectionless_tds = bin.unpack("p", self.data, 9)
if ( connectionless_tds ~= "CONNECTIONLESS_TDS" ) then
stdnse.print_debug(2, "Did not find the expected CONNECTIONLESS_TDS header")
return
end
self.dbinstance = {}
pos, self.dbinstance.name = bin.unpack("p", self.data, 40)
pos = pos + 2
pos, self.dbinstance.port = bin.unpack(">S", self.data, pos)
end,
}
}
-- Main script interface
Helper = {
-- Creates a new helper instance
-- @param host table as received by the action method
-- @param port table as received by the action method
-- @param options table containing:
-- <code>timeout</code> - the amount of time to listen for responses
-- @return o instance of Helper
new = function(self, host, port, options)
local o = {
host = host,
port = port,
options = options or {}
}
setmetatable(o, self)
self.__index = self
return o
end,
-- Sends a ping request to the service and processes the response
-- @return status true on success, false on failure
-- @return instances table of instance tables containing
-- <code>name</code> - the instance name
-- <code>ip</code> - the instance ip
-- <code>port</code> - the instance port
-- err string containing error message on failure
ping = function(self)
local socket = nmap.new_socket("udp")
socket:set_timeout(1000)
-- send 2 packets just in case
for i=1, 2 do
local ping_req = Ping.Request:new()
local status, err = socket:sendto(self.host, self.port, tostring(ping_req))
if ( not(status) ) then
return false, "Failed to send broadcast packet"
end
end
local stime = os.time()
local instances = {}
local timeout = self.options.timeout or ( 20 / ( nmap.timing_level() + 1 ) )
repeat
local status, data = socket:receive()
if ( status ) then
local response = Ping.Response:new(data)
if ( response ) then
local status, _, _, rhost, _ = socket:get_info()
if ( not(status) ) then
socket:close()
return false, "Failed to get socket information"
end
response.dbinstance.ip = rhost
-- avoid duplicates
instances[response.dbinstance.name] = response.dbinstance
end
end
until( os.time() - stime > timeout )
socket:close()
return true, instances
end,
}
action = function()
local timeout = ( 20 / ( nmap.timing_level() + 1 ) )
local host = { ip = "255.255.255.255" }
local port = { number = 2638, protocol = "udp" }
local helper = Helper:new(host, port)
local status, instances = helper:ping()
if ( not(status) ) then
return ("\n ERROR: %s"):format(instances)
end
-- if we don't have any instances, silently abort
if ( next(instances) == nil ) then
return
end
local result = {}
for _, instance in pairs(instances) do
table.insert(result, ("ip=%s; name=%s; port=%d"):format(instance.ip, instance.name, instance.port))
end
table.sort(result)
return stdnse.format_output(true, result)
end