M_06/ A01:2021 — Broken Access Control

Path Traversal

The server joins a base directory with the filename you supply. If you can sneak ../ in, you can step out of /uploads into sensitive system files.

Filename input
Path resolution
base       = /var/www/uploads
raw input  = ../../etc/passwd
url-decoded= ../../etc/passwd
resolved   = /var/etc/passwd
/
etc
passwd
shadow
var
www
uploads
image.jpg
✗ Escaped upload directory — sensitive file would be read.
Vulnerable
const fs = require('fs');
fs.readFile('/var/www/uploads/' + req.query.f);
Secure
const path = require('path');
const base = '/var/www/uploads';
const resolved = path.resolve(base, req.query.f);
if (!resolved.startsWith(base + path.sep))
  return res.sendStatus(400);
fs.readFile(resolved);