RCE on CS:GO client using unsanitized entity ID in EntityMsg message
Team Summary
Official summary from Valve
Title: RCE on CS:GO client using unsanitized entity ID in EntityMsg message Scope: csgo.exe Weakness: Out-of-bounds Read Severity: Critical (9.6) Link: https://hackerone.com/reports/584603 Date: 2019-05-19 17:49:21 +0000 By: @chaynik Details: Vulnerability ------------- `CSVCMsg_EntityMsg` message is used by server to notify client about generic actions regarding entities. The message is described using the following Protocol Buffer: ``` message CSVCMsg_EntityMsg { optional int32 ent_index = 1; optional int32 class_id = 2; optional bytes ent_data = 3; } ``` The pseudocode of function handling this message: ```cpp void ProcessEntityMessage(CSVCMsg_EntityMsg *msg) { IClientNetworkable *entity = entitylist->GetClientNetworkable(msg->ent_index); if (entity) { ... entity->ReceiveMessage(...); ... } ... } ``` Neither handler nor `GetClientNetworkable` check if entity index is valid - an arbitrary integer can be passed. This can lead to memory access outside of entity list and then to virtual function call on invalid object. By careful manipulation it can be used to divert control flow to attacker's payload. Exploitation ------------ The exploit is based on assumption that `client_panorama.dll` base address is known to the attacker. It can be procured using additional memory disclousure vulnerability, like #581774. Alternatively, in case of distributed attack guessing address may be viable (32-bit ASLR has low entropy). The first stage is to find a variable with known address that can be controlled by server. For example, I chose to use map name because its copy is stored in a global variable somewhere in `client_panorama.dll`. Note that it's expected behavior and not a vulnerability. Then I crafted a payload containing ROP chain and fake `IClientNetworkable` object. The payload is sent to server as map name. Obviously, map name is a string and cannot contain null characters, but there's easy way to bypass this limitation by overwriting it several times. The final step is to use the vulnerability to trick client into executing virtual function on the fake object. Entity list is a statically allocated array inside `client_panorama.dll`, so the offset to the payload is constant. An appropriate entity index is calculated from the offset and message is sent. The ROP chain goal is to run Calculator app. Luckily, `client_panorama.dll` imports `IProcessUtils` interface from `tier0.dll` which can be used to start processes. It simplifies ROP chain considerably. Proof of Concept ---------------- The PoC script is demonstrating RCE capability on CS:GO client for Windows (version 13696, 2019-05-16 stable release). 1. Download attached script: F492694 2. Start CS:GO client 3. Use a debugger to get the base address of `client_panorama.dll` and set `CLIENT_BASE` variable in downloaded script 4. Run attached Python 3 script (possibly on another host) **Note:** If you run this script on the same host as client you might need to change the default `PORT` (because for some reason CS:GO client uses it). 5. Connect to the malicious server and wait for `calc.exe` to pop up {F492696} Similarly as in #470520, Steam browser protocol can be used to launch an attack from web browser: 1. Follow steps 1-4 as above 2. Download attached HTML file (F492697) and set IP in iframe URL to malicious server 3. Open downloaded HTML file and wait for `calc.exe` to pop up {F492695} ## Impact An attacker can execute arbitrary code on the computer of anyone who attempts to connect to the server. After succesful exploitation an attacker can gain control over victim's computer and do whatever they want. The connection to the server can be initiated manually by the victim or automatically using Steam browser protocol on malicious web site. 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 CS:GO client will be started if it's not running).
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Bounty
$9000.00
Submitted
Weakness
Out-of-bounds Read