Skip to content

Instantly share code, notes, and snippets.

@Zenexer
Last active February 15, 2018 02:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zenexer/ac7601c0e367d876353137e5099b18a7 to your computer and use it in GitHub Desktop.
Save Zenexer/ac7601c0e367d876353137e5099b18a7 to your computer and use it in GitHub Desktop.
Parsec CSRF vulnerability in version 140-1 and prior

Parsec is a proprietary remote desktop application intended for low-latency remote gaming.

Summary

A vulnerability in versions of the Parsec Gaming program prior to 140-3 permits a remote attacker to send arbitrary commands to the program. On many systems, this permits the attacker to gain full control over the victim computer without the user's knowledge.

Attack vector

For exploitation to succeed, the victim must visit a website with a specially formatted domain name controlled by the attacker. The victim's web browser must run JavaScript on the page and be capable of making WebSocket connections.

Impact

Successful exploitation grants an attacker full control over the Parsec client. As Parsec is a remote desktop application, a full compromise of the client allows for full control over the victim's computer. It's not apparent to the victim that a compromise has occurred.

The attack is most effective against Windows, as Parsec only supported remoting into Windows systems. Other platforms are affected, but direct remote control through Parsec isn't possible. The attacker can still control the client on non-Windows platforms, and creative use of the exposed API may permit a similar degree of compromise as attacks against Windows.

Additionally:

  • If the attacker's Parsec account has been granted restricted access to the victim's device (e.g., view-only), the attacker can grant their own account further permissions, without restriction. (app_server_approve_all)
  • If the victim device has users actively remoting into it, the attacker can forcefully kick (disconnect) those users. (app_server_kick_all)
  • The attacker can retrieve various information from a compromised host via the Parsec API. (app_cfg_get et al)
  • The attacker can enable remote connections even on a client that is configured not to act as a host, provided the compromised device meets the minimum requirements for hosting Parsec sessions. (app_cfg_set, app_server_start)
  • The attacker may be able to retrieve the Parsec credentials belonging the victim, though this hasn't been confirmed with a PoC. (app_api_auth_stored)

Fix

Unless its update mechanism is deliberately impeded, Parsec will forcefully update. Affected users should update Parsec:

  1. Close all browsers to prevent attacks during the update.
  2. Run Parsec.
  3. Wait for Parsec to update.
  4. Restart Parsec to ensure the updated version is running.
  5. Confirm that a patched version is in use by navigating to Settings and observing the version ID in the top-right corner.

Technical details

The Parsec Gaming client is comprised of several components. This vulnerability is concerned with the communication channel between two components in particular:

  1. Native Parsec client
  2. Web-based frontend

The web frontend, typically accessed via parsecgaming.com or the official Electron-based frontend, communicates with the native Parsec client via a WebSocket connection on port 5309. The native client listens on 127.0.0.1:5309, and the frontend connects to ws://127.0.0.1:5309/.

The server component of the native client is open source and published under the name uncurl. Its only known use, as of the time this vulnerability was discovered, is in Parsec. The vulnerability has since been patched.

The server validates four headers from the initial frontend connection request in uncurl_ws_accept:

  1. Upgrade: must be present and equal to websocket
  2. Connection: must be present and equal to upgrade
  3. Origin: must contain one of the allowed origins
  4. Sec-WebSocket-Key: must be present

The vulnerability lies in the logic of the third validator. As seen in uncurl.c prior to the patch, starting on line 539, any one of the allowed origins must appear anywhere in the header value for validation to succeed. Here is the vulnerable code:

UNCURL_EXPORT int32_t uncurl_ws_accept(struct uncurl_conn *ucc, char **origins, int32_t n_origins)
{
	// ...
	bool origin_ok = false;
	for (int32_t x = 0; x < n_origins; x++)
		if (strstr(origin, origins[x])) {origin_ok = true; break;}

If strstr returns anything other than NULL, validation will succeed. In production, the origins array contains at least one string: "parsecgaming.com". Both the Electron app and the in-browser app use an origin of https://parsecgaming.com. However, that's not the only origin that will validate; the following third-party origins will also validate:

  1. https://parsecgaming.com.example.com
  2. https://foobar-parsecgaming.com

Even if the validation string were altered to the more restrictive "https://parsecgaming.com", the first third-party origin will still validate. This necessitates changes to logic of uncurl_ws_accept, implemented in commit e38e769, which corresponds to Parsec version 140-3.

A proof-of-concept is available at parsecgaming.com.zenexer.com. The PoC is able to send arbitrary commands to the Parsec native client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment