mirror of
https://github.com/nmap/nmap.git
synced 2025-12-21 06:59:01 +00:00
Add tso-enum and tso-brute. See #554
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] Script tso-enum enumerates usernames for TN3270 Telnet services, and
|
||||||
|
tso-brute brute-forces passwords for the same services. [Soldier of Fortran]
|
||||||
|
|
||||||
o [NSE] Script vtam-enum brute-forces VTAM application IDs for TN3270 services.
|
o [NSE] Script vtam-enum brute-forces VTAM application IDs for TN3270 services.
|
||||||
[Soldier of Fortran]
|
[Soldier of Fortran]
|
||||||
|
|
||||||
|
|||||||
@@ -520,6 +520,8 @@ Entry { filename = "tls-nextprotoneg.nse", categories = { "default", "discovery"
|
|||||||
Entry { filename = "tn3270-screen.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "tn3270-screen.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "tor-consensus-checker.nse", categories = { "external", "safe", } }
|
Entry { filename = "tor-consensus-checker.nse", categories = { "external", "safe", } }
|
||||||
Entry { filename = "traceroute-geolocation.nse", categories = { "discovery", "external", "safe", } }
|
Entry { filename = "traceroute-geolocation.nse", categories = { "discovery", "external", "safe", } }
|
||||||
|
Entry { filename = "tso-brute.nse", categories = { "intrusive", } }
|
||||||
|
Entry { filename = "tso-enum.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "unittest.nse", categories = { "safe", } }
|
Entry { filename = "unittest.nse", categories = { "safe", } }
|
||||||
Entry { filename = "unusual-port.nse", categories = { "safe", } }
|
Entry { filename = "unusual-port.nse", categories = { "safe", } }
|
||||||
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
|
Entry { filename = "upnp-info.nse", categories = { "default", "discovery", "safe", } }
|
||||||
|
|||||||
271
scripts/tso-brute.nse
Normal file
271
scripts/tso-brute.nse
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
local stdnse = require "stdnse"
|
||||||
|
local shortport = require "shortport"
|
||||||
|
local tn3270 = require "tn3270"
|
||||||
|
local brute = require "brute"
|
||||||
|
local creds = require "creds"
|
||||||
|
local unpwdb = require "unpwdb"
|
||||||
|
local nmap = require "nmap"
|
||||||
|
local string = require "string"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
TSO account brute forcer.
|
||||||
|
|
||||||
|
This script relies on the NSE TN3270 library which emulates a
|
||||||
|
TN3270 screen for NMAP.
|
||||||
|
|
||||||
|
TSO user IDs have the following rules:
|
||||||
|
- it cannot begin with a number
|
||||||
|
- only contains alpha-numeric characters and @, #, $.
|
||||||
|
- it cannot be longer than 7 chars
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage
|
||||||
|
-- nmap -p 2401 --script tso-brute <host>
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- 23/tcp open tn3270 syn-ack IBM Telnet TN3270
|
||||||
|
-- | tso-brute:
|
||||||
|
-- | Node Name:
|
||||||
|
-- | IBMUSER:<skipped> - User logged on. Skipped.
|
||||||
|
-- | ZERO:<skipped> - User logged on. Skipped.
|
||||||
|
-- | COOL:secret - Valid credentials
|
||||||
|
-- |_ Statistics: Performed 6 guesses in 6 seconds, average tps: 1
|
||||||
|
-- Final times for host: srtt: 96305 rttvar: 72303 to: 385517
|
||||||
|
--
|
||||||
|
-- @args tso-brute.commands Commands in a semi-colon seperated list needed
|
||||||
|
-- to access TSO. Defaults to <code>TSO</code>.
|
||||||
|
--
|
||||||
|
-- @args tso-brute.always_logon TSO logon can kick a user off if it guesses
|
||||||
|
-- the correct password. always_logon, when set to <code>true</code>, will logon, even if
|
||||||
|
-- the user is logged in (kicking that user off). The default, <code>false</code> will
|
||||||
|
-- skip that account.
|
||||||
|
--
|
||||||
|
-- @changelog
|
||||||
|
-- 2015-10-29 - v0.1 - created by Soldier of Fortran
|
||||||
|
--
|
||||||
|
-- @author Philip Young
|
||||||
|
-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
|
||||||
|
--
|
||||||
|
|
||||||
|
author = "Soldier of Fortran"
|
||||||
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"intrusive"}
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service({23,992,623}, {"tn3270"})
|
||||||
|
|
||||||
|
--- Registers User IDs that no longer need to be tested
|
||||||
|
--
|
||||||
|
-- @param username to stop checking
|
||||||
|
local function register_invalid( username )
|
||||||
|
if nmap.registry.tsoinvalid == nil then
|
||||||
|
nmap.registry.tsoinvalid = {}
|
||||||
|
end
|
||||||
|
stdnse.debug(2,"Registering %s", username)
|
||||||
|
nmap.registry.tsoinvalid[username] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
Driver = {
|
||||||
|
new = function(self, host, port, options)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
o.host = host
|
||||||
|
o.port = port
|
||||||
|
o.options = options
|
||||||
|
o.tn3270 = tn3270.Telnet:new()
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
connect = function( self )
|
||||||
|
local status, err = self.tn3270:initiate(self.host,self.port)
|
||||||
|
self.tn3270:get_screen_debug(2)
|
||||||
|
if not status then
|
||||||
|
stdnse.debug("Could not initiate TN3270: %s", err )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
disconnect = function( self )
|
||||||
|
self.tn3270:disconnect()
|
||||||
|
self.tn3270 = nil
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
login = function (self, user, pass)
|
||||||
|
|
||||||
|
local commands = self.options['key1']
|
||||||
|
local always_logon = self.options['key2']
|
||||||
|
stdnse.debug(2,"Getting to TSO")
|
||||||
|
local run = stdnse.strsplit(";%s*", commands)
|
||||||
|
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])
|
||||||
|
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 )
|
||||||
|
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
|
||||||
|
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
|
||||||
|
local err = brute.Error:new( "Not at TSO" )
|
||||||
|
err:setRetry( true )
|
||||||
|
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.
|
||||||
|
register_invalid(user)
|
||||||
|
return false, brute.Error:new( "User ID not authorized to use TSO" )
|
||||||
|
else
|
||||||
|
-- It's a valid account so lets try a password
|
||||||
|
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
|
||||||
|
self.tn3270:send_locations({{writeable[1][1],pass},{writeable[11][1],"S"}})
|
||||||
|
else
|
||||||
|
self.tn3270:send_cursor(pass)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.tn3270:get_all_data()
|
||||||
|
while self.tn3270:isClear() do
|
||||||
|
-- the screen is blank for a few while it loads TSO
|
||||||
|
self.tn3270:get_all_data()
|
||||||
|
end
|
||||||
|
|
||||||
|
stdnse.debug(2,"Screen Recieved for User/Pass: %s/%s", user, pass)
|
||||||
|
self.tn3270:get_screen_debug(2)
|
||||||
|
|
||||||
|
if not always_logon and self.tn3270:find("already logged on") then
|
||||||
|
register_invalid(user)
|
||||||
|
return true, creds.Account:new(user, "<skipped>", "User logged on. Skipped.")
|
||||||
|
elseif not (self.tn3270:find("IKJ56421I") or
|
||||||
|
self.tn3270:find("TSS7101E") or
|
||||||
|
self.tn3270:find("TSS714[0-3]E") or
|
||||||
|
self.tn3270:find("TSS7120E")) then
|
||||||
|
-- RACF:
|
||||||
|
-- IKJ56421I PASSWORD NOT AUTHORIZED FOR USERID
|
||||||
|
|
||||||
|
-- Top Secret:
|
||||||
|
-- TSS7101E Password is Incorrect
|
||||||
|
-- TSS7140E Accessor ID Has Expired: No Longer Valid
|
||||||
|
-- TSS7141E Use of Accessor ID Suspended
|
||||||
|
-- TSS7142E Accessor ID Not Yet Available for Use - Still Inactive
|
||||||
|
-- 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))
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Tests the target to see if we can even get to TSO
|
||||||
|
--
|
||||||
|
-- @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_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()
|
||||||
|
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
|
||||||
|
end
|
||||||
|
stdnse.debug("Getting to TSO")
|
||||||
|
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])
|
||||||
|
tn:get_all_data()
|
||||||
|
end
|
||||||
|
tn:get_screen_debug(2)
|
||||||
|
|
||||||
|
if tn:find("ENTER USERID") or
|
||||||
|
tn:find("TSO/E LOGON") then
|
||||||
|
tso = true
|
||||||
|
end
|
||||||
|
tn:disconnect()
|
||||||
|
return tso
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Filter iterator for unpwdb usernames
|
||||||
|
-- TSO is limited to 7 alpha numeric and @, #, $ and can't start with a number
|
||||||
|
-- If this user ID has been confirmed to not be a valid TSO account
|
||||||
|
-- it will stop being passed to the brute engine
|
||||||
|
-- pattern:
|
||||||
|
-- ^%D = The first char must NOT be a digit
|
||||||
|
-- [%w@#%$] = All letters including the special chars @, #, and $.
|
||||||
|
local valid_name = function(x)
|
||||||
|
if nmap.registry.tsoinvalid and nmap.registry.tsoinvalid[x] then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return (string.len(x) <= 7 and string.match(x,"^%D+[%w@#%$]"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Checks string to see if it follows valid password limitations
|
||||||
|
local valid_pass = function(x)
|
||||||
|
local patt = "[%w@#%$]"
|
||||||
|
return (string.len(x) <= 8 and string.match(x,patt))
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function( host, port )
|
||||||
|
local status, result
|
||||||
|
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') or "tso"
|
||||||
|
-- if a user is logged on this script will not try to logon as that user
|
||||||
|
-- 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
|
||||||
|
stdnse.debug("Starting TSO Brute Force")
|
||||||
|
local options = { key1 = commands, key2 = always_logon }
|
||||||
|
local engine = brute.Engine:new(Driver, host, port, options)
|
||||||
|
-- TSO has username restrictions. This sets the iterator to use only valid TSO userids
|
||||||
|
engine:setUsernameIterator(unpwdb.filter_iterator(brute.usernames_iterator(),valid_name))
|
||||||
|
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()
|
||||||
|
else
|
||||||
|
return "Could not get to TSO. Try --script-args=tso-user-enum.commands='logon applid(tso)'. Aborting."
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
225
scripts/tso-enum.nse
Normal file
225
scripts/tso-enum.nse
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
local stdnse = require "stdnse"
|
||||||
|
local shortport = require "shortport"
|
||||||
|
local tn3270 = require "tn3270"
|
||||||
|
local brute = require "brute"
|
||||||
|
local creds = require "creds"
|
||||||
|
local unpwdb = require "unpwdb"
|
||||||
|
local nmap = require "nmap"
|
||||||
|
local string = require "string"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
TSO User ID enumerator for IBM mainframes (z/OS). The TSO logon panel
|
||||||
|
tells you when a user ID is valid or invalid with the message:
|
||||||
|
<code>IKJ56420I Userid <user ID> not authorized to use TSO</code>.
|
||||||
|
|
||||||
|
The TSO logon process can work in two ways:
|
||||||
|
1) You get prompted with <code>IKJ56700A ENTER USERID -</code>
|
||||||
|
to which you reply with the user you want to use.
|
||||||
|
If the user ID is valid it will give you a normal
|
||||||
|
TSO logon screen. Otherwise it will give you the
|
||||||
|
screen logon error above.
|
||||||
|
2) You're given the TSO logon panel and enter your user ID
|
||||||
|
at the <code>Userid ===></code> prompt. If you give
|
||||||
|
it an invalid user ID you receive the error message above.
|
||||||
|
|
||||||
|
This script relies on the NSE TN3270 library which emulates a
|
||||||
|
TN3270 screen for NMAP.
|
||||||
|
|
||||||
|
TSO user IDs have the following rules:
|
||||||
|
- it cannot begin with a number
|
||||||
|
- only contains alpha-numeric characters and @, #, $.
|
||||||
|
- it cannot be longer than 7 chars
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @args tso-enum.commands Commands in a semi-colon seperated list needed
|
||||||
|
-- to access TSO. Defaults to <code>tso</code>.
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- nmap --script=tso-enum -p 23 <targets>
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- nmap -sV -p 9923 10.32.70.10 --script tso-enum --script-args userdb=tso_users.txt,tso-enum.commands="logon applid(tso)"
|
||||||
|
--
|
||||||
|
-- @output
|
||||||
|
-- PORT STATE SERVICE VERSION
|
||||||
|
-- 23/tcp open tn3270 IBM Telnet TN3270
|
||||||
|
-- | tso-enum:
|
||||||
|
-- | TSO User ID:
|
||||||
|
-- | TSO User:RAZOR - Valid User ID
|
||||||
|
-- | TSO User:BLADE - Valid User ID
|
||||||
|
-- | TSO User:PLAGUE - Valid User ID
|
||||||
|
-- |_ Statistics: Performed 6 guesses in 3 seconds, average tps: 2
|
||||||
|
--
|
||||||
|
-- @changelog
|
||||||
|
-- 2015-07-04 - v0.1 - created by Soldier of Fortran
|
||||||
|
-- 2015-10-30 - v0.2 - streamlined the code, relying on brute and unpwdb and
|
||||||
|
-- renamed to tso-enum.
|
||||||
|
|
||||||
|
|
||||||
|
author = "Philip Young aka Soldier of Fortran"
|
||||||
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"intrusive", "brute"}
|
||||||
|
|
||||||
|
portrule = shortport.port_or_service({23,992,623}, {"tn3270"})
|
||||||
|
|
||||||
|
Driver = {
|
||||||
|
new = function(self, host, port, options)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
o.host = host
|
||||||
|
o.port = port
|
||||||
|
o.options = options
|
||||||
|
o.tn3270 = tn3270.Telnet:new()
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
connect = function( self )
|
||||||
|
local status, err = self.tn3270:initiate(self.host,self.port)
|
||||||
|
self.tn3270:get_screen_debug(2)
|
||||||
|
if not status then
|
||||||
|
stdnse.debug("Could not initiate TN3270: %s", err )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
disconnect = function( self )
|
||||||
|
self.tn3270:send_pf(3)
|
||||||
|
self.tn3270:disconnect()
|
||||||
|
self.tn3270 = nil
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
login = function (self, user, pass)
|
||||||
|
-- pass is actually the user id we want to try
|
||||||
|
local commands = self.options['key1']
|
||||||
|
local cmd_DATA = false
|
||||||
|
stdnse.debug(2,"Getting to TSO")
|
||||||
|
local run = stdnse.strsplit(";%s*", commands)
|
||||||
|
for i = 1, #run do
|
||||||
|
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
|
||||||
|
if string.find(string.upper(run[i]),"logon applid") ~= nil then
|
||||||
|
stdnse.verbose(2,"Trying User ID: %s", pass)
|
||||||
|
self.tn3270:send_cursor(run[i] .. " DATA(" .. pass .. ")")
|
||||||
|
cmd_DATA = true
|
||||||
|
else
|
||||||
|
self.tn3270:send_cursor(run[i])
|
||||||
|
end
|
||||||
|
self.tn3270:get_all_data()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.tn3270:get_screen_debug(2)
|
||||||
|
|
||||||
|
if not self.tn3270:find("ENTER USERID") and not self.tn3270:find("TSO/E LOGON") then
|
||||||
|
local err = brute.Error:new( "TSO Unavailable" )
|
||||||
|
-- This error occurs on too many concurrent application requests it
|
||||||
|
-- should be temporary. If not, the script errors and less threads should be used.
|
||||||
|
err:setRetry( true )
|
||||||
|
return false, err
|
||||||
|
end
|
||||||
|
|
||||||
|
if not cmd_DATA then
|
||||||
|
stdnse.verbose(2,"Trying User ID: %s", pass)
|
||||||
|
self.tn3270:send_cursor(pass)
|
||||||
|
self.tn3270:get_all_data()
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
|
||||||
|
stdnse.debug(2,"Screen Recieved for User ID: %s", pass)
|
||||||
|
self.tn3270:get_screen_debug(2)
|
||||||
|
if self.tn3270:find('not authorized to use TSO') then -- invalid user ID
|
||||||
|
return false, brute.Error:new( "Incorrect User ID" )
|
||||||
|
elseif ( self.tn3270:find('NO USER APPLID AVAILABLE') ) or
|
||||||
|
( self.tn3270:isClear() ) or (not self.tn3270:find('TSO/E LOGON') ) then
|
||||||
|
local err = brute.Error:new( "TSO Unavailable" )
|
||||||
|
-- This error occurs on too many concurrent application requests it
|
||||||
|
-- should be temporary. If not, the script errors and less threads should be used.
|
||||||
|
err:setRetry( true )
|
||||||
|
return false, err
|
||||||
|
else
|
||||||
|
stdnse.verbose("Valid TSO User ID: %s", string.upper(pass))
|
||||||
|
return true, creds.Account:new("TSO User",string.upper(pass), " Valid User ID")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Tests the target to see if we can even get to TSO
|
||||||
|
--
|
||||||
|
-- @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
|
||||||
|
-- @return name of security product installed
|
||||||
|
local function tso_test( host, port, commands )
|
||||||
|
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
|
||||||
|
stdnse.debug("Getting to TSO")
|
||||||
|
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])
|
||||||
|
tn:get_all_data()
|
||||||
|
end
|
||||||
|
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
|
||||||
|
secprod = "TopSecret/ACF2"
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Filter iterator for unpwdb
|
||||||
|
-- TSO is limited to 7 alpha numeric and @, #, $ and can't start with a number
|
||||||
|
-- pattern:
|
||||||
|
-- ^%D = The first char must NOT be a digit
|
||||||
|
-- [%w@#%$] = All letters including the special chars @, #, and $.
|
||||||
|
local valid_name = function(x)
|
||||||
|
return (string.len(x) <= 7 and string.match(x,"^%D+[%w@#%$]"))
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') or "tso"
|
||||||
|
local tsotst, secprod, err = tso_test(host, port, commands)
|
||||||
|
if tsotst then
|
||||||
|
local options = { key1 = commands }
|
||||||
|
stdnse.debug("Starting TSO User ID Enumeration")
|
||||||
|
local engine = brute.Engine:new(Driver, host, port, options)
|
||||||
|
engine.options.script_name = SCRIPT_NAME
|
||||||
|
engine:setPasswordIterator(unpwdb.filter_iterator(brute.usernames_iterator(),valid_name))
|
||||||
|
engine.options.passonly = true
|
||||||
|
engine.options:setTitle("TSO User ID")
|
||||||
|
local status, result = engine:start()
|
||||||
|
port.version.extrainfo = "Security: " .. secprod
|
||||||
|
nmap.set_port_version(host, port)
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user