diff --git a/scripts/nje-node-brute.nse b/scripts/nje-node-brute.nse
index 90da97f2e..bd47f2e0c 100644
--- a/scripts/nje-node-brute.nse
+++ b/scripts/nje-node-brute.nse
@@ -33,13 +33,17 @@ target IP (OIP) and a 1 byte response value (R) as outlined below:
* TYPE: Can either be 'OPEN', 'ACK', or 'NAK', in EBCDIC, padded by spaces to make 8 bytes. This script always send 'OPEN' type.
-* RHOST: Name of the local machine initiating the connection. Set to 'FAKE'
+* RHOST: Node name of the local machine initiating the connection. Set to 'FAKE'.
* RIP: Hex value of the local systems IP address. Set to '0.0.0.0'
-* OHOST: The value being enumerated to determine the target system name.
+* OHOST: The value being enumerated to determine the targets NJE node name.
* OIP: IP address, in hex, of the target system. Set to '0.0.0.0'.
-* R: The response. NJE will send an 'R' of 0x01 if the OHOST is wrong or 0x04/0x00 if the OHOST is correct.
+* R: The response. NJE will send an 'R' of 0x01 if the OHOST is wrong or 0x04 if the OHOST is correct.
-Since most systems will only have one node name, it is recommended to use the
+By default this script will attempt the brute force a mainframes OHOST. If supplied with
+the argument nje-node-brute.ohost this script will attempt the bruteforce
+the RHOST, setting OHOST to the value supplied to the argument.
+
+Since most systems will only have one OHOST name, it is recommended to use the
brute.firstonly script argument.
]]
@@ -52,24 +56,27 @@ Since most systems will only have one node name, it is recommended to use the
-- @args nje-node-brute.hostlist The filename of a list of node names to try.
-- Defaults to "nselib/data/vhosts-default.lst"
--
+-- @args nje-node-brute.ohost The target mainframe OHOST. Used to bruteforce RHOST.
+--
-- @output
-- PORT STATE SERVICE REASON
-- 175/tcp open nje syn-ack
-- | nje-node-brute:
-- | Node Name:
--- | Node Name:WASHDC - Valid credentials
+-- | POTATO:CACTUS - Valid credentials
-- |_ Statistics: Performed 6 guesses in 14 seconds, average tps: 0
--
-- @changelog
-- 2015-06-15 - v0.1 - created by Soldier of Fortran
+-- 2016-03-22 - v0.2 - Added RHOST Brute forcing.
author = "Soldier of Fortran"
-license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive", "brute"}
portrule = shortport.port_or_service({175,2252}, "nje")
-local openNJEfmt = "\xd6\xd7\xc5\xd5@@@@\xc6\xc1\xd2\xc5@@@@\0\0\0\0%s\0\0\0\0\0"
+local openNJEfmt = "\xd6\xd7\xc5\xd5@@@@%s\0\0\0\0%s\0\0\0\0\0"
Driver = {
new = function(self, host, port, options)
@@ -86,6 +93,7 @@ Driver = {
-- the high timeout should take delays into consideration
local s, r, opts, _ = comm.tryssl(self.host, self.port, '', { timeout = 50000 } )
if ( not(s) ) then
+ stdnse.debug2("Failed to connect")
return false, "Failed to connect to server"
end
self.socket = s
@@ -100,15 +108,24 @@ Driver = {
-- Generates an NJE 'OPEN' packet with the node name
password = string.upper(password)
stdnse.verbose(2,"Trying... %s", password)
- local openNJE = openNJEfmt:format( drda.StringUtil.toEBCDIC(("%-8s"):format(password)) )
+ local openNJE
+ if self.options['ohost'] then
+ -- One RHOST may have many valid OHOSTs
+ if password == self.options['ohost'] then return false, brute.Error:new( "RHOST cannot be OHOST" ) end
+ openNJE = openNJEfmt:format(drda.StringUtil.toEBCDIC(("%-8s"):format(password)),
+ drda.StringUtil.toEBCDIC(("%-8s"):format(self.options['ohost'])) )
+ else
+ openNJE = openNJEfmt:format(drda.StringUtil.toEBCDIC(("%-8s"):format('FAKE')),
+ drda.StringUtil.toEBCDIC(("%-8s"):format(password)) )
+ end
local status, err = self.socket:send( openNJE )
if not status then return false, "Failed to send" end
local status, data = self.socket:receive_bytes(33)
if not status then return false, "Failed to receive" end
- if ( data:sub(-1) == "\0" ) or
- ( data:sub(-1) == "\x04" ) then
- stdnse.verbose("Valid Node Name Found: %s", password)
- return true, creds.Account:new("Node Name", password, creds.State.VALID)
+ if ( not self.options['ohost'] and ( data:sub(-1) == "\x04" ) ) or
+ ( self.options['ohost'] and ( data:sub(-1) == "\0" ) ) then
+ -- stdnse.verbose(2,"Valid Node Name Found: %s", password)
+ return true, creds.Account:new((self.options['ohost'] or "Node Name"), password, creds.State.VALID)
end
return false, brute.Error:new( "Invalid Node Name" )
end,
@@ -131,6 +148,9 @@ end
action = function( host, port )
-- Oftentimes the LPAR will be one of the subdomain of a system.
local names = host.name and stdnse.strsplit("%.", host.name) or {}
+ local o_host = stdnse.get_script_args('nje-node-brute.ohost') or nil
+ local options = {}
+ if o_host then options = { ohost = o_host:upper() } end
if host.targetname then
host.targetname:gsub("[^.]+", function(n) table.insert(names, n) end)
end
@@ -142,12 +162,13 @@ action = function( host, port )
table.insert(names, l)
end
end
- local engine = brute.Engine:new(Driver, host, port)
- local users = unpwdb.filter_iterator(iter(names), valid_name)
+ if o_host then stdnse.verbose(2,'RHOST Mode, using OHOST: %s', o_host:upper()) end
+ local engine = brute.Engine:new(Driver, host, port, options)
+ local nodes = unpwdb.filter_iterator(iter(names), valid_name)
engine.options:setOption("passonly", true )
- engine:setPasswordIterator(users)
+ engine:setPasswordIterator(nodes)
engine.options.script_name = SCRIPT_NAME
- engine.options:setTitle("Node Name")
+ engine.options:setTitle("Node Name(s)")
local status, result = engine:start()
return result
end