Introducción
El 16 de enero de 2025, Alexandra Alper de Reuters publicó un artículo titulado "Empresa tecnológica china fundada por veteranos de Huawei en el punto de mira del FBI". El artículo explora una investigación en curso del Departamento de Comercio de EE.UU. y el FBI sobre Baicells Technologies, una empresa señalada por posibles problemas de seguridad nacional.
Baicells, fundada en China en 2014, opera en Estados Unidos desde 2015 y suministra equipos de telecomunicaciones a más de 700 redes de todo el país, incluidas las utilizadas por ayuntamientos, centros sanitarios y empresas de servicios públicos. Aunque la empresa ha establecido una presencia significativa en el mercado estadounidense, sus orígenes chinos están suscitando el escrutinio de los reguladores federales, cada vez más recelosos de la influencia extranjera en las infraestructuras de comunicaciones básicas, especialmente dadas las vulnerabilidades críticas detectadas en su hardware.
Curiosamente, Censys desempeñó un papel menor en la investigación que respaldó esta investigación. Nuestra contribución se limitó a proporcionar datos de alto nivel sobre la exposición pública a Internet de los dispositivos de Baicells. Sin embargo, la generación de estas cifras requirió un importante análisis entre bastidores y nos llevó a una madriguera de descubrimientos. Este informe refleja nuestro proceso y ofrece una descripción técnica de los métodos que utilizamos para responder a la petición de Reuters.
Hay que señalar que Censys no tiene pruebas de que ninguna de las acusaciones sea cierta, ni estamos haciendo más acusaciones. Somos una parte neutral que no tiene nada que ver con el asunto. No hemos visto nada concreto que implique intenciones maliciosas por parte de Baicells. Este informe contiene información recopilada utilizando únicamente datos de acceso público para identificar los dispositivos de Baicells conectados a Internet.
Alcance y vulnerabilidades
Cuando Reuters nos preguntó por el recuento de hosts de Baicells, no teníamos cifras concretas porque era la primera vez que oíamos hablar del proveedor. Sin embargo, sabíamos que los datos probablemente existían dentro de nuestros recursos, sólo teníamos que encontrarlos. Nuestro objetivo principal era estimar cuántos dispositivos Baicells conectados a Internet eran vulnerables a CVE-2023-24508 y CVE-2023-0776. Pretendíamos conseguirlo sin realizar ninguna actividad que pudiera interpretarse como maliciosa o ilegal.
Resumen de los CVE revisados
- CVE-2023-24508: Una vulnerabilidad de nivel crítico de preautenticación que afecta a dispositivos como Nova 227, Nova 233 y Nova 243 eNodeBs LTE TDD que ejecutan firmware RTS.
- CVE-2023-0776: Una vulnerabilidad de nivel crítico previa a la autenticación que afecta a dispositivos como el Nova 436Q y el Neutrino 430 LTE que ejecutan firmware QRTB.
¿Qué es Baicells?

Arquitectura típica de red LTE (vía Fujitsu)
Baicells opera en un rincón especializado del sector de las telecomunicaciones, centrándose en el hardware que sirve de puente entre las redes móviles (por ejemplo, LTE y 5G) y las redes IP. Sus productos eNB(eNodeB), por ejemplo, se conectan a redes que interactúan con dispositivos físicos como teléfonos y se gestionan mediante sistemas basados en IP. Sus equipos abarcan una amplia gama de casos de uso y precios, desde robustos LTE para exteriores hasta routers 5G para oficinas domésticas.

Dado que los dispositivos Baicells se encuentran en una intersección tan crítica de la infraestructura de red, su seguridad es de suma importancia; la posibilidad y la probabilidad de que se vean comprometidas no deben tomarse a la ligera, sobre todo teniendo en cuenta que se sabe que estos dispositivos funcionan dentro de las propiedades del gobierno y el ejército de Estados Unidos.
Aunque esto confirmaba la presencia de estos dispositivos en línea, era necesario seguir investigando para determinar su modelo y versiones de firmware, que son dos datos fundamentales que necesitaríamos para determinar si estos dispositivos eran vulnerables a los dos CVE en cuestión.
Nos dimos cuenta de que un subconjunto de los resultados que encontramos en nuestra búsqueda inicial incluía lo que parecía un nombre de modelo en el cuerpo de la respuesta HTTP definido en una variable javascript, por ejemplo "moduletype='BRU3510′;"

Cuando buscamos algunos de estos supuestos nombres de modelo en la web, encontramos un puñado de documentos técnicos relacionados con Baicells, incluida la redacción explícita relacionada con las estaciones base LTE Nova de Baicells.

Encontramos que las interfaces web que habíamos descubierto con esta información estaban todas relacionadas con la marca Nova (RTS) de dispositivos Baicells potencialmente vulnerables a CVE-2023-24508. A continuación se muestra una tabla de los dispositivos Nova conocidos, seguida de los términos de búsqueda de Censys conocidos que utilizamos para identificar un subconjunto de los mismos. Obsérvese que los nombres de los modelos que excluimos de las búsquedas no se encontraron en nuestro conjunto de datos.
 |
Nova 243 |
BRU3501,3510,3511,3528 |
 |
Nova 233 |
mBS1100,1105,11002,11003,11004,11005,11006,11007 |
 |
Nova 277 |
pBS2120,11001,11002,11003,11004,11005,11006 |
En este punto, habíamos encontrado pruebas de hardware que ejecutaba la línea de firmware RTS (CVE-2023-24508), pero aún no habíamos encontrado nada relacionado con dispositivos QRTB (CVE-2023-0776). Sin embargo, todavía había muchos dispositivos Baicells por ahí que quedaban fuera de los términos de búsqueda anteriores.
Identificación de QTRB
Dado que ninguno de los nombres de modelo que aparecieron en nuestra búsqueda inicial coincidía con ninguno de los dispositivos relacionados con CVE-2023-0776, queríamos determinar si había algún mecanismo disponible que pudiera ayudar a su descubrimiento. Comenzamos este proceso descargando y descomprimiendo el firmware QTRB disponible públicamente desde el sitio web de Baicells.
Al examinar los archivos servidos por el servidor web de cara al público, identificamos campos únicos dentro del HTML que podían distinguir los dispositivos Baicells de los no derivados de QTRB. En concreto, el archivo "www/pages/index.html" contenía dos identificadores de campo de formulario distintivos: "loginRuleForm" y "loginRules".

Esto nos permitió crear una sencilla consulta de búsquedaCensys adaptada a estos criterios, lo que nos proporcionó una base para futuras consultas dirigidas a dispositivos QTRB. En el momento de nuestro informe inicial a Reuters, esto coincidía con más de noventa hosts.
A continuación, nos propusimos descubrir puntos finales públicos adicionales en estos dispositivos que pudieran proporcionar nombres de modelos específicos y versiones de firmware. Para ello, realizamos una simple búsqueda grep del término "versión" en todos los archivos HTTP de acceso público del firmware, centrándonos en el directorio "cgi-bin", una ubicación habitual para los datos generados dinámicamente.

El archivo más notable que hacía referencia a una versión era "www/pages/cgi-bin/overview.htm", que extraía los valores "software_version" y "hardware_version" del sistema subyacente y los presentaba al cliente. Como se muestra en la siguiente captura de pantalla, este proceso es una serie de comandos del sistema, con su salida asignada a variables JavaScript.

A continuación, combinamos la CLI Censys con el cliente HTTP "curl" para confirmar que estos puntos finales muestran efectivamente la versión de software (firmware) al usuario. Usando Censys, identificamos los hosts y puertos que coincidían con los criterios de búsqueda mencionados anteriormente, luego pasamos la información del host a curl para solicitar la ruta "/cgi-bin/overview.htm".
censys search --pages -1 \
'services:(http.response.body: "loginRuleForm" and http.response.body: "loginRules")' | \
jq -cr '.[]|.ip as $i|.name as $n|.matched_services[]|"\(.extended_service_name|ascii_downcase)://\($i):\(.port)"' | \
while read l; do \
echo $l; \
curl -sk $l/cgi-bin/overview.htm | grep software_version; \ \
hecho
En el comando anterior, incluimos un grep para filtrar la salida, asegurándonos de que sólo se mostraban los hosts que contenían la variable especificada. Como se muestra en la siguiente captura de pantalla, este método nos permitió extraer la versión de firmware específica que se ejecuta en un número considerable de estos hosts, una pieza crítica de información necesaria para evaluar si estos dispositivos eran vulnerables al CVE en cuestión.

Durante nuestro análisis, identificamos 28 hosts que respondieron con estos datos y se confirmó que ejecutaban una versión vulnerable del firmware QRTB. Aun así, es probable que hubiera más por ahí que no respondieron en su momento.
Identificación de vulnerabilidades RTS
A diferencia de las rutas identificadas para la línea de dispositivos QRTB, no pudimos localizar ningún punto final específico para los dispositivos basados en RTS que revelara información sobre la versión o el modelo. Sin embargo, durante nuestro análisis, descubrimos lo que creemos que es la vulnerabilidad detallada en CVE-2023-24508.
Empezamos descargando dos versiones del firmware RTS de la página web de Baicells: la versión 3.6.6, conocida por su vulnerabilidad, y la versión 3.7.11.6, que incluye un parche para la CVE-2023-24508.
Según el CVE, esta vulnerabilidad implica un problema de preautenticación en la interfaz administrativa HTTP. Para empezar, comparamos el firmware parcheado con la versión vulnerable, centrándonos en los cambios realizados en los archivos del servidor web.
Un cambio especialmente destacable es la adición de una sola línea al archivo "www-nui/cgi-bin/header.htm", que depende de muchos otros scripts que generan contenidos dinámicos para la interfaz web:
eval $( baicells_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.htm" -t $(uci get baicells.global.session_timeout) -b "$COOKIE_browser_time" )
Antes de que podamos apreciar plenamente la importancia crítica de esta adición, primero debemos entender el significado del comando baicells_session_validator. Durante nuestra investigación de los dispositivos Baicells, encontramos repetidamente referencias al término "Gargoyle" en múltiples archivos. Al principio, supusimos que se trataba simplemente de un nombre en clave para el software. Sin embargo, pronto nos dimos cuenta de que el sistema de gestión de estos dispositivos se basa principalmente en el (muy antiguo) proyecto de código abierto con licencia GPLv2, la "Utilidad de gestión de routers Gargoyle".
Esta conexión puede corroborarse examinando el desensamblado del binario "baicells_session_validator" y comparándolo con el código fuente de "session_validator.c" de Gargoyle. Como se muestra a continuación, la sentencia switch/case en "session_validator" de Baicells se alinea casi idénticamente con la de la implementación de Gargoyle:
 |
 |
Baicells session_validator (Ghidra) |
Session_validator de Gargoyle (Github) |
En resumen, este comando se utiliza para autenticar a un usuario mediante nombre de usuario y contraseña o validar que el cliente en cuestión se ha autenticado previamente y ahora tiene una cookie de sesión válida.
Es importante señalar que tanto Gargoyle como Baicells utilizan un lenguaje de scripting llamado Haserl, que es una alternativa ligera a frameworks como PHP. Haserl utiliza shell scripting y Lua como backend para la ejecución de código; sin embargo, Baicells sólo utiliza este último.
Un aspecto crítico que hay que entender es cómo los scripts CGI que utilizan Haserl manejan las interacciones con la entrada del cliente HTTP. En concreto, las entradas de datos de las peticiones HTTP se transforman en variables específicas de Haserl:
- Transformación del encabezado HTTP: Los pares clave-valor de las cabeceras HTTP se convierten en variables precedidas por el nombre de la cabecera. Por ejemplo, una cabecera como "Cookie: blah=cosa; foo=bar" se convertirían en variables de entrada Haserl "$COOKIE_blah=cosa" y "$COOKIE_foo=bar"..
- Argumento de consulta Transformación: Los argumentos de consulta pasados a través de GET o POST se transforman de forma similar. Por ejemplo, una petición como "POST /datos?clave=val" se traduciría a la variable Haserl "$POST_clave=val".
Todo el código responsable de la generación de contenidos dinámicos reside en el directorio "www-nui/cgi-bin". Cada archivo de este directorio tiene su correspondiente JavaScript en el directorio "www-nui/js", ambos accesibles al público.
El propósito de estos archivos JavaScript es manejar las entradas de formulario generadas por los scripts CGI y realizar llamadas AJAX backend a otros subsistemas. Estas llamadas se realizan mediante la función "runAjax()", que se define en el archivo "www-nui/js/common.js".

Uno de los métodos más comunes de llamar a esta función es iniciar una llamada AJAX al archivo "../utility/run_commands.sh" (que también es de acceso público ya que AJAX se inicia en el lado del cliente)
runAjax("POST", "../utility/run_commands.sh", param, stateChangeFunction);
El contenido del archivo "run_commands.sh" revela otro script Haserl con una funcionalidad alarmante:
#!/usr/bin/haserl
<%
#eval $(baicells_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.htm" -t $(uci get baicells.global.session_timeout) -b "$COOKIE_browser_time")
mkdir /tmp/.log
log_file="/tmp/.log/run_cmd.log"
echo "FORM_commands " "$FORM_commands" > $log_file
echo "POST_hash " "$POST_hash" >> $log_file
echo "COOKIE_exp ""$COOKIE_exp" >> $log_file
echo "$HTTP_USER_AGENT" >> $log_file
echo "$REMOTE_ADDR" >> $log_file
echo "COOKIE_browser_time " $COOKIE_browser_time >> $log_file
echo "Content-type: text/plain"
echo ""
#if [ -n "$FORM_commands" ] ; then
echo "begin exec cmd" >> $log_file
tmp_file="/tmp/tmp.sh"
printf "%s" "$FORM_commands" | tr -d "\r" > $tmp_file
sh $tmp_file
echo "end exec cmd" >> $log_file
if [ -e $tmp_file ] ; then
# rm $tmp_file
fi
#fi
echo "Success"
%>
Aquí, la variable "$FORM_commands", derivada de una solicitud HTTP POST, se escribe directamente en un script de shell temporal ("/tmp/tmp.sh") y se ejecuta utilizando el comando "sh". En particular, en la versión vulnerable de este firmware, el comando "baicells_session_validator" está comentado, lo que evita la validación de la sesión. Como resultado, simplemente solicitando este archivo específico podría conducir a la ejecución de código arbitrario con facilidad.
La implementación fija de este firmware integra el "baicells_session_validator" en cada script CGI a través de una dependencia de cabecera y reactiva la comprobación de validación específicamente para "run_commands.sh".
Armado con este conocimiento, un atacante podría teóricamente explotar uno de estos dispositivos Baicells suministrando todos los campos requeridos que Haserl espera como entrada. Por ejemplo, un exploit podría ser tan simple como el siguiente:
curl -k
-X POST \
--data "hash=abcde&commands=$COMMAND\n" \
http://$HOST/utility/run_commands.sh
Sin embargo, no lo hemos confirmado ya que no poseemos ninguno de estos dispositivos, pero comparando la versión vulnerable con la versión arreglada, podemos decir que este método está cerca.
Curiosidades y VPN
Estos dispositivos de Baicells también pueden encontrarse bajo diferentes marcas y nombres, como "ABIT", "Celona", "Lemko" y "Sunsea", y aunque Baicells tiene una presencia significativa en Norteamérica, varios elementos del firmware revelan sus verdaderos orígenes en China. Por ejemplo, encontramos pruebas de que estos sistemas utilizarán 114.114.114.114, un servidor DNS público en China, y una configuración NTP para "cn.pool.ntp.org".
También encontramos que tanto el firmware RTS como QTRB están configurados (o tienen las configuraciones listas) para establecer túneles VPN entre el dispositivo y dos hosts en Microsoft Azure:
El nombre de host "west/east EPC" puede hacer referencia al término de telecomunicaciones "Evolved Packet Core", dado que Baicells ofrece un servicio llamado "CloudEPC", un servicio SaaS proporcionado por Baicells para desplegar un EPC en la nube y utilizar sus servidores para gestionar las diversas funciones de una red LTE, como el enrutamiento de datos entre dispositivos físicos, como teléfonos, y redes externas, como Internet.

Visión general de CloudEPC (Vía Baicells)
Podemos ver estas configuraciones en el firmware QTRB en dos archivos XML que finalmente se convierten en configuraciones VPN StrongSwan legítimas a través de varios scripts de aprovisionamiento e init.
 |
 |
Túnel Config 1 |
Túnel Config 2 |
Debemos señalar que no hay pruebas de que estas configuraciones estén activadas por defecto; pero, parece que todo está preparado para que estas VPN estén activadas, incluido un certificado de cliente fácilmente disponible:

Sin embargo, la línea de firmware RTS tenía un enfoque basado en UCI más directo para la configuración, lo que hacía más fácil ver lo que estaba y lo que no estaba configurado por defecto. Y al igual que el QTRB, vemos esos dos túneles a los hosts Azure configurados, esta vez con una evidencia más concreta de que está habilitado por defecto ("/etc/config/ipsec"):
config vpn 'strongswan'
opción enabled '1
option puerto_derecho '4500
opción left_interface ''
config tunnel
opción enabled '1
opción nombre 'Tunnel1
option gateway 'baicells-westepc-03.cloudapp.net'
option identificador_izquierdo ''
option identificador_derecho ''
option ike_encryption_algorithm 'aes128'
option esp_encryption_algorithm 'aes128'
opción ike_authentication_algorithm "sha1
opción esp_authentication_algorithm "sha1
opción leftsourceip '%config'
opción ike_dh_group "modp768
opción esp_dh_group 'null'
opción ikelifetime '60m'
opción keylife '40m'
opción rekeymargin '5m'
opción keyingtries '%forever'
opción dpdaction 'restart'
opción dpddelay '30s'
opción authby 'psk
opción pre_shared_key 'baicells.westus'
lista rightsubnet '10.3.0.0/24'
configurar túnel
opción enabled '1
opción nombre 'Tunnel2
option gateway 'baicells-eastepc04.eastus.cloudapp.azure.com'
option identificador_izquierdo ''
option identificador_derecho ''
option ike_encryption_algorithm 'aes128'
opción esp_encryption_algorithm 'aes128'
opción ike_authentication_algorithm "sha1
opción esp_authentication_algorithm "sha1
opción leftsourceip '%config'
opción ike_dh_group "modp768
opción esp_dh_group 'null'
opción ikelifetime '60m'
opción keylife '40m'
opción rekeymargin '5m'
opción keyingtries '%forever'
opción dpdaction 'restart'
opción dpddelay '30s'
opción authby 'psk
opción pre_shared_key 'baicells.eastus'
lista rightsubnet '10.5.0.0/24'
Esta configuración se carga aparentemente a través de un script init.d en "/etc/rc.d/S74ipsec" que es un enlace simbólico a "/etc/init.d/ipsec'. Si nos fijamos en la función "start()" vemos que hay varios pasos por los que pasa para finalmente habilitar esta VPN:
start() {
while [ ! -f /tmp/oam.ready ];
do
sleep 1
done
ipsec_log "Ipsec start ..."
CheckInstallation
config_load ipsec
PrepareEnvironment
ConfigVpn
/usr/sbin/ipsec start
}
Aquí, la función "CheckInstallation" se asegura de que la herramienta "/usr/sbin/ip" esté disponible en el sistema. A continuación, "config_load ipsec" es una envoltura de "uci_load" que lee la configuración de "/etc/config/ipsec". A continuación, "PrepareEnvironment" genera un archivo de configuración básica de StrongSwan en "/var/ipsec/ipsec.conf". Por último, se llama a la función "ConfigVpn", que se define como sigue:
Mientras que el "config_get_bool" será verdadero ya que la configuración por defecto para "strongswan" (en "/etc/config/ipsec") es "enabled '1'". Y para cada túnel configurado en esa configuración, "ConfigTunnel" genera una configuración StrongSwan válida. Sin embargo, justo antes de que esto ocurra, vemos una llamada a una función llamada "ConfigOMC".
Esta función "ConfigOMC" es extraña porque configura estáticamente otro túnel VPN a un punto final remoto con el nombre de host "baiomc.chinacloudapp.cn" - un host que actualmente resuelve a la IP 42.159.86.204 - un servidor ubicado en Beijing, China:

42.159.86.204 ha visto su parte justa de servicios interesantes a lo largo de los años, incluyendo servidores SSH y FTP en puertos muy altos y servidores web que suben y bajan con el tiempo con certificados Baicells, lo que proporciona evidencia de que estos hosts se utilizaron activamente hasta el 1 de mayo de 2024, cuando el host vio por última vez un servicio en ejecución.

El término "OMC" es una referencia a otra oferta de servicios de Baicells denominada "CloudCore Operations Management Console", que se describe a sí misma de la siguiente manera:
"Los administradores utilizan el OMC para configurar o modificar los componentes e interfaces de eNB y UE, supervisar la red, solucionar problemas y realizar actualizaciones de software o firmware."
En otras palabras, se trata de una oferta que permite la gestión y configuración a distancia de los dispositivos Baicells.
Dado que no poseemos ninguno de estos dispositivos, no podemos confirmar si estas VPN están habilitadas por defecto en un sistema activo. Aún así, si alguien fuera a utilizar estos servicios CloudEPC u OMC, probablemente sea una buena idea entender que simplemente crean túneles VPN completos en la infraestructura gestionada por Baicells.
Técnicamente, esto podría ser visto como un agujero de alfiler en un dispositivo de cliente Baicells, eludiendo cualquier filtro de entrada; sin embargo, esto no significa que Baicells ha autenticado el acceso al dispositivo real a menos que sea una versión del firmware QRTB que se describe en CVE-2022-24693 que establece que los dispositivos Baicells enviados con credenciales hardcoded.
Incluso ha habido afirmaciones sin fundamento en un foro no oficial de Facebook sobre Baicells que han afirmado que vieron aumentos repentinos no deseados de tráfico yendo a "baiomc.chinacloudapp.cn" allá por 2023. Un post que se puede encontrar con una simple búsqueda en Google.

No podemos insinuar o conocer la intención, pero la existencia de estas configuraciones VPN es una elección de diseño que la mayoría de las personas centradas en la seguridad escudriñarían. Arquitectónicamente, parece incorrecto, pero la realidad puede no ser tan dramática como nuestros sentimientos.
Palabras finales
En un mundo cada vez más interconectado en el que cada vez más de nuestro hardware y software se desarrolla y mantiene fuera de nuestros países de origen, en el que los servicios migran continuamente a "la nube" y en el que crece la paranoia sobre la fiabilidad, es crucial mantener la perspectiva. Debemos recordar que nunca debemos atribuir a la malicia lo que puede explicarse adecuadamente por la inexperiencia o las malas decisiones.
Pero esto tampoco significa que nuestros adversarios no puedan aprovecharse de estas deficiencias, y siempre debemos estar más atentos a nuestras decisiones sobre lo que se ejecuta en las partes más críticas de nuestras redes.
Cuando entendemos lo que es Baicells, lo que hacen y las vulnerabilidades que han tenido, el hecho de que cientos de dispositivos Baicells estén ahí fuera en Internet es un pensamiento preocupante. Dispositivos como estos deberían tener la menor presencia pública posible en Internet; estas interfaces de administración deberían estar detrás de varias capas de seguridad, como cortafuegos y VPN, completamente desconectadas de las miradas indiscretas de posibles atacantes.