contrib.nodejsscan.path_traversal.generic_path_traversal

profile photo of returntocorpreturntocorp
Author
99
Download Count*
License

Untrusted user input in readFile()/readFileSync() can endup in Directory Traversal Attacks.

Run Locally

Run in CI

Defintion

rules:
  - id: generic_path_traversal
    patterns:
      - pattern-either:
          - pattern-inside: |
              require('http');
              ...
          - pattern-inside: |
              require('express');
              ...
          - pattern-inside: |
              require('koa');
              ...
          - pattern-inside: |
              require('electron');
              ...
      - pattern-either:
          - pattern-inside: function ($REQ, $RES, ...) {...}
          - pattern-inside: function $FUNC($REQ, $RES, ...) {...}
          - pattern-inside: $X = function $FUNC($REQ, $RES, ...) {...}
          - pattern-inside: var $X = function $FUNC($REQ, $RES, ...) {...};
          - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, ...) {...})
      - pattern-either:
          - pattern: |
              $X.createReadStream(..., <... $REQ.$QUERY.$VAR ...>, ...)
          - pattern: |
              $X.createReadStream(..., <... $REQ.$QUERY ...>, ...)
          - pattern: |
              $X.readFile(..., <... $REQ.$QUERY.$VAR ...>, ...)
          - pattern: |
              $X.readFile(..., <... $REQ.$QUERY ...>, ...)
          - pattern: |
              $X.readFileSync(..., <... $REQ.$QUERY.$VAR ...>, ...)
          - pattern: |
              $X.readFileSync(..., <... $REQ.$QUERY ...>, ...)
          - pattern: |
              $X.readFileAsync(..., <... $REQ.$QUERY.$VAR ...>, ...)
          - pattern: |
              $X.readFileAsync(..., <... $REQ.$QUERY ...>, ...)
          - pattern: |
              $INP = <... $REQ.$QUERY.$VAR ...>;
              ...
              $X.createReadStream(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY ...>;
              ...
              $X.createReadStream(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY.$VAR ...>;
              ...
              $X.readFile(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY ...>;
              ...
              $X.readFile(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY.$VAR ...>;
              ...
              $X.readFileSync(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY ...>;
              ...
              $X.readFileSync(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY.$VAR ...>;
              ...
              $X.readFileAsync(..., <... $INP ...>, ...);
          - pattern: |
              $INP = <... $REQ.$QUERY ...>;
              ...
              $X.readFileAsync(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY.$VAR;
              ...
              $INP = <... $Y ...>;
              ...
              $X.createReadStream(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY;
              ...
              $INP = <... $Y ...>;
              ...
              $X.createReadStream(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY.$VAR;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFile(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFile(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY.$VAR;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFileSync(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFileSync(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY.$VAR;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFileAsync(..., <... $INP ...>, ...);
          - pattern: |
              $Y = $REQ.$QUERY;
              ...
              $INP = <... $Y ...>;
              ...
              $X.readFileAsync(..., <... $INP ...>, ...);
    message: Untrusted user input in readFile()/readFileSync() can endup in
      Directory Traversal Attacks.
    languages:
      - javascript
    severity: ERROR
    metadata:
      owasp: A05:2017 - Broken Access Control
      cwe: "CWE-23: Relative Path Traversal"
      category: security
      technology:
        - node.js
        - express
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

path_traversal.js

var http = require('http'),
    fileSystem = require('fs'),
    path = require('path');

var config = require('../config');
var Promise = require('bluebird');
Promise.promisifyAll(fileSystem);

var express = require('express');
var app = express();
app.get('/', function (req, res) {
    // ruleid:generic_path_traversal
    var filePath = path.join(__dirname, '/' + req.query.load);
    var readStream = fileSystem.createReadStream(filePath);
    // ruleid:generic_path_traversal
    fileSystem.readFile(req.query.foo);
    // ruleid:generic_path_traversal
    console.log(fileSystem.readFileSync(req.query.nar, 'utf8'));
    // ruleid:generic_path_traversal
    var foo = req.query.y;
    fileSystem.readFile(foo);
    fileSystem.readFile(foo + "bar");
    readStream.pipe(res);
});

app.get('/foo', function (req, res) {
    // ruleid:generic_path_traversal
    var date = req.query.date;
    var fileName = config.dirName + '/' + date;
    var downloadFileName = 'log_' + fileName + '.txt';

    fs.readFileAsync(fileName)
        .then(function (data) {
            res.download(fileName, downloadFileName);
        })
})

app.listen(8888);
// do not match
fileSystem.readFile(ddd);