From 97caf1d084b24b12e201fba5c9e4a1a3f006275b Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 13:15:08 -0800 Subject: [PATCH 01/22] Add preliminary module for interacting with Veeder-Root ATGs --- modules/auxiliary/admin/atg/client.rb | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 modules/auxiliary/admin/atg/client.rb diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb new file mode 100644 index 0000000000..a8b34cc9dc --- /dev/null +++ b/modules/auxiliary/admin/atg/client.rb @@ -0,0 +1,108 @@ +## +# encoding: utf-8 +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Scanner + + def initialize + super( + 'Name' => 'Veeder-Root Automatic Tank Gauge (ATG) Administrative Client', + 'Description' => %q{ + This module acts as a simplistic administrative client for interfacing + with Veeder-Root Automatic Tang Gauges (ATGs) or other devices speaking + the TLS-250 and TLS-350 protocols. + }, + 'Author' => + [ + 'Jon Hart ' # original metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => [ + ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'] + ], + 'DefaultAction' => 'INVENTORY', + 'Actions' => + [ + [ 'DELIVERY', + { + 'Description' => 'I20200 Delivery report', + 'TLS-350_CMD' => "\x01I20200" + } + ], + [ 'INVENTORY', + { + 'Description' => 'I20100 In-tank inventory report', + 'TLS-250_CMD' => "\x01200", + 'TLS-350_CMD' => "\x01I20100" + } + ], + [ 'LEAK', + { + 'Description' => 'I20300 Leak report', + 'TLS-350_CMD' => "\x01I20300" + } + ], + [ 'SHIFT', + { + 'Description' => 'I20400 Shift report', + 'TLS-350_CMD' => "\x01I20400" + } + ], + [ 'STATUS', + { + 'Description' => 'I20500 In-tank status report', + 'TLS-350_CMD' => "\x01I20500" + } + ], + [ 'VERSION', + { + 'Description' => 'Version information', + 'TLS-250_CMD' => "\x01980", + 'TLS-350_CMD' => "\x01I90200" + } + ] + ] + ) + + register_options( + [ + Opt::RPORT(10001) + ], + self.class + ) + deregister_options('SSL', 'SSLCipher', 'SSLVerifyMode', 'SSLVersion') + + register_advanced_options( + [ + OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]) + ], + self.class + ) + end + + def setup + proto_cmd = datastore['PROTOCOL'] + "_CMD" + fail "#{action.name} not defined for #{datastore['PROTOCOL']}" unless action.opts.keys.include?(proto_cmd) + end + + def peer + "#{rhost}:#{rport}" + end + + def run_host(_host) + begin + connect + sock.put(action.opts[datastore['PROTOCOL'] + '_CMD']) + print_status("#{peer}:\n#{sock.get_once}") + ensure + disconnect + end + end +end From 9def67831c8689bd58000090505dea45a3fb91d7 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 13:20:45 -0800 Subject: [PATCH 02/22] Better printing --- modules/auxiliary/admin/atg/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index a8b34cc9dc..938cce76ef 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -100,7 +100,7 @@ class Metasploit3 < Msf::Auxiliary begin connect sock.put(action.opts[datastore['PROTOCOL'] + '_CMD']) - print_status("#{peer}:\n#{sock.get_once}") + print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") ensure disconnect end From 7c9b85551b5f638b1878d7952f8137372d0be9e8 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 14:24:11 -0800 Subject: [PATCH 03/22] Support for setting ATG tank names --- modules/auxiliary/admin/atg/client.rb | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 938cce76ef..f054c3d4cf 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -55,6 +55,12 @@ class Metasploit3 < Msf::Auxiliary 'TLS-350_CMD' => "\x01I20400" } ], + [ 'SET_TANK_NAME', + { + 'Description' => 'S6020 set tank name', + 'TLS-350_CMD' => "\x01S6020" + } + ], [ 'STATUS', { 'Description' => 'I20500 In-tank status report', @@ -73,7 +79,9 @@ class Metasploit3 < Msf::Auxiliary register_options( [ - Opt::RPORT(10001) + Opt::RPORT(10001), + OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]), + OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME), defaults to random']) ], self.class ) @@ -88,8 +96,26 @@ class Metasploit3 < Msf::Auxiliary end def setup - proto_cmd = datastore['PROTOCOL'] + "_CMD" - fail "#{action.name} not defined for #{datastore['PROTOCOL']}" unless action.opts.keys.include?(proto_cmd) + # ensure that the specified command is implemented for the desired version of the TLS protocol + proto_cmd = protocol + "_CMD" + fail "#{action.name} not defined for #{protocol}" unless action.opts.keys.include?(proto_cmd) + + # ensure that the tank number is set for the commands that need it + if action.name == 'SET_TANK_NAME' + fail "TANK_NUMBER #{tank_number} is invalid" if tank_number < 0 + end + end + + def protocol + datastore['PROTOCOL'] + end + + def tank_name + @tank_name ||= (datastore['TANK_NAME'] ? datastore['TANK_NAME'] : Rex::Text.rand_text_alpha(16)) + end + + def tank_number + datastore['TANK_NUMBER'] end def peer @@ -99,8 +125,20 @@ class Metasploit3 < Msf::Auxiliary def run_host(_host) begin connect - sock.put(action.opts[datastore['PROTOCOL'] + '_CMD']) - print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") + case action.name + when 'SET_TANK_NAME' + vprint_status("#{peer} -- setting tank ##{tank_number} to #{tank_name}") + request = action.opts[protocol + '_CMD'] + "#{tank_number}#{tank_name}" + sock.puts(request) + disconnect + connect + sock.puts(actions.select { |a| a.name == 'INVENTORY' }.first.opts[protocol + '_CMD']) + print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") + else + request = action.opts[datastore['PROTOCOL'] + '_CMD'] + sock.puts(request) + print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") + end ensure disconnect end From 4f4e4c734a73806a57ce7015366806e181b2b7d2 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 14:36:59 -0800 Subject: [PATCH 04/22] Handle ATGs w/ > 10 tanks, more strict --- modules/auxiliary/admin/atg/client.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index f054c3d4cf..e82812cde4 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -57,8 +57,8 @@ class Metasploit3 < Msf::Auxiliary ], [ 'SET_TANK_NAME', { - 'Description' => 'S6020 set tank name', - 'TLS-350_CMD' => "\x01S6020" + 'Description' => 'S602 set tank name', + 'TLS-350_CMD' => "\x01S602" } ], [ 'STATUS', @@ -102,7 +102,7 @@ class Metasploit3 < Msf::Auxiliary # ensure that the tank number is set for the commands that need it if action.name == 'SET_TANK_NAME' - fail "TANK_NUMBER #{tank_number} is invalid" if tank_number < 0 + fail "TANK_NUMBER #{tank_number} is invalid" if tank_number < 0 || tank_number > 99 end end @@ -128,15 +128,15 @@ class Metasploit3 < Msf::Auxiliary case action.name when 'SET_TANK_NAME' vprint_status("#{peer} -- setting tank ##{tank_number} to #{tank_name}") - request = action.opts[protocol + '_CMD'] + "#{tank_number}#{tank_name}" - sock.puts(request) + request = action.opts[protocol + '_CMD'] + "#{'%02d' % tank_number}#{tank_name}\n" + sock.put(request) disconnect connect - sock.puts(actions.select { |a| a.name == 'INVENTORY' }.first.opts[protocol + '_CMD']) + sock.put(actions.select { |a| a.name == 'INVENTORY' }.first.opts[protocol + '_CMD'] + "\n") print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") else - request = action.opts[datastore['PROTOCOL'] + '_CMD'] - sock.puts(request) + request = action.opts[datastore['PROTOCOL'] + '_CMD'] + "\n" + sock.put(request) print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") end ensure From dac7738f2935f26949d6e3c30e63d6dc4ba87e1f Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 14:43:06 -0800 Subject: [PATCH 05/22] Clean up description; add more refs --- modules/auxiliary/admin/atg/client.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index e82812cde4..2bbc1ba6bb 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -17,16 +17,21 @@ class Metasploit3 < Msf::Auxiliary 'Description' => %q{ This module acts as a simplistic administrative client for interfacing with Veeder-Root Automatic Tang Gauges (ATGs) or other devices speaking - the TLS-250 and TLS-350 protocols. - }, + the TLS-250 and TLS-350 protocols. This has been tested against + GasPot, a honeypot meant to simulate ATGs; it has not been tested + against anything else, so use at your own risk. + }, 'Author' => [ 'Jon Hart ' # original metasploit module ], 'License' => MSF_LICENSE, - 'References' => [ - ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'] - ], + 'References' => + [ + ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'], + ['URL', 'https://github.com/sjhilt/GasPot'], + ['URL', 'https://community.rapid7.com/community/infosec/blog/2015/01/22/the-internet-of-gas-station-tank-gauges'] + ], 'DefaultAction' => 'INVENTORY', 'Actions' => [ From 143ac474849f7d5f38f5b5b2664a942b9c4f93a8 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 14:47:12 -0800 Subject: [PATCH 06/22] Minor style cleanup --- modules/auxiliary/admin/atg/client.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 2bbc1ba6bb..19c7e47b4b 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -106,9 +106,7 @@ class Metasploit3 < Msf::Auxiliary fail "#{action.name} not defined for #{protocol}" unless action.opts.keys.include?(proto_cmd) # ensure that the tank number is set for the commands that need it - if action.name == 'SET_TANK_NAME' - fail "TANK_NUMBER #{tank_number} is invalid" if tank_number < 0 || tank_number > 99 - end + fail "TANK_NUMBER #{tank_number} is invalid" if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99) end def protocol @@ -133,11 +131,11 @@ class Metasploit3 < Msf::Auxiliary case action.name when 'SET_TANK_NAME' vprint_status("#{peer} -- setting tank ##{tank_number} to #{tank_name}") - request = action.opts[protocol + '_CMD'] + "#{'%02d' % tank_number}#{tank_name}\n" + request = action.opts[protocol + '_CMD'] + "#{format('%02d', tank_number)}#{tank_name}\n" sock.put(request) disconnect connect - sock.put(actions.select { |a| a.name == 'INVENTORY' }.first.opts[protocol + '_CMD'] + "\n") + sock.put(actions.find { |a| a.name == 'INVENTORY' }.opts[protocol + '_CMD'] + "\n") print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") else request = action.opts[datastore['PROTOCOL'] + '_CMD'] + "\n" From d00eba23f93a071f1d1b55157786f029c31f996f Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:02:37 -0800 Subject: [PATCH 07/22] Update references --- modules/auxiliary/admin/atg/client.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 19c7e47b4b..cebe27ab46 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -28,9 +28,10 @@ class Metasploit3 < Msf::Auxiliary 'License' => MSF_LICENSE, 'References' => [ - ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'], + ['URL', 'https://community.rapid7.com/community/infosec/blog/2015/01/22/the-internet-of-gas-station-tank-gauges'], + ['URL', 'http://www.trendmicro.com/vinfo/us/security/news/cybercrime-and-digital-threats/the-gaspot-experiment'], ['URL', 'https://github.com/sjhilt/GasPot'], - ['URL', 'https://community.rapid7.com/community/infosec/blog/2015/01/22/the-internet-of-gas-station-tank-gauges'] + ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'] ], 'DefaultAction' => 'INVENTORY', 'Actions' => From 8dd6003cc2f7b153735c12a586055cac1f2c5732 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:18:27 -0800 Subject: [PATCH 08/22] Add several untested but likely OK TLS-350 commands --- modules/auxiliary/admin/atg/client.rb | 68 ++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index cebe27ab46..bdcefd6188 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -36,6 +36,18 @@ class Metasploit3 < Msf::Auxiliary 'DefaultAction' => 'INVENTORY', 'Actions' => [ + [ 'ALARM', + { + 'Description' => 'I30200 Sensor alarm history (untested)', + 'TLS-350_CMD' => "\x01I30200" + } + ], + [ 'ALARM_RESET', + { + 'Description' => 'IS00300 Remote alarm reset (untested)', + 'TLS-350_CMD' => "\x01IS00300" + } + ], [ 'DELIVERY', { 'Description' => 'I20200 Delivery report', @@ -44,7 +56,7 @@ class Metasploit3 < Msf::Auxiliary ], [ 'INVENTORY', { - 'Description' => 'I20100 In-tank inventory report', + 'Description' => '200/I20100 In-tank inventory report', 'TLS-250_CMD' => "\x01200", 'TLS-350_CMD' => "\x01I20100" } @@ -55,6 +67,36 @@ class Metasploit3 < Msf::Auxiliary 'TLS-350_CMD' => "\x01I20300" } ], + [ 'RELAY', + { + 'Description' => 'I40600 Relay status (untested)', + 'TLS-350_CMD' => "\x01I40600" + } + ], + [ 'RESET', + { + 'Description' => 'IS00100 Reset (untested)', + 'TLS-350_CMD' => "\x01IS00100" + } + ], + [ 'CLEAR_RESET', + { + 'Description' => 'IS00200 Clear Reset Flag (untested)', + 'TLS-350_CMD' => "\x01IS00200" + } + ], + [ 'SENSOR', + { + 'Description' => 'I30100 Sensor status (untested)', + 'TLS-350_CMD' => "\x01I30100" + } + ], + [ 'SENSOR_DIAG', + { + 'Description' => 'IB0100 Sensor diagnostics (untested)', + 'TLS-350_CMD' => "\x01IB0100" + } + ], [ 'SHIFT', { 'Description' => 'I20400 Shift report', @@ -67,12 +109,36 @@ class Metasploit3 < Msf::Auxiliary 'TLS-350_CMD' => "\x01S602" } ], + [ 'SET_TIME', + { + 'Description' => 'S50100 Set time of day (untested)', + 'TLS-350_CMD' => "\x01S50100" + } + ], [ 'STATUS', { 'Description' => 'I20500 In-tank status report', 'TLS-350_CMD' => "\x01I20500" } ], + [ 'SYSTEM_STATUS', + { + 'Description' => 'I10100 System status report (untested)', + 'TLS-350_CMD' => "\x01I10100" + } + ], + [ 'TANK_ALARM', + { + 'Description' => 'I20600 Tank alarm history (untested)', + 'TLS-350_CMD' => "\x01I20600" + } + ], + [ 'TANK_DIAG', + { + 'Description' => 'IA0100 Tank diagnostics (untested)', + 'TLS-350_CMD' => "\x01IA0100" + } + ], [ 'VERSION', { 'Description' => 'Version information', From e67057a5c96a76e36fd4e5ee963bd2a2ed4b5a1c Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:19:37 -0800 Subject: [PATCH 09/22] Add great TLS-350 resource --- modules/auxiliary/admin/atg/client.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index bdcefd6188..52e24ff8da 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -31,7 +31,8 @@ class Metasploit3 < Msf::Auxiliary ['URL', 'https://community.rapid7.com/community/infosec/blog/2015/01/22/the-internet-of-gas-station-tank-gauges'], ['URL', 'http://www.trendmicro.com/vinfo/us/security/news/cybercrime-and-digital-threats/the-gaspot-experiment'], ['URL', 'https://github.com/sjhilt/GasPot'], - ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'] + ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'], + ['URL', 'http://www.chipkin.com/files/liz/576013-635.pdf'] ], 'DefaultAction' => 'INVENTORY', 'Actions' => From 637e570b28b6dd3b6f57a9118ba96e36a0dbc996 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:21:55 -0800 Subject: [PATCH 10/22] Add TLS-250 reference --- modules/auxiliary/admin/atg/client.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 52e24ff8da..5c7cebd24d 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -32,7 +32,8 @@ class Metasploit3 < Msf::Auxiliary ['URL', 'http://www.trendmicro.com/vinfo/us/security/news/cybercrime-and-digital-threats/the-gaspot-experiment'], ['URL', 'https://github.com/sjhilt/GasPot'], ['URL', 'http://www.veeder.com/us/automatic-tank-gauge-atg-consoles'], - ['URL', 'http://www.chipkin.com/files/liz/576013-635.pdf'] + ['URL', 'http://www.chipkin.com/files/liz/576013-635.pdf'], + ['URL', 'http://www.veeder.com/gold/download.cfm?doc_id=6227'] ], 'DefaultAction' => 'INVENTORY', 'Actions' => From 0762b9fa9b2e6a5a6b6887178ed0c791509db38b Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:24:58 -0800 Subject: [PATCH 11/22] Fix option formatting --- modules/auxiliary/admin/atg/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 5c7cebd24d..a1a45bb38b 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -155,7 +155,7 @@ class Metasploit3 < Msf::Auxiliary [ Opt::RPORT(10001), OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]), - OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME), defaults to random']) + OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']) ], self.class ) From de570a15503b920b29813fab00efc45713129141 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:41:05 -0800 Subject: [PATCH 12/22] Improve output when setting tank names --- modules/auxiliary/admin/atg/client.rb | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index a1a45bb38b..414f5fb858 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -199,17 +199,31 @@ class Metasploit3 < Msf::Auxiliary connect case action.name when 'SET_TANK_NAME' - vprint_status("#{peer} -- setting tank ##{tank_number} to #{tank_name}") - request = action.opts[protocol + '_CMD'] + "#{format('%02d', tank_number)}#{tank_name}\n" + # send the set tank name command to change the tank name(s) + if tank_number == 0 + vprint_status("#{peer} -- setting all tank names to #{tank_name}") + else + vprint_status("#{peer} -- setting tank ##{tank_number}'s name to #{tank_name}") + end + request = "#{action.opts[protocol + '_CMD']}#{format('%02d', tank_number)}#{tank_name}\n" sock.put(request) + # reconnect disconnect connect - sock.put(actions.find { |a| a.name == 'INVENTORY' }.opts[protocol + '_CMD'] + "\n") - print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") + # send an inventory probe to show that it succeeded + inventory_probe = "#{actions.find { |a| a.name == 'INVENTORY' }.opts[protocol + '_CMD']}\n" + sock.put(inventory_probe) + inventory_response = sock.get_once # XXX: timeout? + message = "#{peer} #{protocol} #{action.opts['Description']}:\n#{inventory_response}" + if inventory_response.include?(tank_name) + print_good message + else + print_warning message + end else - request = action.opts[datastore['PROTOCOL'] + '_CMD'] + "\n" + request = "#{action.opts[protocol + '_CMD']}\n" sock.put(request) - print_status("#{peer} #{datastore['PROTOCOL']} #{action.opts['Description']}:\n#{sock.get_once}") + print_status("#{peer} #{protocol} #{action.opts['Description']}:\n#{sock.get_once}") end ensure disconnect From c98ab1dad4599248f787862284d62988bc18eec1 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 21:49:40 -0800 Subject: [PATCH 13/22] update SET_TANK_NAME opt to mention necessary opts --- modules/auxiliary/admin/atg/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 414f5fb858..f5df9b3f9b 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -107,7 +107,7 @@ class Metasploit3 < Msf::Auxiliary ], [ 'SET_TANK_NAME', { - 'Description' => 'S602 set tank name', + 'Description' => 'S602 set tank name (use TANK_NUMBER and TANK_NAME options)', 'TLS-350_CMD' => "\x01S602" } ], From 0cfa67f58f2be56a9633f8c355ce73d4de4e33a2 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 10 Nov 2015 22:00:02 -0800 Subject: [PATCH 14/22] Stub out more of the set time, but disable it --- modules/auxiliary/admin/atg/client.rb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index f5df9b3f9b..08d60d0c45 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -113,8 +113,9 @@ class Metasploit3 < Msf::Auxiliary ], [ 'SET_TIME', { - 'Description' => 'S50100 Set time of day (untested)', - 'TLS-350_CMD' => "\x01S50100" + 'Description' => 'S50100 Set time of day (use TIME option) (untested)', + # disabled, unsure how this works just yet + #'TLS-350_CMD' => "\x01S50100" } ], [ 'STATUS', @@ -155,7 +156,8 @@ class Metasploit3 < Msf::Auxiliary [ Opt::RPORT(10001), OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]), - OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']) + OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']), + OptString.new('TIME', [false, "The time to set (use with SET_TIME, defaults to Time.now (~#{Time.now.inspect})"]) ], self.class ) @@ -190,6 +192,14 @@ class Metasploit3 < Msf::Auxiliary datastore['TANK_NUMBER'] end + def time + if datastore['TIME'] + Time.parse(datastore['TIME']).to_i + else + Time.now.to_i + end + end + def peer "#{rhost}:#{rport}" end @@ -220,6 +230,9 @@ class Metasploit3 < Msf::Auxiliary else print_warning message end + when 'SET_TIME' + request = "#{action.opts[protocol + '_CMD']}#{Time.now.to_i}\n" + sock.put(request) else request = "#{action.opts[protocol + '_CMD']}\n" sock.put(request) From 196a88c39a429e66779397eb4941dac0cbb13184 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:06:00 -0800 Subject: [PATCH 15/22] Style nit --- modules/auxiliary/admin/atg/client.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 08d60d0c45..0ac997200d 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -115,7 +115,7 @@ class Metasploit3 < Msf::Auxiliary { 'Description' => 'S50100 Set time of day (use TIME option) (untested)', # disabled, unsure how this works just yet - #'TLS-350_CMD' => "\x01S50100" + # 'TLS-350_CMD' => "\x01S50100" } ], [ 'STATUS', @@ -158,16 +158,14 @@ class Metasploit3 < Msf::Auxiliary OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]), OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']), OptString.new('TIME', [false, "The time to set (use with SET_TIME, defaults to Time.now (~#{Time.now.inspect})"]) - ], - self.class + ] ) deregister_options('SSL', 'SSLCipher', 'SSLVerifyMode', 'SSLVersion') register_advanced_options( [ OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]) - ], - self.class + ] ) end From 6e9afc38eec5baff97f739c599fcc2cbe9ad10dd Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:12:37 -0800 Subject: [PATCH 16/22] print_good when we get something --- modules/auxiliary/admin/atg/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 0ac997200d..2774870d67 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -234,7 +234,7 @@ class Metasploit3 < Msf::Auxiliary else request = "#{action.opts[protocol + '_CMD']}\n" sock.put(request) - print_status("#{peer} #{protocol} #{action.opts['Description']}:\n#{sock.get_once}") + print_good("#{peer} #{protocol} #{action.opts['Description']}:\n#{sock.get_once}") end ensure disconnect From 045bab052e64d3b137fb2cfe1e42e9c54521a6d9 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:18:40 -0800 Subject: [PATCH 17/22] Add configurable timeout --- modules/auxiliary/admin/atg/client.rb | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 2774870d67..f50adde597 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -164,7 +164,8 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ - OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]) + OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]), + OptInt.new('TIMEOUT', [true, 'Time in seconds to wait for responses to our probes', 5]) ] ) end @@ -176,6 +177,18 @@ class Metasploit3 < Msf::Auxiliary # ensure that the tank number is set for the commands that need it fail "TANK_NUMBER #{tank_number} is invalid" if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99) + + fail "Invalid timeout #{timeout} -- must be > 0" unless timeout > 0 + end + + def get_response(request) + sock.put(request) + response = sock.get_once(-1, timeout) + response + end + + def peer + "#{rhost}:#{rport}" end def protocol @@ -198,8 +211,8 @@ class Metasploit3 < Msf::Auxiliary end end - def peer - "#{rhost}:#{rport}" + def timeout + datastore['TIMEOUT'] end def run_host(_host) @@ -220,8 +233,7 @@ class Metasploit3 < Msf::Auxiliary connect # send an inventory probe to show that it succeeded inventory_probe = "#{actions.find { |a| a.name == 'INVENTORY' }.opts[protocol + '_CMD']}\n" - sock.put(inventory_probe) - inventory_response = sock.get_once # XXX: timeout? + inventory_response = get_response(inventory_probe) message = "#{peer} #{protocol} #{action.opts['Description']}:\n#{inventory_response}" if inventory_response.include?(tank_name) print_good message @@ -233,8 +245,8 @@ class Metasploit3 < Msf::Auxiliary sock.put(request) else request = "#{action.opts[protocol + '_CMD']}\n" - sock.put(request) - print_good("#{peer} #{protocol} #{action.opts['Description']}:\n#{sock.get_once}") + response = get_response(request) + print_good("#{peer} #{protocol} #{action.opts['Description']}:\n#{response}") end ensure disconnect From ad22eb844408ea22163b37e5680f0bb619162544 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:24:28 -0800 Subject: [PATCH 18/22] More cleanup --- modules/auxiliary/admin/atg/client.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index f50adde597..4a9b5654a1 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -172,8 +172,7 @@ class Metasploit3 < Msf::Auxiliary def setup # ensure that the specified command is implemented for the desired version of the TLS protocol - proto_cmd = protocol + "_CMD" - fail "#{action.name} not defined for #{protocol}" unless action.opts.keys.include?(proto_cmd) + fail "#{action.name} not defined for #{protocol}" unless action.opts.keys.include?(protocol_opt_name) # ensure that the tank number is set for the commands that need it fail "TANK_NUMBER #{tank_number} is invalid" if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99) @@ -195,6 +194,10 @@ class Metasploit3 < Msf::Auxiliary datastore['PROTOCOL'] end + def protocol_opt_name + protocol + '_CMD' + end + def tank_name @tank_name ||= (datastore['TANK_NAME'] ? datastore['TANK_NAME'] : Rex::Text.rand_text_alpha(16)) end @@ -226,13 +229,13 @@ class Metasploit3 < Msf::Auxiliary else vprint_status("#{peer} -- setting tank ##{tank_number}'s name to #{tank_name}") end - request = "#{action.opts[protocol + '_CMD']}#{format('%02d', tank_number)}#{tank_name}\n" + request = "#{action.opts[protocol_opt_name]}#{format('%02d', tank_number)}#{tank_name}\n" sock.put(request) # reconnect disconnect connect # send an inventory probe to show that it succeeded - inventory_probe = "#{actions.find { |a| a.name == 'INVENTORY' }.opts[protocol + '_CMD']}\n" + inventory_probe = "#{actions.find { |a| a.name == 'INVENTORY' }.opts[protocol_opt_name]}\n" inventory_response = get_response(inventory_probe) message = "#{peer} #{protocol} #{action.opts['Description']}:\n#{inventory_response}" if inventory_response.include?(tank_name) @@ -241,11 +244,9 @@ class Metasploit3 < Msf::Auxiliary print_warning message end when 'SET_TIME' - request = "#{action.opts[protocol + '_CMD']}#{Time.now.to_i}\n" - sock.put(request) + response = get_response("#{action.opts[protocol_opt_name]}#{Time.now.to_i}\n") else - request = "#{action.opts[protocol + '_CMD']}\n" - response = get_response(request) + response = get_response("#{action.opts[protocol_opt_name]}\n") print_good("#{peer} #{protocol} #{action.opts['Description']}:\n#{response}") end ensure From ab3ae675ffccf8f3b06ca78604de615ac318c039 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:26:42 -0800 Subject: [PATCH 19/22] Hide TIME option since SET_TIME is not implemented --- modules/auxiliary/admin/atg/client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 4a9b5654a1..6d802c04a2 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -156,8 +156,7 @@ class Metasploit3 < Msf::Auxiliary [ Opt::RPORT(10001), OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]), - OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']), - OptString.new('TIME', [false, "The time to set (use with SET_TIME, defaults to Time.now (~#{Time.now.inspect})"]) + OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)']) ] ) deregister_options('SSL', 'SSLCipher', 'SSLVerifyMode', 'SSLVersion') @@ -165,6 +164,7 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]), + OptString.new('TIME', [false, "The time to set (use with SET_TIME, defaults to Time.now (~#{Time.now.inspect})"]), OptInt.new('TIMEOUT', [true, 'Time in seconds to wait for responses to our probes', 5]) ] ) From c914c7b22c3ec94de12f614ac1d80c4d567707a3 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 13 Nov 2015 12:28:23 -0800 Subject: [PATCH 20/22] Completely remove SET_TIME --- modules/auxiliary/admin/atg/client.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/client.rb index 6d802c04a2..18e5334c6d 100644 --- a/modules/auxiliary/admin/atg/client.rb +++ b/modules/auxiliary/admin/atg/client.rb @@ -111,13 +111,12 @@ class Metasploit3 < Msf::Auxiliary 'TLS-350_CMD' => "\x01S602" } ], - [ 'SET_TIME', - { - 'Description' => 'S50100 Set time of day (use TIME option) (untested)', - # disabled, unsure how this works just yet - # 'TLS-350_CMD' => "\x01S50100" - } - ], + # [ 'SET_TIME', + # { + # 'Description' => 'S50100 Set time of day (use TIME option) (untested)', + # 'TLS-350_CMD' => "\x01S50100" + # } + # ], [ 'STATUS', { 'Description' => 'I20500 In-tank status report', @@ -164,7 +163,6 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options( [ OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]), - OptString.new('TIME', [false, "The time to set (use with SET_TIME, defaults to Time.now (~#{Time.now.inspect})"]), OptInt.new('TIMEOUT', [true, 'Time in seconds to wait for responses to our probes', 5]) ] ) @@ -243,8 +241,6 @@ class Metasploit3 < Msf::Auxiliary else print_warning message end - when 'SET_TIME' - response = get_response("#{action.opts[protocol_opt_name]}#{Time.now.to_i}\n") else response = get_response("#{action.opts[protocol_opt_name]}\n") print_good("#{peer} #{protocol} #{action.opts['Description']}:\n#{response}") From 74f6ff7752581b3ecaf420b3eb0136b3c3d265d4 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Tue, 17 Nov 2015 12:59:37 -0600 Subject: [PATCH 21/22] Rename to atg_client to match conventions --- modules/auxiliary/admin/atg/{client.rb => atg_client.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/auxiliary/admin/atg/{client.rb => atg_client.rb} (100%) diff --git a/modules/auxiliary/admin/atg/client.rb b/modules/auxiliary/admin/atg/atg_client.rb similarity index 100% rename from modules/auxiliary/admin/atg/client.rb rename to modules/auxiliary/admin/atg/atg_client.rb From e107ec2d170ce73d5455441bffbd920ef75e65fb Mon Sep 17 00:00:00 2001 From: HD Moore Date: Tue, 17 Nov 2015 13:30:46 -0600 Subject: [PATCH 22/22] Change fail to fail_with, fix typo --- modules/auxiliary/admin/atg/atg_client.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/admin/atg/atg_client.rb b/modules/auxiliary/admin/atg/atg_client.rb index 18e5334c6d..9962d57c5b 100644 --- a/modules/auxiliary/admin/atg/atg_client.rb +++ b/modules/auxiliary/admin/atg/atg_client.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Auxiliary 'Name' => 'Veeder-Root Automatic Tank Gauge (ATG) Administrative Client', 'Description' => %q{ This module acts as a simplistic administrative client for interfacing - with Veeder-Root Automatic Tang Gauges (ATGs) or other devices speaking + with Veeder-Root Automatic Tank Gauges (ATGs) or other devices speaking the TLS-250 and TLS-350 protocols. This has been tested against GasPot, a honeypot meant to simulate ATGs; it has not been tested against anything else, so use at your own risk. @@ -170,12 +170,18 @@ class Metasploit3 < Msf::Auxiliary def setup # ensure that the specified command is implemented for the desired version of the TLS protocol - fail "#{action.name} not defined for #{protocol}" unless action.opts.keys.include?(protocol_opt_name) + unless action.opts.keys.include?(protocol_opt_name) + fail_with(Failure::BadConfig, "#{action.name} not defined for #{protocol}") + end # ensure that the tank number is set for the commands that need it - fail "TANK_NUMBER #{tank_number} is invalid" if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99) + if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99) + fail_with(Failure::BadConfig, "TANK_NUMBER #{tank_number} is invalid") + end - fail "Invalid timeout #{timeout} -- must be > 0" unless timeout > 0 + unless timeout > 0 + fail_with(Failure::BadConfig, "Invalid timeout #{timeout} -- must be > 0") + end end def get_response(request)