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/exploit.rb
Views: 1904
1
# -*- coding: binary -*-
2
module Msf
3
4
5
6
###
7
#
8
# The exploit class acts as the base class for all exploit modules. It
9
# provides a common interface for interacting with exploits at the most basic
10
# level.
11
#
12
###
13
class Exploit < Msf::Module
14
15
##
16
# Exceptions
17
##
18
19
# Indicate that the exploit should abort because it has completed
20
class Complete < RuntimeError
21
end
22
23
# Indicate that the exploit should abort because it has failed
24
class Failed < RuntimeError
25
end
26
27
28
##
29
#
30
# Default compatibility settings for exploit modules.
31
#
32
##
33
module CompatDefaults
34
#
35
# Default compatibility specifications for payloads
36
#
37
Payload =
38
{
39
# Support reverse, bind, and noconn connection types
40
# for all exploits unless expressly disabled.
41
'ConnectionType' => 'reverse bind noconn none tunnel',
42
}
43
end
44
45
##
46
#
47
# The various check codes that can be returned from the ``check'' routine.
48
# Please read the following wiki to learn how these codes are used:
49
# https://docs.metasploit.com/docs/development/developing-modules/guides/how-to-write-a-check-method.html
50
#
51
##
52
class CheckCode < Struct.new(:code, :message, :reason, :details)
53
# Do customization here because we need class constants and special
54
# optional values and the block mode of Struct.new does not support that.
55
#
56
#
57
# NOTE: This class relies on the array-like interface of Struct classes to
58
# provide a backwards-compatible interface for the old CheckCode
59
# representation of `['code', 'message']`. Any change to the order or
60
# meaning of fields will need to be evaluated for how it affects the rest
61
# of the codebase.
62
63
class << self
64
def Unknown(reason = nil, details: {})
65
self.new('unknown', reason, details: details)
66
end
67
68
def Safe(reason = nil, details: {})
69
self.new('safe', reason, details: details)
70
end
71
72
def Detected(reason = nil, details: {})
73
self.new('detected', reason, details: details)
74
end
75
76
def Appears(reason = nil, details: {})
77
self.new('appears', reason, details: details)
78
end
79
80
def Vulnerable(reason = nil, details: {})
81
self.new('vulnerable', reason, details: details)
82
end
83
84
def Unsupported(reason = nil, details: {})
85
self.new('unsupported', reason, details: details)
86
end
87
end
88
89
# Deprecated, should use #===
90
#
91
# If you need to determine whether a CheckCode has the same code and
92
# message as another one, {Struct#eql?} is the way to go.
93
def ==(other)
94
self === other
95
end
96
97
# Checks to see whether the other object is also a {CheckCode} and if so,
98
# whether it shares the same code as this one.
99
def ===(other)
100
other.is_a?(self.class) && self.code == other.code
101
end
102
103
def initialize(code, reason, details: {})
104
msg = case code
105
when 'unknown'; 'Cannot reliably check exploitability.'
106
when 'safe'; 'The target is not exploitable.'
107
when 'detected'; 'The service is running, but could not be validated.'
108
when 'appears'; 'The target appears to be vulnerable.'
109
when 'vulnerable'; 'The target is vulnerable.'
110
when 'unsupported'; 'This module does not support check.'
111
else
112
''
113
end
114
super(code, "#{msg} #{reason}".strip, reason, details)
115
end
116
117
#
118
# Can't tell if the target is exploitable or not. This is recommended if the module fails to
119
# retrieve enough information from the target machine, such as due to a timeout.
120
#
121
Unknown = self.Unknown()
122
123
#
124
# The target is safe and is therefore not exploitable. This is recommended after the check
125
# fails to trigger the vulnerability, or even detect the service.
126
#
127
Safe = self.Safe()
128
129
#
130
# The target is running the service in question, but the check fails to determine whether
131
# the target is vulnerable or not.
132
#
133
Detected = self.Detected()
134
135
#
136
# The target appears to be vulnerable. This is recommended if the vulnerability is determined
137
# based on passive reconnaissance. For example: version, banner grabbing, or having the resource
138
# that's known to be vulnerable.
139
#
140
Appears = self.Appears()
141
142
#
143
# The target is vulnerable. Only used if the check is able to actually take advantage of the
144
# bug, and obtain hard evidence. For example: executing a command on the target machine, and
145
# retrieve the output.
146
#
147
Vulnerable = self.Vulnerable()
148
149
#
150
# The module does not support the check method.
151
#
152
Unsupported = self.Unsupported()
153
end
154
155
#
156
# The various basic types of exploits
157
#
158
module Type
159
160
#
161
# Indicates that the exploit is a remote exploit.
162
#
163
Remote = "remote"
164
165
#
166
# Indicates that the exploit is a local exploit.
167
#
168
Local = "local"
169
170
#
171
# Indicates that the exploit can work anywhere it damn pleases.
172
#
173
Omni = "omnipresent"
174
end
175
176
#
177
# The types of stances an exploit can take, such as passive or aggressive.
178
# Stances indicate whether or not the exploit triggers the exploit without
179
# waiting for one or more conditions to be met (aggressive) or whether it
180
# must wait for certain conditions to be satisfied before the exploit can
181
# be initiated (passive)
182
#
183
module Stance
184
185
#
186
# Used to indicate that an exploit takes an aggressive stance. This
187
# means that the exploit proactively triggers a vulnerability.
188
#
189
Aggressive = "aggressive"
190
191
#
192
# Used to indicate that an exploit takes a passive stance. This means
193
# that the exploit waits for interaction from a client or other entity
194
# before being able to trigger the vulnerability.
195
#
196
Passive = "passive"
197
end
198
199
200
#
201
# Load all of the exploit mixins
202
#
203
204
#
205
# Returns an array of all of the exploit mixins. Lame algorithm right now.
206
# We search the Msf::Exploit namespace for all modules that do not have any
207
# constants in them. In the future we can replace this with a better
208
# algorithm. It's just important that it returns an array of all of the
209
# mixin modules.
210
#
211
# @return [Array]
212
def self.mixins
213
mixins = []
214
wl = [ Msf::Exploit ]
215
visited = {}
216
217
until wl.length == 0
218
wl.delete_if { |mod|
219
mod.constants.each { |const|
220
child = mod.const_get(const)
221
222
next if child.to_s !~ /^Msf::Exploit/
223
224
next if visited[child]
225
226
next if child.kind_of?(::Module) == false
227
228
visited[child] = true
229
230
if child.constants.length > 0
231
wl << child
232
else
233
mixins << child
234
end
235
}
236
237
true
238
}
239
end
240
241
return mixins
242
end
243
244
attr_accessor :needs_cleanup
245
246
#
247
# Creates an instance of the exploit module. Mad skillz.
248
#
249
def initialize(info = {})
250
251
# Ghetto compat mirroring for payload compatibilities. This mirrors
252
#
253
# Payload => Compat => xyz
254
#
255
# to
256
#
257
# Compat => Payload => xyz
258
if (info['Payload'] and info['Payload']['Compat'])
259
info['Compat'] = Hash.new if (info['Compat'] == nil)
260
info['Compat']['Payload'] = Hash.new if (info['Compat']['Payload'] == nil)
261
info['Compat']['Payload'].update(info['Payload']['Compat'])
262
end
263
264
# Call the parent constructor after making any necessary modifications
265
# to the information hash.
266
super(info)
267
268
if info.key? 'DefaultTarget'
269
self.default_target = info['DefaultTarget']
270
else
271
self.default_target = 0
272
# Add an auto-target to the exploit if it doesn't have one
273
if info['Targets'] && info['Targets'].count > 1 && !has_auto_target?(info['Targets'])
274
# Finally, only add the target if there is a remote host option
275
if self.respond_to?(:rhost) && self.respond_to?(:auto_targeted_index)
276
auto = ["Automatic", {'AutoGenerated' => true}.merge(info['Targets'][self.default_target][1])]
277
info['Targets'].unshift(auto)
278
end
279
end
280
end
281
282
self.targets = Rex::Transformer.transform(info['Targets'], Array, [ Target ], 'Targets')
283
self.payload_info = info['Payload'] || {}
284
self.successful = false
285
self.session_count = 0
286
self.active_timeout = 120
287
self.fail_reason = Msf::Exploit::Failure::None
288
289
if (info['Payload'] and info['Payload']['ActiveTimeout'])
290
self.active_timeout = info['Payload']['ActiveTimeout'].to_i
291
end
292
293
# Initialize exploit datastore with target information
294
import_target_defaults
295
296
# All exploits can increase the delay when waiting for a session.
297
# However, this only applies to aggressive exploits.
298
if aggressive?
299
register_advanced_options(
300
[
301
OptInt.new('WfsDelay', [ false, "Additional delay in seconds to wait for a session", 2 ])
302
], Msf::Exploit)
303
end
304
305
register_advanced_options(
306
[
307
# Allow all exploits to leverage context keyed encoding
308
OptBool.new('EnableContextEncoding', [ false, "Use transient context when encoding payloads", false ]),
309
OptPath.new('ContextInformationFile', [ false, "The information file that contains context information", nil ]),
310
# Allow all exploits to disable their payload handlers
311
OptBool.new('DisablePayloadHandler', [ false, "Disable the handler code for the selected payload", false ])
312
], Msf::Exploit)
313
end
314
315
def has_auto_target?(targets=[])
316
target_names = targets.collect { |target| target.first}
317
target_names.each do |target|
318
return true if target =~ /Automatic/
319
end
320
return false
321
end
322
323
##
324
#
325
# Core exploit interface
326
#
327
# These are the methods that exploits will override to perform various
328
# tasks, such as checking a target to see if it's vulnerable, automatically
329
# selecting a target, or performing an exploit.
330
#
331
##
332
333
#
334
# Kicks off the actual exploit. Prior to this call, the framework will
335
# have validated the data store using the options associated with this
336
# exploit module. It will also pre-generate the desired payload, though
337
# exploits can re-generate the payload if necessary.
338
#
339
# This method is designed to be overridden by exploit modules.
340
#
341
def exploit
342
end
343
344
#
345
# Performs last-minute sanity checking of exploit parameters. This method
346
# is called during automated exploitation attempts and allows an
347
# exploit to filter bad targets, obtain more information, and choose
348
# better targets based on the available data. Returning anything that
349
# evaluates to "false" will cause this specific exploit attempt to
350
# be skipped. This method can and will change datastore values and
351
# may interact with the backend database.
352
#
353
def autofilter
354
true
355
end
356
357
#
358
# Provides a list of ports that can be used for matching this module
359
# against target systems.
360
#
361
def autofilter_ports
362
@autofilter_ports || []
363
end
364
365
#
366
# Provides a list of services that can be used for matching this module
367
# against target systems.
368
#
369
def autofilter_services
370
@autofilter_services || []
371
end
372
373
#
374
# Adds a port into the list of ports
375
#
376
def register_autofilter_ports(ports=[])
377
@autofilter_ports ||= []
378
@autofilter_ports << ports
379
@autofilter_ports.flatten!
380
@autofilter_ports.uniq!
381
end
382
383
def register_autofilter_services(services=[])
384
@autofilter_services ||= []
385
@autofilter_services << services
386
@autofilter_services.flatten!
387
@autofilter_services.uniq!
388
end
389
390
#
391
# Prepares the module for exploitation, initializes any state, and starts
392
# the payload handler.
393
#
394
def setup
395
alert_user
396
397
# Reset the session counts to zero.
398
reset_session_counts
399
400
return if not payload_instance
401
return if not handler_enabled?
402
403
# Configure the payload handler
404
payload_instance.exploit_config = {
405
'active_timeout' => self.active_timeout
406
}
407
408
# Set up the payload handlers
409
payload_instance.setup_handler
410
411
# Defer starting bind handlers until after exploit completion
412
return if handler_bind?
413
414
# Start the payload handler
415
payload_instance.start_handler
416
end
417
418
#
419
# Performs any cleanup that may be necessary, such as disconnecting
420
# connections and any other such fun things. If a payload is active then
421
# its handler cleanup routines are called as well.
422
#
423
def cleanup
424
if (payload_instance and handler_enabled?)
425
payload_instance.cleanup_handler
426
end
427
self.abort_sockets if self.respond_to?(:abort_sockets)
428
end
429
430
#
431
# Generates the encoded version of the supplied payload using the payload
432
# requirements specific to this exploit. The encoded instance is returned
433
# to the caller. This method is exposed in the manner that it is such
434
# that passive exploits and re-generate an encoded payload on the fly
435
# rather than having to use the pre-generated one.
436
#
437
# The return value is an EncodedPayload instance.
438
#
439
def generate_payload(pinst = nil)
440
# Set the encoded payload to the result of the encoding process
441
self.payload = generate_single_payload(pinst)
442
443
# Save the payload instance
444
self.payload_instance = (pinst) ? pinst : self.payload_instance
445
446
return self.payload
447
end
448
449
#
450
# Allows arbitrary shellcode to be encoded from within an exploit
451
#
452
def encode_shellcode_stub(code, badchars=payload_badchars)
453
platform = self.platform
454
if(self.payload_instance)
455
self.payload_instance.platform
456
end
457
compatible_encoders.each do |name, mod|
458
begin
459
enc = framework.encoders.create(name)
460
raw = enc.encode(code, badchars, nil, platform)
461
return raw if raw
462
rescue ::Exception
463
end
464
end
465
nil
466
end
467
468
#
469
# Allows the payload handler to spawn a new monitor
470
#
471
def add_handler(opts={})
472
return if not payload_instance
473
return if not handler_enabled?
474
payload_instance.add_handler(opts)
475
end
476
477
#
478
# This method generates a non-cached payload which is typically useful for
479
# passive exploits that will have more than one client.
480
#
481
def generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_target = nil)
482
explicit_target ||= target
483
484
if (explicit_target == nil)
485
raise MissingTargetError, "No target has been specified.",
486
caller
487
end
488
489
# If a payload instance was supplied, use it, otherwise
490
# use the active payload instance
491
real_payload = (pinst) ? pinst : self.payload_instance
492
493
if (real_payload == nil)
494
raise MissingPayloadError, "No payload has been selected.",
495
caller
496
end
497
498
# If this is a generic payload, then we should specify the platform
499
# and architecture so that it knows how to pass things on.
500
if real_payload.kind_of?(Msf::Payload::Generic)
501
# Convert the architecture specified into an array.
502
if arch and arch.kind_of?(String)
503
arch = [ arch ]
504
end
505
506
# Define the explicit platform and architecture information only if
507
# it's been specified.
508
if platform
509
real_payload.explicit_platform = Msf::Module::PlatformList.transform(platform)
510
end
511
512
if arch
513
real_payload.explicit_arch = arch
514
end
515
516
# Force it to reset so that it will find updated information.
517
real_payload.reset
518
end
519
520
# Duplicate the exploit payload requirements
521
reqs = self.payload_info.dup
522
523
# Pass save register requirements to the NOP generator
524
reqs['Space'] = payload_space(explicit_target)
525
reqs['SaveRegisters'] = nop_save_registers(explicit_target)
526
reqs['Prepend'] = payload_prepend(explicit_target)
527
reqs['PrependEncoder'] = payload_prepend_encoder(explicit_target)
528
reqs['BadChars'] = payload_badchars(explicit_target)
529
reqs['Append'] = payload_append(explicit_target)
530
reqs['AppendEncoder'] = payload_append_encoder(explicit_target)
531
reqs['DisableNops'] = payload_disable_nops(explicit_target)
532
reqs['MaxNops'] = payload_max_nops(explicit_target)
533
reqs['MinNops'] = payload_min_nops(explicit_target)
534
reqs['Encoder'] = datastore['ENCODER'] || payload_encoder(explicit_target)
535
reqs['Nop'] = datastore['NOP'] || payload_nop(explicit_target)
536
reqs['EncoderType'] = payload_encoder_type(explicit_target)
537
reqs['EncoderOptions'] = payload_encoder_options(explicit_target)
538
reqs['ExtendedOptions'] = payload_extended_options(explicit_target)
539
reqs['Exploit'] = self
540
541
# Pass along the encoder don't fall through flag
542
reqs['EncoderDontFallThrough'] = datastore['EncoderDontFallThrough']
543
544
# Incorporate any context encoding requirements that are needed
545
define_context_encoding_reqs(reqs)
546
547
# Call the encode begin routine.
548
encode_begin(real_payload, reqs)
549
550
# Generate the encoded payload.
551
encoded = EncodedPayload.create(real_payload, reqs)
552
553
# Call the encode end routine which is expected to return the actual
554
# encoded payload instance.
555
return encode_end(real_payload, reqs, encoded)
556
end
557
558
#
559
# Re-generates an encoded payload, typically called after something in the
560
# datastore has changed. An optional platform and architecture can be
561
# supplied as well.
562
#
563
def regenerate_payload(platform = nil, arch = nil, explicit_target = nil)
564
generate_single_payload(nil, platform, arch, explicit_target)
565
end
566
567
#
568
# Called prior to encoding a payload.
569
#
570
def encode_begin(real_payload, reqs)
571
end
572
573
#
574
# Called after an encoded payload has been generated. This gives exploits
575
# or mixins a chance to alter the encoded payload.
576
#
577
def encode_end(real_payload, reqs, encoded)
578
encoded
579
end
580
581
##
582
#
583
# Getters/Setters
584
#
585
# Querying and set interfaces for some of the exploit's attributes.
586
#
587
##
588
589
#
590
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
591
#
592
def self.type
593
Msf::MODULE_EXPLOIT
594
end
595
596
#
597
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
598
#
599
def type
600
Msf::MODULE_EXPLOIT
601
end
602
603
#
604
# If we don't know the exploit type, then I guess it's omnipresent!
605
#
606
def exploit_type
607
Type::Omni
608
end
609
610
#
611
# Generally, all exploits take an aggressive stance.
612
#
613
def stance
614
module_info['Stance'] || Stance::Aggressive
615
end
616
617
#
618
# Returns true if the exploit has an aggressive stance.
619
#
620
def aggressive?
621
stance.include?(Stance::Aggressive)
622
end
623
624
#
625
# Returns if the exploit has a passive stance. Aggressive exploits are always aggressive.
626
#
627
def passive?
628
stance.include?(Stance::Passive) && !stance.include?(Stance::Aggressive)
629
end
630
631
#
632
# Returns the active target for this exploit. If not target has been
633
# defined, nil is returned. If no target was defined but there is a
634
# default target, that one will be automatically used.
635
#
636
def target
637
if self.respond_to?(:auto_targeted_index)
638
if auto_target?
639
auto_idx = auto_targeted_index
640
if auto_idx.present?
641
datastore['TARGET'] = auto_idx
642
else
643
# If our inserted Automatic Target was selected but we failed to
644
# find a suitable target, we just grab the original first target.
645
datastore['TARGET'] = 1
646
end
647
end
648
end
649
650
target_idx = target_index
651
return (target_idx) ? targets[target_idx.to_i] : nil
652
end
653
654
#
655
# The target index that has been selected.
656
#
657
def target_index
658
target_idx =
659
begin
660
Integer(datastore['TARGET'])
661
rescue TypeError, ArgumentError
662
datastore['TARGET']
663
end
664
665
default_idx = default_target || 0
666
# Use the default target if one was not supplied.
667
if (target_idx == nil and default_idx and default_idx >= 0)
668
target_idx = default_idx
669
elsif target_idx.is_a?(String)
670
target_idx = targets.index { |target| target.name == target_idx }
671
end
672
673
return (target_idx) ? target_idx.to_i : nil
674
end
675
676
#
677
# Returns the target's platform, or the one assigned to the module itself.
678
#
679
def target_platform
680
(target and target.platform) ? target.platform : platform
681
end
682
683
#
684
# Returns the target's architecture, or the one assigned to the module
685
# itself.
686
#
687
def target_arch
688
(target and target.arch) ? target.arch : (arch == []) ? nil : arch
689
end
690
691
def normalize_platform_arch
692
c_platform = (target && target.platform) ? target.platform : platform
693
c_arch = (target && target.arch) ? target.arch : (arch == []) ? nil : arch
694
c_arch ||= [ ARCH_X86 ]
695
return c_platform, c_arch
696
end
697
698
#
699
# Returns whether the requested payload is compatible with the module.
700
#
701
# @param name [String] The payload name
702
# @return [Boolean] True if the payload is compatible, False if it is not.
703
#
704
def is_payload_compatible?(name)
705
p = framework.payloads[name]
706
return false unless p
707
708
# Skip over payloads that are too big
709
return false if payload_space && p.cached_size && p.cached_size > payload_space
710
711
begin
712
pi = p.new
713
rescue ::Exception, ::LoadError => e
714
wlog("Module #{name} failed to initialize payload when checking exploit compatibility: #{e}", 'core', LEV_0)
715
return false
716
end
717
718
# Are we compatible in terms of conventions and connections and
719
# what not?
720
return false if !compatible?(pi)
721
722
# If the payload is privileged but the exploit does not give
723
# privileged access, then fail it.
724
return false if !self.privileged && pi.privileged
725
726
return true
727
end
728
729
# Returns a list of compatible payloads based on platform, architecture,
730
# and size requirements.
731
def compatible_payloads(excluded_platforms: [], excluded_archs: [])
732
payloads = []
733
734
c_platform, c_arch = normalize_platform_arch
735
736
# The "All" platform name represents generic payloads
737
results = Msf::Modules::Metadata::Cache.instance.find(
738
'type' => [['payload'], []],
739
'platform' => [[*c_platform.names, 'All'], excluded_platforms],
740
'arch' => [c_arch, excluded_archs]
741
)
742
743
results.each do |res|
744
if is_payload_compatible?(res.ref_name)
745
payloads << [res.ref_name, framework.payloads[res.ref_name]]
746
end
747
end
748
749
payloads
750
end
751
752
#
753
# Returns a list of compatible encoders based on architecture
754
#
755
def compatible_encoders
756
encoders = []
757
758
c_platform, c_arch = normalize_platform_arch
759
760
framework.encoders.each_module_ranked(
761
'Arch' => c_arch, 'Platform' => c_platform) { |name, mod|
762
encoders << [ name, mod ]
763
}
764
765
return encoders;
766
end
767
768
#
769
# This method returns the encoded instruction(s) required to adjust the
770
# stack pointer prior to executing any code. The number of bytes to adjust
771
# is indicated to the routine through the payload 'StackAdjustment'
772
# attribute or through a target's payload 'StackAdjustment' attribute.
773
#
774
def stack_adjustment
775
if target && target.payload_stack_adjustment
776
adj = target.payload_stack_adjustment
777
else
778
adj = payload_info['StackAdjustment']
779
end
780
781
return '' unless adj
782
783
# Get the architecture for the current target or use the one specific to
784
# this exploit
785
arch = (target && target.arch) ? target.arch : self.arch
786
787
# Default to x86 if we can't find a list of architectures
788
if arch && !arch.empty?
789
arch = [arch].flatten.join(', ')
790
else
791
arch = 'x86'
792
end
793
794
Rex::Arch::adjust_stack_pointer(arch, adj) || ''
795
end
796
797
#
798
# Return any text that should be prepended to the payload. The payload
799
# module is passed so that the exploit can take a guess at architecture
800
# and platform if it's a multi exploit. This automatically takes into
801
# account any require stack adjustments.
802
#
803
def payload_prepend(explicit_target = nil)
804
explicit_target ||= target
805
806
if (explicit_target and explicit_target.payload_prepend)
807
p = explicit_target.payload_prepend
808
else
809
p = payload_info['Prepend'] || ''
810
end
811
812
stack_adjustment + p
813
end
814
815
#
816
# Return any text that should be appended to the payload. The payload
817
# module is passed so that the exploit can take a guess at architecture
818
# and platform if it's a multi exploit.
819
#
820
def payload_append(explicit_target = nil)
821
explicit_target ||= target
822
823
if (explicit_target and explicit_target.payload_append)
824
explicit_target.payload_append
825
else
826
payload_info['Append'] || ''
827
end
828
end
829
830
#
831
# Return any text that should be prepended to the encoder of the payload.
832
# The payload module is passed so that the exploit can take a guess
833
# at architecture and platform if it's a multi exploit.
834
#
835
def payload_prepend_encoder(explicit_target = nil)
836
explicit_target ||= target
837
838
if (explicit_target and explicit_target.payload_prepend_encoder)
839
p = explicit_target.payload_prepend_encoder
840
else
841
p = payload_info['PrependEncoder'] || ''
842
end
843
844
p
845
end
846
847
#
848
# Return any text that should be appended to the encoder of the payload.
849
# The payload module is passed so that the exploit can take a guess
850
# at architecture and platform if it's a multi exploit.
851
#
852
def payload_append_encoder(explicit_target = nil)
853
explicit_target ||= target
854
855
if (explicit_target and explicit_target.payload_append_encoder)
856
p = explicit_target.payload_append_encoder
857
else
858
p = payload_info['AppendEncoder'] || ''
859
end
860
861
p
862
end
863
864
#
865
# Whether NOP generation should be enabled or disabled
866
#
867
def payload_disable_nops(explicit_target = nil)
868
explicit_target ||= target
869
870
if (explicit_target and explicit_target.payload_disable_nops)
871
explicit_target.payload_disable_nops
872
else
873
payload_info['DisableNops']
874
end
875
end
876
877
#
878
# Maximum number of nops to use as a hint to the framework.
879
# Nil signifies that the framework should decide.
880
#
881
def payload_max_nops(explicit_target = nil)
882
explicit_target ||= target
883
884
if (explicit_target and explicit_target.payload_max_nops)
885
explicit_target.payload_max_nops
886
else
887
payload_info['MaxNops'] || nil
888
end
889
end
890
891
#
892
# Minimum number of nops to use as a hint to the framework.
893
# Nil signifies that the framework should decide.
894
#
895
def payload_min_nops(explicit_target = nil)
896
explicit_target ||= target
897
898
if (explicit_target and explicit_target.payload_min_nops)
899
explicit_target.payload_min_nops
900
else
901
payload_info['MinNops'] || nil
902
end
903
end
904
905
#
906
# Returns the maximum amount of room the exploit has for a payload.
907
#
908
def payload_space(explicit_target = nil)
909
explicit_target ||= target
910
911
if (explicit_target and explicit_target.payload_space)
912
explicit_target.payload_space
913
elsif (payload_info['Space'])
914
payload_info['Space'].to_i
915
else
916
nil
917
end
918
end
919
920
#
921
# Returns the bad characters that cannot be in any payload used by this
922
# exploit.
923
#
924
def payload_badchars(explicit_target = nil)
925
explicit_target ||= target
926
927
if (explicit_target and explicit_target.payload_badchars)
928
explicit_target.payload_badchars
929
else
930
payload_info['BadChars']
931
end
932
end
933
934
#
935
# Returns the payload encoder that is associated with either the
936
# current target or the exploit in general.
937
#
938
def payload_encoder(explicit_target = nil)
939
explicit_target ||= target
940
941
if (explicit_target and explicit_target.payload_encoder)
942
explicit_target.payload_encoder
943
else
944
payload_info['Encoder']
945
end
946
end
947
948
#
949
# Returns the payload NOP generator that is associated with either the
950
# current target or the exploit in general.
951
#
952
def payload_nop(explicit_target = nil)
953
explicit_target ||= target
954
955
if (explicit_target and explicit_target.payload_nop)
956
explicit_target.payload_nop
957
else
958
payload_info['Nop']
959
end
960
end
961
962
#
963
# Returns the payload encoder type that is associated with either the
964
# current target or the exploit in general.
965
#
966
def payload_encoder_type(explicit_target = nil)
967
explicit_target ||= target
968
969
if (explicit_target and explicit_target.payload_encoder_type)
970
explicit_target.payload_encoder_type
971
else
972
payload_info['EncoderType']
973
end
974
end
975
976
#
977
# Returns the payload encoder option hash that is used to initialize the
978
# datastore of the encoder that is selected when generating an encoded
979
# payload.
980
#
981
def payload_encoder_options(explicit_target = nil)
982
explicit_target ||= target
983
984
if (explicit_target and explicit_target.payload_encoder_options)
985
explicit_target.payload_encoder_options
986
else
987
payload_info['EncoderOptions']
988
end
989
end
990
991
#
992
# Returns the payload extended options hash which is used to provide
993
# a location to store extended information that may be useful to
994
# a particular type of payload or mixin.
995
#
996
def payload_extended_options(explicit_target = nil)
997
explicit_target ||= target
998
999
if explicit_target and explicit_target.payload_extended_options
1000
explicit_target.payload_extended_options
1001
else
1002
payload_info['ExtendedOptions']
1003
end
1004
end
1005
1006
##
1007
#
1008
# NOP requirements
1009
#
1010
# Hints to the nop generator on how it should perform if it's used.
1011
#
1012
##
1013
1014
#
1015
# Returns the list of registers that the NOP generator should save,
1016
# if any. It will use the current target's save registers in precedence
1017
# over those defined globally for the exploit module.
1018
#
1019
# If there are no save registers, nil is returned.
1020
#
1021
def nop_save_registers(explicit_target = nil)
1022
explicit_target ||= target
1023
1024
if (explicit_target and explicit_target.save_registers)
1025
return explicit_target.save_registers
1026
else
1027
return module_info['SaveRegisters']
1028
end
1029
end
1030
1031
#
1032
# Returns the first compatible NOP generator for this exploit's payload
1033
# instance.
1034
#
1035
def nop_generator
1036
return nil if (!payload_instance)
1037
1038
payload_instance.compatible_nops.each { |nopname, nopmod|
1039
return nopmod.new
1040
}
1041
end
1042
1043
1044
#
1045
# Generates a NOP sled using the #make_nops method.
1046
# The difference between this and #make_nops is this method is much faster, good for exploit
1047
# developers that actually want huge chunks of NOPs. The downside of using this is the NOP sled
1048
# is less randomized.
1049
#
1050
# @param count [String] Number of NOPs to return.
1051
# @return [String] NOPs
1052
#
1053
def make_fast_nops(count)
1054
max_nop_chunk_size = 100
1055
1056
if count < max_nop_chunk_size
1057
return make_nops(count)
1058
end
1059
1060
nops = make_nops(max_nop_chunk_size)
1061
nops += nops while nops.length < count
1062
1063
nops[0, count]
1064
end
1065
1066
1067
#
1068
# Generates a nop sled of a supplied length and returns it to the caller.
1069
#
1070
def make_nops(count)
1071
# If we're debugging, then make_nops will return a safe sled. We
1072
# currently assume x86.
1073
if debugging?
1074
return "\x90" * count
1075
end
1076
1077
nop_sled = nil
1078
1079
# If there is no payload instance then we can't succeed.
1080
return nil if (!payload_instance)
1081
1082
payload_instance.compatible_nops.each { |nopname, nopmod|
1083
# Create an instance of the nop module
1084
nop = nopmod.new
1085
1086
# The list of save registers
1087
save_regs = nop_save_registers || []
1088
1089
if (save_regs.empty? == true)
1090
save_regs = nil
1091
end
1092
1093
begin
1094
nop.copy_ui(self)
1095
1096
nop_sled = nop.generate_sled(count,
1097
'BadChars' => payload_badchars || '',
1098
'SaveRegisters' => save_regs)
1099
1100
if nop_sled && nop_sled.length == count
1101
break
1102
else
1103
wlog("#{self.refname}: Nop generator #{nop.refname} failed to generate sled for exploit", 'core', LEV_0)
1104
end
1105
rescue
1106
wlog("#{self.refname}: Nop generator #{nop.refname} failed to generate sled for exploit: #{$!}",
1107
'core', LEV_0)
1108
end
1109
}
1110
1111
nop_sled
1112
end
1113
1114
##
1115
#
1116
# Utility methods for generating random text that implicitly uses the
1117
# exploit's bad character set.
1118
#
1119
##
1120
1121
def rand_text_debug(length, char = 'A')
1122
char * (length.kind_of?(Range) ? length.first : length)
1123
end
1124
1125
#
1126
# Generate random text characters avoiding the exploit's bad
1127
# characters.
1128
#
1129
def rand_text(length, bad=payload_badchars)
1130
if debugging?
1131
rand_text_debug(length)
1132
else
1133
Rex::Text.rand_text(length, bad)
1134
end
1135
end
1136
1137
#
1138
# Generate random english-like avoiding the exploit's bad
1139
# characters.
1140
#
1141
def rand_text_english(length, bad=payload_badchars)
1142
if debugging?
1143
rand_text_debug(length)
1144
else
1145
Rex::Text.rand_text_english(length, bad)
1146
end
1147
end
1148
1149
#
1150
# Generate random high ascii characters avoiding the exploit's bad
1151
# characters.
1152
#
1153
def rand_text_highascii(length, bad=payload_badchars)
1154
if debugging?
1155
rand_text_debug(length)
1156
else
1157
Rex::Text.rand_text_highascii(length, bad)
1158
end
1159
end
1160
1161
#
1162
# Generate random alpha characters avoiding the exploit's bad
1163
# characters.
1164
#
1165
def rand_text_alpha(length, bad=payload_badchars)
1166
if debugging?
1167
rand_text_debug(length)
1168
else
1169
Rex::Text.rand_text_alpha(length, bad)
1170
end
1171
end
1172
1173
#
1174
# Generate random alpha upper characters avoiding the exploit's bad
1175
# characters.
1176
#
1177
def rand_text_alpha_upper(length, bad=payload_badchars)
1178
if debugging?
1179
rand_text_debug(length)
1180
else
1181
Rex::Text.rand_text_alpha_upper(length, bad)
1182
end
1183
end
1184
1185
#
1186
# Generate random alpha lower characters avoiding the exploit's bad
1187
# characters.
1188
#
1189
def rand_text_alpha_lower(length, bad=payload_badchars)
1190
if debugging?
1191
rand_text_debug(length, 'a')
1192
else
1193
Rex::Text.rand_text_alpha_lower(length, bad)
1194
end
1195
end
1196
1197
#
1198
# Generate random alphanumeric characters avoiding the exploit's bad
1199
# characters.
1200
#
1201
def rand_text_alphanumeric(length, bad=payload_badchars)
1202
if debugging?
1203
rand_text_debug(length)
1204
else
1205
Rex::Text.rand_text_alphanumeric(length, bad)
1206
end
1207
end
1208
1209
#
1210
# Generate random numeric characters avoiding the exploit's bad
1211
# characters.
1212
#
1213
def rand_text_numeric(length, bad=payload_badchars)
1214
if debugging?
1215
rand_text_debug(length, '0')
1216
else
1217
Rex::Text.rand_text_numeric(length, bad)
1218
end
1219
end
1220
1221
#
1222
# Generate random hexadecimal characters avoiding the exploit's bad
1223
# characters.
1224
#
1225
def rand_text_hex(length, bad=payload_badchars)
1226
if debugging?
1227
rand_text_debug(length, '0')
1228
else
1229
Rex::Text.rand_text_hex(length, bad)
1230
end
1231
end
1232
1233
#
1234
# Generate a random character avoiding the exploit's bad
1235
# characters.
1236
#
1237
def rand_char(bad=payload_badchars)
1238
if debugging?
1239
"A"
1240
else
1241
Rex::Text.rand_char(bad)
1242
end
1243
end
1244
1245
#
1246
# Generate a non-repeating static random string
1247
#
1248
def pattern_create(length, sets = nil)
1249
Rex::Text.pattern_create(length, sets)
1250
end
1251
1252
#
1253
# The minimum "wait for session" delay is 3 seconds for all exploits, the
1254
# WfsDelay configuration option is added on top of this. The delay allows time
1255
# for the session handler to perform any session verification.
1256
#
1257
def wfs_delay
1258
(datastore['WfsDelay'] || 0).to_i + 3
1259
end
1260
1261
#
1262
# Allow the user to disable the payload handler
1263
#
1264
def handler_enabled?
1265
!datastore['DisablePayloadHandler']
1266
end
1267
1268
#
1269
# If the payload uses a bind handler
1270
#
1271
def handler_bind?
1272
payload_instance && payload_instance.connection_type == 'bind'
1273
end
1274
1275
##
1276
#
1277
# Handler interaction
1278
#
1279
##
1280
1281
#
1282
# Passes the connection to the associated payload handler to see if the
1283
# exploit succeeded and a connection has been established. The return
1284
# value can be one of the Handler::constants.
1285
#
1286
def handler(*args)
1287
if payload_instance && handler_enabled?
1288
payload_instance.handler(*args)
1289
end
1290
end
1291
1292
def interrupt_handler
1293
if payload_instance && handler_enabled? && payload_instance.respond_to?(:interrupt_wait_for_session)
1294
payload_instance.interrupt_wait_for_session()
1295
end
1296
end
1297
1298
##
1299
#
1300
# Session tracking
1301
#
1302
##
1303
1304
#
1305
# This is called by the payload when a new session is created
1306
#
1307
def on_new_session(session)
1308
self.session_count += 1
1309
self.successful = true
1310
end
1311
1312
#
1313
# A boolean for whether a session has been created yet
1314
#
1315
def session_created?
1316
# Start bind handlers before checking session creation
1317
payload_instance.start_handler if handler_bind?
1318
1319
(self.session_count > 0) ? true : false
1320
end
1321
1322
#
1323
# Reset the session counter to zero (which occurs during set up of the
1324
# exploit prior to calling exploit).
1325
#
1326
def reset_session_counts
1327
self.session_count = 0
1328
end
1329
1330
1331
##
1332
# Failure tracking
1333
##
1334
1335
# Raises a Msf::Exploit::Failed exception. It overrides the fail_with method
1336
# in lib/msf/core/module.rb
1337
#
1338
# @param reason [String] A constant from Msf::Module::Failure.
1339
# If the reason does not come from there, then it will default to
1340
# Msf::Module::Failure::Unknown.
1341
# @param msg [String] (Optional) A message about the failure.
1342
# @raise [Msf::Exploit::Failed] A custom Msf::Exploit::Failed exception.
1343
# @return [void]
1344
# @see Msf::Module::Failure
1345
# @see Msf::Module#fail_with
1346
# @example
1347
# fail_with(Msf::Module::Failure::NoAccess, 'Unable to login to upload payload')
1348
def fail_with(reason,msg=nil)
1349
# The reason being registered here will be used later on, so it's important we don't actually
1350
# provide a made-up one.
1351
allowed_values = Msf::Module::Failure.constants.collect {|e| Msf::Module::Failure.const_get(e)}
1352
if allowed_values.include?(reason)
1353
self.fail_reason = reason
1354
else
1355
self.fail_reason = Msf::Module::Failure::Unknown
1356
end
1357
1358
self.fail_detail = msg
1359
raise Msf::Exploit::Failed, (msg || "No failure message given")
1360
end
1361
1362
def setup_fail_detail_from_exception e
1363
# Build a user-friendly error message
1364
msg = "#{e}"
1365
unless e.class == Msf::Exploit::Failed
1366
msg = "#{e.class} #{e}"
1367
end
1368
1369
self.error = e
1370
1371
# Record the detailed reason
1372
self.fail_detail ||= e.to_s
1373
msg
1374
end
1375
1376
#
1377
# Handle the exception
1378
#
1379
def handle_exception e
1380
msg = setup_fail_detail_from_exception e
1381
1382
case e
1383
when Msf::Exploit::Complete
1384
# Nothing to show in this case
1385
return
1386
1387
when Msf::OptionValidateError
1388
self.fail_reason = Msf::Exploit::Failure::BadConfig
1389
::Msf::Ui::Formatter::OptionValidateError.print_error(self, e)
1390
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1391
1392
when Msf::Exploit::Failed
1393
self.print_error("Exploit aborted due to failure: #{self.fail_reason}: #{msg}")
1394
1395
# The caller should have already set self.fail_reason
1396
if self.fail_reason == Msf::Exploit::Failure::None
1397
self.fail_reason = Msf::Exploit::Failure::Unknown
1398
end
1399
1400
when Rex::ConnectionError
1401
self.fail_reason = Msf::Exploit::Failure::Unreachable
1402
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
1403
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1404
1405
when Rex::BindFailed
1406
self.fail_reason = Msf::Exploit::Failure::BadConfig
1407
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
1408
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1409
1410
when Timeout::Error
1411
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
1412
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
1413
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1414
1415
when ::Interrupt
1416
self.fail_reason = Msf::Exploit::Failure::UserInterrupt
1417
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
1418
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1419
else
1420
1421
# Compare as a string since not all error classes may be loaded
1422
case msg
1423
when /access.denied|Login Failed/i # Covers SMB as well as some generic errors
1424
self.fail_reason = Msf::Exploit::Failure::NoAccess
1425
when /connection reset/i
1426
self.fail_reason = Msf::Exploit::Failure::Disconnected
1427
when /connection timed out|SSL_connect|unreachable|connection was refused/i
1428
self.fail_reason = Msf::Exploit::Failure::Unreachable
1429
when /unable.*target/i
1430
self.fail_reason = Msf::Exploit::Failure::NoTarget
1431
when /execution expired/i
1432
self.fail_reason = Msf::Exploit::Failure::TimeoutExpired
1433
when /(doesn.t|not).*vulnerable|may.*patched/i
1434
self.fail_reason = Msf::Exploit::Failure::NotVulnerable
1435
end
1436
1437
# The caller should have already set self.fail_reason
1438
if self.fail_reason == Msf::Exploit::Failure::None
1439
self.fail_reason = Msf::Exploit::Failure::Unknown
1440
end
1441
1442
if self.fail_reason == Msf::Exploit::Failure::Unknown
1443
self.print_error("Exploit failed: #{msg}")
1444
else
1445
self.print_error("Exploit failed [#{self.fail_reason}]: #{msg}")
1446
end
1447
1448
elog("Exploit failed (#{self.refname}): #{msg}", error: e)
1449
end
1450
1451
# Record the error to various places
1452
self.framework.events.on_module_error(self, msg)
1453
1454
# Report the failure (and attempt) in the database
1455
self.report_failure
1456
1457
# Interrupt any session waiters in the handler
1458
self.interrupt_handler
1459
1460
return self.fail_reason
1461
end
1462
1463
def report_failure
1464
return unless framework.db and framework.db.active
1465
1466
info = {
1467
:timestamp => Time.now.utc,
1468
:workspace => framework.db.find_workspace(self.workspace),
1469
:module => self.fullname,
1470
:fail_reason => self.fail_reason,
1471
:fail_detail => self.fail_detail,
1472
:target_name => self.target.name,
1473
:username => self.owner,
1474
:refs => self.references,
1475
:run_id => self.datastore['RUN_ID']
1476
}
1477
1478
if self.datastore['RHOST'] and self.options['RHOST']
1479
info[:host] = self.datastore['RHOST']
1480
end
1481
1482
if self.datastore['RPORT'] and self.options['RPORT']
1483
info[:port] = self.datastore['RPORT']
1484
if self.class.ancestors.include?(Msf::Exploit::Remote::Tcp)
1485
info[:proto] = 'tcp'
1486
end
1487
end
1488
1489
framework.db.report_exploit_failure(info)
1490
end
1491
1492
##
1493
#
1494
# Aliases
1495
#
1496
# These allow access to methods inside this class, even if exploits use mixins that
1497
# override them.
1498
#
1499
##
1500
1501
# Give exploits the ability to use the original +regenerate_payload+ so
1502
# they can avoid needing additional arguments added by overridden versions.
1503
# Used specifically by things that include +TcpServer+ (or a descendant)
1504
# but which are active exploits.
1505
alias :exploit_regenerate_payload :regenerate_payload
1506
1507
1508
##
1509
#
1510
# Attributes
1511
#
1512
##
1513
1514
#
1515
# The reason why the exploit was not successful (one of Msf::Module::Failure)
1516
#
1517
attr_accessor :fail_reason
1518
1519
#
1520
# Detailed exception string indicating why the exploit was not successful
1521
#
1522
attr_accessor :fail_detail
1523
1524
#
1525
# The list of targets.
1526
#
1527
attr_reader :targets
1528
#
1529
# The default target.
1530
#
1531
attr_reader :default_target
1532
#
1533
# The payload requirement hash.
1534
#
1535
attr_reader :payload_info
1536
#
1537
# The active payload instance.
1538
#
1539
attr_accessor :payload_instance
1540
#
1541
# The encoded payload instance. An instance of an
1542
# EncodedPayload object.
1543
#
1544
attr_accessor :payload
1545
1546
#
1547
# The number of active sessions created by this instance
1548
#
1549
attr_reader :session_count
1550
1551
#
1552
# The boolean indicating whether the exploit succeeded
1553
#
1554
attr_reader :successful
1555
1556
1557
protected
1558
1559
#
1560
# Writable copy of the list of targets.
1561
#
1562
attr_writer :targets
1563
#
1564
# Writable copy of the default target.
1565
#
1566
attr_writer :default_target
1567
#
1568
# Writable copy of the payload requirement hash.
1569
#
1570
attr_writer :payload_info
1571
#
1572
# Number of sessions created by this exploit instance.
1573
#
1574
attr_writer :session_count
1575
#
1576
# Maximum number of seconds for active handlers
1577
#
1578
attr_accessor :active_timeout
1579
1580
#
1581
# Boolean indicating whether the exploit succeeded
1582
#
1583
attr_writer :successful
1584
1585
1586
#
1587
# Overrides the base class method and serves to initialize default
1588
# compatibilities for exploits
1589
#
1590
def init_compat
1591
super
1592
1593
#
1594
# Merge in payload compatible defaults
1595
#
1596
p = module_info['Compat']['Payload']
1597
1598
CompatDefaults::Payload.each_pair { |k,v|
1599
(p[k]) ? p[k] << " #{v}" : p[k] = v
1600
}
1601
1602
#
1603
# Set the default save registers if none have been explicitly
1604
# specified.
1605
#
1606
if (module_info['SaveRegisters'] == nil)
1607
module_info['SaveRegisters'] = [ 'esp', 'ebp' ]
1608
end
1609
end
1610
1611
#
1612
# Gets the memory map file and other context information that is
1613
# required when wanting to support context keyed encoding
1614
#
1615
def define_context_encoding_reqs(reqs)
1616
return unless datastore['EnableContextEncoding']
1617
1618
# At present, we don't support any automatic methods of obtaining
1619
# context information. In the future, we might support obtaining
1620
# temporal information remotely.
1621
1622
# Pass along the information specified in our exploit datastore as
1623
# encoder options
1624
reqs['EncoderOptions'] = {} if reqs['EncoderOptions'].nil?
1625
reqs['EncoderOptions']['EnableContextEncoding'] = datastore['EnableContextEncoding']
1626
reqs['EncoderOptions']['ContextInformationFile'] = datastore['ContextInformationFile']
1627
end
1628
1629
end
1630
1631
end
1632
1633