# Unchecked weapon id in WeaponList message parser on client leads to RCE

Unchecked negative weapon id in WeaponList parser underflows rgWeapons array, letting a malicious server overwrite client.dll function pointers and achieve RCE.

- Payout: $3,000
- Severity: critical
- Program: Valve
- Credited: nyancat0131
- Disclosed: 2019-09-17
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/513154
- Library page: https://bugbountylibrary.com/r/h1%3A513154
- Tags: domain:desktop impact:rce kind:bounty platform:hackerone sev:critical tech:windows technique:chained technique:source-review vuln:memory-corruption vuln:rce

**Target:** HLSDK CHudAmmo::MsgFunc_WeaponList / WeaponResource::AddWeapon in hl.exe (CS 1.6 client)
**Root cause:** Weapon.iId is read as a signed char with range [-128,128) and used directly as index into rgWeapons without bounds checking, allowing out-of-bounds write before the array.
**Steps:**
1. Malicious server sends crafted `WeaponList` message with `iId` set to a negative value (e.g. -128..-1) to index before `rgWeapons`.
2. Craft `weapon_pwn.txt` weapon sprite list to control the WEAPON struct contents written out-of-bounds.
3. Use the OOB write to overwrite the `gEngfuncs` function table entry used by `HUD_DirectorMessage` with a ROP gadget address.
4. Send a subsequent `SendCmd` call containing the ROP chain to trigger execution.
5. Result: `calc.exe` pops on the client (PoC).
**How found:** Code review of HLSDK WeaponList parser noticed `iId` is a signed char with no bounds check before indexing `rgWeapons`; calculated offsets in latest CS 1.6 client.dll to determine `gEngfuncs` function table was reachable via negative index.
**Exploitation:** Attacker runs a malicious game server; on client connect it catches `InitHUD` and sends a crafted `WeaponList` message. The negative `iId` causes an OOB write via `rgWeapons[iId] = *wp`, overwriting a `gEngfuncs` function pointer used by `HUD_DirectorMessage`. A crafted weapon sprite list controls the written struct. A following `SendCmd` delivers the ROP chain, achieving code execution on the client.
**Escalation:** Chained OOB write -> function pointer overwrite -> ROP chain delivered via SendCmd for full RCE.
**Insight:** Signed-char fields parsed from network messages and used as array indices are prime OOB targets; map the data section layout to find reachable function-pointer tables (like engine function tables) that a negative index can hit.
