Let me first apologize for the long absence. However, I haven’t been idle. I’ve been working hard to take the OWASP Serverless Top 10 project to its next stages: an open-call to collect as much data as possible, then the final publishing of a serverless-designated top 10 report that will serve as the go-to for every serverless security practitioner and developer. Now, let’s dive into the next security risk in the OWASP Serverless Top 10 XML Attacks or XML External Entity (XXE) attacks.
Personally, I think this risk will not be one of the attacks that get to the final guide. First, cloud functions often run in a closed environment, such as VPC or VNet. So, unless the external-facing function interacts directly with the targeted XML, there is a good chance that this resource will not be able to communicate outside at all. Meaning, the attacker will not be able to steal data in a straightforward, common attack.
But, that’s not all. Another reason for this attack to get off the headlines is the fact that most of the providers have their XML parser as part of their out-of-the-box SDK and it is usually secured by default. So, unless the developer messes with it and opens some backdoors, the default configuration will prevent the parser from parsing external entities.
To be clear – if you’re a developer – use the given XML parsing libraries, but do not add insecure configuration to it, like enabling external DTDs, etc. And, here is your designated meme:
Oh, but we’re just starting with the shaming. Let’s inspect the typical vectors and impacts of XXE attacks. The most common XXE use case is to read local files on the server. If you remember my previous post in the series, sensitive files on the environments can be either the source code of the function itself, or any file that is processed under the /tmp folder.
So an attack, targeting /etc/passwd is not interesting here. But, it’s a risk nonetheless. Instead of sending this payload:
A serverless XXE attacker would send the following payload. Assuming that the developer chose to ignore everything we said so far, this attack could still work:
Another outcome associated with traditional XXE attacks is Denial of Service (DoS), in which the attacker sends a payload that will force the XML parser to consume all the server’s resources until it crashes. One example is the Billion Laughs Attack. However, in this case, the ephemeral nature of serverless provides each incoming request with a designated environment and not only that, most functions do not live more than 30 seconds. So, yes. If the attacker is consistent it might cost a few (very few!) bucks, but it will most definitely not prevent any other user from being served.
The only way it could cause a real DoS, is if the developer really really wants to help the attackers and not only gives a long, unnecessary timeout to the function (up to 15 min), but also sets a low concurrency limit for the function. But, hey – I‘ve seen things before… evil things. &lol.
Other traditional XXE attacks might try to perform a type of SSRF attack, forcing the XML parser to make network requests within the local network, leading to the possibility of further escalation for the attacker. What about serverless? A standard execution of a function has no “internal network.” It leaves on a closed environment, controlled by the provider. If you found an escape – XXE is the least of the problems.
However, there could be serverless architectures where some other cloud resources share the same private subnet as a function that handles the XML parsing. But even if this scenario exists, you will usually not find resources that are accessible directly, without protection.
Don’t believe anything I said. Let’s try. A simple function that reads an XML file from an s3 bucket and parses it:
Uploading the following “good” XML:
Now, let’s look at the logs for our print. Normal:
With “evil” XML:
Out-of-Bound… still nothing:
However, if the developer REALLY wants to, he can open it to some trouble… a slightly modified function. This time the developer enabled DTD:
Let’s have a billion laughs:
After setting the function to 10 minute timeout with 192 mb memory:
According to AWS Lambda pricing, each 100ms on 192 mb function costs $0.000000313. Based on that, to cost the organization $1, the attacker would need to execute more than 10,000 of such “DoS” attacks, on a typical 30 second timeout function. Totally worth it. &lol
Enough with the negativity, let’s see an example of an attack that does work. At least partially. In this example the developer is using the lxml library, and manually making it insecure, by modifying the resolve_entities, load_dtd and no_network flags to the opposite of their default value:
In this case, by sending a simple XXE payload I could cause the XML parser to fetch the function’s source code.
How to Prevent XML Attacks?
Protecting Against the OWASP Serverless Top 10 XML Attacks
Bottom line, the attack exists, if you deal with XML you should be aware of the risks and try not to enable configurations that were disabled in the first place. Other than that:
- Use the service provider’s SDK whenever possible
- Scan supply chain for relevant libraries known vulnerabilities
- If possible, identify and test for XXE attacks via API calls
- Make sure to disable Entity Resolution
And if you can’t? Use Protego’s Function Self Protection and we’ll do that for you.