CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/evasion.rb
Views: 1904
1
2
module Msf
3
class Evasion < Msf::Module
4
5
include Msf::Auxiliary::Report
6
7
class Complete < RuntimeError ; end
8
9
class Failed < RuntimeError ; end
10
11
def initialize(info={})
12
if (info['Payload'] and info['Payload']['Compat'])
13
info['Compat'] = Hash.new if (info['Compat'] == nil)
14
info['Compat']['Payload'] = Hash.new if (info['Compat']['Payload'] == nil)
15
info['Compat']['Payload'].update(info['Payload']['Compat'])
16
end
17
18
super(info)
19
20
self.payload_info = info['Payload'] || {}
21
self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets')
22
23
if info.key? 'DefaultTarget'
24
self.default_target = info['DefaultTarget']
25
else
26
self.default_target = 0
27
# Add an auto-target to the evasion if it doesn't have one
28
if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])
29
# Finally, only add the target if there is a remote host option
30
if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)
31
auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]
32
info['Targets'].unshift(auto)
33
end
34
end
35
end
36
37
if (info['Payload'] and info['Payload']['ActiveTimeout'])
38
self.active_timeout = info['Payload']['ActiveTimeout'].to_i
39
end
40
41
register_options([
42
OptString.new(
43
'FILENAME',
44
[
45
true,
46
'Filename for the evasive file (default: random)',
47
"#{Rex::Text.rand_text_alpha(3..10)}.exe"
48
])
49
], self.class)
50
end
51
52
def self.type
53
Msf::MODULE_EVASION
54
end
55
56
def type
57
Msf::MODULE_EVASION
58
end
59
60
def setup
61
alert_user
62
end
63
64
def file_format_filename
65
datastore['FILENAME']
66
end
67
68
def file_create(data)
69
fname = file_format_filename
70
ltype = "evasion.fileformat.#{self.shortname}"
71
full_path = store_local(ltype, nil, data, fname)
72
print_good "#{fname} stored at #{full_path}"
73
end
74
75
#
76
# Returns the target's platform, or the one assigned to the module itself.
77
#
78
def target_platform
79
(target and target.platform) ? target.platform : platform
80
end
81
82
#
83
# Returns the target's architecture, or the one assigned to the module
84
# itself.
85
#
86
def target_arch
87
(target and target.arch) ? target.arch : (arch == []) ? nil : arch
88
end
89
90
def normalize_platform_arch
91
c_platform = (target && target.platform) ? target.platform : platform
92
c_arch = (target && target.arch) ? target.arch : (arch == []) ? nil : arch
93
c_arch ||= [ ARCH_X86 ]
94
return c_platform, c_arch
95
end
96
97
# Returns whether the requested payload is compatible with the module
98
#
99
# @param [String] name The payload name
100
# @return [Boolean] True if the payload is compatible, False if not.
101
def is_payload_compatible?(name)
102
p = framework.payloads[name]
103
return false unless p
104
105
begin
106
pi = p.new
107
rescue ::Exception, ::LoadError => e
108
wlog("Module #{name} failed to initialize payload when checking evasion compatibility: #{e}", 'core', LEV_0)
109
return false
110
end
111
112
# Are we compatible in terms of conventions and connections and
113
# what not?
114
return false if !compatible?(pi)
115
116
# If the payload is privileged but the evasion does not give
117
# privileged access, then fail it.
118
return false if !self.privileged && pi.privileged
119
120
return true
121
end
122
123
# Returns a list of compatible payloads based on platform, architecture,
124
# and size requirements.
125
def compatible_payloads(excluded_platforms: [], excluded_archs: [])
126
payloads = []
127
128
c_platform, c_arch = normalize_platform_arch
129
130
# The "All" platform name represents generic payloads
131
results = Msf::Modules::Metadata::Cache.instance.find(
132
'type' => [['payload'], []],
133
'platform' => [[*c_platform.names, 'All'], excluded_platforms],
134
'arch' => [c_arch, excluded_archs]
135
)
136
137
results.each do |res|
138
if is_payload_compatible?(res.ref_name)
139
payloads << [res.ref_name, framework.payloads[res.ref_name]]
140
end
141
end
142
143
payloads
144
end
145
146
def run
147
raise NotImplementedError
148
end
149
150
def cleanup
151
end
152
153
def fail_with(reason, msg=nil)
154
raise Msf::Evasion::Failed, "#{reason}: #{msg}"
155
end
156
157
def evasion_commands
158
{}
159
end
160
161
def stance
162
'passive'
163
end
164
165
def passive?
166
true
167
end
168
169
def aggressive?
170
false
171
end
172
173
# Generates the encoded version of the supplied payload using the payload
174
# requirements specific to this evasion module. The encoded instance is returned
175
# to the caller. This method is exposed in the manner that it is such that passive
176
# evasions and re-generate an encoded payload on the fly rather than having to use
177
# the pre-generated one.
178
def generate_payload(pinst = nil)
179
# Set the encoded payload to the result of the encoding process
180
self.payload = generate_single_payload(pinst)
181
182
# Save the payload instance
183
self.payload_instance = (pinst) ? pinst : self.payload_instance
184
185
return self.payload
186
end
187
188
def generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_target = nil)
189
explicit_target ||= target
190
191
# If a payload instance was supplied, use it, otherwise
192
# use the active payload instance
193
real_payload = (pinst) ? pinst : self.payload_instance
194
195
if (real_payload == nil)
196
raise MissingPayloadError, "No payload has been selected.",
197
caller
198
end
199
200
# If this is a generic payload, then we should specify the platform
201
# and architecture so that it knows how to pass things on.
202
if real_payload.kind_of?(Msf::Payload::Generic)
203
# Convert the architecture specified into an array.
204
if arch and arch.kind_of?(String)
205
arch = [ arch ]
206
end
207
208
# Define the explicit platform and architecture information only if
209
# it's been specified.
210
if platform
211
real_payload.explicit_platform = Msf::Module::PlatformList.transform(platform)
212
end
213
214
if arch
215
real_payload.explicit_arch = arch
216
end
217
218
# Force it to reset so that it will find updated information.
219
real_payload.reset
220
end
221
222
# Duplicate the evasion payload requirements
223
reqs = self.payload_info.dup
224
225
# Pass save register requirements to the NOP generator
226
reqs['Space'] = payload_info['Space'] ? payload_info['Space'].to_i : nil
227
reqs['SaveRegisters'] = module_info['SaveRegisters']
228
reqs['Prepend'] = payload_info['Prepend']
229
reqs['PrependEncoder'] = payload_info['PrependEncoder']
230
reqs['BadChars'] = payload_info['BadChars']
231
reqs['Append'] = payload_info['Append']
232
reqs['AppendEncoder'] = payload_info['AppendEncoder']
233
reqs['DisableNops'] = payload_info['DisableNops']
234
reqs['MaxNops'] = payload_info['MaxNops']
235
reqs['MinNops'] = payload_info['MinNops']
236
reqs['Encoder'] = datastore['ENCODER'] || payload_info['Encoder']
237
reqs['Nop'] = datastore['NOP'] || payload_info['Nop']
238
reqs['EncoderType'] = payload_info['EncoderType']
239
reqs['EncoderOptions'] = payload_info['EncoderOptions']
240
reqs['ExtendedOptions'] = payload_info['ExtendedOptions']
241
reqs['ForceEncode'] = payload_info['ForceEncode']
242
reqs['Evasion'] = self
243
244
# Pass along the encoder don't fall through flag
245
reqs['EncoderDontFallThrough'] = datastore['EncoderDontFallThrough']
246
247
# Incorporate any context encoding requirements that are needed
248
define_context_encoding_reqs(reqs)
249
250
# Call the encode begin routine.
251
encode_begin(real_payload, reqs)
252
253
# Generate the encoded payload.
254
encoded = EncodedPayload.create(real_payload, reqs)
255
256
# Call the encode end routine which is expected to return the actual
257
# encoded payload instance.
258
return encode_end(real_payload, reqs, encoded)
259
end
260
261
def define_context_encoding_reqs(reqs)
262
return unless datastore['EnableContextEncoding']
263
264
# At present, we don't support any automatic methods of obtaining
265
# context information. In the future, we might support obtaining
266
# temporal information remotely.
267
268
# Pass along the information specified in our evasion datastore as
269
# encoder options
270
reqs['EncoderOptions'] = {} if reqs['EncoderOptions'].nil?
271
reqs['EncoderOptions']['EnableContextEncoding'] = datastore['EnableContextEncoding']
272
reqs['EncoderOptions']['ContextInformationFile'] = datastore['ContextInformationFile']
273
end
274
275
def encode_begin(real_payload, reqs)
276
end
277
278
def encode_end(real_payload, reqs, encoded)
279
encoded
280
end
281
282
def target
283
if self.respond_to?(:auto_targeted_index)
284
if auto_target?
285
auto_idx = auto_targeted_index
286
if auto_idx.present?
287
datastore['TARGET'] = auto_idx
288
else
289
# If our inserted Automatic Target was selected but we failed to
290
# find a suitable target, we just grab the original first target.
291
datastore['TARGET'] = 1
292
end
293
end
294
end
295
296
target_idx = target_index
297
return (target_idx) ? targets[target_idx.to_i] : nil
298
end
299
300
def target_index
301
target_idx =
302
begin
303
Integer(datastore['TARGET'])
304
rescue TypeError, ArgumentError
305
datastore['TARGET']
306
end
307
308
default_idx = default_target || 0
309
# Use the default target if one was not supplied.
310
if (target_idx == nil and default_idx and default_idx >= 0)
311
target_idx = default_idx
312
elsif target_idx.is_a?(String)
313
target_idx = targets.index { |target| target.name == target_idx }
314
end
315
316
return (target_idx) ? target_idx.to_i : nil
317
end
318
319
def has_auto_target?(targets=[])
320
target_names = targets.collect { |target| target.first}
321
target_names.each do |target|
322
return true if target =~ /Automatic/
323
end
324
return false
325
end
326
327
attr_accessor :default_target
328
329
attr_accessor :targets
330
331
attr_reader :payload_info
332
333
attr_accessor :payload_info
334
335
attr_accessor :payload_instance
336
337
attr_accessor :payload
338
end
339
end
340
341