Skip to content

Commit 0cad99a

Browse files
author
Brent Cook
committed
Land rapid7#3950, @agix's multiple encoder chaining
2 parents b42e029 + e5443e7 commit 0cad99a

File tree

2 files changed

+38
-34
lines changed

2 files changed

+38
-34
lines changed

lib/msf/core/encoded_payload.rb

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ def generate(raw = nil)
4949
self.nop_sled = nil
5050
self.encoder = nil
5151
self.nop = nil
52-
self.iterations = reqs['Iterations'].to_i
53-
self.iterations = 1 if self.iterations < 1
5452

5553
# Increase thread priority as necessary. This is done
5654
# to ensure that the encoding and sled generation get
@@ -71,8 +69,27 @@ def generate(raw = nil)
7169
# Generate the raw version of the payload first
7270
generate_raw() if self.raw.nil?
7371

74-
# Encode the payload
75-
encode()
72+
# If encoder is set, it could be an encoders list
73+
# The form is "<encoder>:<iteration>, <encoder2>:<iteration>"...
74+
if reqs['Encoder']
75+
encoder_str = reqs['Encoder']
76+
encoder_str.scan(/([^:, ]+):?([^,]+)?/).map do |encoder_opt|
77+
reqs['Encoder'] = encoder_opt[0]
78+
79+
self.iterations = (encoder_opt[1] || reqs['Iterations']).to_i
80+
self.iterations = 1 if self.iterations < 1
81+
82+
# Encode the payload with every encoders in the list
83+
encode()
84+
# Encoded payload is now the raw payload to be encoded by the next encoder
85+
self.raw = self.encoded
86+
end
87+
else
88+
self.iterations = reqs['Iterations'].to_i
89+
self.iterations = 1 if self.iterations < 1
90+
# No specified encoder, let BadChars or ForceEncode do their job
91+
encode()
92+
end
7693

7794
# Build the NOP sled
7895
generate_sled()

lib/msf/core/payload/stager.rb

Lines changed: 17 additions & 30 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("StageEncodingFallback", [ false, "Fallback to default encoders or no encoding if the selected StageEncoder is not compatible", true ])
20+
Msf::OptBool.new("StageEncodingFallback", [ false, "Fallback to no encoding if the selected StageEncoder is not compatible", true ])
2121
], Msf::Payload::Stager)
2222

2323
end
@@ -221,22 +221,11 @@ def encode_stage_preserved_registers
221221
# @return [String] Encoded version of +stg+
222222
def encode_stage(stg)
223223
return stg unless encode_stage?
224-
stage_enc_mod = []
224+
stage_enc_mod = nil
225225

226226
# Handle StageEncoder if specified by the user
227227
if datastore['StageEncoder'].to_s.length > 0
228-
# Allow multiple encoders separated by commas
229-
stage_enc_mod = datastore["StageEncoder"].split(',').map(&:strip).select{|x| x.to_s.length > 0}.uniq
230-
end
231-
232-
# Add automatic encoding as a fallback if needed
233-
if datastore['StageEncodingFallback']
234-
stage_enc_mod << nil
235-
end
236-
237-
# If fallback has been disabled and no encoder was parsed, exit early and rop the session
238-
if stage_enc_mod.length == 0
239-
raise RuntimeError, "StageEncoder is invalid and StageEncodingFallback is disabled"
228+
stage_enc_mod = datastore["StageEncoder"]
240229
end
241230

242231
# Allow the user to specify additional registers to preserve
@@ -247,34 +236,32 @@ def encode_stage(stg)
247236
saved_registers.strip!
248237

249238
estg = nil
250-
251-
stage_enc_mod.each do |encoder_refname_from_user|
252-
239+
begin
253240
# Generate an encoded version of the stage. We tell the encoding system
254241
# to save certain registers to ensure that it does not get clobbered.
255242
encp = Msf::EncodedPayload.create(
256243
self,
257244
'Raw' => stg,
258-
'Encoder' => encoder_refname_from_user,
245+
'Encoder' => stage_enc_mod,
259246
'EncoderOptions' => { 'SaveRegisters' => saved_registers },
260247
'ForceSaveRegisters' => true,
261248
'ForceEncode' => true)
262249

263250
if encp.encoder
264-
print_status("Encoded stage with #{encp.encoder.refname}")
251+
if stage_enc_mod
252+
print_status("Encoded stage with #{stage_enc_mod}")
253+
else
254+
print_status("Encoded stage with #{encp.encoder.refname}")
255+
end
265256
estg = encp.encoded
266-
267-
break
268257
end
269-
end
270-
271-
if datastore['StageEncodingFallback'] && estg.nil?
272-
print_warning("StageEncoder failed, falling back to no encoding")
273-
estg = stg
274-
end
275-
276-
unless estg
277-
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
258+
rescue
259+
if datastore['StageEncodingFallback'] && estg.nil?
260+
print_warning("StageEncoder failed, falling back to no encoding")
261+
estg = stg
262+
else
263+
raise RuntimeError, "Stage encoding failed and StageEncodingFallback is disabled"
264+
end
278265
end
279266

280267
estg

0 commit comments

Comments
 (0)