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 = {
BINARY = "\000",
EOR = "\025",
TTYPE = "\024"
--TN3270 = "\040" -- if we enable this it would mean we support TN3270E
-- which we do not support
TTYPE = "\024",
--TN3270 = "\028",
TN3270 = "\040" -- Technically TN3270E
},
command = {
@@ -218,8 +218,16 @@ Telnet = {
NEG_OPERATION_CHECK = 0x02,
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_3270 = "192",
@@ -533,8 +541,7 @@ Telnet = {
end
elseif self.telnet_state == TNS_SB_IAC then
stdnse.debug(3, "Processing SB options")
--nsedebug.print_hex(self.sb_options)
self.sb_options = self.sb_options .. data
-- self.sb_options = self.sb_options .. data -- looks like this is a bug? Why append F0 to the end?
if data == self.commands.SE then
self.telnet_state = TNS_DATA
if self.sb_options:sub(1,1) == self.options.TTYPE and
@@ -571,11 +578,13 @@ Telnet = {
--- Function to negotiate TN3270 sub options
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)
-- stdnse.debug("[TN3270E] We got this: 0x%s", stdnse.tohex(option))
if option == self.tncommands.SEND then
if self.sb_options:sub(3,3) == self.tncommands.DEVICETYPE then
if self.connected_lu == '' then
self:send_data(self.commands.IAC ..
self.commands.SB ..
self.options.TN3270 ..
@@ -585,20 +594,39 @@ Telnet = {
self.commands.IAC ..
self.commands.SE )
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
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
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
tn_loc = tn_loc + 1
end
--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
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)
stdnse.debug(3,"[TN3270] Current LU: %s", self.connected_lu)
end
-- since We've connected lets send our options
self:send_data(self.commands.IAC ..
@@ -614,7 +642,7 @@ Telnet = {
if self.sb_options:sub(3,3) == self.tncommands.IS then
-- they accepted the function request, lets move on
self.negotiated = true
stdnse.verbose(2,"TN3270 Option Negotiation Done!")
stdnse.debug(3,"[TN3270] Option Negotiation Done!")
self:in3270()
elseif self.sb_options:sub(3,3) == self.tncommands.REQUEST then
-- dummy functions for now. Our client doesn't have any
@@ -630,9 +658,7 @@ Telnet = {
self.negotiated = true
self:in3270()
end
end
return true
end,
@@ -668,12 +694,14 @@ Telnet = {
local reply = 0
stdnse.debug(3,"Processing TN3270 Data")
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.request_flag = self.tn_buffer:sub(2,2)
self.tn3270_header.response_flag = self.tn_buffer:sub(3,3)
self.tn3270_header.seq_number = self.tn_buffer:sub(4,5)
if self.tn3270_header.data_type == "\000" then
reply = self:process_3270(self.tn_buffer:sub(6))
stdnse.debug(3,"[TN3270E] Reply: %s", reply)
end
if reply < 0 and self.tn3270_header.request_flag ~= self.TN3270E_RSF_NO_RESPONSE then
self:tn3270e_nak(reply)
@@ -740,7 +768,7 @@ Telnet = {
process_3270 = function ( self, data )
-- the first byte will be the command we have to follow
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
stdnse.debug(3,"TN3270 Command: Erase All Unprotected")
self:clear_unprotected()
@@ -777,6 +805,7 @@ Telnet = {
return self.BAD_COMMAND
end
return 1 -- we may sometimes enter a state where we have nothing which is fine
end,
@@ -992,8 +1021,13 @@ Telnet = {
\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"
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)
return true
return 1
end,
@@ -1004,14 +1038,15 @@ Telnet = {
send_tn3270 = function ( self, data )
local packet = ''
if self.state == self.TN3270E_DATA then
packet = "\x00\x00\x00\x00\x00"
-- we need to create the tn3270E (the E is important) header
-- which, in basic 3270E is 5 bytes of 0x00
packet = string.pack("BBB >I2",
self.DT_3270_DATA, -- type
0, -- request
0, -- response
0
)
--packet = string.pack("BBB >I2",
-- self.DT_3270_DATA, -- type
-- 0, -- request
-- 0, -- response
-- 0
-- )
--self.tn3270_header.seq_number
end
-- create send buffer and double up IACs
@@ -1301,6 +1336,16 @@ Telnet = {
return false
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 )
if not self:any_overwritten() then
return false

View File

@@ -1,5 +1,4 @@
local stdnse = require "stdnse"
local stringaux = require "stringaux"
local shortport = require "shortport"
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
-- issue before printing the screen
-- tn3270-screen.lu a logical unit you with to use fails if can't connect
--
--
-- @changelog
-- 2015-05-30 - v0.1 - created by Soldier of Fortran
-- 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"
@@ -66,14 +67,19 @@ local hidden_field_mt = {
action = function(host, port)
local commands = stdnse.get_script_args(SCRIPT_NAME .. '.commands')
local lu = stdnse.get_script_args(SCRIPT_NAME .. '.lu')
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)
if not status then
stdnse.debug("Could not initiate TN3270: %s", err )
return
else
if commands then
local run = stringaux.strsplit(";%s*", commands)
local run = stdnse.strsplit(";%s*", commands)
for i = 1, #run do
stdnse.debug(1,"Issuing Command (#%s of %s): %s", i, #run ,run[i])
t:send_cursor(run[i])
@@ -101,6 +107,7 @@ action = function(host, port)
local out = stdnse.output_table()
out.screen = t:get_screen()
out["hidden fields"] = hidden
out["logical unit"]= t:get_lu()
return out
end
end