diff options
Diffstat (limited to 'nselib/nrpc.lua')
-rw-r--r-- | nselib/nrpc.lua | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/nselib/nrpc.lua b/nselib/nrpc.lua new file mode 100644 index 0000000..d5af8a6 --- /dev/null +++ b/nselib/nrpc.lua @@ -0,0 +1,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; |