Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/admin/atg/atg_client.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::Tcp8include Msf::Auxiliary::Scanner910def initialize11super(12'Name' => 'Veeder-Root Automatic Tank Gauge (ATG) Administrative Client',13'Description' => %q{14This module acts as a simplistic administrative client for interfacing15with Veeder-Root Automatic Tank Gauges (ATGs) or other devices speaking16the TLS-250 and TLS-350 protocols. This has been tested against17GasPot and Conpot, both honeypots meant to simulate ATGs; it has not18been tested against anything else, so use at your own risk.19},20'Author' =>21[22'Jon Hart <jon_hart[at]rapid7.com>' # original metasploit module23],24'License' => MSF_LICENSE,25'References' =>26[27['URL', 'https://www.rapid7.com/blog/post/2015/01/22/the-internet-of-gas-station-tank-gauges/'],28['URL', 'https://www.trendmicro.com/vinfo/us/security/news/cybercrime-and-digital-threats/the-gaspot-experiment'],29['URL', 'https://github.com/sjhilt/GasPot'],30['URL', 'https://github.com/mushorg/conpot'],31['URL', 'https://www.veeder.com/us/automatic-tank-gauge-atg-consoles'],32['URL', 'https://cdn.chipkin.com/files/liz/576013-635.pdf'],33['URL', 'https://docs.veeder.com/gold/download.cfm?doc_id=6227']34],35'DefaultAction' => 'INVENTORY',36'Actions' =>37[38[ 'ALARM',39{40'Description' => 'I30200 Sensor alarm history (untested)',41'TLS-350_CMD' => "\x01I30200"42}43],44[ 'ALARM_RESET',45{46'Description' => 'IS00300 Remote alarm reset (untested)',47'TLS-350_CMD' => "\x01IS00300"48}49],50[ 'DELIVERY',51{52'Description' => 'I20200 Delivery report',53'TLS-350_CMD' => "\x01I20200"54}55],56[ 'INVENTORY',57{58'Description' => '200/I20100 In-tank inventory report',59'TLS-250_CMD' => "\x01200",60'TLS-350_CMD' => "\x01I20100"61}62],63[ 'LEAK',64{65'Description' => 'I20300 Leak report',66'TLS-350_CMD' => "\x01I20300"67}68],69[ 'RELAY',70{71'Description' => 'I40600 Relay status (untested)',72'TLS-350_CMD' => "\x01I40600"73}74],75[ 'RESET',76{77'Description' => 'IS00100 Reset (untested)',78'TLS-350_CMD' => "\x01IS00100"79}80],81[ 'CLEAR_RESET',82{83'Description' => 'IS00200 Clear Reset Flag (untested)',84'TLS-350_CMD' => "\x01IS00200"85}86],87[ 'SENSOR',88{89'Description' => 'I30100 Sensor status (untested)',90'TLS-350_CMD' => "\x01I30100"91}92],93[ 'SENSOR_DIAG',94{95'Description' => 'IB0100 Sensor diagnostics (untested)',96'TLS-350_CMD' => "\x01IB0100"97}98],99[ 'SHIFT',100{101'Description' => 'I20400 Shift report',102'TLS-350_CMD' => "\x01I20400"103}104],105[ 'SET_TANK_NAME',106{107'Description' => 'S602 set tank name (use TANK_NUMBER and TANK_NAME options)',108'TLS-350_CMD' => "\x01S602"109}110],111# [ 'SET_TIME',112# {113# 'Description' => 'S50100 Set time of day (use TIME option) (untested)',114# 'TLS-350_CMD' => "\x01S50100"115# }116# ],117[ 'STATUS',118{119'Description' => 'I20500 In-tank status report',120'TLS-350_CMD' => "\x01I20500"121}122],123[ 'SYSTEM_STATUS',124{125'Description' => 'I10100 System status report (untested)',126'TLS-350_CMD' => "\x01I10100"127}128],129[ 'TANK_ALARM',130{131'Description' => 'I20600 Tank alarm history (untested)',132'TLS-350_CMD' => "\x01I20600"133}134],135[ 'TANK_DIAG',136{137'Description' => 'IA0100 Tank diagnostics (untested)',138'TLS-350_CMD' => "\x01IA0100"139}140],141[ 'VERSION',142{143'Description' => 'Version information',144'TLS-250_CMD' => "\x01980",145'TLS-350_CMD' => "\x01I90200"146}147]148]149)150151register_options(152[153Opt::RPORT(10001),154OptInt.new('TANK_NUMBER', [false, 'The tank number to operate on (use with SET_TANK_NAME, 0 to change all)', 1]),155OptString.new('TANK_NAME', [false, 'The tank name to set (use with SET_TANK_NAME, defaults to random)'])156]157)158deregister_options('SSL', 'SSLCipher', 'SSLVerifyMode', 'SSLVersion')159160register_advanced_options(161[162OptEnum.new('PROTOCOL', [true, 'The Veeder-Root TLS protocol to speak', 'TLS-350', %w(TLS-350 TLS-250)]),163OptInt.new('TIMEOUT', [true, 'Time in seconds to wait for responses to our probes', 5])164]165)166end167168def setup169# ensure that the specified command is implemented for the desired version of the TLS protocol170unless action.opts.keys.include?(protocol_opt_name)171fail_with(Failure::BadConfig, "#{action.name} not defined for #{protocol}")172end173174# ensure that the tank number is set for the commands that need it175if action.name == 'SET_TANK_NAME' && (tank_number < 0 || tank_number > 99)176fail_with(Failure::BadConfig, "TANK_NUMBER #{tank_number} is invalid")177end178179unless timeout > 0180fail_with(Failure::BadConfig, "Invalid timeout #{timeout} -- must be > 0")181end182end183184def get_response(request)185sock.put(request)186response = sock.get_once(-1, timeout)187response.strip!188response += " (command not understood)" if response == "9999FF1B"189response190end191192def protocol193datastore['PROTOCOL']194end195196def protocol_opt_name197protocol + '_CMD'198end199200def tank_name201@tank_name ||= (datastore['TANK_NAME'] ? datastore['TANK_NAME'] : Rex::Text.rand_text_alpha(16))202end203204def tank_number205datastore['TANK_NUMBER']206end207208def time209if datastore['TIME']210Time.parse(datastore['TIME']).to_i211else212Time.now.to_i213end214end215216def timeout217datastore['TIMEOUT']218end219220def run_host(_host)221begin222connect223case action.name224when 'SET_TANK_NAME'225# send the set tank name command to change the tank name(s)226if tank_number == 0227vprint_status("Setting all tank names to #{tank_name}")228else229vprint_status("Setting tank ##{tank_number}'s name to #{tank_name}")230end231request = "#{action.opts[protocol_opt_name]}#{format('%02d', tank_number)}#{tank_name}\n"232sock.put(request)233# reconnect234disconnect235connect236# send an inventory probe to show that it succeeded237inventory_probe = "#{actions.find { |a| a.name == 'INVENTORY' }.opts[protocol_opt_name]}\n"238inventory_response = get_response(inventory_probe)239message = "#{protocol} #{action.opts['Description']}:\n#{inventory_response}"240if inventory_response.include?(tank_name)241print_good message242else243print_warning message244end245else246response = get_response("#{action.opts[protocol_opt_name]}\n")247print_good("#{protocol} #{action.opts['Description']}:")248print_line(response)249end250ensure251disconnect252end253end254end255256257