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
|
--- A minimalistic library to support Domino RPC
--
-- Summary
-- -------
-- The library currently only supports user enumeration and uses chunks of
-- captured data to do so.
--
-- Overview
-- --------
-- The library contains the following classes:
--
-- o DominoPacket
-- - The packet class holding the packets sent between the client and the
-- IBM Lotus Domino server
--
-- o Helper
-- - A helper class that provides easy access to the rest of the library
--
-- Example
-- -------
-- The following sample code illustrates how scripts can use the Helper class
-- to interface the library:
--
-- <code>
-- helper = nrpc.Helper:new(host, port)
-- status, err = nrpc:Connect()
-- status, res = nrpc:isValidUser("Patrik Karlsson")
-- status, err = nrpc:Close()
-- </code>
--
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
-- @author Patrik Karlsson <patrik@cqure.net>
--
--
-- Version 0.1
-- Created 07/23/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
--
local match = require "match"
local nmap = require "nmap"
local stdnse = require "stdnse"
local string = require "string"
_ENV = stdnse.module("nrpc", stdnse.seeall)
-- The Domino Packet
DominoPacket = {
--- Creates a new DominoPacket instance
--
-- @param data string containing the packet data
-- @return a new DominoPacket instance
new = function( self, data )
local o = {}
setmetatable(o, self)
self.__index = self
o.data = data
return o
end,
--- Reads a packet from the socket
--
-- @param domsock socket connected to the server
-- @return Status (true or false).
-- @return Error code (if status is false).
read = function( self, domsock )
local status, data = domsock:receive_buf(match.numbytes(2), true)
local len = string.unpack( "<I2", data )
return domsock:receive_buf(match.numbytes(len), true)
end,
--- converts the packet to a string
__tostring = function(self)
return string.pack("<s2", self.data )
end,
}
Helper = {
--- Creates a new Helper instance
--
-- @param host table as received by the script action method
-- @param port table as received by the script action method
new = function(self, host, port)
local o = {}
setmetatable(o, self)
self.__index = self
o.host = host
o.port = port
o.domsock = nmap.new_socket()
return o
end,
--- Connects the socket to the Domino server
--
-- @return status true on success, false on failure
-- @return err error message if status is false
connect = function( self )
self.domsock:set_timeout(5000)
if( not( self.domsock:connect( self.host.ip, self.port.number, "tcp" ) ) ) then
return false, ("ERROR: Failed to connect to Domino server %s:%d\n"):format(self.host, self.port)
end
return true
end,
--- Disconnects from the Lotus Domino Server
--
-- @return status true on success, false on failure
-- @return err error message if status is false
disconnect = function( self )
return self.domsock:close()
end,
--- Attempt to check whether the user exists in Domino or not
--
-- @param username string containing the user name to guess
-- @return status true on success false on failure
-- @return domino_id if it exists and status is true
-- err if status is false
isValidUser = function( self, username )
local data = stdnse.fromhex("00001e00000001000080000007320000700104020000fb2b2d00281f1e000000124c010000000000")
local status, id_data
local data_len, total_len, pkt_type, valid_user
self.domsock:send( tostring(DominoPacket:new( data )) )
data = DominoPacket:new():read( self.domsock )
data = stdnse.fromhex("0100320002004f000100000500000900")
.. string.char(#username + 1)
.. stdnse.fromhex("000000000000000000000000000000000028245573657273290000")
.. string.pack("z", username)
self.domsock:send( tostring(DominoPacket:new( data ) ) )
status, id_data = DominoPacket:new():read( self.domsock )
pkt_type = string.unpack("B", id_data, 3)
valid_user = string.unpack("B", id_data, 11)
total_len = string.unpack("<I2", id_data, 13)
if ( pkt_type == 0x16 ) then
if ( valid_user == 0x19 ) then
return true
else
return false
end
end
if ( pkt_type ~= 0x7e ) then
return false, "Failed to retrieve ID file"
end
status, data = DominoPacket:new():read( self.domsock )
id_data = id_data:sub(33) .. data:sub(11, total_len - #id_data + 11)
return true, id_data
end,
}
return _ENV;
|