From e570925c3757f3ef3289641b78419d263995f67d Mon Sep 17 00:00:00 2001 From: patrik Date: Sat, 14 Aug 2010 08:33:16 +0000 Subject: [PATCH] o [NSE] Renamed db2-info and db2-brute scripts to drda-*. Updated script and library to reflect name change. Added support other DRDA based databases such as IBM Informix Dynamic Server and Apache Derby. [Patrik] --- CHANGELOG | 5 + nselib/drda.lua | 264 ++++++++++++++++++++++++++--------------- scripts/drda-brute.nse | 29 ++--- scripts/drda-info.nse | 63 ++++++---- 4 files changed, 229 insertions(+), 132 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1e7edfa35..908413db9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Renamed db2-info and db2-brute scripts to drda-*. Updated script + and library to reflect name change. Added support other DRDA based + databases such as IBM Informix Dynamic Server and Apache Derby. + [Patrik] + o [Nsock] Added a new function, nsi_set_hostname, to set the intended hostname of the target. This allows the use of Server Name Indication in SSL connections. This was suggested by Nuno Goncalves. diff --git a/nselib/drda.lua b/nselib/drda.lua index 7bd8e8e26..2e560c8dc 100644 --- a/nselib/drda.lua +++ b/nselib/drda.lua @@ -1,9 +1,9 @@ --- --- DB2 Library supporting a very limited subset of operations. +-- DRDA Library supporting a very limited subset of operations. -- -- Summary -- * The library currently provides functionality to: (1) Query the server for --- basic settings using the code>getServerInfo function of the helper +-- basic settings using the getServerInfo function of the helper -- class. (2) Authenticate to a DB2 server using a plain-text username and -- password. -- @@ -23,12 +23,16 @@ -- ** A smallish socket wrapper that provides fundamental buffering -- * StringUtil -- ** Provides EBCDIC/ASCII conversion functions +-- * Comm +-- ** Provides fundamental communication support (send/receive DRDAPacket) +-- * DRDAPacket +-- ** A class holding one or more DRDA's and provides some basic access methods -- -- The following sample code illustrates how scripts can use the Helper class -- to interface with the library: -- -- --- db2helper = db2.Helper:new() +-- db2helper = drda.Helper:new() -- status, err = db2helper:connect(host, port) -- status, res = db2helper:getServerInfo() -- status, err = db2helper:close() @@ -45,16 +49,22 @@ -- -- --- Version 0.1 +-- Version 0.2 -- Created 05/08/2010 - v0.1 - created by Patrik Karlsson --- +-- Revised 07/27/2010 - v0.2 - Added the comm class and made a few improvements +-- to sending and receiving packets. Changed the +-- helper login method to support: +-- x IBM DB2 +-- x Apache Derby +-- x IBM Informix Dynamic Server -module(... or "db2", package.seeall) +module(... or "drda", package.seeall) require "bin" -- CodePoint constants CodePoint = { + CODEPNT = 0x000c, TYPDEFNAM = 0x002f, TYPDEFOVR = 0x0035, ACCSEC = 0x106d, @@ -62,6 +72,8 @@ CodePoint = { EXCSAT = 0x1041, PRDID = 0x112e, SRVCLSNM = 0x1147, + SVRCOD = 0x1149, + SYNERRCD = 0x114a, SRVRLSLV = 0x115a, EXTNAM = 0x115e, SRVNAM = 0x116d, @@ -69,14 +81,20 @@ CodePoint = { PASSWORD = 0x11a1, SECMEC = 0x11a2, SECCHKCD = 0x11a4, + SECCHKRM = 0x1219, + SYNTAXRM = 0x124c, MGRLVLLS = 0x1404, EXCSATRD = 0x1443, + ACCSECRD = 0x14ac, ACCRDB = 0x2001, PRDDATA = 0x2104, RDBACCL = 0x210f, RDBNAM = 0x2110, + CRRTKN = 0x2135, + ACCRDBRM = 0x2201, RDBNFNRM = 0x2211, RDBAFLRM = 0x221a, + RDBATHRM = 0x22cb, } -- Security Mechanism @@ -95,6 +113,46 @@ SecMec = ENC_USER_ENC_PASS_ENC_NEWPASS_ENC_DATA = 0x000E, } +DRDAPacket = { + + new = function(self, drda_array) + local o = {} + setmetatable(o, self) + self.__index = self + o.drda_array = drda_array + o.count = #drda_array + return o + end, + + getDRDAByCodePoint = function( self, codepoint ) + for i=1, #self.drda_array do + if ( self.drda_array[i].DDM.CodePoint == codepoint ) then + return self.drda_array[i] + end + end + end, + + getDRDA = function( self, n ) + return ( #self.drda_array >= n ) and self.drda_array[n] or nil + end, + + __tostring = function( self ) + local data = "" + -- do some DDM fixup in here + for i=1, #self.drda_array do + if ( i == 1 and #self.drda_array > 1 ) then + self.drda_array[1].DDM.Format = 0x41 + else + self.drda_array[i].DDM.Format = 0x01 + end + self.drda_array[i].DDM.CorelId = i + data = data .. tostring(self.drda_array[i]) + end + return data + end + +} + -- Distributed Relational Database Architecture (DRDA) Class DRDA = { @@ -126,11 +184,11 @@ DRDA = { -- @return err string containing the error message if status is false addParameter = function( self, param ) if ( not(self.DDM) ) then - stdnse.print_debug("db2.DRDA.addParameter: DDM must be set prior to adding parameters") + stdnse.print_debug("drda.DRDA.addParameter: DDM must be set prior to adding parameters") return false, "DDM must be set prior to adding parameters" end if ( not(param) ) then - stdnse.print_debug("db2.DRDA.addParameter: Param cannot be nil") + stdnse.print_debug("drda.DRDA.addParameter: Param cannot be nil") return false, "Param cannot be nil" end @@ -159,17 +217,17 @@ DRDA = { --- Converts the DRDA class to a string -- -- @return data containing the object instance - toString = function(self) + __tostring = function(self) local data if ( not(self.DDM) ) then - stdnse.print_debug("db2.DRDA.toString: DDM cannot be nil") + stdnse.print_debug("drda.DRDA.toString: DDM cannot be nil") return nil end data = bin.pack(">SCCSSS", self.DDM.Length, self.DDM.Magic, self.DDM.Format, self.DDM.CorelId, self.DDM.Length2, self.DDM.CodePoint ) for k,v in ipairs(self.Parameters) do - data = data .. v:toString() + data = data .. tostring(v) end return data end, @@ -180,7 +238,7 @@ DRDA = { -- @return Status (true or false). -- @return Error code (if status is false). send = function( self, db2socket ) - return db2socket:send( self:toString() ) + return db2socket:send( tostring(self) ) end, --- Receives data from the db2socket and builds a DRDA object @@ -196,7 +254,7 @@ DRDA = { -- first read atleast enough so that we can populate the DDM status, data = db2socket:recv( DDM_SIZE ) if ( not(status) ) then - stdnse.print_debug("db2.DRDA.receive: %s", data) + stdnse.print_debug("drda.DRDA.receive: %s", data) return false, ("Failed to read at least %d bytes from socket"):format(DDM_SIZE) end @@ -246,7 +304,7 @@ DRDAParameter = { --- Converts the DRDA Parameter object to a string -- -- @return data string containing the DRDA Parameter - toString = function( self ) + __tostring = function( self ) local data = bin.pack(">SS", self.Length, self.CodePoint ) if ( self.Data ) then @@ -330,7 +388,7 @@ DDM = { end, --- Converts the DDM object to a string - toString = function( self ) + __tostring = function( self ) return bin.pack(">SCCSSS", self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint) end, @@ -342,7 +400,7 @@ DDM = { local pos = 1 if ( #str < DDM_SIZE ) then - return -1, ("db2.DDM.fromString: str was less than DDM_SIZE (%d)"):format( DDM_SIZE ) + return -1, ("drda.DDM.fromString: str was less than DDM_SIZE (%d)"):format( DDM_SIZE ) end pos, self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint = bin.unpack( ">SCCSSS", str ) @@ -433,7 +491,7 @@ Command = -- @param typdefnam string containing the data type definition name -- @param typdefovr string containing the data type definition override -- @return drda DRDA instance - ACCRDB = function( database, rdbaccl, prdid, prddata, typdefnam, typdefovr ) + ACCRDB = function( database, rdbaccl, prdid, prddata, typdefnam, crrtkn, typdefovr ) local drda = DRDA:new( DDM:new( CodePoint.ACCRDB ) ) drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) ) ) @@ -449,6 +507,9 @@ Command = if( typdefnam ) then drda:addParameter( DRDAParameter:new( CodePoint.TYPDEFNAM, StringUtil.toEBCDIC( typdefnam ) ) ) end + if( crrtkn ) then + drda:addParameter( DRDAParameter:new( CodePoint.CRRTKN, crrtkn ) ) + end if( typdefovr ) then drda:addParameter( DRDAParameter:new( CodePoint.TYPDEFOVR, typdefovr ) ) end @@ -477,6 +538,7 @@ Helper = { -- @return Error code (if status is false). connect = function( self, host, port ) self.db2socket = DB2Socket:new() + self.comm = Comm:new( self.db2socket ) return self.db2socket:connect(host.ip, port.number, port.protocol) end, @@ -495,33 +557,27 @@ Helper = { getServerInfo = function( self ) local mgrlvlls = bin.pack("H", "1403000724070008240f00081440000814740008") local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" ) - local drda, response, param, status, err + local drda, response, param, status, err, packet - status, err = self.db2socket:sendDRDA( { drda_excsat } ) - if ( not(status) ) then - return false, err - end - - status, drda = self.db2socket:recvDRDA() - if( not(status) ) then - return false, drda - end + status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat } ) ) + if ( not(status) ) then return false, err end - if ( #drda > 0 and drda[1].DDM.CodePoint == CodePoint.EXCSATRD ) then + drda = packet:getDRDAByCodePoint( CodePoint.EXCSATRD ) + if ( drda ) then response = {} - param = drda[1]:getParameter( CodePoint.EXTNAM ) + param = drda:getParameter( CodePoint.EXTNAM ) if ( param ) then response.extname = param:getDataAsASCII() end - param = drda[1]:getParameter( CodePoint.SRVCLSNM ) + param = drda:getParameter( CodePoint.SRVCLSNM ) if ( param ) then response.srvclass = param:getDataAsASCII() end - param = drda[1]:getParameter( CodePoint.SRVNAM ) + param = drda:getParameter( CodePoint.SRVNAM ) if ( param ) then response.srvname = param:getDataAsASCII() end - param = drda[1]:getParameter( CodePoint.SRVRLSLV ) + param = drda:getParameter( CodePoint.SRVRLSLV ) if ( param ) then response.prodrel = param:getDataAsASCII() end @@ -541,79 +597,112 @@ Helper = { -- @return err message (if status if false) login = function( self, database, username, password ) local drda = {} - local data, param, status, err, _ + local packet, data, param, status, err, _ local mgrlvlls = bin.pack("H", "1403000724070008240f00081440000814740008") local secmec, prdid = "\00\03", "JCC03010" + local tdovr = bin.pack("H", "0006119c04b80006119d04b00006119e04b8") + local crrtkn= bin.pack("H", "d5c6f0f0f0f0f0f14bc3c6f4c4012a11168414") local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" ) local drda_accsec = Command.ACCSEC( secmec, database ) local drda_secchk = Command.SECCHK( secmec, database, username, password ) - local drda_accrdb = Command.ACCRDB( database ) + local drda_accrdb = Command.ACCRDB( database, string.char(0x24,0x07), "DNC10060", nil, "QTDSQLASC", crrtkn, tdovr) + + status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat, drda_accsec } ) ) + if( not(status) ) then return false, "ERROR: Login failed" end - status, err = self.db2socket:sendDRDA( { drda_excsat, drda_accsec } ) - if ( not(status) ) then - stdnse.print_debug("db2.Helper.login: ERROR: DB2Socket error: %s", err ) - return false, ("ERROR: DB2Socket error: %s"):format( err ) + if ( packet:getDRDAByCodePoint( CodePoint.RDBNFNRM ) or + packet:getDRDAByCodePoint( CodePoint.RDBAFLRM ) ) then + stdnse.print_debug("drda.Helper.login: ERROR: RDB not found") + return false, "ERROR: Database not found" end - status, drda = self.db2socket:recvDRDA() - if( not(status) ) then - stdnse.print_debug("db2.Helper.login: ERROR: DB2Socket error: %s", drda ) - return false, ("ERROR: DB2Socket error: %s"):format( drda ) + drda = packet:getDRDAByCodePoint( CodePoint.ACCSECRD ) + if ( not(drda) ) then + return false, "ERROR: Response did not contain any valid security mechanisms" end - if ( 2 > #drda ) then - stdnse.print_debug("db2.Helper.login: db2.Helper.login: ERROR: Expected two DRDA records") - return false, "ERROR: Expected two DRDA records" - end - - -- Check if the DB is accessible - for i=1, #drda do - if ( drda[i].DDM.CodePoint == CodePoint.RDBNFNRM or - drda[i].DDM.CodePoint == CodePoint.RDBAFLRM ) then - stdnse.print_debug("db2.Helper.login: ERROR: RDB not found") - return false, "ERROR: Database not found" - end - end - - param = drda[2]:getParameter( CodePoint.SECMEC ) + param = drda:getParameter( CodePoint.SECMEC ) if ( not(param) ) then - stdnse.print_debug("db2.Helper.login: ERROR: Response did not contain any valid security mechanisms") + stdnse.print_debug("drda.Helper.login: ERROR: Response did not contain any valid security mechanisms") return false, "ERROR: Response did not contain any valid security mechanisms" end if ( select(2, bin.unpack(">S", param:getData())) ~= SecMec.USER_PASSWORD ) then - stdnse.print_debug("db2.Helper.login: ERROR: Securite Mechanism not supported") + stdnse.print_debug("drda.Helper.login: ERROR: Securite Mechanism not supported") return false, "ERROR: Security mechanism not supported" end - status, err = self.db2socket:sendDRDA( { drda_secchk, drda_accrdb } ) + status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_secchk, drda_accrdb } ) ) + if( not(status) ) then return false, "ERROR: Login failed" end + + -- + -- At this point we have a few differences in behaviour + -- * DB2 has told us earlier if the DB does not exist + -- * Apache Derby will do so here, regardless of the login was + -- successfull or not + -- * Informix will tell us that the DB does not exist IF the + -- login was successfull + -- + -- Therefore the order of these checks are important!! + if ( packet:getDRDAByCodePoint( CodePoint.ACCRDBRM ) ) then + return true + -- Apache Derby responds differently with usernames containing spaces + elseif ( packet:getDRDAByCodePoint( CodePoint.RDBATHRM ) ) then + return false, "ERROR: Login failed" + -- Informix responds with a SECCHKRM DDM response + elseif ( packet:getDRDAByCodePoint( CodePoint.SECCHKRM ) ) then + drda = packet:getDRDAByCodePoint( CodePoint.SECCHKRM ) + param= drda:getParameter( CodePoint.SECCHKCD ) + if ( param and param:getData() == "\0" ) then + return true + end + elseif ( packet:getDRDAByCodePoint( CodePoint.RDBNFNRM ) or + packet:getDRDAByCodePoint( CodePoint.RDBAFLRM ) ) then + return false, "ERROR: Database not found" + end + + return false, "ERROR: Login failed" + + end, + +} + +-- The communication class +Comm = { + + new = function(self, socket) + local o = {} + setmetatable(o, self) + self.__index = self + o.socket = socket + return o + end, + + --- Sends a packet to the server and receives the response + -- + -- @param DRDAPacket + -- @return status true on success, false on failure + -- @return packet an instance of DRDAPacket + exchDRDAPacket = function( self, packet ) + local drda, err + local status, err = self.socket:sendDRDA( packet ) + if ( not(status) ) then - stdnse.print_debug("db2.Helper.login: ERROR: DB2Socket error: %s", err ) + stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", err ) return false, ("ERROR: DB2Socket error: %s"):format( err ) end - - status, drda = self.db2socket:recvDRDA() + + status, drda = self.socket:recvDRDA() if( not(status) ) then - stdnse.print_debug("db2.Helper.login: ERROR: DB2Socket error: %s", drda ) + stdnse.print_debug("drda.Helper.login: ERROR: DB2Socket error: %s", drda ) return false, ("ERROR: DB2Socket error: %s"):format( drda ) end - param = drda[1]:getParameter( CodePoint.SECCHKCD ) - if ( not(param) ) then - stdnse.print_debug("db2.Helper.login: ERROR: Authentication failed") - return false, "ERROR: Authentication failed" - end - - local secchkcd = select( 2, bin.unpack( "C", param:getData() ) ) - if ( 0 ~= secchkcd ) then - stdnse.print_debug( "db2.Helper.login: ERROR: Authentication failed, error code: %d", secchkcd ) - return false, ("ERROR: Authentication failed, error code: %d"):format(secchkcd) - end - - return true - end, + return true, DRDAPacket:new( drda ) + + end } @@ -704,24 +793,7 @@ DB2Socket = { -- @return Status (true or false). -- @return Error code (if status is false). sendDRDA = function( self, drda ) - local data = "" - - if ( 0 == #drda ) then - data = drda:toString() - else - -- do some DDM fixup in here - for i=1, #drda do - if ( i == 1 and #drda > 1 ) then - drda[1].DDM.Format = 0x41 - else - drda[i].DDM.Format = 0x01 - end - drda[i].DDM.CorelId = i - data = data .. drda[i]:toString() - end - end - - return self:send(data) + return self:send(tostring(drda)) end, --- Reads a single or multiple DRDA's of the socket diff --git a/scripts/drda-brute.nse b/scripts/drda-brute.nse index c3e304a49..fd55ff2d5 100644 --- a/scripts/drda-brute.nse +++ b/scripts/drda-brute.nse @@ -1,19 +1,19 @@ description = [[ -Performs password guessing against IBM DB2. +Performs password guessing against databases supporting the IBM DB2 protocol such as Informix, DB2 and Derby ]] --- --- @args db2-brute.threads the amount of accounts to attempt to brute +-- @args drda-brute.threads the amount of accounts to attempt to brute -- force in parallell (default 10). --- @args db2-brute.dbname the database name against which to guess +-- @args drda-brute.dbname the database name against which to guess -- passwords (default "SAMPLE"). -- -- @usage --- nmap -p 50000 --script db2-brute +-- nmap -p 50000 --script drda-brute -- -- @output --- 50000/tcp open ibm-db2 --- | db2-brute: +-- 50000/tcp open drda +-- | drda-brute: -- |_ db2admin:db2admin => Login Correct author = "Patrik Karlsson" @@ -22,15 +22,16 @@ categories={"intrusive", "auth"} require "stdnse" require "shortport" -require "db2" +require "drda" require "unpwdb" -- Version 0.3 -- Created 05/08/2010 - v0.1 - created by Patrik Karlsson -- Revised 05/09/2010 - v0.2 - re-wrote as multi-threaded -- Revised 05/10/2010 - v0.3 - revised parallellised design +-- Revised 08/14/2010 - v0.4 - renamed script and library from db2* to drda* -portrule = shortport.port_or_service({50000,60000},"ibm-db2", "tcp", {"open", "open|filtered"}) +portrule = shortport.port_or_service({50000,60000}, "drda", "tcp", {"open", "open|filtered"}) --- Credential iterator -- @@ -65,14 +66,14 @@ doLogin = function( host, port, database, creds, valid_accounts ) for username, password in creds do -- Checks if a password was already discovered for this account if ( nmap.registry.db2users == nil or nmap.registry.db2users[username] == nil ) then - helper = db2.Helper:new() + helper = drda.Helper:new() helper:connect( host, port ) stdnse.print_debug( "Trying %s/%s against %s...", username, password, host.ip ) status, response = helper:login( database, username, password ) helper:close() if ( status ) then - -- Add credentials for future db2 scripts to use + -- Add credentials for future drda scripts to use if nmap.registry.db2users == nil then nmap.registry.db2users = {} end @@ -92,7 +93,7 @@ end -- @return status true on success, false on failure isValidDb = function( host, port, database ) local status, response - local helper = db2.Helper:new() + local helper = drda.Helper:new() helper:connect( host, port ) -- Authenticate with a static probe account to see if the db is valid @@ -127,13 +128,13 @@ action = function( host, port ) local result, response, status = {}, nil, nil local valid_accounts, threads = {}, {} local usernames, passwords, creds - local database = nmap.registry.args['db2-brute.dbname'] or "SAMPLE" + local database = nmap.registry.args['drda-brute.dbname'] or "SAMPLE" local condvar = nmap.condvar( valid_accounts ) - local max_threads = nmap.registry.args['db2-brute.threads'] and tonumber( nmap.registry.args['db2-brute.threads'] ) or 10 + local max_threads = nmap.registry.args['drda-brute.threads'] and tonumber( nmap.registry.args['drda-brute.threads'] ) or 10 -- Check if the DB specified is valid if( not(isValidDb(host, port, database)) ) then - return ("The databases %s was not found. (Use --script-args db2-brute.dbname= to specify database)"):format(database) + return ("The databases %s was not found. (Use --script-args drda-brute.dbname= to specify database)"):format(database) end status, usernames = unpwdb.usernames() diff --git a/scripts/drda-info.nse b/scripts/drda-info.nse index a7e41f87f..1302d1bcc 100644 --- a/scripts/drda-info.nse +++ b/scripts/drda-info.nse @@ -1,13 +1,14 @@ description = [[ -Attempts to extract information from IBM DB2 Server instances. The script sends a -DB2 EXCSAT (exchange server attributes) command packet and parses the response. +Attempts to extract information from database servers supporting the DRDA +protocol. The script sends a DRDA EXCSAT (exchange server attributes) +command packet and parses the response. ]] --- -- @output -- PORT STATE SERVICE --- 50000/tcp open ibm-db2 --- | db2-info: DB2 Version: 8.02.9 +-- 50000/tcp open drda +-- | drda-info: DB2 Version: 8.02.9 -- | Server Platform: QDB2/SUN -- | Instance Name: db2inst1 -- |_ External Name: db2inst1db2agent00002B430 @@ -20,7 +21,7 @@ categories = {"safe", "discovery", "version"} require "stdnse" require "shortport" -require "db2" +require "drda" -- Version 0.1 -- Created 05/08/2010 - v0.1 - created by Patrik Karlsson @@ -29,8 +30,8 @@ require "db2" -- parseVersion was ripped from the old db2-info.nse written by Tom Sellers -- -portrule = shortport.version_port_or_service({50000,60000}, - "ibm-db2", "tcp", +portrule = shortport.version_port_or_service({50000,60000,9090,1526,1527}, + {"drda"}, "tcp", {"open", "open|filtered"}) --- Converts the prodrel server string to a version string @@ -38,8 +39,9 @@ portrule = shortport.version_port_or_service({50000,60000}, -- @param server_version string containing the product release -- @return ver string containing the version information local function parseVersion( server_version ) - - if string.sub(server_version,1,3) == "SQL" then + local pfx = string.sub(server_version,1,3) + + if pfx == "SQL" or pfx == "IFX" then local major_version = string.sub(server_version,4,5) -- strip the leading 0 from the major version, for consistency with @@ -50,6 +52,8 @@ local function parseVersion( server_version ) local minor_version = string.sub(server_version,6,7) local hotfix = string.sub(server_version,8) server_version = major_version .. "." .. minor_version .. "." .. hotfix + elseif( pfx == "CSS" ) then + return server_version:match("%w+\/(.*)") end return server_version @@ -57,35 +61,50 @@ end action = function( host, port ) - local db2helper = db2.Helper:new() + local helper = drda.Helper:new() local status, response + local results = {} - status, response = db2helper:connect(host, port) + status, response = helper:connect(host, port) if( not(status) ) then return response end - status, response = db2helper:getServerInfo() + status, response = helper:getServerInfo() if( not(status) ) then return response end - db2helper:close() - + helper:close() + -- Set port information - port.version.name = "ibm-db2" - port.version.product = "IBM DB2 Database Server" - port.version.name_confidence = 100 + if ( response.srvclass and response.srvclass:match("IDS\/") ) then + port.version.name = "drda" + port.version.product = "IBM Informix Dynamic Server" + port.version.name_confidence = 100 + table.insert( results, ("Informix Version: %s"):format( parseVersion(response.prodrel) ) ) + elseif ( response.srvclass and response.srvclass:match("Apache Derby") ) then + port.version.name = "drda" + port.version.product = "Apache Derby Server" + port.version.name_confidence = 100 + table.insert( results, ("Derby Version: %s"):format( parseVersion(response.prodrel) ) ) + elseif ( response.srvclass and response.srvclass:match("DB2") ) then + port.version.name = "drda" + port.version.product = "IBM DB2 Database Server" + port.version.name_confidence = 100 + table.insert( results, ("DB2 Version: %s"):format( parseVersion(response.prodrel) ) ) + else + table.insert( results, ("Version: %s"):format( response.prodrel ) ) + end nmap.set_port_state(host, port, "open") if response.srvclass ~= nil then port.version.extrainfo = response.srvclass end nmap.set_port_version(host, port, "hardmatched") -- Generate results - local results = "DB2 Version: " .. parseVersion(response.prodrel) .. "\n" - results = results .. "Server Platform: " .. response.srvclass .. "\n" - results = results .. "Instance Name: " .. response.srvname .. "\n" - results = results .. "External Name: " .. response.extname + table.insert( results, ("Server Platform: %s"):format( response.srvclass ) ) + table.insert( results, ("Instance Name: %s"):format( response.srvname ) ) + table.insert( results, ("External Name: %s"):format( response.extname ) ) - return results + return stdnse.format_output( true, results ) end