Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
rook2pawn opened this issue Oct 23, 2021 · 13 comments

Comments

@rook2pawn
Copy link

rook2pawn commented Oct 23, 2021

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.
rook2pawn@6645278

@rook2pawn rook2pawn changed the title Powerful attack on http-server caught in wild. Forces out of memory attack Proxy ? based powerful attack on http-server caught in wild. Can force out of memory Oct 23, 2021
@thornjad
Copy link
Member

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?

@rook2pawn
Copy link
Author

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
Copy link
Author

rook2pawn commented Oct 30, 2021

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)

@kade-d
Copy link

kade-d commented Nov 12, 2021

+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.

@rook2pawn
Copy link
Author

rook2pawn commented Nov 12, 2021

@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.

@padapada09
Copy link

padapada09 commented Nov 22, 2021

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

@johannesloetzsch
Copy link

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…

@rook2pawn
Copy link
Author

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.

@johannesloetzsch
Copy link

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 added a commit to johannesloetzsch/http-server that referenced this issue Dec 3, 2021
Allows serving of SPAs
* with correct status code 200
* without using the defekt `Catch-all redirect`

fixes issue http-party#757
@johannesloetzsch
Copy link

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

@github-actions
Copy link

This issue has been inactive for 180 days

@github-actions github-actions bot added the stale label Jun 27, 2022
@chris-pilot-group
Copy link

chris-pilot-group commented Aug 2, 2022

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

@github-actions github-actions bot removed the stale label Aug 2, 2022
@tvld
Copy link

tvld commented Nov 23, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants