The SSRF Vulnerability
The key issue for this vulnerability was that the route
/files/import
on Directus downloads and saves the response from a URL that is provided by the user. The original SSRF vulnerability (
CVE-2022-23080
) was exploiting this feature to download sensitive content from restricted IP addresses (eg.
127.0.0.1
). In response, Directus added a validation check for the
importOne
function in
/api/src/services/file.ts
to reject all URLs that resolve to an IP address within a block list (setting
IMPORT_IP_DENY_LIST
). The following JavaScript code was the code snippet from
importOne
in version
v9.22.4
.
let ip = resolvedUrl.hostname;
if (net.isIP(ip) === 0) {
try {
ip = (await lookupDNS(ip)).address;
} catch (err: any) {
logger.warn(err, `Couldn't lookup the DNS for url ${importURL}`);
throw new ServiceUnavailableException(`Couldn't fetch file from url "${importURL}"`, {
service: 'external-file',
});
}
}
if (env.IMPORT_IP_DENY_LIST.includes('0.0.0.0')) {
const networkInterfaces = os.networkInterfaces();
for (const networkInfo of Object.values(networkInterfaces)) {
if (!networkInfo) continue;
for (const info of networkInfo) {
if (info.address === ip) {
logger.warn(`Requested URL ${importURL} resolves to localhost.`);
throw new ServiceUnavailableException(`Couldn't fetch file from url "${importURL}"`, {
service: 'external-file',
});
}
}
}
}
if (env.IMPORT_IP_DENY_LIST.includes(ip)) {
logger.warn(`Requested URL ${importURL} resolves to a denied IP address.`);
throw new ServiceUnavailableException(`Couldn't fetch file from url "${importURL}"`, {
service: 'external-file',
});
}
Simplifying what the above code does:
-
If the hostname is a domain it
resolves the IP address for the domain
(foreshadowing).
-
Checks if the resolved IP address is within a block list to prevent accessing restricted IPs (eg.
127.0.0.1
).
-
If the resolved IP address is allowed, then it will send a request using
axios
and saves the response.
The issue with this process is that domain names are
resolved twice
. The first time for validating the destination IP address and when
axios
sends a request
. Therefore, we can bypass the SSRF validation by resolving a domain to an allowed address then resolving to a blocked IP address!
But how on earth can you do that?
DNS Rebinding This Vulnerability
DNS rebinding is an attack method that manipulates the resolution of domains. Broadly explaining how it works, the attacker can configure a DNS server with a short time to live (TTL) record that prevents resolved domains being cached and switching the IP addresses.
For this vulnerability, an attacker can bypass the SSRF validation by resolving to an allowed IP address for the first DNS query then to a blocked one when
axios
sends a request to access sensitive content.
The Exploit
I was way too lazy to configure my own DNS server. So I just used
rebinder
that generates a domain that randomly resolves to two different IP addresses. For an example,
7f000001.8efa468e.rbndr.us
will resolve to either
142.250.70.142
or
127.0.0.1
randomly.
To demonstrate the vulnerability, I ran a static web server listening on
127.0.0.1
on my Directus server that had a
secret file
at
http://127.0.0.1/secret.txt
. Then spammed the following request with the domain
7f000001.8efa468e.rbndr.us
until I was lucky enough to have the domain resolve to
142.250.70.142
first then
127.0.0.1
to access
http://127.0.0.1/secret.txt
.
To confirm the SSRF bypass was successful, the following screenshot shows that request to
http://127.0.0.1/secret.txt
was sent by Directus (IP address
127.0.0.1
).
You can then download the response as a file from Directus to steal the sensitive data.
Noice
A Note About Using Redirection to Bypass the SSRF Validation
Now some of you might of noticed that DNS rebinding was a
little bit overkill
for bypassing the SSRF validation check. Another method to bypass the SSRF vulnerability would be simply redirecting the
axios
request to the blocked IP address.
Yes redirection would have bypassed the SSRF validation.
However, I decided to demonstrate a DNS rebinding attack over redirection to reduce the risk that the patch would still have a bypass. If the developers just patched the redirection SSRF bypass, then there is a possibility that DNS rebinding could still work to bypass the SSRF validation. However, if the DNS rebinding method was prevented it would also prevent redirection attacks since a fix for DNS rebinding would also patch redirection attacks.
Speaking of which...