XPATH Injection Java

From OWASP
Jump to: navigation, search

Last revision (mm/dd/yy): 03/06/2012


Contents

Injection context

Some applications use XML based datastore and sometimes XPATH query language to retrieve data from theses stores. The application can construct XPATH query expression from user input in order to select user dedicated data.

Injection objective

The objective of the injection is to submit a piece of XPATH language that will change the normal behavior of the target expression in order to retrieve more or differents data than expected.

Injection examples

For the examples we will take a case of an application that store employees informations using XML store with this structure:

<?xml version="1.0" encoding="utf-8"?>
<employees>
  <employee id="AS789" firstname="John" lastname="Doo" annualsalary="70000"/>
  <employee id="AS719" firstname="Isabela" lastname="Dobora" annualsalary="90000"/>
  <employee id="AS219" firstname="Eric" lastname="Lambert" annualsalary="65000"/>
</employees>

The XPATH expression to select an employee node used by application is:

/employees/employee[@id='EMPLOYEE_ID']

The code (JavaEE6 Servlet for example) used to perform selection is:

package org.owasp.javaproject.xpathinjection;

import java.io.IOException;
import java.io.StringReader;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.jaxen.XPath;
import org.jaxen.dom.DOMXPath;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

/**
 * Sample service to retrieve employees salary
 */
@SuppressWarnings("serial")
@WebServlet("/EmployeesSalaryService")
public class EmployeesSalaryService extends HttpServlet {

	private static final String DATASOURCE_XML = "Put XML Structure above here";

	/**
	 * {@inheritDoc}
	 * 
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// For the sample we load the XML Document at each request but this not a good way for real application.....
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(new InputSource(new StringReader(DATASOURCE_XML)));

			// Retrieve employee ID from the input HTTP request
			String eID = request.getParameter("employeeID");
			if (eID == null) {
				eID = "";
			}

			// Create XPATH expression
			String xpathExpr = "/employees/employee[@id='" + eID + "']";
			XPath expression = new DOMXPath(xpathExpr);

			// Apply expression on XML document
			List nodes = expression.selectNodes(doc);
			for (int i = 0; i < nodes.size(); i++) {
				Element employee = (Element) nodes.get(i);
				response.getWriter().print(employee.getAttribute("lastname") 
				+ " " 
				+ employee.getAttribute("firstname") 
				+ " : " 
				+ employee.getAttribute("annualsalary") 
				+ "<br>");
			}
		} catch (Exception e) {
			response.sendError(HttpServletResponse.SC_BAD_REQUEST);
			e.printStackTrace();
		}
	}

}

Here the sensitive information is the annual salary then it's will be the target of the injection.

The application expect to receive, for the employee ID, an value like "AS789" but what is the application behavior if a user submit another value pattern ?

Sample value n°1:

'%20or%20'1'='1

Result: All employees nodes are selected (in this case the user do not known the XML structure).

XPATHInjection01.png

Sample value n°2:

'%20or%20fn:contains(fn:lower-case(@lastname),'dobora')%20or%20'

Result: Employee where the last name contains "dobora" is selected (in this case the user has guessed the XML structure).

XPATHInjection02.png

Injection countermeasure

Input used into an XPATH expression must not contains any of the characters below:

( ) = ' [ ] : , * / WHITESPACE

According to our example context, the modification to apply can be to create an application transversal utility method that check the presence of characters above and reject the value submitted if it's contains any one.


Checking utility method example:

public boolean checkValueForXpathInjection(String value) throws Exception {
	boolean isValid = true;
	if ((value != null) && !"".equals(value)) {
		String xpathCharList = "()='[]:,*/ ";
		// Always to avoid encoding evading....
		String decodedValue = URLDecoder.decode(value, Charset.defaultCharset().name());
		for (char c : decodedValue.toCharArray()) {
			if (xpathCharList.indexOf(c) != -1) {
				isValid = false;
				break;
			}
		}
	}
	return isValid;
}


Checking utility use example:

/**
 * {@inheritDoc}
 * 
 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 */
@SuppressWarnings("rawtypes")
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	try {

		// Check input
		if (!checkValueForXpathInjection(request.getParameter("employeeID"))) {
			response.sendError(HttpServletResponse.SC_BAD_REQUEST);
			// Trace injection
			// Exit
			return;
		}

		.....

		}
	} catch (Exception e) {
		response.sendError(HttpServletResponse.SC_BAD_REQUEST);
		e.printStackTrace();
	}
}

Note

See into your web framework if validation content methods exists or use OWASP dedicated API ;o)