User Tools

Site Tools


hack:xpath_injection_java

Contexte de l'attaque

Certaines applications utilisent des magasins de données basé sur la langue XML et parfois des requête XPATH pour récupérer des données dans ces thèses magasins. L'application peut construire des requêtes XPATH à partir des données entrées par l'utilisateur afin de sélectionner les données,

Objectif de l'attaque

L'objectif de l'injection est de présenter une partie du langage XPath qui va changer le comportement normal de l'expression cible afin de récupérer des données plus ou moins differentes que prévu.

Exemples d'injection pour les exemples nous allons prendre un cas d'une application qui stocke les informations des employés en utilisant des magasins XML avec cette 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>

L'expression XPath pour sélectionner un noeud d'employé utilisé par l'application est la suivante:

/employees/employe [@ id = 'employe_id']

Le code (JavaEE6 servlet par exemple) utilisé pour effectuer la sélection est:

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();
		}
	}
 }

L' informations sensible étant le salaire annuel alors ce sera la cible de l'injection.

L'application s'attend à recevoir, pour l'identification de l'employé, une valeur comme “AS789” mais quel est le comportement de l'application si un utilisateur soumet un autre modèle de la valeur?

La valeur de l'échantillon n ° 1:

<nowiki>'%20or%20'1'='1</nowiki>

Résultat: Tous les noeuds employés sont sélectionnés (dans ce cas, l'utilisateur n'a pas besoin de connaître la structure XML).

  La valeur de l'échantillon n ° 2:

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

Resultat: Le employés dont le nom de famille contient «Dobora» sont sélectionnés (dans ce cas, l'utilisateur doit avoir deviner la structure XML).

Protection

Les informations entrées dans une expression XPath ne doivent aucun des caractères suivants:

() = '[]:, * / WHITESPACE 

Dans les cas présentés en exemple , la protection à appliquer pourrait être de créer un filtre permettant de vérifier la présence de caractères et de les rejeter.

Exemple de méthode de vérification:

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;
 }

Vérification de l'utilisation de cette méthode:

/**
 * {@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();
	}
 }
hack/xpath_injection_java.txt · Last modified: 2019/02/13 13:10 by 127.0.0.1