HexBrain

Valve · Report #484745

GoldSrc: Buffer Overflow in DELTA_ParseDelta function leads to RCE

Validstatus
criticalseverity
$3,000bounty
26upvotes
4 May 2021disclosed

Summary

Description

The bug is triggered by 2 packets. First one is svc_deltadescription which describes memory layout of such structures as event_t, weapon_data_t, ... It is sent as a list of fields' descriptions: type, offset and others. Next, DELTA_ParseDelta fills these structures when corresponding delta packets are received. The problem is that this function doesn't check if field_offset + field_size doesn't exceed bounds of allocated memory for these structures which can lead to buffer overflow.

To actually trigger this overflow we need to send specially crafted delta information. I found that svc_event packet is parsed in ParseEvent function that allocates event_t structure on the stack and then fills it in vulnerable DELTA_ParseDelta function.

Using this info we can craft two packets that will triger stack overflow. In my exploit I used following memory layout for event_t structure:

payload:
  - type=String
  - offset=0xac  # offset of return address in ParseEvent function
int1:
  - type=Integer
  - offset=0xac + <int1 offset in payload>
...
intn:
  - type=Integer
  - offset=0xac + <intn offset in payload>

The first field is used for the payload. Other extra integer fields are used to put data in the payload that has 2 or more zeros (for example 0x0b for syscall) since DELTA_ParseDelta copies string until it meets the null character \0.

NX is enabled, so it is not possible to execute shellcode on the stack or any other writable memory region directly. However, the main executable hl is loaded at the fixed address, which means we can build some ROPs without leaking addresses. I decided to take it one step further and build a rop chain to pop calc, so I checked other libraries and found int 0x80 gadget in hw.so. Though, it will be loaded on different addresses on each run, which means that a rop chain has to calculate the base address of hw.so at runtime.

I came up with the following rop chain (you can check the full one in the attached extra materials):

  1. Call strncpy to build /usr/bin/xcalc and DISPLAY=:0 strings in .bss section from bytes that scattered across readonly sections
  2. Call Sys_LoadModule("hw.so") to get its base address
  3. Prepare execve syscall arguments and jmp to int 0x80

Steps to reproduce

This poc exploit pops xcalc. In my demo I used clean ubuntu 18.10, but it should work in other environments that have /usr/bin/xcalc.

  1. Make sure that you have python3 installed to run server
  2. Start server with python3 poc.py F411266
  3. Launch Counter-Strike 1.6
  4. Connect to 127.0.0.1

After these steps xcalc should pop up.

PoC Demo

{F411267}

Impact

Remote Code Execution on client.

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