Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2019-16784-POC — Un exploit de prueba de concepto para PyInstaller CVE-2019-16783 | Kitploit
Herramientas/GitHubGitHub/ckrielle/cve-2019-16784-poc
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónDesarrollo de PayloadsExplotación de BinariosLabs y Práctica
GitHubckrielle/cve-2019-16784-poc

CVE-2019-16784-POC

Un exploit de prueba de concepto para PyInstaller CVE-2019-16783

Ver Repositorio
2hace 2 añosAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2019-16784 POC

Este es mi POC para la vulnerabilidad de Windows PyInstaller versión < 3.6 que existe para la opción --onefile. Un atacante podría lograr la ejecución de comandos y posiblemente LPE secuestrando una DLL importada por la DLL del intérprete de Python utilizada por el binario de PyInstaller. A continuación, una breve explicación de la vulnerabilidad y el proceso de explotación. Mi agradecimiento a Alter Solutions por encontrar la vulnerabilidad y escribir sobre su hallazgo en PagedOut #3 (página 55 del pdf).

La Vulnerabilidad

La vulnerabilidad fue causada por una creación débil de un directorio utilizado por PyInstaller en tiempo de ejecución del binario ejecutado. PyInstaller construye un directorio _MEIPIDX en el directorio temporal del usuario y coloca diferentes cosas en él, como la DLL del intérprete de Python utilizada para ejecutar el código Python empaquetado en un ejecutable PE.

El problema con este proceso era que el directorio construido para NT AUTHORITY\SYSTEM era C:\Windows\Temp, lo que permitía a alguien tanto adivinarlo como escribir dentro de él. Por lo tanto, era posible un secuestro de DLL, por ejemplo, cuando se ejecutaba el intérprete de Python. Aquí está el commit que corrige la vulnerabilidad. En lugar de depender solo de algunas funciones API estándar para crear el directorio, los desarrolladores implementaron su propia función para tener más control sobre la creación del directorio.

El Proceso de Explotación

Como este fue mi primer POC, comentaré un par de problemas que encontré en el camino.

Configuración del Entorno de Pruebas

En primer lugar, configurar un entorno para este POC no fue particularmente difícil, ya que todo lo que necesitaba era la versión correcta del paquete. Sin embargo, cuando lo instalé, se bloqueaba:

root@kitploit:~
Traceback (most recent call last):
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
...
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\site-packages\PyInstaller\building\utils.py", line 653, in <genexpr>
    strip_paths_in_code(const_co, new_filename)
  File "c:\users\ckrielle\appdata\local\programs\python\python38\lib\site-packages\PyInstaller\building\utils.py", line 660, in strip_paths_in_code
    return code_func(co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize,
TypeError: an integer is required (got type bytes)

Después de buscar un poco, vi que mi versión de Python era la culpable (estoy usando 3.8.10). Mi versión de Python dificultó la instalación de cualquier otra versión 3.8.x, ya que al instalar, el instalador encontraba mi versión Python38 y devolvía un error. También intenté compilar otra versión 3.8, pero no pude porque necesitaba Visual Studio 2015, mientras que tengo 2022. Finalmente, opté por descargar Python 3.7.5, que funcionó perfectamente. Así que creé un entorno virtual para la versión 3.7.

Entendí que configurar el entorno puede variar desde ya tenerlo listo hasta potencialmente llevar mucho tiempo configurarlo correctamente. Aunque es importante, podría restar diversión a la explotación real de nuestro objetivo.

Escribiendo el Exploit

Hay dos pasos en nuestro proceso de explotación: encontrar el directorio del proceso empaquetado con PyInstaller y escribir nuestra DLL de exploit allí. Para la primera parte, podemos encontrar el PID a través de las funciones estándar de WINAPI (CreateToolhelp32Snapshot, Process32First, Process32Next). Esto funcionó sin problemas. Después, necesitamos encontrar el último número del directorio _MEI. El exploit original sugiere usar solo la función GetFileAttributesA y verificar si el código de estado devuelto es FILE_ATTRIBUTE_DIRECTORY. Sin embargo, esto no me funcionó. Mi solución fue crear un archivo en cada candidato de directorio, y si el archivo se creaba con éxito, entonces el directorio existía. Por alguna razón, el estado devuelto para el archivo por GetFileAttributesA era FILE_ATTRIBUTE_ARCHIVE, así que verifico eso. Antes de continuar, el bucle mientras se busca el PID es porque queremos inyectar nuestras DLLs cuando se ejecuta el proceso objetivo, para tenerlas listas antes de que ocurra la carga.

Para la DLL, necesitamos secuestrar una DLL que el intérprete de Python (python37.dll) importa. Para obtener las DLLs que importa el intérprete, podríamos abrir la DLL con PE-Bear. Una de las DLLs del sistema importadas es version.dll. Así que podemos crear nuestra propia DLL y abusar del orden de búsqueda del cargador de Windows colocándola en el directorio temporal del proceso empaquetado con PyInstaller. De esa manera, cuando quiera importar la DLL, importará nuestra DLL maliciosa, en lugar de la correcta.

Importaciones de python37.dll

Sin embargo, hacer esto no funcionará. La razón es que la importación de la función que el intérprete de Python llama desde version.dll (específicamente VerQueryValueW de la imagen) no se resuelve. Por lo tanto, el programa se bloquea. Para solucionar este problema, necesitamos hacer proxy de DLL. En resumen, configuramos nuestra DLL maliciosa para exportar las funciones de la DLL original, y traemos la DLL original renombrada, para que pueda cargarla y llamar a la función desde allí. Así que para nuestro exploit, compilaremos una DLL maliciosa con un DllMain que nos permita lograr nuestra ejecución de código. Exportaremos todas las funciones de version.dll, y copiaremos la DLL original del sistema version2.dll y la colocaremos en el mismo directorio. De esa manera, version.dll puede reenviar las llamadas de función a version2.dll. Y una vez que tengamos estas DLLs, todo lo que necesitamos hacer es copiarlas en el directorio del proceso y esperar a obtener ejecución de código. Para una mejor explicación de Proxy/Secuestro de DLL, lea el artículo enlazado.

Funciones exportadas de la DLL maliciosa version.dll

Aunque en retrospectiva estos pasos son todos fáciles y directos, no lo fueron mientras desarrollaba el POC. Hace un tiempo, me llevó un poco entender el proceso del exploit, y una vez que empecé a programar comencé a entenderlo más. En cuanto a la DLL, intenté compilarla yo mismo de la manera que se insinuaba en el repositorio de POC de Alter Solutions. Tienen una DLL separada para la ejecución de código y otra diferente para el proxy, que cargaba la payload.dll en tiempo de ejecución (DllMain se llama al cargar). Sin embargo, no pude compilarla correctamente. Al final, después de leer el artículo anterior, decidí usar el repositorio DLLProxyProject, que compiló la DLL que quería, y se puede usar generalmente para producir una DLL para fines de proxy. Intenté copiar su archivo DLLMain.cpp y compilarlo con el archivo de encabezado exports.h. Y aunque se ejecutó, produjo un error:

root@kitploit:~
Fatal Python error: init_sys_streams: can't initialize sys standard streams
OSError: [WinError 6] The handle is invalid

Current thread 0x00002ea8 (most recent call first):

Este error podría evitarse con el archivo Utils.cpp, así que decidí mantener ese proyecto para mi compilación de DLL (aunque hubiera sido más agradable si lo hubiera hecho completamente yo mismo).

Explotando Nuestro Objetivo

Después de configurar el entorno (usé psexec para obtener un shell de NT AUTHORITY\SYSTEM), ejecuté el exploit, ejecuté el binario objetivo y obtuve ejecución de código como administrador.

Éxito del POC

Comentarios Finales

Esta fue una experiencia muy agradable, y estoy contento de haberla vivido. Realmente quiero producir más POCs para otros CVEs, y este fue un primer objetivo perfecto. Leer la descripción de la vulnerabilidad fue interesante, ya que entendí que la principal dificultad de implementar un POC tú mismo es llenar los espacios en blanco de cosas que el autor no explicó (ya sea a propósito o no), y simplemente entender lo que estás leyendo. Fue una vulnerabilidad simple, así que no invertí mucho esfuerzo en entenderla. En el futuro cercano, después de hacer un par más, intentaré hacer un POC para una vulnerabilidad de corrupción de memoria.

Descargar herramienta