mirror of
https://github.com/nmap/nmap.git
synced 2026-02-02 19:49:11 +00:00
Fixes and enhancements to tso/vtam scripts. Closes #649
This commit is contained in:
@@ -94,48 +94,65 @@ Driver = {
|
||||
|
||||
local commands = self.options['key1']
|
||||
local always_logon = self.options['key2']
|
||||
local skip = self.options['skip']
|
||||
stdnse.debug(2,"Getting to TSO")
|
||||
local run = stdnse.strsplit(";%s*", commands)
|
||||
stdnse.verbose(2,"Trying User ID/Password: %s/%s", user, pass)
|
||||
for i = 1, #run do
|
||||
stdnse.debug(2,"%s: Issuing Command (#%s of %s): %s",user , i, #run ,run[i])
|
||||
self.tn3270:send_cursor(run[i])
|
||||
stdnse.debug(2,"Issuing Command (#%s of %s): %s", i, #run ,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()
|
||||
end
|
||||
|
||||
if ( self.tn3270:find('NO USER APPLID AVAILABLE') ) then
|
||||
local err = brute.Error:new( "No APPLID Available" )
|
||||
-- This error occurs on too many concurrent application requests
|
||||
-- it should be temporary.
|
||||
err:setRetry( true )
|
||||
if self.tn3270:find("***") then -- For ACF2/TopSecret if required
|
||||
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")
|
||||
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
|
||||
end
|
||||
|
||||
stdnse.verbose(2,"Trying User ID/Password: %s/%s", user, pass)
|
||||
stdnse.debug(2,"Sending User ID: %s", 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
|
||||
if not skip then
|
||||
stdnse.debug(2,"Trying User ID: %s", user)
|
||||
self.tn3270:send_cursor(user)
|
||||
self.tn3270:get_all_data()
|
||||
end
|
||||
|
||||
|
||||
stdnse.debug(2,"Screen Recieved for User ID: %s", user)
|
||||
self.tn3270:get_screen_debug(2)
|
||||
|
||||
if not self.tn3270:find('Enter LOGON parameters below') then
|
||||
stdnse.debug(2,"Screen Recieved for User ID: %s", user)
|
||||
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" )
|
||||
err:setRetry( true )
|
||||
err:setReduce(true)
|
||||
stdnse.debug(1,"TSO Unavailable for UserID %s", pass )
|
||||
return false, err
|
||||
end
|
||||
|
||||
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)
|
||||
-- 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)
|
||||
return false, brute.Error:new( "User ID not authorized to use TSO" )
|
||||
else
|
||||
@@ -143,10 +160,10 @@ Driver = {
|
||||
stdnse.debug(2,"%s is a valid TSO User ID. Trying Password: %s", string.upper(user), pass)
|
||||
if always_logon then
|
||||
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"}})
|
||||
else
|
||||
self.tn3270:send_cursor(pass)
|
||||
self.tn3270:send_cursor(pass)
|
||||
end
|
||||
|
||||
self.tn3270:get_all_data()
|
||||
@@ -159,6 +176,7 @@ Driver = {
|
||||
self.tn3270:get_screen_debug(2)
|
||||
|
||||
if not always_logon and self.tn3270:find("already logged on") then
|
||||
-- IKJ56425I LOGON rejected User already logged on to system
|
||||
register_invalid(user)
|
||||
return true, creds.Account:new(user, "<skipped>", "User logged on. Skipped.")
|
||||
elseif not (self.tn3270:find("IKJ56421I") or
|
||||
@@ -176,14 +194,13 @@ Driver = {
|
||||
-- TSS7143E Accessor ID Has Been Inactive Too Long
|
||||
-- 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)
|
||||
else
|
||||
stdnse.verbose(self.tn3270:get_screen():sub(1,80))
|
||||
return false, brute.Error:new( "Incorrect password" )
|
||||
end
|
||||
|
||||
-- IKJ56425I LOGON rejected User already logged on to system
|
||||
end
|
||||
end
|
||||
}
|
||||
@@ -194,34 +211,98 @@ Driver = {
|
||||
-- @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
|
||||
|
||||
-- @return name of security product installed
|
||||
local function tso_test( host, port, commands )
|
||||
local tso = false -- initially we're not at TSO logon panel
|
||||
stdnse.debug("Checking for TSO")
|
||||
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)
|
||||
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 tso
|
||||
return false
|
||||
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)
|
||||
for i = 1, #run do
|
||||
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
|
||||
tn:send_cursor(run[i])
|
||||
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("ENTER USERID") or
|
||||
tn:find("TSO/E LOGON") then
|
||||
tso = true
|
||||
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
|
||||
tn:disconnect()
|
||||
return tso
|
||||
end
|
||||
|
||||
-- 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
|
||||
-- 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
|
||||
|
||||
if tso_test(host, port, commands) then
|
||||
local tsotst, secprod, err = tso_test(host, port, commands)
|
||||
if tsotst then
|
||||
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)
|
||||
-- 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: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:setOption("useraspass", false )
|
||||
engine.options:setTitle("TSO Accounts")
|
||||
status, result = engine:start()
|
||||
return result
|
||||
else
|
||||
return "Could not get to TSO. Try --script-args=tso-user-enum.commands='logon applid(tso)'. Aborting."
|
||||
return err
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user