23

I found this website which talks about fixing a Redis vulnerability by exploiting that same vulnerability.

The website in question has a "patch me" button, and if you have a password-less Redis server running on your machine, it will patch it.

In other words, the website itself connects to the Redis Server in your computer and executes some commands.

If you look into the website code you find, predictably, this:

    var text = "the code to run";
    var bad = "EVAL "  + JSON.stringify(text) + " 0\r\n";
    var x = new XMLHttpRequest();
    x.open("POST", "http://localhost:6379");
    x.send(bad);

To my surprise, this works!

I thought the Cross-Domain Policy would stop this from running, but it doesn't.

Why does this work, and how can I now not be paranoid that every website I go into is reading the entire contents of my Redis server?

It is because it's only writing but not reading? Still, any website in the world could empty my local Redis server / write to anything else listening to a port in my machine without authentication.

Am I missing anything here?

Daniel Magliola
  • 413
  • 1
  • 4
  • 7
  • 3
    Do you mean Same-Origin Policy? That only applies to reading data from another origin, not sending it. – Neil McGuigan Jun 19 '15 at 16:06
  • 3
    BTW: if origin website is `https` this doesn't work anymore, as `http` AJAX to `localhost` is not allowed. (and `localhost` can't have a globally valid SSL certificate) – lapo May 31 '18 at 07:45

2 Answers2

11

Im surprised nobody has pointed out that the accepted answer (by meltdownmonk) is wrong.

"It will not break cross domain policy, because the request will not cross domains. It will stay local. One way to avoid cross domain policies, is to get the target victim to make the HTTP request themselves. Thus the request never crosses domains."

"It's not the website itself connecting to your Redis machine. It's you connecting to your Redis machine, executing client side code/scripts that you ran by clicking the link"

"The attacker doesn't have full control over the process. They rely on the owner of the Redis server to execute the code."

"...it's not the attacker that executes them, it's the owner, and so no Cross Domain Policies are violated."

This is not how the Same-Origin-Policy (SOP) and Cross Origin Resource Sharing (CORS) work. Of course the request will cross domains when a website tries to connect to localhost. Also it is the website itself trying to connect to your redis and not the user - the attacker does not have to rely on the user. There is no difference whether the code runs automatically in the background or if the user clicks a button.

A website is basically able to send requests to localhost on different ports and can thereby even run a port scan. The browser's CORS implementation will ensure that data cannot be read by javascript. Therefore, the attacker cannot steal data from localhost and send it to a server. This is only true of course as long as your services on localhost do not explicitly allow CORS requests to be made (when they sent allow-origin headers, the attacker can steal data).

Apart from this, requests are still possible and therefore CSRF attacks are also possible. Such a CSRF attack could be triggered with a simple javascript HTTP-request (which does not require a CORS preflight check), but also HTML form data sent via GET/POST and websockets can be used to establish a connection to local services.

So to sum it up, if you visit a website, this website will be able to send requests to your local services on your computer on different ports. Reading data from your local services is normally not possible.

maxeh
  • 346
  • 3
  • 15
  • 1
    Your answer is better than @meltdownmonk's but still technically wrong. CORS preflight only occurs for "non-basic" requests, which use custom headers, anything other than a few verbs (GET, POST, or HEAD), or anything other than a few content types. In general, if you could do it using an HTML form, you can do it using JS without triggering a preflight. Even setting the "withCredentials" property to true doesn't trigger a preflight (because form submissions are *always* with credentials, and preflights are only needed for things a form submission can't do). – CBHacking May 27 '20 at 09:57
  • Thanks for the information, however, it does not matter if there is a preflight request or not (depending on the browsers implementation) as CSRF is possible anyway and reading data is not possible - this was basically my main point. Still I have adjusted my answer according to your points. – maxeh May 27 '20 at 10:20
  • @Max to be clear, CBHacking is correct and the distinction does matter (although your answer is correct as-is). If the request is in anyway"nonstandard" then the browser will send a pre-flight request first and so even the write will not happen. Well, there are potential caveats if the server does things *really* insecurely.... – Conor Mancone May 27 '20 at 12:06
  • 1
    @max that's embarrassing! I will have to review and research a bit more and update. I was working with a bunch of CORS issues on a site I was hosting and based a lot of my answer on the experiences I had with that, but I must have misunderstood what was really happening. – meltdownmonk May 28 '20 at 12:07
-2

Was pointed out due to incorrect assumptions about the issue that this answer below is wrong. If I get a chance I will revisit, or just delete this answer. Sorry!

To answer the question: Yes a website can make an HTTP request to localhost. It will not break cross domain policy, because the request will not cross domains. It will stay local. One way to avoid cross domain policies, is to get the target victim to make the HTTP request themselves. Thus the request never crosses domains.

To help you understand the issue you described:

The attack is not sending any data out, nor is it making a connection to anywhere other than the local Redis machine. It's not the website itself connecting to your Redis machine. It's you connecting to your Redis machine, executing client side code/scripts that you ran by clicking the link. Basically: You click link > Link downloaded and executes some code -> code generates an http request -> http request goes from your machine, to your machine.

The vulnerability of the Redis server in this situation is Cross Site Request Forgery. The attacker leverages the victims (in this case, the owner of the server) authentication to execute the attack.

The attacker doesn't have full control over the process. They rely on the owner of the Redis server to execute the code. Only the owner (or someone else local to the Redis server) has the visibility (and perhaps the permission and trust relationship) to access 127.0.0.1 (Localhost)

All that the code can do is execute commands that the local user can execute, but it's not the attacker that executes them, it's the owner, and so no Cross Domain Policies are violated.

The only people affected by links like that would be people running Redis servers. If you don't have one, the link won't do anything. Also, it will only run on the local Redis server. The attacker can't really choose where the exploit will happen.

Look up Cross Site Request Forgery. https://en.wikipedia.org/wiki/Cross-site_request_forgery

schroeder
  • 123,438
  • 55
  • 284
  • 319
meltdownmonk
  • 168
  • 4
  • I understand this, but... a) Me clicking the link was optional, he could've run the AJAX request onload. b) Even without a vulnerability in Redis, he could've happily had run FLUSHALL, for example. c) *with* the vulnerability, he can probably escape sandboxes and do nasty stuff. Again, with a piece of JS that could run onload on any website... But that's not my point, the point is writing to local ports on my machine... Most developers have local Redis without passwords, and I'm sure they don't know browsing the web could clear their Redis DBs... I wonder how many other things like this I have – Daniel Magliola Jun 19 '15 at 14:11
  • 1
    There is a reason websites are not allowed to do stuff, like, for example, writing to your hard drive, or deleting files. It wouldn't be the website, it'd be you, running the code in the website, with your priviledges, so they could only access files you can access, but that doesn't quite mitigate it. In this case, "all they can do" is clean / write to my local Redis server. That sounds pretty bad on its own, but I wonder what other services I have running that you could write to and harm me in some way... – Daniel Magliola Jun 19 '15 at 14:13
  • I'm not sure what your question is then... You are correct, Cross Site Request Forgery could be a vulnerability in other services you run. – meltdownmonk Jun 19 '15 at 14:16
  • There are things Redis could do that would ensure their server can't be cleaned or written to. Usually using nonces (random one time use numbers) that are required for each request/command to the server. The attacker won't be able to supply these from their script. – meltdownmonk Jun 19 '15 at 14:18
  • This could also apply to an unsecured, local MySQL server, couldn't it? Couldn't someone write commands to MySQL using this same technique? (just using MySQL as an example) – Daniel Magliola Jun 19 '15 at 14:23
  • Yes, SQL injection could happen via Cross Site Request Forgery (CSRF), but it would require the MySQL server to be accessible via a web interface that can send commands to it. The attacker needs to find a way to get you to run a script that executes commands that you (the owner of the MySQL server) have access to. CSRF depends on a web application that has the ability to execute dangerous commands. If the web application can execute powerful MySQL commands, then that could be a problem. – meltdownmonk Jun 19 '15 at 14:29
  • There are plenty of Web Applications with CSRF vulnerabilities such as: wordpress, drupal (known vulnerabilities get patched pretty quickly though) – meltdownmonk Jun 19 '15 at 14:34
  • So if MySQL would require a web interface, why doesn't Redis need one? – Daniel Magliola Jun 19 '15 at 14:34
  • Oh, my bad. Web interface in terms of: The server is listening on certain ports, and responds to http requests, like get and post. It doesn't need to be graphical. – meltdownmonk Jun 19 '15 at 15:21
  • Yeah, I got the non-graphical part. I just didn't know you could do HTTP requests to Redis, I thought it was plain text over TCP. Anyway, thanks for your answers! – Daniel Magliola Jun 22 '15 at 20:28
  • There are some wrong assumptions in this answer - have a look at my answer: https://security.stackexchange.com/a/232277/88501 – maxeh May 27 '20 at 09:42
  • Indeed. This answer is completely wrong. The explanation grossly misunderstands the same origin policy and how this hotfix works. – Conor Mancone May 27 '20 at 11:55