AS |
Hôtes non vulnérables |
Hôtes vulnérables |
Total des hôtes |
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 |
HINET Data Communication Business Group |
284 (71.36%) |
114 (28.64%) |
398 |
KDDI CORPORATION |
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 |
DTAG Opérations des fournisseurs d'accès à Internet |
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 LG DACOM Corporation |
167 (81.46%) |
38 (18.54%) |
205 |
Répartition par version (Top 20)
La plupart des versions de Pulse Connect déployées ne sont vulnérables à aucun des avis de sécurité que nous avons examinés. La plus populaire est 9.1.14.18105 (9.1R14), avec 3 177 hôtes utilisant cette version, suivie de près par 9.1.15.18393 (9.1R15), avec 2 319 hôtes ; toutes deux ne sont pas vulnérables.
Version |
A-t-il de la vulnérabilité ? |
Hôtes |
9.1.14.18105 |
Non |
3,177 |
9.1.15.18393 |
Non |
2,319 |
9.1.12.14139 |
Non |
2,026 |
8.3.7.65025 |
Non |
1,699 |
9.1.13.15339 |
Non |
1,530 |
9.1.14.16847 |
Non |
923 |
9.1.11.12319 |
Oui (SA44784) |
887 |
9.1.14.21347 |
Non |
857 |
9.1.15.21389 |
Non |
789 |
9.1.13.16253 |
Non |
701 |
9.1.13.18121 |
Non |
583 |
9.1.11.13127 |
Oui (SA44858) |
573 |
8.1.15.59747 |
Non |
395 |
9.1.9.9701 |
Oui (SA44784, SA44858) |
358 |
9.1.12.15299 |
Non |
352 |
9.1.8.8511 |
Oui (SA44784, SA44858) |
211 |
9.0.5.64107 |
Oui (SA44784, SA44858) |
166 |
8.2.12.64003 |
Non |
162 |
9.1.11.12173 |
Oui (SA44858) |
145 |
9.1.4.4763 |
Oui (SA44516, SA44588, SA44784, SA44858) |
108 |
Prise d'empreintes digitales Pulse Connect Secure
Introduction
Historiquement, lorsqu'un logiciel est mis à jour et publié, nous avons constaté que les nouvelles versions présentent des différences visibles par rapport aux versions précédentes. Avec suffisamment de temps et de données, ces différences (parfois nuancées) peuvent être trouvées et (avec un peu de chance) utilisées pour dire avec certitude quelle version du logiciel tourne sur un serveur.
Par exemple, ces légères différences sont souvent visibles dans le corps de la réponse HTTP lorsque le logiciel s'exécute sur HTTP, bien qu'elles soient parfois ambiguës à première vue. Le plus souvent, ces différences sont introduites par des outils externes qui facilitent le processus de construction et de déploiement (tels que les systèmes d'intégration continue (CI) ou webpack pour Javascript). Ces systèmes génèrent automatiquement des noms de fichiers dans des formats qui peuvent changer d'une version à l'autre lorsque le contenu a été modifié, créant ainsi des artefacts visibles qui identifient le logiciel de manière unique.
Dans de nombreux cas, nous sommes limités à l'utilisation des données brutes de l'hôte que nous collectons au cours de nos analyses (bannières et réponses au protocole). C'est pourquoi nous avons souvent recours à des techniques et des méthodes plus abstraites pour identifier les logiciels et les services que nous touchons. Plus important encore, nous développons ces techniques pour réduire au minimum notre interaction réelle à long terme avec un service en cours d'exécution.
Identification
Dans la capture d'écran de la recherche Censys pour un service Pulse Connect ci-dessus, plusieurs segments de la réponse HTTP ont été surlignés en jaune. Les indicateurs de ce type sont généralement une combinaison d'un nom de fichier suffixé par un ensemble de caractères aléatoires, probablement générés par un programme tel que "sha256sum", qui calcule un condensé de message SHA256 du contenu du fichier. Disposer de ces informations pour un seul hôte n'est pas très utile, mais si l'on prend un peu de recul et que l'on considère l'ensemble des hôtes sur Internet, des schémas commencent à se dessiner. Comme nous pouvons le voir, Pulse contient plusieurs exemples de ces artefacts au rendu unique.
Notre objectif premier est d'associer ces noms de fichiers aléatoires à une version spécifique du logiciel. Mais d'abord, nous devons déterminer si nous pouvons même utiliser les données ci-dessus pour identifier des versions spécifiques en recherchant toutes les autres instances de ce service fonctionnant sur Internet afin de comparer les données. Dans le cas de Pulse Connect, un élément commun trouvé dans la réponse HTTP du service est la chaîne "/dana-na/" (trouvée à la fois dans le corps et dans la chaîne de redirection HTTP). La requête de recherche Censys suivante devrait donc permettre d'identifier la plupart des services Pulse Connect :
services.http.response.body : `/dana-na/`
Une fois cette caractéristique centrale trouvée, nous devons comprendre combien d'arrangements de noms de fichiers uniques de ces données existent sur l'internet. Si chaque hôte inclut un modèle de nom de fichier entièrement différent, ou si chaque hôte a le même modèle de nom de fichier, il est peu probable que cet artifice puisse être associé à une version spécifique. Nous recherchons une distribution quelque peu uniforme de "hachages" de noms de fichiers uniques sur plusieurs hôtes (plus il y a d'hôtes, mieux c'est).
Censys Les clients d'Enterprise Data connaissent peut-être notre interface BigQuery, qui permet aux utilisateurs d'écrire du code SQL pour étudier les hôtes et les services. Pour ce faire, l'utilisation de BigQuery est probablement l'un des moyens les plus faciles de répondre à la question de ce nom de fichier. La requête suivante analysera ces noms de fichiers (apparemment) aléatoires (file_hash) et comptera le nombre d'hôtes associés à chacun d'eux (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) AS host_count
FROM
`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
ORDER BY
nombre_d'hôtes DESC
Au moment de la rédaction de ce document, cette requête a trouvé 159 instances uniques de ce nom de fichier préfixé "/dana-na/css/ds_". Nous pouvons ensuite exporter les résultats de cette requête et obtenir une représentation visuelle de la distribution des noms de fichiers :
Dans le graphique ci-dessus, l'axe des abscisses représente le nom de fichier "hash" trouvé dans le corps de la réponse HTTP, et l'axe des ordonnées représente le nombre d'hôtes contenant cette chaîne. Cela signifie que plusieurs appareils contiennent le même nom de fichier, ce qui indique qu'il peut y avoir un modèle qui pourrait donner lieu à des versions spécifiques.
L'étape suivante consiste à déterminer s'il existe un moyen d'obtenir la version réelle du logiciel pour l'associer à ces noms de fichiers. Lorsque nous avons pris l'empreinte de GitLab, nous avons écrit des scripts pour extraire chaque image étiquetée dans le dépôt Docker public de GitLab afin de faire cette association. Dans le cas de Pulse, cette tâche n'était pas aussi simple.
Étant donné que les services VPN nécessitent (généralement) un accès de niveau administratif sur un hôte client pour fonctionner, le plus souvent, le logiciel client VPN est disponible en téléchargement sur le serveur. Pulse Connect n'est pas différent, et après quelques recherches rapides sur Google, les utilisateurs ont découvert que le client peut être téléchargé en demandant le chemin "/dana-cached/hc/HostCheckerInstaller.osx".
Ce fichier "HostCheckerInstaller.osx" est un exécutable qui comprend la version du logiciel en cours d'exécution intégrée dans un fichier de configuration des préférences (PLIST). Nous devons télécharger cet exécutable et en rechercher le contenu pour extraire ces informations. Par exemple, la commande suivante récupérera le binaire d'un serveur Pulse Connect et imprimera la chaîne de caractères de la version intégrée.
~$ curl -sk https://HOST:PORT/dana-cached/hc/HostCheckerInstaller.osx \N-o HostCheckerInstaller.osx && strings
-o HostCheckerInstaller.osx && strings HostCheckerInstaller.osx | \N- grep -A1 -m1 " version " - -o HostCheckerInstaller.osx
grep -A1 -m1 'version'
Nous voulons télécharger ce binaire à partir de trois serveurs Pulse Connect ou plus pour chaque hachage unique que nous avons trouvé avec notre requête SQL. L'idée ici est de vérifier à partir de plusieurs sources s'il existe une corrélation directe entre ces noms de fichiers et la version spécifique de Pulse Connect. Si plusieurs hôtes ont le même modèle de nom de fichier, mais que le binaire que nous avons téléchargé de chaque hôte nous donne une chaîne de version différente, cela sera considéré comme une corrélation échouée.
Pour ce faire, nous devons combiner les données dont nous disposons déjà (une liste des hachages de noms de fichiers uniques), l'utilitaire de ligne de commande Censys search et un peu de script shell. Par exemple, si nous voulons savoir quelle version est associée au nom de fichier : "/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js">/font>.
Nous prenons un hôte aléatoire sur Censys en utilisant le terme de recherche suivant :
services.http.response.body : "/dana-na/css/ds_d0208775377750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8.js"
Pour ces résultats, trouvez le port et le service où ce modèle correspond, et téléchargez le client VPN à partir du serveur comme suit :
~$ curl -sk https:///dana-cached/hc/HostCheckerInstaller.osx \N -o 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>
Après avoir effectué cette opération sur quelques hôtes présentant le même modèle de nom de fichier, nous pouvons affirmer avec une certaine confiance que "ds_d02087753750cb7eeb6341e70188f7cd46d4fbd2c3e99aa4549d0890d28af8" est la version 22.2.16 build 21349 de Pulse Connect.
Nous avons créé ce script shell qui va parcourir chaque nom de fichier unique de la réponse à notre requête SQL, émettre une requête Censys Search à l'aide de l'utilitaire de ligne de commande pour rechercher le modèle de nom de fichier dans le corps de la réponse HTTP, puis choisir quatre résultats aléatoires et télécharger le binaire "HostCheckerInstaller.osx" à partir des hôtes. L'astuce consiste à formater le fichier de sortie de manière à ce qu'il soit facile d'associer le hachage du nom de fichier dans le corps de la réponse à l'hôte à partir duquel nous l'avons téléchargé.
Une fois ce script exécuté, nous devrions avoir un répertoire de fichiers préfixé par le modèle de nom de fichier que nous recherchons et suffixé par l'adresse IP à partir de laquelle le script a téléchargé le fichier. Nous pouvons alors itérer sur chaque fichier et récupérer la chaîne de la version intégrée :
~$ 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>
Nous pouvons ensuite utiliser ces informations pour générer un rapport de toutes les versions trouvées et valider que chaque modèle de nom de fichier unique que nous recherchions a une chaîne de version correspondante unique dans le fichier téléchargé. Tout d'abord, nous créons un petit script pour générer un fichier CSV contenant les données de version pour chaque hôte :
#!/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 exemple d'exécution du script ci-dessus utilisant les données que nous avons extraites ressemble à ce qui suit :
~$ bash make_report.sh hashes.txt bins | tee versions.csv
hôte,chemin,version
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
Ensuite, nous pouvons créer le rapport agrégé qui nous indique combien d'hôtes nous avons vérifié pour un chemin unique. Comme indiqué ci-dessus, nous téléchargeons le client à partir de quatre hôtes pour chaque chemin d'accès unique, et nous nous attendons donc à ce que chaque combinaison chemin d'accès+version unique ait quatre lignes correspondantes.
~$ 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
Une fois que nous avons vérifié manuellement que chaque chemin unique est directement associé à une version (ce qui est le cas), nous pouvons créer une matrice de vulnérabilité pour les avis de sécurité qui nous intéressent le plus.
Pour cette partie du travail, nous devons suivre chaque vulnérabilité sur laquelle nous voulons faire un rapport. Pour ce billet, nous avons analysé sept avis de sécurité (AS) importants de Pulse Connect, qui ont chacun un ou plusieurs CVE associés :
SA43604 |
Vulnérabilité de débordement de tampon de pile (CVE-2018-5299) |
SA43877 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.0R1/9.0R2 |
SA44101 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.0RX |
SA44516 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.1R8 |
SA44588 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.1R8.2 |
SA44784 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.1R11.4 |
SA44858 |
Résolution de multiples vulnérabilités dans Pulse Connect Secure 9.1R12 |
Mais avant de poursuivre, on peut remarquer que les numéros de version figurant dans les avis de sécurité de Pulse ne correspondent pas exactement aux numéros de version figurant sur les appareils eux-mêmes. Par exemple, voici un extrait d'un avis de sécurité de Pulse Connect :
Ici, nous voyons que "8.3R1" est affecté par une vulnérabilité particulière ; ce format de version doit d'abord être converti en "8.3.1" pour correspondre au format de version que nous trouvons sur les hôtes. Mais si nous regardons de plus près, il nous manque la dernière série de chiffres trouvée dans nos données, qui est le "build number". Pour obtenir le numéro de build d'une version particulière de Pulse Connect, nous utilisons nos compétences Google pour trouver les notes de version. Par exemple, si nous voulions trouver le numéro de version de la version "8.3R1", nous chercherions "Pulse 8.3R1" sur Google et ferions défiler les notes de mise à jour.
|
|
Résultats Google pour "Pulse 8.3R1" (en anglais) |
Notes de mise à jour |
Dans cet exemple, nous pouvons dire que la version vulnérable "8.3R1" a le numéro de construction "55339", et peut être formatée comme "8.3.1.55339" pour correspondre à ce qui est trouvé sur les hôtes. Ce numéro de version est très important pour déterminer les versions corrigées du logiciel Pulse Connect.
Pour générer une matrice de vulnérabilité, nous avons créé un petit script python utilisant l'API "semver" pour faire correspondre les versions à chacun des sept avis de sécurité que nous avons énumérés ci-dessus. Ce script lit notre fichier CSV de chemins de fichiers uniques et de numéros de version découverts, et ajoute de nouvelles colonnes représentant les avis de sécurité auxquels cette version est vulnérable.
Le script ci-dessus prend deux arguments, un fichier d'entrée et un fichier de sortie. Voici un exemple d'exécution de ce script, le fichier d'entrée est le fichier CSV que nous avons généré dans la dernière section, et le fichier de sortie est standard mais également redirigé vers le fichier "vulnerability_matrix.csv".
~$ python3 parse_version.py path_version.csv /dev/stdout | tee vulnerability_matrix.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
Nous voyons ici que pour chaque nom de fichier unique, nous avons la version associée et une table de vérité pour chacun des sept avis de sécurité que nous analysons. Nous prenons ensuite ce nouveau fichier CSV et l'importons dans une nouvelle table BigQuery à l'aide de l'utilitaire de ligne de commande BigQuery :
~$ bq load --source_format CSV \
--replace --autodetect \
<bigquery-project-id>:<database>.pulse-vulnerability-matrix \
vulnerability_matrix.csv
La commande ci-dessus générera automatiquement un schéma de base de données BigQuery et chargera les données. Le tableau résultant devrait ressembler à la capture d'écran suivante :
Avec tout cela en place, nous pouvons maintenant facilement utiliser cette table nouvellement créée pour joindre les données de notre ensemble de données Internet global afin d'établir un rapport sur les hôtes et les services vulnérables à ces avis de sécurité. La requête SQL suivante nous donnera une vue d'ensemble de chaque avis de sécurité et du nombre de services sur l'internet qu'ils affectent.
AVEC
pulse_hosts AS (
SELECT
identifiant_hôte.ipv4,
REGEXP_EXTRACT(SAFE_CONVERT_BYTES_TO_STRING(service.http.response.body), ".*(/dana-na/css/ds_[a-f0-9]{64}.js).*") AS file_hash,
FROM
`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 = VRAI) SA44516,
COUNTIF(pulse.SA44588 = TRUE) SA44588,
COUNTIF(pulse.SA44784 = TRUE) SA44784,
COUNTIF(pulse.SA44858 = VRAI) SA44858
FROM
`pulse_hosts`
LEFT JOIN
`db.table.pulse-vulnerability-matrix` pulse
ON (file_hash=pulse.path)
Comment Censys peut-il vous aider ?