This article covers a vulnerability discovered in GOG Galaxy, which may result in Local Privilege Escalation due to a lack of authorization of commands sent via a local TCP connection. The attacker may exploit this vulnerability to gain SYSTEM privileges in Windows system where GOG Galaxy software is installed.
I’ve recently started looking at the security posture of various games-related platforms as they look like a rather promising target. Modern games are installed by billions of users. Very often, to install the game, a user has to use specific platforms – some of the games are distributed using Steam, some using Epic Games store… Apart from that, separate platforms may be needed to actually launch the game or to interact with its social features.
The potential impact of security issues discovered in those platforms may be quite huge.
Their typical architecture is quite similar and usually includes at least one component which is running with higher privileges – often with SYSTEM privileges. The role of such a component may be to allow seamless game installations, moving files around or simply installing updates.
In this article, I would like to cover the vulnerability discovered in GOG Galaxy. The vulnerability has been reported on August 22nd and was recently fixed. The fix was deployed on 2019-10-07 in version 1.2.60. Affected are all previous versions (including previous builds of Galaxy 2.0 Beta). The oldest version that I could find was GOG Galaxy 18.104.22.1688.
This vulnerability has been assigned identifier CVE-2019-15511.
Service’s binary GalaxyClientService.exe does not properly restrict commands sent via a local TCP connection. There are no origin, authentication or authorization verification mechanisms involved, and any valid command send to the service will result in execution with SYSTEM privileges. The commands do not allow for arbitrary code execution per se, instead, the protocol defines a number of privileged commands, such as FixDirectoryPrivilegesRequest that can be used to take over any file. The full list of commands will be covered further in the article.
The service is automatically started during the initialization of GOG Client. By verifying its permissions, we can see that it can be also manually started or stopped by any user. It runs with Local System privileges.
The ability to start the service on demand will be very useful at the end of the attack.
The GOG Client needs to somehow communicate with the service. Various launchers are using different protocols, some are based on the file interfaces, some are using pipes. In the case of Galaxy, we have to look into local TCP traffic. The communication between GOG Galaxy client and the service can be analyzed using Procmon from Sysinternals suite. The TCP traffic exchanged between two processes, indicates that service is binding to port 9978/TCP right after it is started and the client briefly exchanges several requests with it.
Peeking into traffic sent over localhost is possible with newer versions of Wireshark with Npcap driver (packets don’t go over normal network drivers so special support is required). Having Procmon running at the same time allows correlating the packets with observed actions (e.g. creation of new directory). Another useful source of information is logs written on the disk by the service itself. They contain detailed information about performed actions (including internal names), but also errors in case malformed packets are seen.
The service is using some custom-made protocol, but it’s quite easy to notice some patterns inside it.
The red traffic comes from the client, while blue traffic comes from the service. After these packets were exchanged, the directory called C:\ProgramData\GOG.com\Galaxy\temp was modified and Full Control access was granted to Everyone group. Everyone includes, well, everyone, hence it’s really interesting to see if the packet can be anyhow manipulated.
The basic approach in this situation is to try to replay the packet. If the action can be replayed, it means that there is no time-based signature or anything like that. I’ve changed “temp” directory permissions (so that only SYSTEM could access it) and manually replayed the packet – as expected the permissions for Everone have been restored. The TCP request was coming from my custom process that had nothing to do with GOG Galaxy. No special authentication was involved, the service simply did what was requested.
The next step was to modify the path and try to do the same on another directory. However, this time it failed.
I did not receive any reply and Procmon did not register any activity on that path. I began to analyze other successful operations to see the pattern inside messages.
The hex number in the blue square represents the length of the path. The hex number in the red square is equal to the path length + 2. The green part seems to be sort of dynamic, it also has a variable size. Knowing all that, I’ve constructed another packet – I’ve decided to simply hardcode the green part of the packet.
This time it worked perfectly!
On the second attempt, I’ve also verified that the same functionality can be used to hijack regular files. To further escalate privileges the attacker would take over one of the system services and replace it with a malicious file, such as reverse shell or implant such as CQService. Which service to target? GalaxyClientService is a perfect candidate itself, as its SDDL allows the user to restart the service on demand.
This is not over, though. By triggering other actions, such as game installation it is possible to identify other types of commands. The 6th byte, which so far was always equal to 0x03, represents the command type. By reading service logs, it is possible to discover the internal names of those packets.
- “Invalid”: 0x00,
- “LaunchElevatedRequest”: 0x01,
- “LaunchElevatedResponse”: 0x02,
- “FixDirectoryPrivilegesRequest”: 0x03,
- “FixDirectoryPrivilegesResponse”: 0x04,
- “CreateDirectoryRequest”: 0x05,
- “CreateDirectoryResponse”: 0x06,
- “QueryProcessInfoRequest”: 0x07,
- “QueryProcessInfoResponse”: 0x08,
- “InstallServiceRequest”: 0x09,
- “InstallServiceResponse”: 0x0A,
- “DeleteServiceRequest”: 0x0B,
- “DeleteServiceResponse”: 0x0C,
- “MoveAndVerifyGlobalDependencyRequest”: 0x0D,
- “MoveAndVerifyGlobalDependencyResponse”: 0x0E
For instance, to create C:\Windows\Cqure directory we can emit the following packet:
I haven’t fully analyzed the packet structure. Other promising commands, such as InstallServiceRequest, are expecting slightly different data. Nevertheless, it was enough to craft LPE capable exploit. The PoC has been shared with GOG security team and they have fixed unauthenticated communication with the service. I haven’t looked into the new implementation in detail.
The PoC exploit can be found here: https://github.com/adenkiewicz/CVE-2019-15511
Follow me on Twitter @YetAnotherTruth where I share many other interesting findings!
2019-08-22: Reported to vendor
2019-10-07: Issue fixed in version 1.2.60
2019-11-13: Received confirmation that issue is fixed
2019-11-21: Public Disclosure
Adrian Denkiewicz, Cybersecurity Specialist at CQURE, Ethical Hacker, Penetration Tester, Red Teamer, Software Developer, and Trainer. Adrian is deeply interested in the offensive side of security, ranging from modern web attacks, through operating system internals, to low level exploit development. Passionate about learning a bit of everything, but mostly things related to astronomy and rocket science – Adrian has even completed an online rocket science course!