AS |
Hosts no vulnerables |
Anfitriones vulnerables |
Total de hosts |
France Telecom - Orange |
334 (48.69%) |
352 (51.31%) |
686 |
AMAZON-O2 |
596 (91.55%) |
55 (8.45%) |
651 |
MICROSOFT-CORP-MSN-AS-BLOCK |
604 (93.21%) |
44 (6.79%) |
648 |
OCN NTT Communications Corporation |
491 (84.51%) |
90 (15.45%) |
581 |
AKAMAI-ASN1 |
575 (100%) |
0 (0.0%) |
575 |
TELEFONICA_DE_ESPANA |
478 (97.55%) |
12 (2.45%) |
490 |
Grupo empresarial de comunicación de datos HINET |
284 (71.36%) |
114 (28.64%) |
398 |
CORPORACIÓN KDDI |
206 (54.93%) |
169 (45.07%) |
375 |
CLARANET-AS ClaraNET LTD |
362 (96.53%) |
13 (3.47%) |
375 |
UUNET |
318 (90.86%) |
32 (9.14%) |
350 |
UCOM ARTERIA Networks Corporation |
251 (72.33%) |
96 (27.67%) |
347 |
AS17054 |
75 (21.61%) |
272 (78.39%) |
347 |
IS |
306 (96.23%) |
12 (3.77%) |
318 |
Operaciones del proveedor de servicios de Internet DTAG |
278 (88.25%) |
37 (11.75%) |
315 |
ATT-INTERNET4 |
238 (85.3%) |
41 (14.7%) |
279 |
KIXS-AS-KR Korea Telecom |
214 (77.26%) |
63 (22.74%) |
277 |
PRUASN |
259 (100%) |
0 (0.0%) |
259 |
COMCAST-7922 |
205 (83.67%) |
40 (16.33%) |
245 |
NETDEPON |
236 (99.16%) |
2 (0.84%) |
238 |
LGDACOM Corporación LG DACOM |
167 (81.46%) |
38 (18.54%) |
205 |
Desglose por versión (Top 20)
La mayoría de las versiones de Pulse Connect desplegadas no son vulnerables a ninguno de los avisos de seguridad que hemos analizado. La más popular es 9.1.14.18105 (9.1R14), con 3.177 hosts que ejecutan esta versión, seguida de cerca por 9.1.15.18393 (9.1R15), con 2.319 hosts; ambas no son vulnerables.
Versión |
¿Tiene vulnerabilidad? |
Anfitriones |
9.1.14.18105 |
No |
3,177 |
9.1.15.18393 |
No |
2,319 |
9.1.12.14139 |
No |
2,026 |
8.3.7.65025 |
No |
1,699 |
9.1.13.15339 |
No |
1,530 |
9.1.14.16847 |
No |
923 |
9.1.11.12319 |
Sí (SA44784) |
887 |
9.1.14.21347 |
No |
857 |
9.1.15.21389 |
No |
789 |
9.1.13.16253 |
No |
701 |
9.1.13.18121 |
No |
583 |
9.1.11.13127 |
Sí (SA44858) |
573 |
8.1.15.59747 |
No |
395 |
9.1.9.9701 |
Sí (SA44784, SA44858) |
358 |
9.1.12.15299 |
No |
352 |
9.1.8.8511 |
Sí (SA44784, SA44858) |
211 |
9.0.5.64107 |
Sí (SA44784, SA44858) |
166 |
8.2.12.64003 |
No |
162 |
9.1.11.12173 |
Sí (SA44858) |
145 |
9.1.4.4763 |
Sí (SA44516, SA44588, SA44784, SA44858) |
108 |
Huellas dactilares Pulse Connect Secure
Introducción
Históricamente, cuando el software se actualiza y se lanza al mercado, descubrimos que las nuevas versiones presentan diferencias visibles con respecto a las versiones anteriores. Con tiempo y datos suficientes, esas diferencias (a veces matizadas) pueden encontrarse y (con suerte) utilizarse para decir con seguridad qué versión del software se está ejecutando en un servidor.
Por ejemplo, estas ligeras diferencias pueden verse con frecuencia en el cuerpo de la respuesta HTTP cuando el software se ejecuta a través de HTTP, aunque a veces resulte ambiguo a primera vista. Y la mayoría de las veces, estas diferencias son introducidas por herramientas externas que ayudan en el proceso de compilación y despliegue (como los sistemas de integración continua (CI) o webpack para Javascript). Estos sistemas autogeneran nombres de archivo en formatos que pueden cambiar de una compilación a otra cuando se ha modificado el contenido, creando en última instancia artefactos visibles que identifican el software de forma única.
En muchos casos, estamos limitados a utilizar los datos brutos del host que recopilamos durante nuestros escaneos (banners y respuestas de protocolo). Por este motivo, a menudo recurrimos a técnicas y métodos más prácticos para identificar el software y los servicios que tocamos. Y lo que es más importante, desarrollamos estas técnicas para reducir al mínimo nuestra interacción real a largo plazo con un servicio en ejecución.
Identificación
En la captura de pantalla de búsqueda de Censys para un servicio de Pulse Connect, varios segmentos de la respuesta HTTP aparecen resaltados en amarillo. Los indicadores de este tipo suelen ser una combinación de un nombre de archivo con un sufijo y un montón de caracteres aleatorios, probablemente generados por un programa como "sha256sum", que calcula un resumen de mensajes SHA256 del contenido del archivo. Disponer de esta información para un solo host no es muy útil, pero cuando se da un paso atrás y se observa el conjunto de todos los hosts de Internet, empiezan a materializarse los patrones. Como podemos ver, Pulse contiene varios ejemplos de estos artefactos renderizados de forma única.
Nuestro objetivo principal es asociar estos nombres de archivo de aspecto aleatorio con una versión de software específica. Pero primero, debemos determinar si podemos siquiera utilizar los datos anteriores para identificar versiones específicas buscando todas las demás instancias de este servicio que se ejecutan en Internet para comparar los datos. En el caso de Pulse Connect, un elemento común que se encuentra en la respuesta HTTP del servicio es la cadena "/dana-na/" (que se encuentra tanto en el cuerpo como dentro de la cadena de redireccionamiento HTTP). Por lo tanto, la siguiente consulta de búsqueda Censys debería funcionar para identificar la mayoría de los servicios Pulse Connect:
services.http.response.body: `/dana-na/`
Una vez encontrada esta característica central, necesitamos entender cuántos arreglos de nombre de archivo únicos de estos datos existen en Internet. Si cada host incluye un patrón de nombre de archivo completamente diferente, o si cada host tiene el mismo patrón de nombre de archivo, entonces es poco probable que este artificio pueda asociarse a una versión específica. Buscamos una distribución algo uniforme de "hashes" de nombre de archivo únicos entre varios hosts (cuantos más hosts, mejor).
Censys Es posible que los clientes de Enterprise Data estén familiarizados con nuestra interfaz BigQuery, que permite a los usuarios escribir SQL para investigar hosts y servicios. Para ello, el uso de BigQuery es probablemente una de las maneras más fáciles de responder a la pregunta de este nombre de archivo. La siguiente consulta analizará estos nombres de archivo (aparentemente) aleatorios (file_hash) y contará el número de hosts asociados a cada uno (host_count).
SELECT
REGEXP_EXTRACT(SAFE_CONVERT_BYTES_TO_STRING(service.http.response.body),
".*/dana-na/css/ds_([a-f0-9]{64}.js).*") AS file_hash,
COUNT(DISTINCT host_identifier.ipv4) COMO host_count
DE
`censys-io.universal_Internet_dataset.current` main,
UNNEST(services) service
WHERE
SAFE_CONVERT_BYTES_TO_STRING(service.http.response.body) LIKE '%/dana-na/%'
GROUP BY
file_hash
ORDENADO POR
host_count DESC
En el momento de escribir esto, esta consulta encontró 159 instancias únicas de este nombre de archivo con prefijo "/dana-na/css/ds_". A continuación, podemos exportar los resultados de esta consulta y obtener una representación visual de la distribución de los nombres de archivo:
En el gráfico anterior, el eje x representa el nombre de archivo "hash" encontrado en el cuerpo de la respuesta HTTP, y el eje y representa el número de hosts que contenían esa cadena. Esto significa que varios dispositivos incluyen el mismo nombre de archivo, lo que indica que puede haber un patrón que podría dar lugar a versiones específicas.
El siguiente paso es determinar si hay alguna forma de obtener la versión real del software para asociarla con estos nombres de archivo. Cuando tomamos las huellas digitales de GitLab, escribimos scripts para extraer cada imagen etiquetada del repositorio público Docker de GitLab para hacer esta asociación. En el caso de Pulse, esta tarea no fue tan sencilla.
Dado que los servicios VPN (normalmente) requieren acceso a nivel administrativo en un host cliente para funcionar, la mayoría de las veces, el software cliente VPN estará disponible para su descarga desde el servidor. Pulse Connect no es diferente, y tras una rápida búsqueda en Google, los usuarios han descubierto que el cliente puede descargarse solicitando la ruta "/dana-cached/hc/HostCheckerInstaller.osx".
Este archivo "HostCheckerInstaller.osx" es un ejecutable que incluye la versión del software en ejecución dentro de un archivo de configuración de preferencias (PLIST). Necesitamos descargar este ejecutable y buscar en su contenido para extraer esta información. Por ejemplo, el siguiente comando obtendrá el binario de un servidor Pulse Connect e imprimirá la cadena de versión incrustada.
~$ curl -sk https://HOST:PORT/dana-cached/hc/HostCheckerInstaller.osx \
-o HostCheckerInstaller.osx && strings HostCheckerInstaller.osx | \
grep -A1 -m1 'version'
Queremos descargar este binario de tres o más servidores de Pulse Connect por cada hash único que hayamos encontrado con nuestra consulta SQL. La idea aquí es verificar desde más de una fuente si existe una correlación directa entre estos nombres de archivo y la versión específica de Pulse Connect. Si varios hosts tienen el mismo patrón de nombre de archivo, pero el binario que descargamos de cada host nos da una cadena de versión diferente, esto se consideraría una correlación fallida.
Para conseguirlo, tenemos que combinar los datos que ya tenemos (una lista de los hashes únicos de los nombres de archivo), la utilidad de línea de comandos de búsqueda Censys y un poco de shell scripting. Así, por ejemplo, si quisiéramos averiguar qué versión está asociada al nombre de archivo: "/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js">/font>
Tomamos un host al azar en Censys utilizando el siguiente término de búsqueda:
services.http.response.body: "/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js"
Para obtener estos resultados, busque el puerto y el servicio en los que coincida este patrón y descargue el cliente VPN del servidor de esta forma:
~$ curl -sk https:///dana-cached/hc/HostCheckerInstaller.osx \
-o HostCheckerInstaller.osx
Finally, search through the downloaded binary by looking for the string “<key>version</key>”, the value of which will be the software version.
~$ strings HostCheckerInstaller.osx | grep -A1 '<key>version</key>'
<key>version</key>
<string>22.2.16.21349</string>
Después de ejecutar esto en unos cuantos hosts con el mismo patrón de nombre de archivo, podemos afirmar con cierta seguridad que "ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8" es Pulse Connect versión 22.2.16 compilación 21349.
Hemos creado este script de shell que iterará a través de cada nombre de archivo único de nuestra respuesta de consulta SQL, emitirá una solicitud de búsqueda Censys utilizando la utilidad de línea de comandos para buscar el patrón de nombre de archivo en un cuerpo de respuesta HTTP, luego elegirá cuatro resultados aleatorios y descargará el binario "HostCheckerInstaller.osx" de los hosts. El truco está en formatear el archivo de salida para que sea fácil asignar el hash del nombre de archivo del cuerpo de la respuesta al host desde el que lo descargamos.
Una vez que este script haya terminado de ejecutarse, deberíamos tener un directorio de archivos con el prefijo del patrón de nombre de archivo que estamos buscando y el sufijo de la dirección IP desde donde el script descargó el archivo. A continuación, podemos iterar sobre cada archivo y obtener la cadena de versión incrustada:
~$ for file in bins/*; do echo $file; strings $file | grep -A1 -m1 '<key>version</key>'; echo "" ;done
bins/00c5cc1ea977e9c13feb1f8853d034de26b4d079f85005ae990114345940095b__192.168.3.64
<key>version</key>
<string>9.1.5.5460</string>
bins/00c5cc1ea977e9c13feb1f8853d034de26b4d079f85005ae990114345940095b__192.168.100.4
<key>version</key>
<string>9.1.5.5460</string>
A continuación, podemos utilizar esta información para generar un informe de todas las versiones encontradas y validar que cada patrón de nombre de archivo único que estábamos buscando tiene una cadena de versión única correspondiente en el archivo descargado. En primer lugar, creamos un pequeño script para generar un CSV que contenga los datos de versión de cada host:
#!/usr/bin/env bash
HASHFILE=$1
BINDIR=$2
echo "host,path,version"
while read line; do
INPATH_STRIPPED=$(echo $line | sed 's/\/dana-na\/css\/ds_//g'| cut -d'.' -f1)
files=$(find $BINDIR -type f -name "*${INPATH_STRIPPED}*")
for file in $files; do
ip=$(echo $file | awk -F'__' '{print $2}')
v=$(strings $file | grep -A1 -m1 "<key>version</key>" | tail -n 1 | sed 's/<string>//g' | sed 's/<\/string>//g')
echo "$ip,$line,$v"
done
done < $HASHFILE
Un ejemplo de ejecución del script anterior con los datos que hemos extraído tiene el siguiente aspecto:
~$ bash make_report.sh hashes.txt bins | tee versions.csv
host,ruta,versión
10.1.2.3,/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js,9.1.14.18105
10.6.1.1,/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js,9.1.14.18105
10.1.2.1,/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js,9.1.14.18105
10.1.1.5,/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js,9.1.14.18105
10.4.9.2,/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js,9.1.14.18105
A continuación, podemos crear el informe agregado que nos indica cuántos hosts hemos comprobado para una única ruta. Como se ha indicado anteriormente, descargamos el cliente desde cuatro hosts para cada ruta única, por lo que esperamos que cada combinación única de ruta+versión tenga cuatro líneas coincidentes.
~$ cat versions.csv | awk -F, '{print $2","$3}' | sort | uniq -c | sort -nr
4 /dana-na/css/ds_fd9c25fc621eb26eb49c16c7028d1bd90cf5f7c1aab102ffc8b7659912a8b20a.js,9.1.9.9189
4 /dana-na/css/ds_f92149ac6a768f91e748db511ab310d84e7f84512bb3f272c69c94d0d68757db.js,9.1.4.5035
4 /dana-na/css/ds_f2aacd8bd5408b7c3c1d4633e178ad10de68367f03b366fd194c70a51fbd8621.js,8.1.14.59737
Una vez comprobado manualmente que cada ruta única está directamente asociada a una versión (que lo está), podemos crear una matriz de vulnerabilidades para los avisos de seguridad que más nos interesen.
Para realizar esta parte del trabajo, debemos rastrear cada vulnerabilidad sobre la que queremos informar, para este post, hemos analizado siete avisos de seguridad (SA) destacados de Pulse Connect, cada uno de los cuales tiene uno o más CVE asociados:
SA43604 |
Vulnerabilidad de desbordamiento de búfer de pila (CVE-2018-5299) |
SA43877 |
Múltiples vulnerabilidades resueltas en Pulse Connect Secure 9.0R1/9.0R2 |
SA44101 |
Múltiples vulnerabilidades resueltas en Pulse Connect Secure 9.0RX |
SA44516 |
Múltiples vulnerabilidades resueltas en Pulse Connect Secure 9.1R8 |
SA44588 |
Múltiples vulnerabilidades resueltas en Pulse Connect Secure 9.1R8.2 |
SA44784 |
Múltiples vulnerabilidades resueltas en Pulse Connect Secure 9.1R11.4 |
SA44858 |
Vulnerabilidades múltiples resueltas en Pulse Connect Secure 9.1R12 |
Pero antes de continuar, uno puede darse cuenta de que los números de versión que se encuentran en los avisos de seguridad de Pulse no coinciden exactamente con los números de versión que se encuentran en los propios dispositivos. Por ejemplo, este es un extracto de un aviso de seguridad de Pulse Connect:
Aquí, vemos que "8.3R1" está afectado por una vulnerabilidad particular; este formato de versión debe convertirse primero a "8.3.1" para que coincida con el formato de versión que encontramos en los hosts. Pero si miramos más de cerca, nos falta el último conjunto de dígitos que se encuentra en nuestros datos, que es el "número de compilación". Para obtener el número de compilación de una versión concreta de Pulse Connect, utilizamos nuestros conocimientos de Google para encontrar las notas de la versión. Por ejemplo, si quisiéramos encontrar el número de compilación de la versión "8.3R1", buscaríamos en Google "Pulse 8.3R1" y nos desplazaríamos hasta las notas de la versión.
|
|
Resultados de Google para "Pulse 8.3R1" |
Notas de publicación |
En este ejemplo, podemos decir que la versión vulnerable "8.3R1" tiene el número de compilación "55339", y se puede formatear como "8.3.1.55339" para que coincida con lo que se encuentra en los hosts. Este número de compilación es muy importante para determinar las versiones parcheadas del software Pulse Connect.
Para generar una matriz de vulnerabilidades, hemos creado un pequeño script en python que utiliza la API "semver" para hacer coincidir las versiones con cada uno de los siete avisos de seguridad que hemos enumerado anteriormente. Este script lee nuestro CSV de rutas de archivo únicas y números de versión descubiertos, y añade nuevas columnas que representan a qué avisos de seguridad es vulnerable esa versión.
El script anterior toma dos argumentos, un archivo de entrada y un archivo de salida. El siguiente es un ejemplo de la ejecución de este script, la entrada es el archivo CSV que generamos en la última sección, y la salida es estándar pero también redirigida al archivo "vulnerability_matrix.csv".
~$ python3 parse_version.py ruta_version.csv /dev/stdout | tee vulnerabilidad_matriz.csv
path,version,SA43604,SA43877,SA44101,SA44516,SA44588,SA44784,SA44858
/dana-na/css/ds_00c5cc1ea977e9c13feb1f8853d034de26b4d079f85005ae990114345940095b.js,9.1.5.5460,False,False,False,True,True,True,True
/dana-na/css/ds_065be83c9cf5a8d6da2a66a5b9c8f7d95d2f1a02815c7b2cebdeba0b7feaedea.js,9.1.10.12179,False,False,False,False,False,True,True
/dana-na/css/ds_10636a65bffaf6e64eba54360e47f389bd3c7d398af38ab052099bc167780d61.js,9.1.14.16847,False,False,False,False,False,False,False
/dana-na/css/ds_118434847ad133161d5a347570f89c743e30f402cc6235c24f90ae0110a03098.js,9.1.10.10119,False,False,False,False,False,True,True
/dana-na/css/ds_11954f0b01a1b777450dd7be52f5e31554cc6ef3f078e4bbd1bc992e87aa369f.js,8.1.3.35989,False,True,True,False,False,False,False
/dana-na/css/ds_11aaa782e76aab152312ee9fa1e1fb6292c85162262ec05670517c63842110ba.js,9.1.11.14929,False,False,False,False,False,False,True
Aquí vemos que para cada nombre de archivo único, tenemos la versión asociada y una tabla de verdad para cada uno de los siete avisos de seguridad que estamos analizando. A continuación, tomamos este nuevo archivo CSV y lo importamos en una nueva tabla BigQuery utilizando la utilidad de línea de comandos BigQuery:
~$ bq load --source_format CSV \
--replace --autodetect \
<bigquery-project-id>:<database>.pulse-vulnerability-matrix \
vulnerability_matrix.csv
El comando anterior generará automáticamente un esquema de base de datos BigQuery y cargará los datos. La tabla resultante debería parecerse a la siguiente captura de pantalla:
Con todo esto en su sitio, ahora podemos utilizar fácilmente esta tabla recién creada para unir los datos de nuestro conjunto de datos global de Internet e informar sobre los hosts y servicios vulnerables a estos avisos de seguridad. La siguiente consulta SQL nos dará una visión general de cada aviso de seguridad y del número de servicios de Internet a los que afecta.
CON
pulse_hosts AS (
SELECCIONE
identificador_host.ipv4,
REGEXP_EXTRACT(SAFE_CONVERT_BYTES_TO_STRING(service.http.response.body), ".*(/dana-na/css/ds_[a-f0-9]{64}.js).*") AS file_hash,
DE
`censys-io.universal_Internet_dataset.current` main,
UNNEST(services) service
WHERE
service.service_name = 'HTTP'
AND SAFE_CONVERT_BYTES_TO_STRING(service.http.response.body) LIKE '%/dana-na/%')
SELECT
COUNT(*) TOTAL,
COUNTIF(pulse.SA43604 = TRUE) SA43604,
COUNTIF(pulse.SA43877 = TRUE) SA43877,
COUNTIF(pulse.SA44101 = TRUE) SA44101,
COUNTIF(pulse.SA44516 = TRUE) SA44516,
COUNTIF(pulse.SA44588 = TRUE) SA44588,
COUNTIF(pulse.SA44784 = TRUE) SA44784,
COUNTIF(pulso.SA44858 = TRUE) SA44858
DE
pulso_hosts
LEFT JOIN
`db.table.pulse-vulnerability-matrix` pulse
ON (file_hash=ruta.pulso)
¿Cómo puede ayudar Censys ?