http-server icon indicating copy to clipboard operation
http-server copied to clipboard

Proxy ? based powerful attack on http-server caught in wild. Can force out of memory

Open rook2pawn opened this issue 4 years ago • 13 comments

I run http-server primarily for SPA with proxy redirect. I prefer to just use http-server directly without an NGINX or some other firewall for my projects.

Environment Versions

  1. OS Type : Debian GNU/Linux 9.13 (stretch)
  2. Node version: v14.18.1
  3. http-server version: v13.0.2

Steps to reproduce

  1. make a request (POST, GET, etc) such that the url = '/?/?/?/?/?........... (repeated for about a hundred times) ..../?/?/api'
  2. This will force http-server to end up using all the available memory
  3. sample start http-server ./web -o -c-1 -p 8080 --proxy http://localhost:8080?"

Suggestion

  1. I would propose a PR that links to this issue that deflects against this simple but powerful attack. that uses url.slice(0,4) === '/?/?' The more advanced way to handle this is to not use regex (intensive) but an indexOf analysis so we can parse legitamate query variables vs an actual attack.

Request thoughts and interest in handling this attack? I can propose an precise curl command and repository to demonstrate. Let me know.

Have an immediate fix i implemented here before we even touch parse. https://github.com/rook2pawn/http-server/commit/6645278d947e888c991ab27847bafae327970be1

rook2pawn avatar Oct 23 '21 20:10 rook2pawn

After the first ?, that's just a crazy large query-string, right? Does it matter what the rest of the query is?

so we can parse legitamate query variables vs an actual attack

I don't think it's up to the server to determine what is a legitimate query string, beyond the basics, but it does seem basic to guard against too much memory being used.

Is there a stack trace or any kind of error during the crash? Or is it not actually crashing?

thornjad avatar Oct 26 '21 14:10 thornjad

Yes, it was actually crashing on my Digital ocean box. I've since created this repository in an attempt to recreate it however my memory is much higher on my machine. https://github.com/rook2pawn/show-http-attack

I will attempt to grab the log on the crash by running my service using the current published version. Stay tuned ill post the update here.

rook2pawn avatar Oct 27 '21 11:10 rook2pawn

I've updated the repo and was able to repro the error but did not get it to crash but it definitely starts to go into an uncontrolled loop. from https://github.com/rook2pawn/show-http-attack/blob/master/request.js

const http = require("http");

const genPath = (numRepeat) => {
  return "/?".repeat(numRepeat);
};
const options = {
  host: "127.0.0.1",
  port: 8080,
  path: genPath(140).concat("/api"),
  method: "POST",
};

// Make a request
const req = http.request(options, (res) => {
  res.setEncoding("utf8");
  res.on("data", (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on("end", () => {
    console.log("No more data in response.");
  });
});
req.end();

POST is required. GET will work fine, and POST will make it go out of control. (Want to add that curl disallowed such a long request so you need to build the attack like here)

rook2pawn avatar Oct 30 '21 08:10 rook2pawn

+1 for this. noticed this on my local environment today with a POST request to a non-valid URL. Currently using http-server in a live environment but this is a huge vulnerability.

kade-d avatar Nov 12 '21 00:11 kade-d

@kade-d I made one small change here that stops this request before it takes any computational power.

It only uses String.slice and equality so this is very efficient and has kept my http-server up since I've implemented this fix on my own fork.

rook2pawn avatar Nov 12 '21 02:11 rook2pawn

I think @thornjad has a point when saying it's not up to the server to determine what is a legitimate query string

padapada09 avatar Nov 22 '21 13:11 padapada09

Thanks to everyone working on this issue :)

I was running into the same problem, when using the Catch-all redirect with any other request method than GET. All it takes to reproduce it is:

curl -X POST http://localhost:8080

In my opinion it is a major bug, preventing http-server to be used an productive systems for SPAs before this is fixed.

Working solution for me is serving the SPA via 404.html as described in the README.md:

cp index.html 404.html

However, this impacts the returned HTTP status code to be 404 instead of 200.

I see 3 different solutions for the bug to be resolved:

  1. Fix the implementation, so that the --proxy option can be used for arbitrary request methods
  2. Provide a new commandline option (called e.g. --spa or --fallback) that serves index.html instead of returning 404
  3. Merge the mitigation suggested by @rook2pawn

When help is wanted to implement 1. or 2., let me know…

johannesloetzsch avatar Dec 02 '21 12:12 johannesloetzsch

I think it would be helpful if anyone with context can help explain what is the proxy option, how it is implemented, and the relationship with ? Before more solution-ing, I think we could all appreciate a high level understanding on why this is happening.

rook2pawn avatar Dec 02 '21 22:12 rook2pawn

I think it would be helpful if anyone with context can help explain what is the proxy option, how it is implemented, and the relationship with ? Before more solution-ing, I think we could all appreciate a high level understanding on why this is happening.

Using ? causes a change in the redirected url, so that the original path is interpreted as variable. Since the redirected url doesn't contain any path information, it falls back to the default index.html.

johannesloetzsch avatar Dec 03 '21 13:12 johannesloetzsch

I really need this fix, so until my pull request or something similar is available at upstream, I published a package of the fork: https://www.npmjs.com/package/@johannesloetzsch/http-server

For those, using the nix package manager, there is also a branch, providing a reproducible build via a flake.nix: https://github.com/johannesloetzsch/http-server/tree/nix

johannesloetzsch avatar Dec 28 '21 16:12 johannesloetzsch

This issue has been inactive for 180 days

github-actions[bot] avatar Jun 27 '22 12:06 github-actions[bot]

Hi There,

Just to confirm that that issue is still an issue. I've noticed that it only seems to be post requests when a --proxy argument is passed to http-server. Furthermore,

If you pass --proxy http://www.google.com then http-server doesn't present the bug. I've tried it with POST and OPTIONS requests, GET is fine, others may not be ok either

chris-pilot-group avatar Aug 02 '22 10:08 chris-pilot-group

yeah... also seem I can't get CMD [ "http-server", "--proxy http://localhost:8080?", "dist" ] to work

tvld avatar Nov 23 '22 13:11 tvld