Injection Attacks
XPath - Blind Exploitation
After discussing how to exfiltrate data by manually iterating through the entire XML schema, we will now focus on the blind exploitation of XPath injection. In cases where the web application does not display the query results to us, it is still possible to exfiltrate data with a methodology similar to blind SQL injection. However, there is no sleep function in XPath, so we need an indicator by the web application that tells us whether the query returns any results. This leaks binary information to us, which allows us to exfiltrate data without it being displayed.
Methodology
We will discuss how to exfiltrate the XML schema first, allowing us to inject XPath queries to target the interesting data. This enables us to exfiltrate the name of element nodes to construct XPath queries without wildcards to narrow our queries to target interesting data points. To do so, we can use the name(), substring(), string-length(), and count() functions. The name() function can be called on any node and gives us the name of that node. The substring() function allows us to exfiltrate the name of a node one character at a time. The string-length() function enables us to determine the length of a node name to know when to stop the exfiltration. Lastly, the count() function returns the number of children of an element node.
We will discuss the methodology for blind data exfiltration based on our sample web application with an XPath injection in a predicate of the XPath query.
Note: If the XPath injection point is not inside of a predicate, we can apply the same methodology as discussed below by appending our own predicate.
Exploitation
When starting the web application below, we can see a message board web application that allows us to message users of the platform anonymously by providing their username:
Whether we provide a valid username or not, the web application reacts differently. If we provide a valid username, it tells us that the message was successfully sent:

However, if the username was invalid, we get a different response:

Confirming XPath Injection
Before starting the blind exploitation, we must determine whether the web application is vulnerable to XPath injection. Since the username we provide is checked for validity, we can assume it is used in an XPath query similar to the following:
/users/user[username='admin']
Thus our provided username is inserted into a predicate. We can confirm this suspicion by supplying the username invalid' or '1'='1. This results in the following XPath query:
/users/user[username='invalid' or '1'='1']
The username we provided is invalid, however, the query should still return data due to our injected or clause, which results in a universally true predicate. Thus, the web application responds as if we provided a valid username:

Therefore, we confirmed that the web application is vulnerable to blind XPath injection.
Exfiltrating the Length of a Node's Name
To exfiltrate the length of the root node's name, we can use the payload invalid' or string-length(name(/*[1]))=1 and '1'='1, resulting in the following XPath query:
/users/user[username='invalid' or string-length(name(/*[1]))=1 and '1'='1']
The query /*[1] selects the root element node. Since the username invalid does not exist and '1'='1' is universally true, this query returns data only if string-length(name(/*[1]))=1 is true, meaning the length of the root element node's name is 1. In our case, the query does not return any data:

Thus, our guessed length of 1 was incorrect. Now we need to increment the length until we find the correct value, which in our case is 5:

Thus, we successfully determined the length of the root node's name to be 5.
Note: We can use other operators like <,<=,>, and >= to speed up the search.
Exfiltrating a Node's Name
Now that we know the length of the node's name, we can exfiltrate the name character by character. For that, we can use the payload invalid' or substring(name(/*[1]),1,1)='a' and '1'='1, resulting in the following XPath query:
/users/user[username='invalid' or substring(name(/*[1]),1,1)='a' and '1'='1']
The above query returns data only if the first character of the root node's name equals a, which is not the case:

We need to iterate through all possible characters until we find the correct one, which in our case is u:

We successfully exfiltrated the first character of the root node's name. Now we can move on to the second character with the payload invalid' or substring(name(/*[1]),2,1)='a' and '1'='1 where we again have to check all possible characters until we find a match. If we repeat this until we reach the length we determined in the previous step, we can exfiltrate the full name of the root node as users.
Exfiltrating the Number of Child Nodes
To determine the number of child nodes for a given node, we can use the count() function in a payload like this: invalid' or count(/users/*)=1 and '1'='1, resulting in the following XPath query:
/users/user[username='invalid' or count(/users/*)=1 and '1'='1']
This query returns data if we successfully found the number of child nodes of the users node, which in our case is 2:

We can now return to the previous step and target the users node's first child by addressing it with /users/*[1]. Starting with the node name's length and then the name itself. We must repeat this step until we have reached the maximum depth. Furthermore, we can address siblings by increasing the position. For instance, we can target the users node's second child by addressing it with /users/*[2].
This way, we can iteratively exfiltrate the entire XML schema. In our case, doing so reveals the following schema:
<users>
<user>
<username>???</username>
<password>???</password>
<desc>???</desc>
</user>
<user>
<username>???</username>
<password>???</password>
<desc>???</desc>
</user>
</users>
Exfiltrating Data
Now that we know the XML schema, we can inject a targeted payload to exfiltrate the data we want to acquire. We can re-use the same methodology as before. Let us start with the username. First, we need to determine the username's length. For that, we can use a payload like this: invalid' or string-length(/users/user[1]/username)=1 and '1'='1, resulting in the following XPath query:
/users/user[username='invalid' or string-length(/users/user[1]/username)=1 and '1'='1']
In our case, we can determine the username's length to be 5:

Now we can move on to exfiltrate the username. Consider a payload like this: invalid' or substring(/users/user[1]/username,1,1)='a' and '1'='1, resulting in the following XPath query:
/users/user[username='invalid' or substring(/users/user[1]/username,1,1)='a' and '1'='1']
The above query returns data only if the first character of the first user's username equals a, which is the case:

Again, we can iterate through all characters until we successfully exfiltrate the entire username, admin. From our schema exfiltration, we already know that there are two users in total, so we can apply this methodology to all users and their properties to exfiltrate the entire data set.
Note: Writing a small script for this task is recommended.
Time-based Exploitation
XPath does not contain a sleep function, so exploitation similar to blind SQL injection is impossible in XPath injection vulnerabilities. However, we can abuse the processing time of the web application to create behavior similar to a sleep function. We need this in cases where the web application serves the same response, whether the XPath query returned data or not, and where we have insufficient information to cause a positive query outcome. An example in the previously discussed case would be if we cannot guess a valid username. For this example, we will focus on a web application that returns a generic response whether we provide a valid or invalid user:

In this case, we cannot apply the methodology discussed above. However, we can force the web application to iterate over the entire XML document exponentially, which takes a measurable amount of processing time. This can be achieved by recursively calling the count function with stacked predicates to force the web application to iterate over all nodes in the XML document exponentially. Consider the following payload in the username parameter:
invalid' or substring(/users/user[1]/username,1,1)='a' and count((//.)[count((//.))]) and '1'='1
This results in the following XPath query:
/users/user[username='invalid' or substring(/users/user[1]/username,1,1)='a' and count((//.)[count((//.))]) and '1'='1']
If the condition substring(/users/user[1]/username,1,1)='a' is true, the second part of the and clause needs to be evaluated, such that the web application evaluates count((//.)[count((//.))]) causing it to exponentially iterate over the entire XML document resulting in significant processing time. On the other hand, if the initial condition is false, the second part of the and clause does not need to be evaluated since the predicate will return false no matter what the second part evaluates. Therefore, the web application does not evaluate it. This difference in processing time enables us to determine whether our injected condition is true.
In our example web application, we know the first character of the first username is a, since this causes a processing time of 477ms:

A different character results in a processing time of 1ms:

We can combine this time-based exploit with the methodology described above to exfiltrate the XML schema followed by the XML data.
Remember that the processing time depends on the size of the XML document. If the XML document is small, we might need to stack additional predicates with calls to the count function to achieve a measurable difference in processing time. However, if the XML document is large, this payload can quickly cause a significant load on the web server, potentially resulting in Denial-of-Service (DoS). Thus, it is crucial to be careful with this kind of payload.
/ 1 spawns left
Questions
Answer the question(s) below to complete this Section and earn cubes!
Click here to spawn the target system!
Target:
Click here to spawn the target system!
+10 Streak pts
Table of Contents
Introduction to Injection Attacks
Introduction to Injection AttacksXPath Injection
Introduction to XPath Injection XPath - Authentication Bypass XPath - Data Exfiltration XPath - Advanced Data Exfiltration XPath - Blind Exploitation XPath Injection Prevention & ToolsLDAP Injection
Introduction to LDAP Injection LDAP - Authentication Bypass LDAP - Data Exfiltration & Blind Exploitation LDAP Injection PreventionHTML Injection in PDF Generators
Introduction to PDF Generation Vulnerabilities Exploitation of PDF Generation Vulnerabilities Prevention of PDF Generation VulnerabilitiesSkills Assessment
Skills AssessmentMy Workstation
OFFLINE
/ 1 spawns left