Antes de ver una inyección de XPath, veamos que es el lenguaje XPath:

"XPath (XML Path Language) es un lenguaje que permite construir expresiones que recorren y procesan un documento XML. La idea es parecida a las expresiones regulares para seleccionar partes de un texto sin atributos (plain text). XPath permite buscar y seleccionar teniendo en cuenta la estructura jerárquica del XML. XPath fue creado para su uso en el estándar XSLT, en el que se usa para seleccionar y examinar la estructura del documento de entrada de la transformación".

Una de las virtudes de XPath, es que puede seleccionar información dentro de un documento XML, haciendo referencia a cualquier tipo de dato, mostrando el resultado en una representación en forma de "árbol de nodos". Dentro de cada árbol, existen diferentes tipos de nodos:

- Raíz.
- Elemento.
- Atributo.
- Texto.
- Comentarios.
- Instrucción de procesamiento.

Otro de los puntos fuertes son sus expresiones (instrucciones del lenguaje), en las que se incluyen operaciones, como por ejemplo los "location path": /usuario/contraseña. Esta operación hace referencia a todos los elementos contraseña que descienden de cualquier elemento usuario que a su vez, desciende el nodo raíz.

Operaciones a destacar:

- /usuario/dir[@private="si"] -> selecciona los elementos cuyo predicado private sea un "si".
- //usuario/nombre -> selecciona todos los nombre de los usuarios.
- //usuario/node() -> selecciona todos los nodos descendientes de usuario de cualquier tipo: text(), comment(), processinginstruction().

Funciones a destacar:

- count(): count(//usuario/child::node()) -> el resultado será el número de nodos de todos los usuarios.
- stringlength(string): stringlength(//usuario[position()=1]/child::node()[position()=1]) -> devolverá el tamaño del primer string del primer nodo del primer usuario.

- substring(string, num, num):substring((//usuario[position()=1]/child::node()[position()=1),1,1) -> devolverá la primera letra del primer nodo del primer usuario.

Una vez tenida una cierta idea de cómo funciona XPath, vamos a ver un ejemplo práctico para poder realizar la inyección XPath:

Estamos ante una aplicación común, en la que se nos pide el usuario y la contraseña para poder acceder a una zona privada. Como es habitual, tenemos dos entradas de texto, en la cuales estarán permitidas cadenas alfanuméricas y quizás algún carácter especial. Probamos a meter únicamente en el usuario una comilla simple ', y esperamos la respuesta de la aplicación. Con un poco de suerte, recibiremos un error de este estilo:

System.Xml.XPath.XPathException:
Error during parse of
string(//usuario[nombre/text()=''' and contraseña/text()='']/cuenta/text())
Bien, el error nos muestra información importante, ya que aparece la petición realizada y podemos deducir la estructura del xml al que hace referencia, que sería algo así:

<usuario>
<nombre></nombre>
<contraseña></contraseña>
<cuenta></cuenta>
</usuario>

Una vez conocida la estructura y como se realizan las peticiones, empezaremos a inyectar código. Probaremos a meter en el campo de usuario la siguiente instrucción ' or 1=1 or ''='. La petición realizada, quedaría de la siguiente manera "string(//usuario[nombre/text()='' or 1=1 or ''='' and contraseña/text()='']/cuenta/text())". Si todo sale bien, la consulta nos debería de devolver el primer usuario de la lista del xml, dándonos acceso a la aplicación.

Pero, ¿qué pasaría si el aplicativo no devuelve nada después de realizar peticiones en busca de usuarios, contraseñas, etc., si como hemos podido observar, el campo usuario parece ser vulnerable?, ¿significa eso que la aplicación no es vulnerable? Puede que sea así, pero también podríamos estar delante de un posible Blind XPath Injection.

En este caso, para saber si la consulta que realizamos nos devuelve algo, nos fijaremos si las respuesta recibida es verdadera o falsa. Imaginemos que tenemos un usuario y contraseña y necesitamos saber qué tipo de privilegio tiene, si es cuenta de administrador, usuario normal o invitado. Basándonos en la estructura obtenida anteriormente, la petición a realizar sería la siguiente:

' or substring((//usuario[position()=1]/child::node()[position()=3]),1,1)="a" or ''='
Lo que estamos pidiendo en la petición es que, queremos saber si la primera letra del tipo de cuenta del primer usuario es "a". Si la respuesta es verdadera, la aplicación nos devolverá una respuesta positiva, en este caso acceso al aplicativo. Si fuera una respuesta falsa, se recargaría la página del login de nuevo.


Como se puede observar, este tipo de inyección es muy parecida a la inyección SQL, pero como pasa con todo lo parecido, siempre hay algo distinto.


Néstor López del Moral, Dept. Auditoría S21sec
http://blog.s21sec.com/2010/07/xpath-injection.html