1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-17 21:19:01 +00:00

Fixes and enhancements to tso/vtam scripts. Closes #649

This commit is contained in:
dmiller
2017-01-20 23:27:19 +00:00
parent 8cc713e534
commit a134cc916e
4 changed files with 234 additions and 86 deletions

View File

@@ -9000,7 +9000,7 @@ match http m|^HTTP/1\.1 400 Bad Request\r\nDate: Mon, 21 Feb 2011 17:38:00 GMT\r
match http m|^HTTP/1\.1 307 Temporary Redirect\r\n.*Content-Length: 0\r\nConnection: keep-alive\r\nServer: AmazonS3\r\n\r\n$|s p/Amazon S3 httpd/ match http m|^HTTP/1\.1 307 Temporary Redirect\r\n.*Content-Length: 0\r\nConnection: keep-alive\r\nServer: AmazonS3\r\n\r\n$|s p/Amazon S3 httpd/
match http m|^HTTP/1\.1 200 OK\nServer: BO/([\w._-]+)\nDate: .*\nContent-type: text/html\nPublic: GET, POST\nConnection: keep-alive\n\n| p/BO2K built-in httpd/ v/$1/ match http m|^HTTP/1\.1 200 OK\nServer: BO/([\w._-]+)\nDate: .*\nContent-type: text/html\nPublic: GET, POST\nConnection: keep-alive\n\n| p/BO2K built-in httpd/ v/$1/
match http m|^HTTP/1\.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHello, non-Bayeux request\. Yet another one$| p/Node.js/ i/Faye Bayeux protocol/ cpe:/a:nodejs:node.js/ match http m|^HTTP/1\.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHello, non-Bayeux request\. Yet another one$| p/Node.js/ i/Faye Bayeux protocol/ cpe:/a:nodejs:node.js/
match http m|^HTTP/1\.0 500 Internal Server Error\r\nCONTENT-TYPE: text/html\r\nDate: .*\r\nServer: IBM_CICS_Transaction_Server/([\w._-]+)\(zOS\)\r\n| p/IBM CICS Transaction Server/ v/$1/ o|z/OS| cpe:/o:ibm:z%2fos/ match http m|^HTTP/1\.[01] \d\d\d [^\r\n]*\r\nCONTENT-TYPE: text/html\r.*\nServer: IBM_CICS_Transaction_Server/([\w._-]+)\(zOS\)\r\n|s p/IBM CICS Transaction Server/ v/$1/ o|z/OS| cpe:/o:ibm:z%2fos/
match http m|^HTTP/1\.1 200 OK\r\nServer: corehttp-([\w._-]+)\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<html><body><pre>| p/CoreHTTP/ v/$1/ i/directory listing/ match http m|^HTTP/1\.1 200 OK\r\nServer: corehttp-([\w._-]+)\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<html><body><pre>| p/CoreHTTP/ v/$1/ i/directory listing/
# http://code.google.com/p/webfinger/ # http://code.google.com/p/webfinger/
match http m|^HTTP/1\.1 400 Bad request\r\n\r\n$| p/WebFinger httpd/ match http m|^HTTP/1\.1 400 Bad request\r\n\r\n$| p/WebFinger httpd/

View File

@@ -94,48 +94,65 @@ Driver = {
local commands = self.options['key1'] local commands = self.options['key1']
local always_logon = self.options['key2'] local always_logon = self.options['key2']
local skip = self.options['skip']
stdnse.debug(2,"Getting to TSO") stdnse.debug(2,"Getting to TSO")
local run = stdnse.strsplit(";%s*", commands) local run = stdnse.strsplit(";%s*", commands)
stdnse.verbose(2,"Trying User ID/Password: %s/%s", user, pass)
for i = 1, #run do for i = 1, #run do
stdnse.debug(2,"%s: Issuing Command (#%s of %s): %s",user , i, #run ,run[i]) stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
self.tn3270:send_cursor(run[i]) if i == #run and run[i]:upper():find("LOGON APPLID") and skip then
stdnse.debug(2,"Trying User ID: %s", user)
self.tn3270:send_cursor(run[i] .. " DATA(" .. user .. ")")
elseif i == #run and skip then
stdnse.debug(2,"Trying User ID: %s", user)
self.tn3270:send_cursor(run[i] .. " " .. user)
else
self.tn3270:send_cursor(run[i])
end
self.tn3270:get_all_data() self.tn3270:get_all_data()
end end
if ( self.tn3270:find('NO USER APPLID AVAILABLE') ) then if self.tn3270:find("***") then -- For ACF2/TopSecret if required
local err = brute.Error:new( "No APPLID Available" ) self.tn3270:send_enter()
-- This error occurs on too many concurrent application requests self.tn3270:get_all_data()
-- it should be temporary. end
err:setRetry( true )
if not self.tn3270:find("ENTER USERID")
and not self.tn3270:find("TSO/E LOGON")
and not self.tn3270:find("IKJ56710I INVALID USERID") then
local err = brute.Error:new( "TSO Unavailable" )
-- This error occurs on too many concurrent application requests it
-- should be temporary. We use the new setReduce function.
err:setReduce(true)
stdnse.debug(1,"TSO Unavailable for UserID %s", pass )
return false, err return false, err
end end
stdnse.verbose(2,"Trying User ID/Password: %s/%s", user, pass) if not skip then
stdnse.debug(2,"Sending User ID: %s", user) stdnse.debug(2,"Trying User ID: %s", user)
self.tn3270:send_cursor(user)
self.tn3270:send_cursor(user)
self.tn3270:get_all_data()
if self.tn3270:find("***") then
self.tn3270:send_enter() -- some systems require an enter after sending the user
self.tn3270:get_all_data() self.tn3270:get_all_data()
end end
stdnse.debug(2,"Screen Recieved for User ID: %s", user) stdnse.debug(2,"Screen Recieved for User ID: %s", user)
self.tn3270:get_screen_debug(2) self.tn3270:get_screen_debug(2)
if not self.tn3270:find('Enter LOGON parameters below') then if not self.tn3270:find('Enter LOGON parameters below') then
stdnse.debug(2,"Screen Recieved for User ID: %s", user) stdnse.debug(2,"Screen Recieved for User ID: %s", user)
self.tn3270:get_screen_debug(2) self.tn3270:get_screen_debug(2)
-- Sometimes mainframes get overloaded -- This error occurs on too many concurrent application requests it
-- should be temporary. We use the new setReduce function.
local err = brute.Error:new( "Not at TSO" ) local err = brute.Error:new( "Not at TSO" )
err:setRetry( true ) err:setReduce(true)
stdnse.debug(1,"TSO Unavailable for UserID %s", pass )
return false, err return false, err
end end
if self.tn3270:find('not authorized to use TSO') then -- invalid user ID if self.tn3270:find('not authorized to use TSO') then -- invalid user ID
stdnse.debug(2,"Got Message: IKJ56420I Userid %s not authorized to use TSO.", user) stdnse.debug(2,"Got Message: IKJ56420I Userid %s not authorized to use TSO.", user)
-- Store the invalid ID in the registry so we don't keep trying it with subsequent passwords -- Store the invalid ID in the registry so we don't keep trying it with subsequent passwords
-- when using default brute library. -- when using the brute library.
register_invalid(user) register_invalid(user)
return false, brute.Error:new( "User ID not authorized to use TSO" ) return false, brute.Error:new( "User ID not authorized to use TSO" )
else else
@@ -143,10 +160,10 @@ Driver = {
stdnse.debug(2,"%s is a valid TSO User ID. Trying Password: %s", string.upper(user), pass) stdnse.debug(2,"%s is a valid TSO User ID. Trying Password: %s", string.upper(user), pass)
if always_logon then if always_logon then
local writeable = self.tn3270:writeable() local writeable = self.tn3270:writeable()
-- This turns on -- This turns on the 'reconnect' which may boot users off
self.tn3270:send_locations({{writeable[1][1],pass},{writeable[11][1],"S"}}) self.tn3270:send_locations({{writeable[1][1],pass},{writeable[11][1],"S"}})
else else
self.tn3270:send_cursor(pass) self.tn3270:send_cursor(pass)
end end
self.tn3270:get_all_data() self.tn3270:get_all_data()
@@ -159,6 +176,7 @@ Driver = {
self.tn3270:get_screen_debug(2) self.tn3270:get_screen_debug(2)
if not always_logon and self.tn3270:find("already logged on") then if not always_logon and self.tn3270:find("already logged on") then
-- IKJ56425I LOGON rejected User already logged on to system
register_invalid(user) register_invalid(user)
return true, creds.Account:new(user, "<skipped>", "User logged on. Skipped.") return true, creds.Account:new(user, "<skipped>", "User logged on. Skipped.")
elseif not (self.tn3270:find("IKJ56421I") or elseif not (self.tn3270:find("IKJ56421I") or
@@ -176,14 +194,13 @@ Driver = {
-- TSS7143E Accessor ID Has Been Inactive Too Long -- TSS7143E Accessor ID Has Been Inactive Too Long
-- TSS7120E PASSWORD VIOLATION THRESHOLD EXCEEDED -- TSS7120E PASSWORD VIOLATION THRESHOLD EXCEEDED
stdnse.verbose(2,"Valid User/Pass" .. user .. "/" .. pass.. "MSG:" .. self.tn3270:get_screen():sub(1,80)) -- The 'MSG allows testers to discern any relevant messages they may get for the account'
stdnse.verbose(2,"Valid User/Pass: " .. user .. "/" .. pass)
stdnse.verbose(3,"Valid MSG for " .. user .. "/" .. pass .. ": " .. self.tn3270:get_screen():sub(1,80))
return true, creds.Account:new(user, pass, creds.State.VALID) return true, creds.Account:new(user, pass, creds.State.VALID)
else else
stdnse.verbose(self.tn3270:get_screen():sub(1,80))
return false, brute.Error:new( "Incorrect password" ) return false, brute.Error:new( "Incorrect password" )
end end
-- IKJ56425I LOGON rejected User already logged on to system
end end
end end
} }
@@ -194,34 +211,98 @@ Driver = {
-- @param port port NSE object -- @param port port NSE object
-- @param commands script-args of commands to use to get to TSO -- @param commands script-args of commands to use to get to TSO
-- @return status true on success, false on failure -- @return status true on success, false on failure
-- @return name of security product installed
local function tso_test( host, port, commands ) local function tso_test( host, port, commands )
local tso = false -- initially we're not at TSO logon panel
stdnse.debug("Checking for TSO") stdnse.debug("Checking for TSO")
local tn = tn3270.Telnet:new() local tn = tn3270.Telnet:new()
local status, err = tn:initiate(host,port)
local tso = false -- initially we're not at TSO logon panel
local secprod = "RACF"
tn:get_screen_debug(2) -- prints TN3270 screen to debug
if not status then
stdnse.debug("Could not initiate TN3270: %s", err )
return tso, "Could not Initiate TN3270"
end
local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do
stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
tn:send_cursor(run[i])
tn:get_all_data()
end
tn:get_screen_debug(2)
if tn:find("***") then
secprod = "TopSecret/ACF2"
end
if tn:find("ENTER USERID") or tn:find("TSO/E LOGON") then
tso = true
-- Patch OA44855 removed the ability to enumerate users
tn:send_cursor("notreal")
tn:get_all_data()
if tn:find("IKJ56476I ENTER PASSWORD") then
return false, secprod, "Enumeration is not possible. PASSWORDPREPROMPT is set to ON."
end
end
tn:send_pf(3)
tn:disconnect()
return tso, secprod, "Could not get to TSO. Try --script-args=tso-enum.commands='logon applid(tso)'. Aborting."
end
--- Tests the target to see if we can speed up brute forcing
-- VTAM/USSTable will sometimes allow you to put the userid
-- in the command area either through data() or just adding
-- the userid. This function will test for both
--
-- @param host host NSE object
-- @param port port NSE object
-- @param commands script-args of commands to use to get to TSO
-- @return status true on success, false on failure
local function tso_skip( host, port, commands )
stdnse.debug("Checking for IKJ56700A message skip")
local tn = tn3270.Telnet:new()
stdnse.debug2("Connecting TN3270 to %s:%s", host.targetname or host.ip, port.number) stdnse.debug2("Connecting TN3270 to %s:%s", host.targetname or host.ip, port.number)
local status, err = tn:initiate(host,port) local status, err = tn:initiate(host,port)
stdnse.debug2("Displaying initial TN3270 Screen:") stdnse.debug2("Displaying initial TN3270 Screen:")
tn:get_screen_debug(2) -- prints TN3270 screen to debug tn:get_screen_debug(2) -- prints TN3270 screen to debug
if not status then if not status then
stdnse.debug("Could not initiate TN3270: %s", err ) stdnse.debug("Could not initiate TN3270: %s", err )
return tso return false
end end
stdnse.debug("Getting to TSO") -- We're connected now to test.
local data = false
if commands:upper():find('LOGON APPLID') then
stdnse.debug(2,"Using LOGON command (%s) trying DATA() command", commands )
data = true
else
stdnse.debug(2,"Not using LOGON command, testing adding userid to command" )
end
local run = stdnse.strsplit(";%s*", commands) local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do for i = 1, #run do
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i]) stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
tn:send_cursor(run[i]) if i == #run then
if data then
stdnse.debug(2,"Sending "..run[i].." DATA(FAKEUSER)")
tn:send_cursor(run[i].." DATA(FAKEUSER)")
else
stdnse.debug(2,"Sending "..run[i].." FAKEUSER")
tn:send_cursor(run[i].." FAKEUSER")
end
else
tn:send_cursor(run[i])
end
tn:get_all_data() tn:get_all_data()
end end
tn:get_screen_debug(2) tn:get_screen_debug(2)
if tn:find("ENTER USERID") or if tn:find("IKJ56710I INVALID USERID") or
tn:find("TSO/E LOGON") then tn:find("Enter LOGON parameters below") then
tso = true stdnse.debug('IKJ56700A message skip supported')
return true
else
return false
end end
tn:disconnect()
return tso
end end
-- Filter iterator for unpwdb usernames -- Filter iterator for unpwdb usernames
@@ -252,20 +333,20 @@ action = function( host, port )
-- because a user is only allowed to logon from one location. If you turn always_logon on -- because a user is only allowed to logon from one location. If you turn always_logon on
-- it will logon if it finds a valid username/password, kicking that user off -- it will logon if it finds a valid username/password, kicking that user off
local always_logon = stdnse.get_script_args(SCRIPT_NAME .. '.always_logon') or false local always_logon = stdnse.get_script_args(SCRIPT_NAME .. '.always_logon') or false
local tsotst, secprod, err = tso_test(host, port, commands)
if tso_test(host, port, commands) then if tsotst then
stdnse.debug("Starting TSO Brute Force") stdnse.debug("Starting TSO Brute Force")
local options = { key1 = commands, key2 = always_logon } local options = { key1 = commands, key2 = always_logon, skip = tso_skip(host, port, commands) }
local engine = brute.Engine:new(Driver, host, port, options) local engine = brute.Engine:new(Driver, host, port, options)
-- TSO has username restrictions. This sets the iterator to use only valid TSO userids -- TSO has username/password restrictions.
-- This sets the iterators to use only valid TSO userids/passwords
engine:setUsernameIterator(unpwdb.filter_iterator(brute.usernames_iterator(),valid_name)) engine:setUsernameIterator(unpwdb.filter_iterator(brute.usernames_iterator(),valid_name))
engine:setPasswordIterator(unpwdb.filter_iterator(brute.passwords_iterator(), valid_pass)) engine:setPasswordIterator(unpwdb.filter_iterator(brute.passwords_iterator(),valid_pass))
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME
engine.options:setOption("useraspass", false )
engine.options:setTitle("TSO Accounts") engine.options:setTitle("TSO Accounts")
status, result = engine:start() status, result = engine:start()
return result
else else
return "Could not get to TSO. Try --script-args=tso-user-enum.commands='logon applid(tso)'. Aborting." return err
end end
return result
end end

View File

@@ -55,6 +55,7 @@ TSO user IDs have the following rules:
-- 2015-07-04 - v0.1 - created by Soldier of Fortran -- 2015-07-04 - v0.1 - created by Soldier of Fortran
-- 2015-10-30 - v0.2 - streamlined the code, relying on brute and unpwdb and -- 2015-10-30 - v0.2 - streamlined the code, relying on brute and unpwdb and
-- renamed to tso-enum. -- renamed to tso-enum.
-- 2017-1-13 - v0.3 - Fixed 'data' bug and added options checking to speedup
author = "Philip Young aka Soldier of Fortran" author = "Philip Young aka Soldier of Fortran"
@@ -92,53 +93,59 @@ Driver = {
login = function (self, user, pass) login = function (self, user, pass)
-- pass is actually the user id we want to try -- pass is actually the user id we want to try
local commands = self.options['key1'] local commands = self.options['key1']
local cmd_DATA = false local skip = self.options['skip']
stdnse.debug(2,"Getting to TSO") stdnse.debug(2,"Getting to TSO")
local run = stdnse.strsplit(";%s*", commands) local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do for i = 1, #run do
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i]) stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
if string.find(string.upper(run[i]),"logon applid") ~= nil then if i == #run and run[i]:upper():find("LOGON APPLID") and skip then
stdnse.verbose(2,"Trying User ID: %s", pass) stdnse.verbose(2,"Trying User ID: %s", pass)
self.tn3270:send_cursor(run[i] .. " DATA(" .. pass .. ")") self.tn3270:send_cursor(run[i] .. " DATA(" .. pass .. ")")
cmd_DATA = true elseif i == #run and skip then
stdnse.verbose(2,"Trying User ID: %s", pass)
self.tn3270:send_cursor(run[i] .. " " .. pass)
else else
self.tn3270:send_cursor(run[i]) self.tn3270:send_cursor(run[i])
end end
self.tn3270:get_all_data() self.tn3270:get_all_data()
end end
self.tn3270:get_screen_debug(2) if self.tn3270:find("***") then
self.tn3270:send_enter()
self.tn3270:get_all_data()
end
if not self.tn3270:find("ENTER USERID") and not self.tn3270:find("TSO/E LOGON") then if not self.tn3270:find("ENTER USERID")
local err = brute.Error:new( "TSO Unavailable" ) and not self.tn3270:find("TSO/E LOGON")
and not self.tn3270:find("IKJ56710I INVALID USERID") then
local err = brute.Error:new("Too many connections")
-- This error occurs on too many concurrent application requests it -- This error occurs on too many concurrent application requests it
-- should be temporary. If not, the script errors and less threads should be used. -- should be temporary. We use the new setReduce function.
err:setRetry( true ) err:setReduce(true)
stdnse.debug(1,"TSO Unavailable for UserID %s", pass )
return false, err return false, err
end end
if not cmd_DATA then if not skip then
stdnse.verbose(2,"Trying User ID: %s", pass) stdnse.verbose(2,"Trying User ID: %s", pass)
self.tn3270:send_cursor(pass) self.tn3270:send_cursor(pass)
self.tn3270:get_all_data() self.tn3270:get_all_data()
-- some systems require an enter after sending a valid user ID -- some systems require an enter after sending a valid user ID
if self.tn3270:find("***") then
self.tn3270:send_enter()
self.tn3270:get_all_data()
end
end end
stdnse.debug(2,"Screen Recieved for User ID: %s", pass) stdnse.debug(2,"Screen Recieved for User ID: %s", pass)
self.tn3270:get_screen_debug(2) self.tn3270:get_screen_debug(2)
if self.tn3270:find('not authorized to use TSO') then -- invalid user ID if self.tn3270:find('not authorized to use TSO') or
self.tn3270:find('IKJ56710I INVALID USERID') then -- invalid user ID
return false, brute.Error:new( "Incorrect User ID" ) return false, brute.Error:new( "Incorrect User ID" )
elseif ( self.tn3270:find('NO USER APPLID AVAILABLE') ) or elseif self.tn3270:find('NO USER APPLID AVAILABLE') or self.tn3270:isClear()
( self.tn3270:isClear() ) or (not self.tn3270:find('TSO/E LOGON') ) then or not (self.tn3270:find('TSO/E LOGON') or
local err = brute.Error:new( "TSO Unavailable" ) self.tn3270:find("IKJ56710I INVALID USERID")) then
-- This error occurs on too many concurrent application requests it -- This error occurs on too many concurrent application requests it
-- should be temporary. If not, the script errors and less threads should be used. -- should be temporary. We use the new setReduce function here to reduce number of connections.
err:setRetry( true ) local err = brute.Error:new( "TSO Unavailable" )
err:setReduce(true)
stdnse.debug(1,"TSO Unavailable for UserID %s", pass )
return false, err return false, err
else else
stdnse.verbose("Valid TSO User ID: %s", string.upper(pass)) stdnse.verbose("Valid TSO User ID: %s", string.upper(pass))
@@ -165,35 +172,89 @@ local function tso_test( host, port, commands )
stdnse.debug("Could not initiate TN3270: %s", err ) stdnse.debug("Could not initiate TN3270: %s", err )
return tso, "Could not Initiate TN3270" return tso, "Could not Initiate TN3270"
end end
stdnse.debug("Getting to TSO")
local run = stdnse.strsplit(";%s*", commands) local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do for i = 1, #run do
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i]) stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
tn:send_cursor(run[i]) tn:send_cursor(run[i])
tn:get_all_data() tn:get_all_data()
end end
tn:get_screen_debug(2) tn:get_screen_debug(2)
if tn:find("ENTER USERID") or tn:find("TSO/E LOGON") then
tso = true
-- Patch OA44855 removed the ability to enumerator users
-- we check for that here
tn:send_cursor("notreal")
tn:get_all_data()
if tn:find("IKJ56476I ENTER PASSWORD") then
return false, "Could not enumerate. PASSWORDPREPROMPT is set to ON."
end
end
if tn:find("***") then if tn:find("***") then
secprod = "TopSecret/ACF2" secprod = "TopSecret/ACF2"
end end
if tn:find("ENTER USERID") or tn:find("TSO/E LOGON") then
tso = true
-- Patch OA44855 removed the ability to enumerate users
tn:send_cursor("notreal")
tn:get_all_data()
if tn:find("IKJ56476I ENTER PASSWORD") then
return false, secprod, "Enumeration is not possible. PASSWORDPREPROMPT is set to ON."
end
end
tn:send_pf(3) tn:send_pf(3)
tn:disconnect() tn:disconnect()
return tso, secprod, "Could not get to TSO. Try --script-args=tso-enum.commands='logon applid(tso)'. Aborting." return tso, secprod, "Could not get to TSO. Try --script-args=tso-enum.commands='logon applid(tso)'. Aborting."
end end
--- Tests the target to see if we can speed up brute forcing
-- VTAM/USSTable will sometimes allow you to put the userid
-- in the command area either through data() or just adding
-- the userid. This function will test for both
--
-- @param host host NSE object
-- @param port port NSE object
-- @param commands script-args of commands to use to get to TSO
-- @return status true on success, false on failure
local function tso_skip( host, port, commands )
stdnse.debug("Checking for IKJ56700A message skip")
local tn = tn3270.Telnet:new()
stdnse.debug2("Connecting TN3270 to %s:%s", host.targetname or host.ip, port.number)
local status, err = tn:initiate(host,port)
stdnse.debug2("Displaying initial TN3270 Screen:")
tn:get_screen_debug(2) -- prints TN3270 screen to debug
if not status then
stdnse.debug("Could not initiate TN3270: %s", err )
return false
end
-- We're connected now to test.
local data = false
if commands:upper():find('LOGON APPLID') then
stdnse.debug(2,"Using LOGON command (%s) trying DATA() command", commands )
data = true
else
stdnse.debug(2,"Not using LOGON command, testing adding userid to command" )
end
local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do
stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
if i == #run then
if data then
stdnse.debug(2,"Sending "..run[i].." DATA(FAKEUSER)")
tn:send_cursor(run[i].." DATA(FAKEUSER)")
else
stdnse.debug(2,"Sending "..run[i].." FAKEUSER")
tn:send_cursor(run[i].." FAKEUSER")
end
else
tn:send_cursor(run[i])
end
tn:get_all_data()
end
tn:get_screen_debug(2)
if tn:find("IKJ56710I INVALID USERID") or
tn:find("Enter LOGON parameters below") then
stdnse.debug('IKJ56700A message skip supported')
return true
else
return false
end
end
-- Filter iterator for unpwdb -- Filter iterator for unpwdb
-- TSO is limited to 7 alpha numeric and @, #, $ and can't start with a number -- TSO is limited to 7 alpha numeric and @, #, $ and can't start with a number
-- pattern: -- pattern:
@@ -207,7 +268,7 @@ action = function(host, port)
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') or "tso" local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') or "tso"
local tsotst, secprod, err = tso_test(host, port, commands) local tsotst, secprod, err = tso_test(host, port, commands)
if tsotst then if tsotst then
local options = { key1 = commands } local options = { key1 = commands, skip = tso_skip(host, port, commands) }
stdnse.debug("Starting TSO User ID Enumeration") stdnse.debug("Starting TSO User ID Enumeration")
local engine = brute.Engine:new(Driver, host, port, options) local engine = brute.Engine:new(Driver, host, port, options)
engine.options.script_name = SCRIPT_NAME engine.options.script_name = SCRIPT_NAME

View File

@@ -54,6 +54,8 @@ found for application IDs.
-- 2015-07-04 - v0.1 - created by Soldier of Fortran -- 2015-07-04 - v0.1 - created by Soldier of Fortran
-- 2015-11-04 - v0.2 - significant upgrades and speed increases -- 2015-11-04 - v0.2 - significant upgrades and speed increases
-- 2015-11-14 - v0.3 - rewrote iterator -- 2015-11-14 - v0.3 - rewrote iterator
-- 2017-01-13 - v0.4 - Fixed 'macros' bug with default vtam screen and test
-- and added threshold for macros screen checking
-- --
author = "Philip Young aka Soldier of Fortran" author = "Philip Young aka Soldier of Fortran"
@@ -120,11 +122,13 @@ Driver = {
local macros = self.options['key3'] local macros = self.options['key3']
local cmdfmt = "logon applid(%s)" local cmdfmt = "logon applid(%s)"
local type = "applid" local type = "applid"
local threshold = 75
-- instead of sending 'logon applid(<appname>)' when macros=true -- instead of sending 'logon applid(<appname>)' when macros=true
-- we try to logon with just the command -- we try to logon with just the command
if macros then if macros then
cmdfmt = "%s" cmdfmt = "%s"
type ="macro" type ="macro"
threshold = 90 -- sometimes the screen barely changes
end end
stdnse.verbose(2,"Trying VTAM ID: %s", pass) stdnse.verbose(2,"Trying VTAM ID: %s", pass)
@@ -134,10 +138,9 @@ Driver = {
self.tn3270:get_screen_debug(2) self.tn3270:get_screen_debug(2)
local current_screen = self.tn3270:get_screen_raw() local current_screen = self.tn3270:get_screen_raw()
if (self.tn3270:find('UNABLE TO ESTABLISH SESSION') or if (self.tn3270:find('UNABLE TO ESTABLISH SESSION') or -- thanks goes to Dominic White for creating these
self.tn3270:find('COMMAND UNRECOGNI[SZ]ED') or self.tn3270:find('COMMAND UNRECOGNI[SZ]ED') or
self.tn3270:find('UNABLE TO CONNECT TO THE REQUESTED APPLICATION') or self.tn3270:find('USSMSG0[1-4]') or
self.tn3270:find('USSMSG0[1-4]') or
self.tn3270:find('SESSION NOT BOUND') or self.tn3270:find('SESSION NOT BOUND') or
self.tn3270:find('INVALID COMMAND') or self.tn3270:find('INVALID COMMAND') or
self.tn3270:find('PARAMETER OMITTED') or self.tn3270:find('PARAMETER OMITTED') or
@@ -149,9 +152,11 @@ Driver = {
self.tn3270:find('syntax invalid') or self.tn3270:find('syntax invalid') or
self.tn3270:find('INVALID SYSTEM') or self.tn3270:find('INVALID SYSTEM') or
self.tn3270:find('NOT VALID') or self.tn3270:find('NOT VALID') or
self.tn3270:find('INVALID USERID, APPLID') ) or -- thanks goes to Domonic White for creating these self.tn3270:find('INVALID USERID, APPLID') ) or
screen_diff(previous_screen, current_screen) > 75 then self.tn3270:find('UNABLE TO CONNECT TO THE REQUESTED APPLICATION') or
screen_diff(previous_screen, current_screen) > threshold then
-- Looks like an invalid APPLID. -- Looks like an invalid APPLID.
stdnse.verbose(2,'Invalid Application ID: %s',string.upper(pass))
return false, brute.Error:new( "Invalid VTAM Application ID" ) return false, brute.Error:new( "Invalid VTAM Application ID" )
else else
stdnse.verbose(2,"Valid Application ID: %s",string.upper(pass)) stdnse.verbose(2,"Valid Application ID: %s",string.upper(pass))
@@ -200,10 +205,12 @@ local function vtam_test( host, port, commands, macros)
tn:get_all_data() tn:get_all_data()
tn:get_screen_debug(2) tn:get_screen_debug(2)
local isVTAM = false local isVTAM = false
if tn:find('IBMECHO ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') then if not macros and tn:find('IBMECHO ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') then
stdnse.debug2("IBMTEST Returned: IBMECHO ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.") stdnse.debug2("IBMTEST Returned: IBMECHO ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.")
stdnse.debug1("VTAM Test Success!") stdnse.debug1("VTAM Test Success!")
isVTAM = true isVTAM = true
elseif macros then
isVTAM = true
end end
if not macros then if not macros then
@@ -239,7 +246,6 @@ action = function(host, port)
local macros = stdnse.get_script_args(SCRIPT_NAME .. '.macros') or false -- if set to true, doesn't prepend the commands with 'logon applid' local macros = stdnse.get_script_args(SCRIPT_NAME .. '.macros') or false -- if set to true, doesn't prepend the commands with 'logon applid'
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') -- Commands to send to get to VTAM local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') -- Commands to send to get to VTAM
local vtam_ids = {"tso", "CICS", "IMS", "NETVIEW", "TPX"} -- these are defaults usually seen local vtam_ids = {"tso", "CICS", "IMS", "NETVIEW", "TPX"} -- these are defaults usually seen
vtam_id_file = ( (vtam_id_file and nmap.fetchfile(vtam_id_file)) or vtam_id_file ) or vtam_id_file = ( (vtam_id_file and nmap.fetchfile(vtam_id_file)) or vtam_id_file ) or
nmap.fetchfile("nselib/data/vhosts-default.lst") nmap.fetchfile("nselib/data/vhosts-default.lst")