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:
@@ -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/
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user