Skip to content

Commit 29eb3eb

Browse files
author
HD Moore
committed
Fix up the StageEncodingFallback logic and error handling
1 parent 4d3e353 commit 29eb3eb

File tree

1 file changed

+46
-25
lines changed

1 file changed

+46
-25
lines changed

lib/msf/core/payload/stager.rb

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def initialize(info={})
1717
Msf::OptBool.new("EnableStageEncoding", [ false, "Encode the second stage payload", false ]),
1818
Msf::OptString.new("StageEncoder", [ false, "Encoder to use if EnableStageEncoding is set", nil ]),
1919
Msf::OptString.new("StageEncoderSaveRegisters", [ false, "Additional registers to preserve in the staged payload if EnableStageEncoding is set", "" ]),
20-
Msf::OptBool.new("StageEncodingNoFallBack", [ false, "If encoders choosen in StageEncoder are not compatible to stage encoding fallback to no encoding otherwise fallback to automatic selected one", true ])
20+
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
2121
], Msf::Payload::Stager)
2222

2323
end
@@ -94,14 +94,12 @@ def stage_over_connection?
9494
true
9595
end
9696

97-
9897
#
9998
# Whether to use an Encoder on the second stage
10099
#
101100
# @return [Boolean]
102101
def encode_stage?
103-
# Convert to string in case it hasn't been normalized
104-
!!(datastore['EnableStageEncoding'].to_s == "true" || datastore["StageEncoder"].to_s.length > 0)
102+
!!(datastore['EnableStageEncoding'])
105103
end
106104

107105
#
@@ -136,7 +134,16 @@ def handle_connection(conn, opts={})
136134
p = generate_stage
137135

138136
# Encode the stage if stage encoding is enabled
139-
p = encode_stage(p)
137+
begin
138+
p = encode_stage(p)
139+
rescue ::RuntimeError
140+
warning_msg = "Failed to stage"
141+
warning_msg << " (#{conn.peerhost})" if conn.respond_to? :peerhost
142+
warning_msg << ": #{$!}"
143+
print_warning warning_msg
144+
conn.close if conn.respond_to? :close
145+
return
146+
end
140147

141148
# Give derived classes an opportunity to an intermediate state before
142149
# the stage is sent. This gives derived classes an opportunity to
@@ -198,7 +205,6 @@ def handle_intermediate_stage(conn, payload)
198205
false
199206
end
200207

201-
202208
#
203209
# Takes an educated guess at the list of registers an encoded stage
204210
# would need to preserve based on the Convention
@@ -213,11 +219,22 @@ def encode_stage_preserved_registers
213219
# @return [String] Encoded version of +stg+
214220
def encode_stage(stg)
215221
return stg unless encode_stage?
222+
stage_enc_mod = []
216223

217-
if datastore["StageEncoder"].nil? or datastore["StageEncoder"].empty?
218-
stage_enc_mod = nil
219-
else
220-
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip)
224+
# Handle StageEncoder if specified by the user
225+
if datastore['StageEncoder'].to_s.length > 0
226+
# Allow multiple encoders separated by commas
227+
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
228+
end
229+
230+
# Add automatic encoding as a fallback if needed
231+
if datastore['StageEncodingFallback']
232+
stage_enc_mod << nil
233+
end
234+
235+
# If fallback has been disabled and no encoder was parsed, exit early and rop the session
236+
if stage_enc_mod.length == 0
237+
raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
221238
end
222239

223240
# Allow the user to specify additional registers to preserve
@@ -226,7 +243,10 @@ def encode_stage(stg)
226243
encode_stage_preserved_registers
227244
).strip
228245

229-
(stage_enc_mod || [nil]).each do |encoder_refname_from_user|
246+
estg = nil
247+
248+
stage_enc_mod.each do |encoder_refname_from_user|
249+
230250
# Generate an encoded version of the stage. We tell the encoding system
231251
# to save certain registers to ensure that it does not get clobbered.
232252
encp = Msf::EncodedPayload.create(
@@ -236,23 +256,24 @@ def encode_stage(stg)
236256
'EncoderOptions' => { 'SaveRegisters' => saved_registers },
237257
'ForceSaveRegisters' => true,
238258
'ForceEncode' => true)
239-
if (encp.encoder == nil)
240-
print_warning("Encoder #{encoder_refname_from_user} did not succeed")
241-
if !datastore['StageEncodingNoFallBack']
242-
print_warning("Fallback to automatic StageEncoder selection")
243-
encoder_refname_from_user = nil
244-
redo
245-
else
246-
print_warning("Fallback to no encoder")
247-
end
248-
else
259+
260+
if encp.encoder
249261
print_status("Encoded stage with #{encp.encoder.refname}")
262+
estg = encp.encoded
263+
break
250264
end
251-
# If the encoding succeeded, use the encoded buffer. Otherwise, fall
252-
# back to using the non-encoded stage
253-
stg = encp.encoded || stg
254265
end
255-
stg
266+
267+
if datastore['StageEncodingFallback'] && estg.nil?
268+
print_warning("StageEncoder failed, falling back to no encoding")
269+
estg = stg
270+
end
271+
272+
unless estg
273+
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
274+
end
275+
276+
estg
256277
end
257278

258279
# Aliases

0 commit comments

Comments
 (0)