## ## This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Auxiliary include Msf::Auxiliary::Report def initialize(info = {}) super( 'Name' => 'Extract zip from Modbus communication', 'Description' => %q{ This module is able to extract a zip file sent through Modbus from a pcap. Tested with Schneider TM221CE16R }, 'Author' => [ 'José Diogo Monteiro ', 'Luis Rosa ' ], 'License' => MSF_LICENSE ) register_options [ Opt::RPORT(502), OptEnum.new('MODE', [true, 'Extract zip from upload/download capture', 'UPLOAD', ['UPLOAD','DOWNLOAD']]), OptString.new('PCAPFILE', [ true, 'Pcap to read', '' ]), OptString.new('FILENAME', [ false, 'Zip file output name']) ] end FIRST_BYTE_UPLOAD = 12 FIRST_BYTE_DOWNLOAD = 16 def extract_zip(packet, zip_packet, first_byte, data, packet_number) # ZIP start signature h = packet.payload.scan(/\x50\x4B\x03\x04.*/) if h.size.nonzero? print_status "Zip start on packet #{packet_number + 1}" data = h[0] zip_packet += 1 return zip_packet, data end # ZIP end signature (central directory record) h = packet.payload.scan(/.*\x50\x4B\x05\x06................../) if h.size.nonzero? print_status "Zip end on packet #{packet_number + 1}" data += h[0][first_byte..-1] zip_packet += 1 return zip_packet, data end # ZIP data if zip_packet == 1 unless packet.payload[first_byte..-1].nil? data += packet.payload[first_byte..-1] end end return zip_packet, data end def run packets = PacketFu::PcapFile.read_packets datastore['PCAPFILE'] zip_packet = 0 data = '' packets.each_with_index do |packet, i| if datastore['MODE'] == 'UPLOAD' if packet.respond_to?(:tcp_src) and packet.tcp_src == datastore['RPORT'] zip_packet, data = extract_zip(packet, zip_packet, FIRST_BYTE_UPLOAD, data, i) end elsif datastore['MODE'] == 'DOWNLOAD' if packet.respond_to?(:tcp_dst) and packet.tcp_dst == datastore['RPORT'] zip_packet, data = extract_zip(packet, zip_packet, FIRST_BYTE_DOWNLOAD, data, i) end end break if zip_packet == 2 end filename = datastore['FILENAME'] || 'project.zip' unless data.empty? path = store_loot(filename, 'application/zip', datastore['RHOSTS'], data, filename, 'modbus.zip') print_good "Zip file saved in loot: #{path}" else print_status "Zip file not found in #{datastore['PCAPFILE']}" end end end