HexBrain

Valve · Report #584603

RCE on CS:GO client using unsanitized entity ID in EntityMsg message

Validstatus
criticalseverity
$9,000bounty
209upvotes
27 May 2021disclosed

Summary

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:

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).

How it was found

The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original