diff --git a/lib/msf/core/exploit.rb b/lib/msf/core/exploit.rb index 81c37cab047c5..cacc39667c9e4 100644 --- a/lib/msf/core/exploit.rb +++ b/lib/msf/core/exploit.rb @@ -544,6 +544,18 @@ def generate_single_payload(pinst = nil, platform = nil, arch = nil, explicit_ta # Incorporate any context encoding requirements that are needed define_context_encoding_reqs(reqs) + # For generic payloads, constrain encoder (and NOP) module selection to the + # architecture and platform of the concrete payload that was resolved above. + # Without this, EncodedPayload#compatible_encoders falls back to the generic + # payload's ARCH_ALL and considers encoders for every architecture. An + # arch-inappropriate encoder (e.g. riscv64le/byte_xori applied to x86 + # shellcode) can then spin effectively forever brute-forcing a key that + # avoids the exploit's bad characters. + if real_payload.is_a?(Msf::Payload::Generic) + reqs['Arch'] ||= real_payload.resolved_arch + reqs['Platform'] ||= real_payload.resolved_platform + end + # Call the encode begin routine. encode_begin(real_payload, reqs) diff --git a/lib/msf/core/payload/generic.rb b/lib/msf/core/payload/generic.rb index 1a5e387fe1fd2..4a2c580a379b3 100644 --- a/lib/msf/core/payload/generic.rb +++ b/lib/msf/core/payload/generic.rb @@ -161,6 +161,31 @@ def redirect_to_actual(name, *args) # attr_accessor :explicit_arch + # + # Returns the architecture of the concrete payload that this generic payload + # resolves to, or nil if it cannot be determined yet. Unlike {#arch} (which + # advertises ARCH_ALL for compatibility matching), this reflects the payload + # that will actually be generated, so callers such as encoder selection can + # scope themselves to the right architecture. + # + # @return [Array, nil] + def resolved_arch + actual_arch + rescue NoCompatiblePayloadError + nil + end + + # + # Returns the platform of the concrete payload that this generic payload + # resolves to, or nil if it cannot be determined yet. + # + # @return [Msf::Module::PlatformList, nil] + def resolved_platform + actual_platform + rescue NoCompatiblePayloadError + nil + end + protected #