Zyxel GS1900: RCE sin autenticación explotada en la naturaleza (CVE-2026-107441)
Los conmutadores Zyxel GS1900 anteriores al parche 3 de la versión 2.90 aceptan una petición HTTP sin autenticación que ejecuta comandos como root.
Resumen
- Una escritura fuera de límites en
dispatcher.cgidel conmutador GS1900 permite a un atacante sin autenticación ejecutar comandos del sistema operativo como root. Binarly encontró el exploit en el conjunto de herramientas de un actor malicioso y lo probó en hardware real. - Diez modelos GS1900 con firmware 2.90(xxx.2)C0 o anterior están afectados. Zyxel publicó las versiones corregidas 2.90(xxx.3)C0 el 22 de octubre de 2026 y su aviso el 3 de noviembre de 2026.
- Zyxel la califica como 8.8 High y Binarly como 9.8 Critical en CVSS v3.1. GreyNoise observó 996 conmutadores explotados. CVE-2026-107441 no está en el catálogo KEV de CISA al 4 de noviembre de 2026; CVE-2026-7273 sí lo está, desde el 21 de septiembre de 2026.
- Actualice cada modelo de la lista a su versión 2.90(xxx.3)C0 ahora. Ninguna solución alternativa de configuración cierra la falla; consulte "¿Cómo lo corrijo?" para reducir la exposición mientras programa una ventana de mantenimiento.
¿Estoy afectado?
Todas estas condiciones deben cumplirse para que un conmutador esté expuesto:
- El dispositivo es uno de los diez modelos GS1900 que enumera Zyxel, con firmware 2.90(xxx.2)C0 o anterior.
- La interfaz de administración web del conmutador es alcanzable desde una red que el atacante puede usar. Zyxel describe al atacante como presente en la red local y adyacente. Binarly afirma que el exploit solo necesita alcanzar por HTTP el servicio de administración, sin adyacencia en el protocolo.
- No está instalado el firmware 2.90(xxx.3)C0 de ese modelo. La actualización 2.90(xxx.2)C0 de junio de 2026 no corrige esta falla.
Zyxel indica que los productos aún comercializados que no aparecen en su aviso no están afectados. El aviso enumera cada par de modelo y versión.
| Modelo | Versiones afectadas | Versión corregida |
|---|---|---|
| GS1900-8 | 2.90(AAHH.2)C0 y anteriores | 2.90(AAHH.3)C0 |
| GS1900-8HP | 2.90(AAHI.2)C0 y anteriores | 2.90(AAHI.3)C0 |
| GS1900-10HP | 2.90(AAZI.2)C0 y anteriores | 2.90(AAZI.3)C0 |
| GS1900-16 | 2.90(AAHJ.2)C0 y anteriores | 2.90(AAHJ.3)C0 |
| GS1900-24 | 2.90(AAHL.2)C0 y anteriores | 2.90(AAHL.3)C0 |
| GS1900-24E | 2.90(AAHK.2)C0 y anteriores | 2.90(AAHK.3)C0 |
| GS1900-24EP | 2.90(ABTO.2)C0 y anteriores | 2.90(ABTO.3)C0 |
| GS1900-24HPv2 | 2.90(ABTP.2)C0 y anteriores | 2.90(ABTP.3)C0 |
| GS1900-48 | 2.90(AAHN.2)C0 y anteriores | 2.90(AAHN.3)C0 |
| GS1900-48HPv2 | 2.90(ABTQ.2)C0 y anteriores | 2.90(ABTQ.3)C0 |
Compruebe qué ejecuta el conmutador:
- Inicie sesión en el configurador web del conmutador. La pantalla Getting Started muestra el Model Name y la Firmware Version, como una cadena del tipo
2.90(AAHL.2)C0. - Compare el modelo y la versión con la lista del aviso. Para los modelos enumerados, toda versión anterior a
.3)C0está afectada, incluidas.2)C0,.1)C0y.0)C0. Solo una versión terminada en.3)C0incluye el parche de noviembre. - El conmutador no tiene gestor de paquetes. Anote la versión en su inventario, porque un mismo número de modelo puede ejecutar varias versiones de firmware.
¿Cómo lo corrijo?
- Descargue el firmware 2.90(xxx.3)C0 del modelo exacto desde la biblioteca de descargas de Zyxel. El sufijo propio del modelo importa: un GS1900-8 usa AAHH, un GS1900-24 usa AAHL, etcétera. El aviso del 3 de noviembre enlaza la tabla de modelos y el anuncio de la versión.
- En el configurador web, abra Maintenance > Firmware Upgrade, elija HTTP, seleccione el archivo
.bixdel modelo y aplíquelo. Conserve la copia de seguridad de la configuración tomada antes de la actualización. - Tras el reinicio, vuelva a Getting Started y confirme que la Firmware Version muestra la versión
.3)C0. - Corrija todos los modelos enumerados, no solo el que mira a Internet. El exploit necesita alcanzar la interfaz de administración, y una VLAN de administración plana ofrece ese acceso tras cualquier compromiso.
Ninguna solución alternativa del proveedor cierra la falla. Si no dispone de una ventana de mantenimiento, reduzca la exposición mientras espera:
- Mueva la interfaz de administración a una VLAN de administración dedicada.
- Limite el acceso con reglas de cortafuegos que solo permitan hosts de administración conocidos.
- Desactive la administración WAN y la administración remota cuando el dispositivo ofrezca esas opciones.
- Vigile los cambios de configuración y los reinicios inesperados del conmutador.
Esas medidas solo reducen quién puede alcanzar el servicio vulnerable. No corrigen la falta de comprobaciones de límites, y Zyxel no publicó ninguna configuración que haga seguro el analizador. Un conmutador que sigue siendo alcanzable sigue siendo explotable.
¿Cuál es la causa raíz?
dispatcher.cgi es el programa CGI que hay detrás de las páginas de configuración web del conmutador. Se ejecuta bajo el servidor web Boa y analiza el cuerpo de una petición HTTP POST en un búfer global llamado reqParameters. El búfer tiene 0x23000 bytes, divididos en 140 ranuras de 1024 bytes. Un segundo global, count, registra cuántos parámetros se han analizado.
Binarly descompiló el firmware 2.90(AAHH.1)C0 y publicó el bucle vulnerable. La copia no tiene comprobación de longitud y el contador no tiene límite superior:
for ( pos = strchr(src, '&'); pos != nullptr; pos = strchr(pos + 1, '&') )
{
dest = &reqParameters[1024 * count];
memcpy(dest, src, pos - src);
dest[pos - src] = 0;
v10 = strchr(dest, '=');
if ( v10 != nullptr )
{
if ( v10[1] == '&' )
dest[512] = 0;
else
urlDecode(dest + 512, v10 + 1);
*v10 = 0;
}
src = pos + 1;
++count;
}
src es el cuerpo de la petición y pos marca el siguiente &. Para cada campo, el bucle calcula &reqParameters[1024 * count], copia todo hasta el separador e incrementa count. Un campo de más de 1024 bytes desborda su ranura. Nada comprueba que count se mantenga por debajo de 140.
Los dos globales están juntos en la sección .bss. El listado de IDA de Binarly muestra la disposición:
.bss:10003BC0 reqParameters: .space 0x23000
.bss:10026BC0 count: .space 4
El campo 140 es el desencadenante. Cuando count vale 139, la copia empieza en la última ranura, reqParameters[1024 * 139], y un campo de 1028 bytes escribe cuatro bytes más allá del final del búfer. Esos cuatro bytes son count. Un atacante que envía un valor de 32 bits en esa posición sustituye el contador de parámetros por un número arbitrario.
Después del bucle, un segundo bloque procesa el último campo, que no tiene & final. Reutiliza el count corrompido:
if ( -src < strlen(src) )
{
dest = &reqParameters[1024 * count];
len = strlen(src);
memcpy(dest, src, len);
dest[strlen(src)] = 0;
...
++count;
}
count se multiplica por 1024 en una expresión con signo de 32 bits. Un valor como 0x013bffff desborda el producto hacia un desplazamiento negativo, y dest apunta antes de reqParameters en lugar de dentro. La escritura cae en la tabla de desplazamientos globales (GOT) del proceso, la tabla de direcciones de funciones resueltas. El exploit elige la entrada de strcmp.
El programa llama después a web_util_paramVal_ret, que recorre la matriz de parámetros con strcmp(reqParameters, param). El primer parámetro, controlado por el atacante, es el comando que se ejecutará. Con la entrada strcmp sustituida por la dirección de system, la comparación se convierte en system("id") y se ejecuta con los privilegios del proceso CGI, que Binarly validó como root.
Un segundo modo de exploit corrompe los registros guardados y la dirección de retorno en lugar de la GOT. Regresa mediante un gadget de la uClibc del dispositivo para llamar a system. Ambos modos corrompen el mismo contador mediante la misma copia sin comprobación. El exploit capturado contiene direcciones codificadas para firmwares de 2.10 a 2.90 y ataca primero el GS1900-24.
¿Cómo se explota?
- El atacante envía una petición HTTP POST a
/cgi-bin/dispatcher.cgi. El cuerpo capturado contiene un primer campo con el comando, 139 separadores&, un campo de 1024 bytes seguido inmediatamente de un valor de contador de 32 bits, un separador y la dirección que el atacante quiere colocar en la GOT. web_util_initParaPairscopia cada campo enreqParameterssin comprobación de longitud. El campo 140 desborda la última ranura y sobrescribecountcon el valor de 32 bits.- El bloque fuera del bucle calcula
&reqParameters[1024 * count]con el contador corrompido. La multiplicación con signo desborda y el destino apunta antes del búfer global, a la entrada de la GOT elegida. - El mismo bloque copia el último campo en esa dirección y sustituye la entrada
strcmppor la dirección desystem. web_util_paramVal_retllama astrcmpcon el primer parámetro. La llamada llega ahora asystem, y el primer parámetro se ejecuta como root.
La petición no necesita sesión, credenciales ni interacción del usuario. Binarly probó el exploit en hardware real y en firmware emulado, y publicó la disposición de la petición y los dos modos. La muestra capturada es un script Python ofuscado con PyArmor; GreyNoise desofuscó el mismo script y encontró la misma corrupción del contador de parámetros.
¿Cómo se desarrolla el ataque?
Una sola petición HTTP sin autenticación corrompe el contador de parámetros, redirige un puntero de función en la GOT y convierte la siguiente comparación en un comando como root.
¿Qué puede hacer un atacante?
Un atacante que alcanza la interfaz web puede ejecutar comandos del sistema operativo como root en el conmutador. Binarly demostró la ejecución con system("id") en el proceso CGI y validó el contexto de trabajo como root. El aviso de Zyxel indica que la falla puede ejecutar comandos del sistema mediante una petición HTTP manipulada.
El impacto incluye leer y cambiar la configuración del conmutador. GreyNoise observó a un actor extraer datos de configuración, hashes de contraseña root e información de red de 996 conmutadores en 48 países. Esos registros dan al atacante la topología de administración y un hash de contraseña para atacar sin conexión.
El registro CVE de Zyxel asigna un CVSS v3.1 de 8.8, CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, porque trata el ataque como adyacente a la red. Binarly evalúa 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, porque el servicio de administración es HTTP y cualquier ruta hasta él basta.
Las condiciones son las mismas que en "¿Estoy afectado?": alcanzar por red la interfaz de administración, sin autenticación y sin interacción del usuario. Zyxel describe al atacante como presente en la red local y adyacente. Binarly evalúa el vector de ataque como red, porque el servicio es HTTP y un router o una regla NAT puede exponerlo más allá del segmento local.
Este artículo separa dos afirmaciones de explotación. GreyNoise atribuyó la actividad de agosto a CVE-2026-7273, la falla que Zyxel corrigió en junio. Binarly comprobó que el exploit capturado ataca la falla del analizador que después se denominó CVE-2026-107441.
Binarly también comprobó que las diez versiones corregidas en junio seguían siendo vulnerables. El acceso del actor y el robo de datos están establecidos por GreyNoise. La etiqueta CVE que pretendía el actor importa menos que el hecho de que el parche de junio no cerró el camino.
¿Por qué funciona la corrección?
El parche de noviembre comprueba el contador antes de calcular el destino y sustituye la copia sin límites por una función con límites. Binarly publicó el nuevo bucle:
for ( pos = strchr(queries, '&'); pos != nullptr; pos = strchr(pos + 1, '&') )
{
dest = &reqParameters[1024 * counter];
if ( counter >= 140 ) // the global counter is checked before the copy
return 0;
web_util_paramCopy(&reqParameters[1024 * counter], 512, src, pos - src);
...
++counter;
}
La prueba counter >= 140 se ejecuta antes de la copia, así que el campo 140 ya no puede alcanzar la ranura que contiene count. web_util_paramCopy limita cada campo a 511 bytes, así que un campo tampoco puede desbordar su ranura de 1024 bytes. Los dos cambios cierran las dos mitades de la falla: la corrupción del contador y la copia sin límites.
El parche de junio no lo hacía. Añadía estas comprobaciones:
if ( ++counter == 140 )
return 0;
...
if ( counter >= 141 )
counter = 140;
La primera comprobación se ejecuta después de la copia que corrompe counter. Una vez sobrescrito el valor, la prueba de igualdad falla y el bloque fuera del bucle se ejecuta igual. La segunda comprobación solo reinicia un contador que ya se usó para calcular un destino. Binarly probó las diez versiones corregidas en junio el 28 de septiembre de 2026 y encontró todas explotables.
El aviso de Binarly también recomienda activar Full RELRO para que la GOT sea de solo lectura. El aviso de Zyxel no dice si las nuevas versiones lo activan. El parche cierra la primitiva de escritura demostrada. No hace inmutable la GOT, así que trate Full RELRO como defensa en profundidad y no como sustituto de la actualización.
¿Cómo compruebo si estuve comprometido?
El conmutador puede no registrar el cuerpo de la petición POST que desencadena la falla. Empiece por el malware y la infraestructura de mando y control, y después revise lo que contenía el conmutador.
Binarly publicó hashes de la puerta trasera JITTERLY y del rootkit SIXZUT que deposita. Los valores SHA-256 de su aviso y su artículo son:
- JITTERLY:
0f6e757e82c4d91df5bd249f775b9970b59dee42cc0dfe40f879d77fc16821c6,663a8088faca8e126a11648f5671fcf4eaf96435e10daf63a1d1b17d8385154c,82d072ab03d90c0131b06a576eadf2c986a51f0de986d50db4e49be01bf125cb. - SIXZUT:
295133156b6a7d95b9c92f832f49e35235f1fbd3906e75c9202ef4cd65d1018c,64677002011bc2e4bc642a4154a20fdb95620ebd0144b98fc60f917901ec8b92,728810b07e911b235f6450e784391e39f68819a0a5d209662162916ffea25146.
El actor usó el dominio 981666[.]xyz con estos hosts:
p1.981666[.]xyz,p2.981666[.]xyz,p3.981666[.]xyz.s0.981666[.]xyzas9.981666[.]xyz.
El análisis de Binarly enumera estas direcciones IP: 104.223.65[.]148, 203.88.123[.]148, 104.225.153[.]141 y 166.88.227[.]181. El malware usó los puertos TCP 443, 6443, 8080, 8082, 5432 y 6379. Binarly publicó reglas YARA para JITTERLY y SIXZUT en su artículo.
Si un conmutador era alcanzable y no estaba corregido, suponga que se llevaron la configuración y el hash de la contraseña root. Cambie la contraseña del administrador local, las cadenas de comunidad SNMP y cualquier secreto RADIUS, TACACS+ o VPN almacenado en la configuración.
Revise los registros del conmutador por cambios de configuración, nuevos usuarios locales y reinicios inesperados. Un intento fallido puede no dejar rastro en el dispositivo, así que la ausencia de una entrada de registro no prueba que el conmutador esté intacto.
Cronología
El primer parche salió 140 días antes del aviso que lo sustituyó, y Binarly encontró las diez versiones corregidas todavía vulnerables 104 días después de ese primer parche.
- 2026-06-16: Zyxel publica el aviso CVE-2026-7273 y las versiones corregidas 2.90(xxx.2)C0.
- 2026-08-17: Alrededor de esta fecha, GreyNoise observa a un actor extraer datos de 996 conmutadores GS1900 en 48 países.
- 2026-09-21: CISA añade CVE-2026-7273 al catálogo Known Exploited Vulnerabilities.
- 2026-09-28: Binarly confirma que las diez versiones anunciadas como correcciones de CVE-2026-7273 siguen vulnerables.
- 2026-09-29: Binarly notifica al equipo de seguridad de producto de Zyxel.
- 2026-10-11: Zyxel confirma la nueva vulnerabilidad y reserva CVE-2026-107441.
- 2026-10-22: Zyxel publica el firmware 2.90(xxx.3)C0 para los diez modelos.
- 2026-11-03: Zyxel publica su aviso, Binarly publica BRLY-2026-057 y se publica el registro CVE.
Preguntas frecuentes
¿La actualización CVE-2026-7273 protege un conmutador GS1900?
No. La actualización 2.90(xxx.2)C0 del 16 de junio de 2026 añadió comprobaciones después de la copia vulnerable, y Binarly encontró las diez versiones corregidas todavía explotables el 28 de septiembre de 2026. Un conmutador necesita la versión 2.90(xxx.3)C0.
¿CVE-2026-107441 está en el catálogo KEV de CISA?
No, a 4 de noviembre de 2026, la nueva CVE no está en el catálogo Known Exploited Vulnerabilities. La anterior CVE-2026-7273 está en él desde el 21 de septiembre de 2026, con fecha límite federal del 24 de septiembre de 2026.
¿Qué modelos GS1900 están afectados?
Los diez modelos que enumera Zyxel están afectados en la versión 2.90(xxx.2)C0 y anteriores. Zyxel indica que los productos aún comercializados que no aparecen en su aviso no están afectados, así que compruebe el par de modelo y firmware en lugar del nombre de la familia.
¿Los ataques en la naturaleza usaron CVE-2026-107441?
GreyNoise vinculó la actividad de agosto con CVE-2026-7273. Binarly comprobó que el exploit capturado ataca la falla del contador de parámetros que después se denominó CVE-2026-107441, y que el parche de junio no la bloqueaba. Ambas etiquetas describen el mismo analizador, y el firmware de noviembre es la primera versión que cierra el camino demostrado por Binarly.
¿Puedo bloquear el ataque restringiendo la interfaz de administración?
Restringir la interfaz reduce quién puede alcanzar el servicio vulnerable, pero no corrige la falta de comprobaciones de límites. Zyxel no publicó ninguna solución alternativa que haga seguro el analizador. Un conmutador que sigue siendo alcanzable en cualquier interfaz sigue siendo explotable, así que programe la actualización.
¿La corrección es completa?
El parche de noviembre comprueba el contador antes de la copia y limita cada campo a 511 bytes, lo que cierra las dos primitivas de escritura demostradas por Binarly. Binarly también recomienda Full RELRO para impedir que se sobrescriba la GOT. El aviso de Zyxel no dice si las nuevas versiones lo activan, así que aplique el firmware y trate RELRO como un control adicional.
Encuentre conmutadores Zyxel GS1900 expuestos con Ostorlab
El descubrimiento de superficie de ataque de Ostorlab inventaría las interfaces de administración expuestas a Internet, incluidos los dispositivos de red, para saber qué conmutadores corregir primero. Úselo para encontrar las páginas de administración GS1900 que su organización expone antes que un atacante.
Referencias
- Zyxel, "Zyxel security advisory for out-of-bounds write vulnerability in GS1900 series switches" (3 de noviembre de 2026). https://www.zyxel.com/global/en/support/security-advisories/zyxel-security-advisory-for-out-of-bounds-write-vulnerability-in-gs1900-series-switches-11-03-2026 (verificado el 4 de noviembre de 2026)
- Zyxel, "Zyxel security advisory for stack-based buffer overflow vulnerability in GS1900 series switches" (16 de junio de 2026). https://www.zyxel.com/global/en/support/security-advisories/zyxel-security-advisory-for-stack-based-buffer-overflow-vulnerability-in-gs1900-series-switches-06-16-2026 (verificado el 4 de noviembre de 2026)
- Binarly, "Pre-Auth RCE in Zyxel GS1900 Exploited in the Wild as a Zero-Day" (3 de noviembre de 2026). https://www.binarly.io/blog/zyxel-gs1900-rce-cve-2026-107441 (verificado el 4 de noviembre de 2026)
- Binarly, "BRLY-2026-057: Out-of-bounds write vulnerability in Zyxel GS1900 switches" (3 de noviembre de 2026). https://www.binarly.io/advisories/brly-2026-057 (verificado el 4 de noviembre de 2026)
- GreyNoise, "Open Season on Kapibala: Attacker Steals Over 18,000 Government Records Through WordPress Exploitation" (28 de septiembre de 2026), sección sobre la campaña contra los ZyXEL GS1900: 996 conmutadores en 48 países, atribuida a CVE-2026-7273. https://www.greynoise.io/blog/open-season-on-kapibala-attacker-steals-government-records-wordpress-exploitation (verificado el 4 de noviembre de 2026)
- CVE Program, "CVE-2026-107441" (publicado el 3 de noviembre de 2026). https://www.cve.org/CVERecord?id=CVE-2026-107441 (verificado el 4 de noviembre de 2026)
- CVE Program, "CVE-2026-7273" (publicado el 16 de junio de 2026). https://www.cve.org/CVERecord?id=CVE-2026-7273 (verificado el 4 de noviembre de 2026)
- Zyxel, "GS1900 Series User's Guide, V2.90 edition 2" (páginas 61 y 242). https://download.zyxel.com/GS1900-8/user_guide/GS1900-8_V2.90_Ed2.pdf (verificado el 4 de noviembre de 2026)
- CISA, "Known Exploited Vulnerabilities Catalog" (feed verificado el 4 de noviembre de 2026). https://www.cisa.gov/known-exploited-vulnerabilities-catalog (verificado el 4 de noviembre de 2026)