Signedness issue in ClassInfo message handler leads to RCE on CS:GO client
Team Summary
Official summary from Valve
Title: Signedness issue in ClassInfo message handler leads to RCE on CS:GO client Scope: csgo.exe Weakness: Array Index Underflow Severity: Critical (9.6) Link: https://hackerone.com/reports/876719 Date: 2020-05-17 20:31:35 +0000 By: @chaynik Details: Vulnerability ------------- `CSVCMsg_ClassInfo` message is used by Source Engine to pass information about entity classes. It is described by the following Protobuf: ``` message CSVCMsg_ClassInfo { message class_t { optional int32 class_id = 1; optional string data_table_name = 2; optional string class_name = 3; } optional bool create_on_client = 1; repeated .CSVCMsg_ClassInfo.class_t classes = 2; } ``` The bug is present in `CSVCMsg_ClassInfo` message handler on client. The pseudocode of function that handles this message: ```cpp bool ProcessClassInfo(CSVCMsg_ClassInfo *msg) { ... int nClasses = msg->classes_size; ClassInfo *pClasses = new ClassInfo[nClasses]; ... for (int i = 0; i < nClasses; i++) { class_t *src = msg->classes[i]; if (src->class_id >= nClasses) { // class_id can be negative! ... return false; } ClassInfo *dst = &pClasses[src->class_id]; ... } ... } ``` An array of appropriate size is allocated to hold the received information. The array is indexed by `class_id`, which is improperly sanitized: it can be an arbitrary negative integer. This allows an out of bounds write, which can be exploited to perform remote code execution. Any Source Engine (and Source 2) game that uses Protobuf network messages should be affected by this vulnerability, including CS:GO and Dota 2. Only CS:GO has been tested. Exploit details --------------- The Proof-of-Concept exploit consists of two main phases: 1. ASLR bypass - the bug is used to get base address of `client_panorama.dll` 2. Remote code execution - the bug is used to divert control flow to ROP chain In order to craft a [ROP](https://en.wikipedia.org/wiki/Return-oriented_programming) chain, attacker needs to know the absolute address of some application module. The [ASLR](https://en.wikipedia.org/wiki/Address_space_layout_randomization) attempts to prevent it by randomizing memory layout. ### Bypassing the ASLR Source Engine has mechanism that allows server to set and query "cvars" - variables that control various game-related settings. The exploit leverages cvars to steal a pointer to predictable memory location in game process: 1. Spray the heap with entities - we want to make heap allocations more predictable - if we allocate 500+ entities there is high chance that last of them are side-by-side 2. Delete last 20 entities - deallocated data, including pointers to vtables, remains on heap 3. Set some cvar to a string of appropriate length - we want it to be allocated in place of old entities - we want the vtable pointer of some old entity to be right after the end of the string 4. Use the vulnerability to overwrite null terminator of cvar string - we want the class-infos to get allocated next to cvar - if we succeed, the cvar string will be extended to contain the vtable pointer 5. Query the cvar string - the leaked vtable pointer allows us to calculate `client_panorama.dll` base address There is one issue with this idea: the client breaks connection after the vulnerability is used, due to some late sanity check. There's an easy way around it though. Server can queue a `retry` command to be executed on client, so the client automatically reconnects. ### Executing code After succesful pointer leakage, a ROP chain that runs `calc.exe` is crafted using gadgets from `client_panorama.dll`. The RCE is performed as follows: 1. Deliver the ROP chain in `CCSUsrMsg_ShowMenu` user message - client stores it in global buffer in `client_panorama.dll` - we can easily calculate address to it 2. Spray the heap with entities - we want to make heap allocations more predictable 3. Use the vulnerability to overwrite vtable pointer of some entity - we want the class-infos to get allocated after last entity 4. The client breaks connection and deallocates entities - the fake vtable will divert control flow to our ROP chain - the ROP chain will launch Calculator app Reproduction ------------ The PoC script simulates a malicious CS:GO server. It demonstrates RCE capability on CS:GO client for Windows (version 13752, 2020-05-14 stable release). 1. Download the attached Python 3 script: F831986 2. Run the script (possibly on another host) 3. Start CS:GO client 4. Connect to the malicious server 5. Wait for `calc.exe` to pop up Similarly as in #470520, Steam browser protocol can be used to launch an attack from web browser: 1. Download the attached Python 3 script: F831986 2. Run the script (possibly on another host) 3. Download attached HTML file - F831987 4. Set address in iframe URL to the malicious server 5. Open downloaded HTML file and confirm `Open steam` 6. Wait for `calc.exe` to pop up ## Impact An attacker can execute arbitrary code on the computer of anyone who attempts to connect to the server. After successful exploitation an attacker can gain control over victim's computer. The connection to the server can be initiated manually by the victim or automatically by visiting malicious web site via Steam browser protocol. The likelihood of victim joining the server via in-game server browser can be greatly improved by faking high player count and further social engineering. Many players sort server list by player amount. In case of an attack from web browser many users don't need to click `Open steam` and this method requires no further interaction from user - connection will be initiated without confirmation (even game client will be started if it's not running).
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Bounty
$7500.00
Submitted
Weakness
Array Index Underflow