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

Adds TN3270E support to the tn3270 library. Additionally adds support for logical unit setting. Closes #1318

This commit is contained in:
paulino
2019-01-08 21:34:37 +00:00
parent 65c0376c59
commit 3de3ee8aff
2 changed files with 82 additions and 30 deletions

View File

@@ -64,9 +64,9 @@ Telnet = {
options = { options = {
BINARY = "\000", BINARY = "\000",
EOR = "\025", EOR = "\025",
TTYPE = "\024" TTYPE = "\024",
--TN3270 = "\040" -- if we enable this it would mean we support TN3270E --TN3270 = "\028",
-- which we do not support TN3270 = "\040" -- Technically TN3270E
}, },
command = { command = {
@@ -218,8 +218,16 @@ Telnet = {
NEG_OPERATION_CHECK = 0x02, NEG_OPERATION_CHECK = 0x02,
NEG_COMPONENT_DISCONNECTED = 0x03, NEG_COMPONENT_DISCONNECTED = 0x03,
-- Attention Identifiers (AID) -- TN3270E Negotiation Options
TN3270E_ASSOCIATE = 0x00,
TN3270E_CONNECT = 0x01,
TN3270E_DEVICE_TYPE = 0x02,
TN3270E_FUNCTIONS = 0x03,
TN3270E_IS = 0x04,
TN3270E_REASON = 0x05,
TN3270E_REJECT = 0x06,
TN3270E_REQUEST = 0x07,
TN3270E_SEND = 0x08,
-- SFE Attributes -- SFE Attributes
SFE_3270 = "192", SFE_3270 = "192",
@@ -533,8 +541,7 @@ Telnet = {
end end
elseif self.telnet_state == TNS_SB_IAC then elseif self.telnet_state == TNS_SB_IAC then
stdnse.debug(3, "Processing SB options") stdnse.debug(3, "Processing SB options")
--nsedebug.print_hex(self.sb_options) -- self.sb_options = self.sb_options .. data -- looks like this is a bug? Why append F0 to the end?
self.sb_options = self.sb_options .. data
if data == self.commands.SE then if data == self.commands.SE then
self.telnet_state = TNS_DATA self.telnet_state = TNS_DATA
if self.sb_options:sub(1,1) == self.options.TTYPE and if self.sb_options:sub(1,1) == self.options.TTYPE and
@@ -571,11 +578,13 @@ Telnet = {
--- Function to negotiate TN3270 sub options --- Function to negotiate TN3270 sub options
negotiate_tn3270 = function ( self ) negotiate_tn3270 = function ( self )
stdnse.debug(3, "Processing tn data subnegotiation options") stdnse.debug(3, "[TN3270] Processing tn data subnegotiation options ")
local option = self.sb_options:sub(2,2) local option = self.sb_options:sub(2,2)
-- stdnse.debug("[TN3270E] We got this: 0x%s", stdnse.tohex(option))
if option == self.tncommands.SEND then if option == self.tncommands.SEND then
if self.sb_options:sub(3,3) == self.tncommands.DEVICETYPE then if self.sb_options:sub(3,3) == self.tncommands.DEVICETYPE then
if self.connected_lu == '' then
self:send_data(self.commands.IAC .. self:send_data(self.commands.IAC ..
self.commands.SB .. self.commands.SB ..
self.options.TN3270 .. self.options.TN3270 ..
@@ -585,20 +594,39 @@ Telnet = {
self.commands.IAC .. self.commands.IAC ..
self.commands.SE ) self.commands.SE )
else else
stdnse.debug(3,"Received TN3270 Send but not device type. Weird.") stdnse.debug(3,"[TN3270] Sending LU: %s", self.connected_lu)
self:send_data(self.commands.IAC ..
self.commands.SB ..
self.options.TN3270 ..
self.tncommands.DEVICETYPE ..
self.tncommands.REQUEST ..
self.device_type ..
self.tncommands.CONNECT ..
self.connected_lu ..
self.commands.IAC ..
self.commands.SE )
end
else
stdnse.debug(3,"[TN3270] Received TN3270 Send but not device type. Weird.")
return false
end end
elseif option == self.tncommands.DEVICETYPE then -- Mainframe is confirming device type. Good! elseif option == self.tncommands.DEVICETYPE then -- Mainframe is confirming device type. Good!
if self.sb_options:sub(3,3) == self.tncommands.IS then if self.sb_options:sub(3,3) == self.tncommands.REJECT then
-- Welp our LU request failed, shut it down
stdnse.debug(3,"[TN3270] Received TN3270 REJECT.")
return false
elseif self.sb_options:sub(3,3) == self.tncommands.IS then
local tn_loc = 1 local tn_loc = 1
while self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.commands.SE and while self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.commands.SE and
self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.tncommands.CONNECT do self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.tncommands.CONNECT do
tn_loc = tn_loc + 1 tn_loc = tn_loc + 1
end end
--XXX Unused variable??? Should this be tn_loc? --XXX Unused variable??? Should this be tn_loc?
local sn_loc = 1 -- local sn_loc = 1
if self.sb_options:sub(4+tn_loc,4+tn_loc) == self.tncommands.CONNECT then if self.sb_options:sub(4+tn_loc,4+tn_loc) == self.tncommands.CONNECT then
self.connected_lu = self.sb_options:sub(5+tn_loc, #self.sb_options-1) self.connected_lu = self.sb_options:sub(5+tn_loc, #self.sb_options)
self.connected_dtype = self.sb_options:sub(4,3+tn_loc) self.connected_dtype = self.sb_options:sub(4,3+tn_loc)
stdnse.debug(3,"[TN3270] Current LU: %s", self.connected_lu)
end end
-- since We've connected lets send our options -- since We've connected lets send our options
self:send_data(self.commands.IAC .. self:send_data(self.commands.IAC ..
@@ -614,7 +642,7 @@ Telnet = {
if self.sb_options:sub(3,3) == self.tncommands.IS then if self.sb_options:sub(3,3) == self.tncommands.IS then
-- they accepted the function request, lets move on -- they accepted the function request, lets move on
self.negotiated = true self.negotiated = true
stdnse.verbose(2,"TN3270 Option Negotiation Done!") stdnse.debug(3,"[TN3270] Option Negotiation Done!")
self:in3270() self:in3270()
elseif self.sb_options:sub(3,3) == self.tncommands.REQUEST then elseif self.sb_options:sub(3,3) == self.tncommands.REQUEST then
-- dummy functions for now. Our client doesn't have any -- dummy functions for now. Our client doesn't have any
@@ -630,9 +658,7 @@ Telnet = {
self.negotiated = true self.negotiated = true
self:in3270() self:in3270()
end end
end end
return true return true
end, end,
@@ -668,12 +694,14 @@ Telnet = {
local reply = 0 local reply = 0
stdnse.debug(3,"Processing TN3270 Data") stdnse.debug(3,"Processing TN3270 Data")
if self.state == self.TN3270E_DATA then if self.state == self.TN3270E_DATA then
stdnse.debug(3,"[TN3270E] Processing TN3270 Data header: %s", stdnse.tohex(self.tn_buffer:sub(1,5)))
self.tn3270_header.data_type = self.tn_buffer:sub(1,1) self.tn3270_header.data_type = self.tn_buffer:sub(1,1)
self.tn3270_header.request_flag = self.tn_buffer:sub(2,2) self.tn3270_header.request_flag = self.tn_buffer:sub(2,2)
self.tn3270_header.response_flag = self.tn_buffer:sub(3,3) self.tn3270_header.response_flag = self.tn_buffer:sub(3,3)
self.tn3270_header.seq_number = self.tn_buffer:sub(4,5) self.tn3270_header.seq_number = self.tn_buffer:sub(4,5)
if self.tn3270_header.data_type == "\000" then if self.tn3270_header.data_type == "\000" then
reply = self:process_3270(self.tn_buffer:sub(6)) reply = self:process_3270(self.tn_buffer:sub(6))
stdnse.debug(3,"[TN3270E] Reply: %s", reply)
end end
if reply < 0 and self.tn3270_header.request_flag ~= self.TN3270E_RSF_NO_RESPONSE then if reply < 0 and self.tn3270_header.request_flag ~= self.TN3270E_RSF_NO_RESPONSE then
self:tn3270e_nak(reply) self:tn3270e_nak(reply)
@@ -740,7 +768,7 @@ Telnet = {
process_3270 = function ( self, data ) process_3270 = function ( self, data )
-- the first byte will be the command we have to follow -- the first byte will be the command we have to follow
local com = data:sub(1,1) local com = data:sub(1,1)
stdnse.debug(3, "Value Received: 0x%s", stdnse.tohex(com)) stdnse.debug(3, "[PROCESS 3270] Value Received: 0x%s", stdnse.tohex(com))
if com == self.command.EAU then if com == self.command.EAU then
stdnse.debug(3,"TN3270 Command: Erase All Unprotected") stdnse.debug(3,"TN3270 Command: Erase All Unprotected")
self:clear_unprotected() self:clear_unprotected()
@@ -777,6 +805,7 @@ Telnet = {
return self.BAD_COMMAND return self.BAD_COMMAND
end end
return 1 -- we may sometimes enter a state where we have nothing which is fine
end, end,
@@ -992,8 +1021,13 @@ Telnet = {
\x87\x88\xa1\xa6\xa8\x96\x99\xb0\xb1\xb2\xb3\xb4\xb6\x00\x08\x81\z \x87\x88\xa1\xa6\xa8\x96\x99\xb0\xb1\xb2\xb3\xb4\xb6\x00\x08\x81\z
\x84\x00\x0a\x00\x04\x00\x06\x81\x99\x00\x00\xff\xef" \x84\x00\x0a\x00\x04\x00\x06\x81\x99\x00\x00\xff\xef"
stdnse.debug(3, "Current WSF : %s", stdnse.tohex(wsf_data:sub(4,4)) ) stdnse.debug(3, "Current WSF : %s", stdnse.tohex(wsf_data:sub(4,4)) )
if self.state == self.TN3270E_DATA then
-- We need to add the header here since we're in TN3270E mode
query_options = "\x00\x00\x00\x00\x00" .. query_options
end
self:send_data(query_options) self:send_data(query_options)
return true return 1
end, end,
@@ -1004,14 +1038,15 @@ Telnet = {
send_tn3270 = function ( self, data ) send_tn3270 = function ( self, data )
local packet = '' local packet = ''
if self.state == self.TN3270E_DATA then if self.state == self.TN3270E_DATA then
packet = "\x00\x00\x00\x00\x00"
-- we need to create the tn3270E (the E is important) header -- we need to create the tn3270E (the E is important) header
-- which, in basic 3270E is 5 bytes of 0x00 -- which, in basic 3270E is 5 bytes of 0x00
packet = string.pack("BBB >I2", --packet = string.pack("BBB >I2",
self.DT_3270_DATA, -- type -- self.DT_3270_DATA, -- type
0, -- request -- 0, -- request
0, -- response -- 0, -- response
0 -- 0
) -- )
--self.tn3270_header.seq_number --self.tn3270_header.seq_number
end end
-- create send buffer and double up IACs -- create send buffer and double up IACs
@@ -1301,6 +1336,16 @@ Telnet = {
return false return false
end, end,
set_lu = function (self, LU)
-- Sets an LU
self.connected_lu = LU
end,
get_lu = function ( self )
return self.connected_lu
end,
overwrite_data = function ( self ) overwrite_data = function ( self )
if not self:any_overwritten() then if not self:any_overwritten() then
return false return false

View File

@@ -1,5 +1,4 @@
local stdnse = require "stdnse" local stdnse = require "stdnse"
local stringaux = require "stringaux"
local shortport = require "shortport" local shortport = require "shortport"
local tn3270 = require "tn3270" local tn3270 = require "tn3270"
@@ -45,11 +44,13 @@ Hidden fields will be listed below the screen with (row, col) coordinates.
-- --
-- @args tn3270-screen.commands a semi-colon separated list of commands you want to -- @args tn3270-screen.commands a semi-colon separated list of commands you want to
-- issue before printing the screen -- issue before printing the screen
-- tn3270-screen.lu a logical unit you with to use fails if can't connect
-- --
-- --
-- @changelog -- @changelog
-- 2015-05-30 - v0.1 - created by Soldier of Fortran -- 2015-05-30 - v0.1 - created by Soldier of Fortran
-- 2015-11-14 - v0.2 - added commands argument -- 2015-11-14 - v0.2 - added commands argument
-- 2018-09-07 - v0.3 - added support for Logical Units
-- --
author = "Philip Young aka Soldier of Fortran" author = "Philip Young aka Soldier of Fortran"
@@ -66,14 +67,19 @@ local hidden_field_mt = {
action = function(host, port) action = function(host, port)
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands') local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands')
local lu = stdnse.get_script_args(SCRIPT_NAME .. '.lu')
local t = tn3270.Telnet:new() local t = tn3270.Telnet:new()
if lu then
stdnse.debug("Setting LU: %s", lu)
t:set_lu(lu)
end
local status, err = t:initiate(host,port) local status, err = t:initiate(host,port)
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 return
else else
if commands then if commands then
local run = stringaux.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(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
t:send_cursor(run[i]) t:send_cursor(run[i])
@@ -101,6 +107,7 @@ action = function(host, port)
local out = stdnse.output_table() local out = stdnse.output_table()
out.screen = t:get_screen() out.screen = t:get_screen()
out["hidden fields"] = hidden out["hidden fields"] = hidden
out["logical unit"]= t:get_lu()
return out return out
end end
end end