{"id":23215,"date":"2025-10-24T14:48:24","date_gmt":"2025-10-24T14:48:24","guid":{"rendered":"http:\/\/localhost\/?p=23215"},"modified":"2025-10-24T14:48:24","modified_gmt":"2025-10-24T14:48:24","slug":"persistence-exploit-suggester","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=23215","title":{"rendered":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2025-10-24T19:10:47&#8243;,&#8221;description&#8221;:&#8221;This module suggests persistence modules that can be used.           The modules are suggested based on the architecture and platform           that the user has a shell opened as well as the&#8230;&#8221;,&#8221;published&#8221;:&#8221;2025-10-24T19:01:07&#8243;,&#8221;modified&#8221;:&#8221;2025-10-24T19:01:07&#8243;,&#8221;type&#8221;:&#8221;metasploit&#8221;,&#8221;title&#8221;:&#8221;Persistence Exploit Suggester&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-&#8220;,&#8221;bulletinFamily&#8221;:&#8221;exploit&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[],&#8221;sourceData&#8221;:&#8221;##\\n# This module requires Metasploit: https:\/\/metasploit.com\/download\\n# Current source: https:\/\/github.com\/rapid7\/metasploit-framework\\n##\\n\\nclass MetasploitModule \\u003c Msf::Post\\n\\n  include Msf::Auxiliary::Report\\n\\n  def initialize(info = {})\\n    super(\\n      update_info(\\n        info,\\n        &#8216;Name&#8217; =\\u003e &#8216;Persistence Exploit Suggester&#8217;,\\n        &#8216;Description&#8217; =\\u003e %q{\\n          This module suggests persistence modules that can be used.\\n          The modules are suggested based on the architecture and platform\\n          that the user has a shell opened as well as the available exploits\\n          in meterpreter.\\n          It&#8217;s important to note that not all modules will be checked.\\n          Exploits are chosen based on these conditions: session type,\\n          platform, architecture, and required default options.\\n        },\\n        &#8216;License&#8217; =\\u003e MSF_LICENSE,\\n        &#8216;Author&#8217; =\\u003e [ &#8216;h00die&#8217; ],\\n        &#8216;Platform&#8217; =\\u003e all_platforms,\\n        &#8216;SessionTypes&#8217; =\\u003e [ &#8216;meterpreter&#8217;, &#8216;shell&#8217; ],\\n        &#8216;Notes&#8217; =\\u003e {\\n          &#8216;Stability&#8217; =\\u003e [],\\n          &#8216;Reliability&#8217; =\\u003e [],\\n          &#8216;SideEffects&#8217; =\\u003e []\\n        }\\n      )\\n    )\\n    register_options [\\n      Msf::OptInt.new(&#8216;SESSION&#8217;, [ true, &#8216;The session to run this module on&#8217; ]),\\n      Msf::OptBool.new(&#8216;SHOWDESCRIPTION&#8217;, [true, &#8216;Displays a detailed description for the available exploits&#8217;, false])\\n    ]\\n\\n    register_advanced_options(\\n      [\\n        # most linux persistence modules are arch-cmd but for payload purposes only\\n        # but usually we end up with a meterpreter session, thus making these invalid\\n        # so disable this check by default\\n        Msf::OptBool.new(&#8216;ValidateArch&#8217;, [true, &#8216;Validate architecture&#8217;, false]),\\n        Msf::OptBool.new(&#8216;ValidatePlatform&#8217;, [true, &#8216;Validate platform&#8217;, true]),\\n        Msf::OptBool.new(&#8216;ValidateMeterpreterCommands&#8217;, [true, &#8216;Validate Meterpreter commands&#8217;, false]),\\n        # https:\/\/github.com\/rapid7\/rex-text\/blob\/a72151d409cd812978f63ad0c330efbc8f44b977\/lib\/rex\/text\/color.rb#L13\\n        Msf::OptString.new(&#8216;Colors&#8217;, [false, &#8216;Valid, Invalid and Ignored colors for module checks (unset to disable)&#8217;, &#8216;grn\/red\/blu&#8217;])\\n      ]\\n    )\\n  end\\n\\n  def valid_colors?(color_str = datastore[&#8216;Colors&#8217;])\\n    tokens = color_str.split(&#8216;\/&#8217;)\\n    tokens.each do |tok|\\n      print_warning \\&#8221;#{tok} is unlikely to have any functionality for printing colors.\\&#8221; if tok == &#8216;clr&#8217;\\n\\n      unless Rex::Text::Color::SUPPORTED_FORMAT_CODES.include?(\\&#8221;%#{tok}\\&#8221;)\\n        print_error \\&#8221;#{tok} is NOT valid color. Please see https:\/\/github.com\/rapid7\/rex-text\/blob\/a72151d409cd812978f63ad0c330efbc8f44b977\/lib\/rex\/text\/color.rb#L13 for valid color options\\&#8221;\\n        return false\\n      end\\n    end\\n    true\\n  end\\n\\n  def all_platforms\\n    Msf::Module::Platform.subclasses.collect { |c| c.realname.downcase }\\n  end\\n\\n  def session_arch\\n    # Prefer calling native arch when available, as most LPEs will require this (e.g. x86, x64) as opposed to Java\/Python Meterpreter&#8217;s values (e.g. Java, Python)\\n    session.respond_to?(:native_arch) ? session.native_arch : session.arch\\n  end\\n\\n  def is_module_arch?(mod)\\n    mod_arch = mod.target.arch || mod.arch\\n    mod_arch.include?(session_arch)\\n  rescue StandardError =\\u003e e\\n    print_error \\&#8221;Failed to check module arch for #{mod.fullname} =\\u003e #{e}\\&#8221;\\n  end\\n\\n  def is_module_wanted?(mod)\\n    mod[:result][:incompatibility_reasons].empty?\\n  end\\n\\n  def is_session_type?(mod)\\n    # There are some modules that do not define any compatible session types.\\n    # We could assume that means the module can run on all session types,\\n    # Or we could consider that as incorrect module metadata.\\n    mod.session_types.include?(session.type)\\n  end\\n\\n  def is_module_platform?(mod)\\n    return false if mod.target.nil?\\n\\n    platform_obj = Msf::Module::Platform.find_platform session.platform\\n\\n    module_platforms = mod.target.platform ? mod.target.platform.platforms : mod.platform.platforms\\n    module_platforms.include? platform_obj\\n  rescue ArgumentError =\\u003e e\\n    # When not found, find_platform raises an ArgumentError\\n    elog(&#8216;Could not find a platform&#8217;, error: e)\\n    return false\\n  end\\n\\n  def has_required_module_options?(mod)\\n    get_all_missing_module_options(mod).empty?\\n  end\\n\\n  def get_all_missing_module_options(mod)\\n    missing_options = []\\n    mod.options.each_pair do |option_name, option|\\n      missing_options \\u003c\\u003c option_name if option.required \\u0026\\u0026 option.default.nil? \\u0026\\u0026 mod.datastore[option_name].blank?\\n    end\\n    missing_options\\n  end\\n\\n  def valid_incompatibility_reasons(mod, verify_reasons)\\n    # As we can potentially ignore some `reasons` (e.g. accepting arch values which are, on paper, not compatible),\\n    # this keeps track of valid reasons why we will not consider the module that we are evaluating to be valid.\\n    valid_reasons = []\\n    valid_reasons \\u003c\\u003c \\&#8221;Missing required module options (#{get_all_missing_module_options(mod).join(&#8216;. &#8216;)})\\&#8221; unless verify_reasons[:has_required_module_options]\\n\\n    incompatible_opts = []\\n    incompatible_opts \\u003c\\u003c &#8216;architecture&#8217; unless verify_reasons[:is_module_arch]\\n    incompatible_opts \\u003c\\u003c &#8216;platform&#8217; unless verify_reasons[:is_module_platform]\\n    incompatible_opts \\u003c\\u003c &#8216;session type&#8217; unless verify_reasons[:is_session_type]\\n    valid_reasons \\u003c\\u003c \\&#8221;Not Compatible (#{incompatible_opts.join(&#8216;, &#8216;)})\\&#8221; if incompatible_opts.any?\\n\\n    valid_reasons \\u003c\\u003c &#8216;Missing\/unloadable Meterpreter commands&#8217; if verify_reasons[:missing_meterpreter_commands].any?\\n    valid_reasons\\n  end\\n\\n  def set_module_options(mod)\\n    ignore_list = [&#8216;ACTION&#8217;, &#8216;TARGET&#8217;].freeze\\n    datastore.each_pair do |k, v|\\n      mod.datastore[k] = v unless ignore_list.include?(k.upcase)\\n    end\\n    if !mod.datastore[&#8216;SESSION&#8217;] \\u0026\\u0026 session.present?\\n      mod.datastore[&#8216;SESSION&#8217;] = session.sid\\n    end\\n  end\\n\\n  def set_module_target(mod)\\n    session_platform = Msf::Module::Platform.find_platform(session.platform)\\n    target_index = mod.targets.find_index do |target|\\n      # If the target doesn&#8217;t define its own compatible platforms or architectures, default to the parent (module) values.\\n      target_platforms = target.platform\\u0026.platforms || mod.platform.platforms\\n      target_architectures = target.arch || mod.arch\\n\\n      target_platforms.include?(session_platform) \\u0026\\u0026 target_architectures.include?(session_arch)\\n    end\\n    mod.datastore[&#8216;Target&#8217;] = target_index if target_index\\n  end\\n\\n  def setup\\n    return unless session\\n\\n    print_status \\&#8221;Collecting persistence modules for #{session.session_type}&#8230;\\&#8221;\\n\\n    setup_validation_options\\n    if valid_colors?\\n      setup_color_options\\n    else\\n      fail_with(Failure::BadConfig, &#8216;Colors options set incorrectly&#8217;)\\n    end\\n\\n    # Collects persistence modules into an array\\n    @persistence_modules = []\\n    exploit_refnames = framework.exploits.module_refnames\\n    exploit_refnames.each_with_index do |name, index|\\n      print \\&#8221;%bld%blu[*]%clr Collecting exploit #{index + 1} \/ #{exploit_refnames.count}\\\\r\\&#8221;\\n      next unless name.include? &#8216;\/persistence\/&#8217;\\n\\n      mod = framework.exploits.create name\\n      next unless mod\\n\\n      set_module_options mod\\n      set_module_target mod\\n      verify_result = verify_mod(mod)\\n      @persistence_modules \\u003c\\u003c { module: mod, result: verify_result } if verify_result[:has_check]\\n    end\\n  end\\n\\n  def verify_mod(mod)\\n    return { has_check: false } unless mod.is_a?(Msf::Exploit::Local) \\u0026\\u0026 mod.has_check?\\n\\n    result = {\\n      has_check: true,\\n      is_module_platform: (@validate_platform ? is_module_platform?(mod) : true),\\n      is_module_arch: (@validate_arch ? is_module_arch?(mod) : true),\\n      has_required_module_options: has_required_module_options?(mod),\\n      missing_meterpreter_commands: (@validate_meterpreter_commands \\u0026\\u0026 session.type == &#8216;meterpreter&#8217;) ? meterpreter_session_incompatibility_reasons(session) : [],\\n      is_session_type: is_session_type?(mod)\\n    }\\n    result[:incompatibility_reasons] = valid_incompatibility_reasons(mod, result)\\n    result\\n  end\\n\\n  def setup_validation_options\\n    @validate_arch = datastore[&#8216;ValidateArch&#8217;]\\n    @validate_platform = datastore[&#8216;ValidatePlatform&#8217;]\\n    @validate_meterpreter_commands = datastore[&#8216;ValidateMeterpreterCommands&#8217;]\\n  end\\n\\n  def setup_color_options\\n    @valid_color, @invalid_color, @ignored_color =\\n      (datastore[&#8216;Colors&#8217;] || &#8221;).split(&#8216;\/&#8217;)\\n\\n    @valid_color = \\&#8221;%#{@valid_color}\\&#8221; unless @valid_color.blank?\\n    @invalid_color = \\&#8221;%#{@invalid_color}\\&#8221; unless @invalid_color.blank?\\n    @ignored_color = \\&#8221;%#{@ignored_color}\\&#8221; unless @ignored_color.blank?\\n  end\\n\\n  def show_found_exploits\\n    unless datastore[&#8216;VERBOSE&#8217;]\\n      print_status \\&#8221;#{@persistence_modules.length} exploit checks are being tried&#8230;\\&#8221;\\n      return\\n    end\\n\\n    vprint_status \\&#8221;The following #{@persistence_modules.length} exploit checks are being tried:\\&#8221;\\n    @persistence_modules.each do |x|\\n      vprint_status x[:module].fullname\\n    end\\n  end\\n\\n  def run\\n    runnable_exploits = @persistence_modules.select { |mod| is_module_wanted?(mod) }\\n    if runnable_exploits.empty?\\n      print_error &#8216;No suggestions available.&#8217;\\n      vprint_line\\n      vprint_session_info\\n      vprint_status unwanted_modules_table(@persistence_modules.reject { |mod| is_module_wanted?(mod) })\\n      return\\n    end\\n\\n    show_found_exploits\\n    results = runnable_exploits.map.with_index do |mod, index|\\n      print \\&#8221;%bld%blu[*]%clr Running check method for exploit #{index + 1} \/ #{runnable_exploits.count}\\\\r\\&#8221;\\n      begin\\n        checkcode = mod[:module].check\\n      rescue StandardError =\\u003e e\\n        elog(\\&#8221;#Local Persistence Suggester failed with: #{e.class} when using #{mod[:module].shortname}\\&#8221;, error: e)\\n        vprint_error \\&#8221;Check with module #{mod[:module].fullname} failed with error #{e.class}\\&#8221;\\n        next { module: mod[:module], errors: [&#8216;The check raised an exception.&#8217;] }\\n      end\\n\\n      if checkcode.nil?\\n        vprint_error \\&#8221;Check failed with #{mod[:module].fullname} for unknown reasons\\&#8221;\\n        next { module: mod[:module], errors: [&#8216;The check failed for unknown reasons.&#8217;] }\\n      end\\n\\n      # See def is_check_interesting?\\n      unless is_check_interesting? checkcode\\n        vprint_status \\&#8221;#{mod[:module].fullname}: #{checkcode.message}\\&#8221;\\n        next { module: mod[:module], errors: [checkcode.message] }\\n      end\\n\\n      # Prints the full name and the checkcode message for the exploit\\n      print_good \\&#8221;#{mod[:module].fullname}: #{checkcode.message}\\&#8221;\\n\\n      # If the datastore option is true, a detailed description will show\\n      if datastore[&#8216;SHOWDESCRIPTION&#8217;]\\n        # Formatting for the description text\\n        Rex::Text.wordwrap(Rex::Text.compress(mod[:module].description), 2, 70).split(\/\\\\n\/).each do |line|\\n          print_line line\\n        end\\n      end\\n\\n      next { module: mod[:module], checkcode: checkcode.message }\\n    end\\n\\n    print_line\\n    print_status valid_modules_table(results)\\n\\n    vprint_line\\n    vprint_session_info\\n    vprint_status unwanted_modules_table(@persistence_modules.reject { |mod| is_module_wanted?(mod) })\\n\\n    report_data = {}\\n    results.each do |result|\\n      report_data[result[:module].fullname] = result[:checkcode] if result[:checkcode]\\n    end\\n\\n    report_note({\\n      host: session.session_host,\\n      type: &#8216;persistence.suggested_module&#8217;,\\n      data: report_data\\n    })\\n  end\\n\\n  def valid_modules_table(results)\\n    name_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new\\n    check_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new\\n\\n    # Split all the results by their checkcode.\\n    # We want the modules that returned a checkcode to be at the top.\\n    checkcode_rows, without_checkcode_rows = results.partition { |result| result[:checkcode] }\\n    rows = (checkcode_rows + without_checkcode_rows).map.with_index do |result, index|\\n      color = result[:checkcode] ? @valid_color : @invalid_color\\n      check_res = result.fetch(:checkcode) { result[:errors].join(&#8216;. &#8216;) }\\n      name_styler.merge!({ result[:module].fullname =\\u003e color })\\n      check_styler.merge!({ check_res =\\u003e color })\\n\\n      [\\n        index + 1,\\n        result[:module].fullname,\\n        result[:checkcode] ? &#8216;Yes&#8217; : &#8216;No&#8217;,\\n        check_res\\n      ]\\n    end\\n\\n    Rex::Text::Table.new(\\n      &#8216;Header&#8217; =\\u003e \\&#8221;Valid modules for session #{session.sid}:\\&#8221;,\\n      &#8216;Indent&#8217; =\\u003e 1,\\n      &#8216;Columns&#8217; =\\u003e [ &#8216;#&#8217;, &#8216;Name&#8217;, &#8216;Potentially Vulnerable?&#8217;, &#8216;Check Result&#8217; ],\\n      &#8216;SortIndex&#8217; =\\u003e -1,\\n      &#8216;WordWrap&#8217; =\\u003e false, # Don&#8217;t wordwrap as it messes up coloured output when it is broken up into more than one line\\n      &#8216;ColProps&#8217; =\\u003e {\\n        &#8216;Name&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [name_styler]\\n        },\\n        &#8216;Potentially Vulnerable?&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [::Msf::Ui::Console::TablePrint::CustomColorStyler.new({ &#8216;Yes&#8217; =\\u003e @valid_color, &#8216;No&#8217; =\\u003e @invalid_color })]\\n        },\\n        &#8216;Check Result&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [check_styler]\\n        }\\n      },\\n      &#8216;Rows&#8217; =\\u003e rows\\n    )\\n  end\\n\\n  def unwanted_modules_table(unwanted_modules)\\n    arch_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new\\n    platform_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new\\n    session_type_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new\\n\\n    rows = unwanted_modules.map.with_index do |mod, index|\\n      begin\\n        platforms = mod[:module].target.platform\\u0026.platforms\\u0026.any? ? mod[:module].target.platform.platforms : mod[:module].platform.platforms\\n      rescue NoMethodError\\n        platforms = nil\\n      end\\n      platforms ||= []\\n      begin\\n        arch = mod[:module].target.arch\\u0026.any? ? mod[:module].target.arch : mod[:module].arch\\n      rescue NoMethodError\\n        arch = nil\\n      end\\n      arch ||= []\\n\\n      arch.each do |a|\\n        if a != session_arch\\n          if @validate_arch\\n            color = @invalid_color\\n          else\\n            color = @ignored_color\\n          end\\n        else\\n          color = @valid_color\\n        end\\n\\n        arch_styler.merge!({ a.to_s =\\u003e color })\\n      end\\n\\n      platforms.each do |module_platform|\\n        if module_platform != ::Msf::Module::Platform.find_platform(session.platform)\\n          if @validate_platform\\n            color = @invalid_color\\n          else\\n            color = @ignored_color\\n          end\\n        else\\n          color = @valid_color\\n        end\\n\\n        platform_styler.merge!({ module_platform.realname =\\u003e color })\\n      end\\n\\n      mod[:module].session_types.each do |session_type|\\n        color = session_type == session.type ? @valid_color : @invalid_color\\n        session_type_styler.merge!(session_type.to_s =\\u003e color)\\n      end\\n\\n      [\\n        index + 1,\\n        mod[:module].fullname,\\n        mod[:result][:incompatibility_reasons].join(&#8216;. &#8216;),\\n        platforms.any? ? platforms.map(\\u0026:realname).sort.join(&#8216;, &#8216;) : &#8216;No defined platforms&#8217;,\\n        arch.any? ? arch.sort.join(&#8216;, &#8216;) : &#8216;No defined architectures&#8217;,\\n        mod[:module].session_types.any? ? mod[:module].session_types.sort.join(&#8216;, &#8216;) : &#8216;No defined session types&#8217;\\n      ]\\n    end\\n\\n    Rex::Text::Table.new(\\n      &#8216;Header&#8217; =\\u003e \\&#8221;Incompatible modules for session #{session.sid}:\\&#8221;,\\n      &#8216;Indent&#8217; =\\u003e 1,\\n      &#8216;Columns&#8217; =\\u003e [ &#8216;#&#8217;, &#8216;Name&#8217;, &#8216;Reasons&#8217;, &#8216;Platform&#8217;, &#8216;Architecture&#8217;, &#8216;Session Type&#8217; ],\\n      &#8216;WordWrap&#8217; =\\u003e false,\\n      &#8216;ColProps&#8217; =\\u003e {\\n        &#8216;Architecture&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [arch_styler]\\n        },\\n        &#8216;Platform&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [platform_styler]\\n        },\\n        &#8216;Session Type&#8217; =\\u003e {\\n          &#8216;Stylers&#8217; =\\u003e [session_type_styler]\\n        }\\n      },\\n      &#8216;Rows&#8217; =\\u003e rows\\n    )\\n  end\\n\\n  def vprint_session_info\\n    vprint_status &#8216;Current Session Info:&#8217;\\n    vprint_status \\&#8221;  Session Type: #{session.type}\\&#8221;\\n    vprint_status \\&#8221;  Architecture: #{session_arch}\\&#8221;\\n    vprint_status \\&#8221;  Platform: #{session.platform}\\&#8221;\\n  end\\n\\n  def is_check_interesting?(checkcode)\\n    [\\n      Msf::Exploit::CheckCode::Vulnerable,\\n      Msf::Exploit::CheckCode::Appears,\\n      Msf::Exploit::CheckCode::Detected\\n    ].include? checkcode\\n  end\\n\\n  def print_status(msg = &#8221;)\\n    super(session ? \\&#8221;#{session.session_host} &#8211; #{msg}\\&#8221; : msg)\\n  end\\n\\n  def print_good(msg = &#8221;)\\n    super(session ? \\&#8221;#{session.session_host} &#8211; #{msg}\\&#8221; : msg)\\n  end\\n\\n  def print_error(msg = &#8221;)\\n    super(session ? \\&#8221;#{session.session_host} &#8211; #{msg}\\&#8221; : msg)\\n  end\\nend\\n&#8221;,&#8221;sourceHref&#8221;:&#8221;https:\/\/github.com\/rapid7\/metasploit-framework\/blob\/master\/modules\/post\/multi\/recon\/persistence_suggester.rb&#8221;,&#8221;cvss&#8221;:{&#8220;score&#8221;:0,&#8221;severity&#8221;:&#8221;NONE&#8221;,&#8221;vector&#8221;:&#8221;NONE&#8221;,&#8221;version&#8221;:&#8221;NONE&#8221;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/www.rapid7.com\/db\/modules\/post\/multi\/recon\/persistence_suggester\/&#8221;,&#8221;category_name&#8221;:&#8221;Exploit&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2025-10-24T19:10:47&#8243;,&#8221;description&#8221;:&#8221;This module suggests persistence modules that can be used. The modules are suggested based on the architecture and platform that the user has a shell&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,8,12,169,13,33,7,11,5],"class_list":["post-23215","post","type-post","status-publish","format-standard","hentry","category-category_exploit","tag-cve","tag-cvss","tag-exploit","tag-metasploit","tag-news","tag-none","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=23215\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2025-10-24T19:10:47&#8243;,&#8221;description&#8221;:&#8221;This module suggests persistence modules that can be used. The modules are suggested based on the architecture and platform that the user has a shell...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=23215\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-24T14:48:24+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-\",\"datePublished\":\"2025-10-24T14:48:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215\"},\"wordCount\":2636,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"exploit\",\"metasploit\",\"news\",\"NONE\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_exploit\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=23215#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215\",\"name\":\"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2025-10-24T14:48:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=23215\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=23215#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=23215","og_locale":"en_US","og_type":"article","og_title":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2025-10-24T19:10:47&#8243;,&#8221;description&#8221;:&#8221;This module suggests persistence modules that can be used. The modules are suggested based on the architecture and platform that the user has a shell...","og_url":"https:\/\/zero.redgem.net\/?p=23215","og_site_name":"zero redgem","article_published_time":"2025-10-24T14:48:24+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=23215#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=23215"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-","datePublished":"2025-10-24T14:48:24+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=23215"},"wordCount":2636,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","exploit","metasploit","news","NONE","Security","tapic","Vulnerability"],"articleSection":["category_exploit"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=23215#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=23215","url":"https:\/\/zero.redgem.net\/?p=23215","name":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER- zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2025-10-24T14:48:24+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=23215#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=23215"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=23215#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"Persistence Exploit Suggester_MSF:POST-MULTI-RECON-PERSISTENCE_SUGGESTER-"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/23215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=23215"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/23215\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=23215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=23215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=23215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}