TFTP File Transfer Utility
🗓️ 20 Dec 2011 16:06:44Reported by todb <[email protected]>Type
metasploit🔗 www.rapid7.com👁 48 Views
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Rex::Proto::TFTP
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'TFTP File Transfer Utility',
'Description' => %q{
This module will transfer a file to or from a remote TFTP server.
Note that the target must be able to connect back to the Metasploit system,
and NAT traversal for TFTP is often unsupported.
Two actions are supported: "Upload" and "Download," which behave as one might
expect -- use 'set action Actionname' to use either mode of operation.
If "Download" is selected, at least one of FILENAME or REMOTE_FILENAME
must be set. If "Upload" is selected, either FILENAME must be set to a valid path to
a source file, or FILEDATA must be populated. FILENAME may be a fully qualified path,
or the name of a file in the Msf::Config.local_directory or Msf::Config.data_directory.
},
'Author' => [ 'todb' ],
'References' =>
[
['URL', 'http://www.faqs.org/rfcs/rfc1350.html'],
['URL', 'http://www.networksorcery.com/enp/protocol/tftp.htm']
],
'Actions' => [
[ 'Download', 'Description' => "Download REMOTE_FILENAME as FILENAME from the server."],
[ 'Upload', 'Description' => "Upload FILENAME as REMOTE_FILENAME to the server."]
],
'DefaultAction' => 'Upload',
'License' => MSF_LICENSE
)
register_options([
OptString.new( 'FILENAME', [false, "The local filename" ]),
OptString.new( 'FILEDATA', [false, "Data to upload in lieu of a real local file." ]),
OptString.new( 'REMOTE_FILENAME', [false, "The remote filename"]),
OptAddress.new('RHOST', [true, "The remote TFTP server"]),
OptPort.new( 'LPORT', [false, "The local port the TFTP client should listen on (default is random)" ]),
OptAddressLocal.new('LHOST', [false, "The local address the TFTP client should bind to"]),
OptString.new( 'MODE', [false, "The TFTP mode; usual choices are netascii and octet.", "octet"]),
Opt::RPORT(69)
])
end
def mode
datastore['MODE'] || "octet"
end
def remote_file
return datastore['REMOTE_FILENAME'] if datastore['REMOTE_FILENAME']
return ::File.split(datastore['FILENAME']).last if datastore['FILENAME']
end
def rport
datastore['RPORT'] || 69
end
def rhost
datastore['RHOST']
end
# Used only to store loot, doesn't actually have any semantic meaning
# for the TFTP protocol.
def datatype
case datastore['MODE']
when "netascii"
"text/plain"
else
"application/octet-stream"
end
end
def file
if action.name == "Upload"
fdata = datastore['FILEDATA'].to_s
fname = datastore['FILENAME'].to_s
if not fdata.empty?
fdata_decorated = "DATA:#{datastore['FILEDATA']}"
elsif ::File.readable? fname
fname
else
fname_local = ::File.join(Msf::Config.local_directory,fname)
fname_data = ::File.join(Msf::Config.data_directory,fname)
return fname_local if ::File.file?(fname_local) and ::File.readable?(fname_local)
return fname_data if ::File.file?(fname_data) and ::File.readable?(fname_data)
return nil # Couldn't find it, giving up.
end
else # "Download"
fname = ::File.split(datastore['FILENAME'] || datastore['REMOTE_FILENAME']).last rescue nil
end
end
# Experimental message prepending thinger. Might make it up into the
# standard Metasploit lib like vprint_status and friends.
def rtarget(ip=nil)
if (ip or rhost) and rport
[(ip || rhost),rport].map {|x| x.to_s}.join(":") << " "
elsif (ip or rhost)
"#{rhost} "
else
""
end
end
# This all happens before run(), and should give an idea on how to use
# the TFTP client mixin. Essentially, you create an instance of the
# Rex::Proto::TFTP::Client class, fill it up with the relevant host and
# file data, set it to either :upload or :download, then kick off the
# transfer as you like.
def setup
@lport = datastore['LPORT'] || (1025 + rand(0xffff-1025))
@lhost = datastore['LHOST'] || "0.0.0.0"
@local_file = file
@remote_file = remote_file
@tftp_client = Rex::Proto::TFTP::Client.new(
"LocalHost" => @lhost,
"LocalPort" => @lport,
"PeerHost" => rhost,
"PeerPort" => rport,
"LocalFile" => @local_file,
"RemoteFile" => @remote_file,
"Mode" => mode,
"Context" => {'Msf' => self.framework, 'MsfExploit' => self},
"Action" => action.name.to_s.downcase.intern
)
end
def run
case action.name
when 'Upload'
if file
run_upload()
else
print_error "Need at least a local file name or file data to upload."
return
end
when 'Download'
if remote_file
run_download()
else
print_error "Need at least a remote file name to download."
return
end
else
print_error "Unknown action: '#{action.name}'"
end
while not @tftp_client.complete
select(nil,nil,nil,1)
print_status [rtarget,"TFTP transfer operation complete."].join
save_downloaded_file() if action.name == 'Download'
break
end
end
# Run in case something untoward happened with the connection and the
# client object didn't get stopped on its own. This can happen with
# transfers that got interrupted or malformed (like sending a 0 byte
# file).
def cleanup
if @tftp_client and @tftp_client.respond_to? :complete
while not @tftp_client.complete
select(nil,nil,nil,1)
vprint_status "Cleaning up the TFTP client ports and threads."
@tftp_client.stop
end
end
end
def run_upload
print_status "Sending '#{file}' to #{rhost}:#{rport} as '#{remote_file}'"
ret = @tftp_client.send_write_request { |msg| print_tftp_status(msg) }
end
def run_download
print_status "Receiving '#{remote_file}' from #{rhost}:#{rport} as '#{file}'"
ret = @tftp_client.send_read_request { |msg| print_tftp_status(msg) }
end
def save_downloaded_file
print_status "Saving #{remote_file} as '#{file}'"
fh = @tftp_client.recv_tempfile
data = File.open(fh,"rb") {|f| f.read f.stat.size} rescue nil
if data and not data.empty?
unless framework.db.active
print_status "No database connected, so not actually saving the data:"
print_line data
end
this_service = report_service(
:host => rhost,
:port => rport,
:name => "tftp",
:proto => "udp"
)
store_loot("tftp.file",datatype,rhost,data,file,remote_file,this_service)
else
print_status [rtarget,"Did not find any data, so nothing to save."].join
end
fh.unlink rescue nil # Windows often complains about unlinking tempfiles
end
def print_tftp_status(msg)
case msg
when /Aborting/, /errors.$/
print_error [rtarget,msg].join
when /^WRQ accepted/, /^Sending/, /complete!$/
print_good [rtarget,msg].join
else
vprint_status [rtarget,msg].join
end
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
07 Jan 2024 20:02Current
7.3High risk
Vulners AI Score7.3