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/tftp/tftp_transfer_util.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##456class MetasploitModule < Msf::Auxiliary7include Rex::Proto::TFTP8include Msf::Auxiliary::Report910def initialize11super(12'Name' => 'TFTP File Transfer Utility',13'Description' => %q{14This module will transfer a file to or from a remote TFTP server.15Note that the target must be able to connect back to the Metasploit system,16and NAT traversal for TFTP is often unsupported.1718Two actions are supported: "Upload" and "Download," which behave as one might19expect -- use 'set action Actionname' to use either mode of operation.2021If "Download" is selected, at least one of FILENAME or REMOTE_FILENAME22must be set. If "Upload" is selected, either FILENAME must be set to a valid path to23a source file, or FILEDATA must be populated. FILENAME may be a fully qualified path,24or the name of a file in the Msf::Config.local_directory or Msf::Config.data_directory.25},26'Author' => [ 'todb' ],27'References' =>28[29['URL', 'http://www.faqs.org/rfcs/rfc1350.html'],30['URL', 'http://www.networksorcery.com/enp/protocol/tftp.htm']31],32'Actions' => [33[ 'Download', 'Description' => "Download REMOTE_FILENAME as FILENAME from the server."],34[ 'Upload', 'Description' => "Upload FILENAME as REMOTE_FILENAME to the server."]35],36'DefaultAction' => 'Upload',37'License' => MSF_LICENSE38)39register_options([40OptString.new( 'FILENAME', [false, "The local filename" ]),41OptString.new( 'FILEDATA', [false, "Data to upload in lieu of a real local file." ]),42OptString.new( 'REMOTE_FILENAME', [false, "The remote filename"]),43OptAddress.new('RHOST', [true, "The remote TFTP server"]),44OptPort.new( 'LPORT', [false, "The local port the TFTP client should listen on (default is random)" ]),45OptAddressLocal.new('LHOST', [false, "The local address the TFTP client should bind to"]),46OptString.new( 'MODE', [false, "The TFTP mode; usual choices are netascii and octet.", "octet"]),47Opt::RPORT(69)48])49end5051def mode52datastore['MODE'] || "octet"53end5455def remote_file56return datastore['REMOTE_FILENAME'] if datastore['REMOTE_FILENAME']57return ::File.split(datastore['FILENAME']).last if datastore['FILENAME']58end5960def rport61datastore['RPORT'] || 6962end6364def rhost65datastore['RHOST']66end6768# Used only to store loot, doesn't actually have any semantic meaning69# for the TFTP protocol.70def datatype71case datastore['MODE']72when "netascii"73"text/plain"74else75"application/octet-stream"76end77end7879def file80if action.name == "Upload"81fdata = datastore['FILEDATA'].to_s82fname = datastore['FILENAME'].to_s83if not fdata.empty?84fdata_decorated = "DATA:#{datastore['FILEDATA']}"85elsif ::File.readable? fname86fname87else88fname_local = ::File.join(Msf::Config.local_directory,fname)89fname_data = ::File.join(Msf::Config.data_directory,fname)90return fname_local if ::File.file?(fname_local) and ::File.readable?(fname_local)91return fname_data if ::File.file?(fname_data) and ::File.readable?(fname_data)92return nil # Couldn't find it, giving up.93end94else # "Download"95fname = ::File.split(datastore['FILENAME'] || datastore['REMOTE_FILENAME']).last rescue nil96end97end9899# Experimental message prepending thinger. Might make it up into the100# standard Metasploit lib like vprint_status and friends.101def rtarget(ip=nil)102if (ip or rhost) and rport103[(ip || rhost),rport].map {|x| x.to_s}.join(":") << " "104elsif (ip or rhost)105"#{rhost} "106else107""108end109end110111# This all happens before run(), and should give an idea on how to use112# the TFTP client mixin. Essentially, you create an instance of the113# Rex::Proto::TFTP::Client class, fill it up with the relevant host and114# file data, set it to either :upload or :download, then kick off the115# transfer as you like.116def setup117@lport = datastore['LPORT'] || (1025 + rand(0xffff-1025))118@lhost = datastore['LHOST'] || "0.0.0.0"119@local_file = file120@remote_file = remote_file121122@tftp_client = Rex::Proto::TFTP::Client.new(123"LocalHost" => @lhost,124"LocalPort" => @lport,125"PeerHost" => rhost,126"PeerPort" => rport,127"LocalFile" => @local_file,128"RemoteFile" => @remote_file,129"Mode" => mode,130"Context" => {'Msf' => self.framework, 'MsfExploit' => self},131"Action" => action.name.to_s.downcase.intern132)133end134135def run136case action.name137when 'Upload'138if file139run_upload()140else141print_error "Need at least a local file name or file data to upload."142return143end144when 'Download'145if remote_file146run_download()147else148print_error "Need at least a remote file name to download."149return150end151else152print_error "Unknown action: '#{action.name}'"153end154while not @tftp_client.complete155select(nil,nil,nil,1)156print_status [rtarget,"TFTP transfer operation complete."].join157save_downloaded_file() if action.name == 'Download'158break159end160end161162# Run in case something untoward happened with the connection and the163# client object didn't get stopped on its own. This can happen with164# transfers that got interrupted or malformed (like sending a 0 byte165# file).166def cleanup167if @tftp_client and @tftp_client.respond_to? :complete168while not @tftp_client.complete169select(nil,nil,nil,1)170vprint_status "Cleaning up the TFTP client ports and threads."171@tftp_client.stop172end173end174end175176def run_upload177print_status "Sending '#{file}' to #{rhost}:#{rport} as '#{remote_file}'"178ret = @tftp_client.send_write_request { |msg| print_tftp_status(msg) }179end180181def run_download182print_status "Receiving '#{remote_file}' from #{rhost}:#{rport} as '#{file}'"183ret = @tftp_client.send_read_request { |msg| print_tftp_status(msg) }184end185186def save_downloaded_file187print_status "Saving #{remote_file} as '#{file}'"188fh = @tftp_client.recv_tempfile189data = File.open(fh,"rb") {|f| f.read f.stat.size} rescue nil190if data and not data.empty?191unless framework.db.active192print_status "No database connected, so not actually saving the data:"193print_line data194end195this_service = report_service(196:host => rhost,197:port => rport,198:name => "tftp",199:proto => "udp"200)201store_loot("tftp.file",datatype,rhost,data,file,remote_file,this_service)202else203print_status [rtarget,"Did not find any data, so nothing to save."].join204end205fh.unlink rescue nil # Windows often complains about unlinking tempfiles206end207208def print_tftp_status(msg)209case msg210when /Aborting/, /errors.$/211print_error [rtarget,msg].join212when /^WRQ accepted/, /^Sending/, /complete!$/213print_good [rtarget,msg].join214else215vprint_status [rtarget,msg].join216end217end218end219220221