Les « gros » proxys web d'entreprise proposent souvent une fonctionnalité d'analyse et de catégorisation d'URL en temps réel. Quand et comment est faite cette analyse ? Quelles informations sont utilisées ? Quel niveau de protection est assuré par ce mécanisme ? Cet article va étudier le fonctionnement de l'offre WebPulse proposée dans les Blue Coat ProxySG, et répondre à la plupart de ces interrogations.
1. Principe
Commençons par décrire succinctement les grands principes de la solution.
Afin d'améliorer la pertinence et la qualité du filtrage des flux web, Blue Coat propose une fonctionnalité d'analyse en temps réel ou en arrière-plan des ressources accédées par les utilisateurs : WebPulse [WP]. Le traitement est délégué à une infrastructure externe (cloud Blue Coat), permettant également de mutualiser les résultats sur tous les clients.
Le principe est rappelé dans la figure 1, et décrit dans [WP_F].
Fig. 1 : Cheminement des requêtes.
Il faut noter que seules les URL non catégorisées [BC_C] sont transmises à l’extérieur pour analyse, et la quantité dépend donc des habitudes de navigation des utilisateurs (mon oreillette de droite annonce 5 % des requêtes, tandis que celle de gauche va jusqu’à 13 %). Le flux de sortie est en HTTP ou HTTPS, et peut se voir expurger des plans d’adressage locaux [WP_LN].
La documentation [WP_FAQ411] précise les différentes informations envoyées, selon la version du produit. Sans reproduire ici tous les détails, il est important de noter la présence de la clé de licence, les en-têtes User_Agent et Referer, la méthode HTTP, et bien sûr l'URL (scheme + host + port + path + query string).
Et en cette ère post Snowden, il est rassurant de lire le texte suivant sur cette même page :
« This data transmitted from ProxySGs to Webpulse is confidential.
Blue Coat uses this data to provide content filtering and malware protection updates to its customers.
This data is not used to profile a customer’s web usage. »
2. Pourquoi aller plus loin ?
Après cette introduction, prenons un peu de recul et analysons les pour et les contre en termes fonctionnels.
Les bénéfices de WebPulse semblent intéressants :
- analyse en temps réel d’URL inconnues ;
- mutualisation des résultats entre les clients ;
- donc meilleure réactivité probable face aux nouvelles attaques.
Au-delà de ces avantages, quels pourraient être les inconvénients ?
- extraction d’une partie de la navigation des employés de l’entreprise, assortie d’une identification possible des individus (cf. [EFF_UA]) ;
- augmentation notable de la latence du service proxy (250 à 750 ms, cf. [WP_L]) ;
- double requête sur la cible.
Essayons maintenant de voir si la qualité de la protection est suffisamment bonne pour que les risques de fuite d’informations et de dégradation des services (proxy et cible) puissent être considérés comme résiduels.
3. Double requête sur la cible
Nous allons analyser le comportement du service WebPulse vis-à-vis de la cible, un serveur HTTP nginx hébergé par un Raspberry Pi.
Les traces présentées ci-après sont celles d’un service nginx (version 1.2.1), pour lequel la configuration des traces est la suivante :
# Extrait de la configuration d’un serveur nginx
log_format test_log '$remote_addr [$time_iso8601] "$request" '
'$status $body_bytes_sent '
'"$http_user_agent"';
Comme prévu, Blue Coat effectue une requête en provenance d’une IP lui appartenant, la 199.19.249.196 (cf. [BC_WHOIS]), suivie de celle issue du navigateur de l’utilisateur, passé par le proxy d'entreprise (IP 1.2.3.4) :
199.19.249.196 [2014-04-15T16:50:07+02:00] "GET /2ko.html HTTP/1.1" 200 2048 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T16:50:07+02:00] "GET /2ko.html HTTP/1.1" 200 2085 "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0) Gecko/20100101 Firefox/29.0"
Passons maintenant à un autre client HTTP : curl.
1.2.3.4 [2014-04-15T17:02:05+02:00] "GET /2ko.html HTTP/1.1" 304 0 "curl/7.32.0"
La page est en cache au niveau du proxy, la requête n’est pas rejouée par WebPulse, même si la requête n'est pas absolument identique à la première (User_Agent différent).
Essayons sur une autre page :
1.2.3.4 [2014-04-15T17:02:27+02:00] "GET /5ko.html HTTP/1.1" 200 5120 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:02:27+02:00] "GET /5ko.html HTTP/1.1" 200 5120 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
La nouvelle URL est bien testée par WebPulse.
Le lecteur doit maintenant se poser la question de l’intérêt de ce test avec curl : tout simplement parce qu’un test précédent montrait que lorsque la requête client était effectuée via curl, cette IP ne faisait pas une, mais deux requêtes supplémentaires : ce comportement était très surprenant, mais semble être un bug (maintenant disparu), car n'étant pas reproduit ni avec d'autres IP, ni actuellement.
1.2.3.4 [2014-03-13T18:44:59+01:00] "GET /10ko.html HTTP/1.1" 200 10240 "-" "curl/7.32.0"
199.19.249.196 [2014-03-13T18:44:59+01:00] "GET /10ko.html HTTP/1.1" 200 10240 "Mozilla/4.0 (compatible ; MSIE 7.0 ; Windows NT 5.1 ; InfoPath.1 ; .NET CLR 2.0.50727 ; .NET CLR 1.1.4322 ; MS-RTC LM 8 ; .NET CLR 3.0.4506.2152 ;.NET CLR 3.5.30729)"
199.19.249.196 [2014-03-13T18:44:59+01:00] "GET /10ko.html HTTP/1.1" 200 10240 "Mozilla/4.0 (compatible ; MSIE 7.0 ; Windows NT 5.1 ; InfoPath.1 ; .NET CLR 2.0.50727 ; .NET CLR 1.1.4322 ; MS-RTC LM 8 ; .NET CLR 3.0.4506.2152 ;.NET CLR 3.5.30729)"
Le bilan est donc clair : pour une requête utilisateur, le service cible reçoit 2 requêtes. Bel effet amplificateur, à fortement relativiser, car en cas de deuxième requête « similaire » (à priori même URL) à la première, seule celle du client est reçue par la cible.
4. Quelle(s) méthode(s) ?
Après avoir testé un simple GET, étudions l'ensemble des méthodes HTTP, et analysons le comportement de WebPulse en fonction de celles-ci.
La commande utilisée est la suivante :
for method in GET POST PUT HEAD TRACE DELETE; do echo $method ; curl -X $method "http://test.example.org/${method}.html"; done
Les résultats obtenus sont présentés ci-après, avec en première ligne la requête client, et en deuxième celle de WebPulse.
1.2.3.4 [2014-04-15T17:54:58+02:00] "POST /POST.html HTTP/1.1" 405 166 "curl/7.32.0"
1.2.3.4 [2014-04-15T17:55:41+02:00] "GET /GET.html HTTP/1.1" 200 3 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:55:41+02:00] "GET /GET.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T17:55:41+02:00] "PUT /PUT.html HTTP/1.1" 411 174 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:55:41+02:00] "GET /PUT.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T17:56:05+02:00] "HEAD /HEAD.html HTTP/1.1" 200 0 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:56:05+02:00] "GET /HEAD.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T17:56:23+02:00] "TRACE /TRACE.html HTTP/1.1" 405 166 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:56:23+02:00] "GET /TRACE.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T17:56:52+02:00] "DELETE /DELETE.html HTTP/1.1" 405 166 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:56:52+02:00] "GET /DELETE.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
199.19.249.196 [2014-04-15T17:57:52+02:00] "GET /OPTION.html HTTP/1.1" 200 3 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Au-delà de la configuration incomplète du service nginx, provoquant parfois des codes d’erreur, le tableau suivant récapitule la situation :
Méthode HTTP |
Comportement client |
Comportement WebPulse |
POST |
POST, code retour 405 |
Pas de requête |
GET |
GET, code retour 200 |
GET, code retour 200 |
PUT |
PUT, code retour 411 |
GET, code retour 200 |
HEAD |
HEAD, code retour 200 |
Pas de requête |
TRACE |
TRACE, code retour 405 |
GET, code retour 200 |
DELETE |
DELETE, code retour 405 |
GET, code retour 200 |
OPTION |
Page d’erreur proxy « Network Error (tcp_error) » |
GET, code retour 200 |
Au bilan, toutes les méthodes sont transformées en GET, sauf POST et HEAD qui sont ignorées.
Je laisse au lecteur imaginer les effets de bord dans le cas d’applications ayant une interprétation des principes CRUD (cf. [CRUD]) divergente de celle - correcte - de Blue Coat (qui n'a jamais vu de mise à jour en GET ?).
5. Des octets oubliés
Après avoir testé des ressources à la taille réduite, continuons les tests sur des ressources de taille plus importante, 2 et 5 Mo :
199.19.249.196 [2014-04-15T17:24:00+02:00] "GET /2000ko.html HTTP/1.1" 200 153758 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR
3.5.30729)"
1.2.3.4 [2014-04-15T17:24:17+02:00] "GET /2000ko.html HTTP/1.1" 200 2048000 "curl/7.32.0"
199.19.249.196 [2014-04-15T17:24:33+02:00] "GET /5000ko.html HTTP/1.1" 200 143360 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T17:25:21+02:00] "GET /5000ko.html HTTP/1.1" 200 5120000 "curl/7.32.0"
Sur ces deux tests, WebPulse récupère seulement 153 ko au lieu de 2 Mo, puis 143 ko au lieu de 5 Mo.
Le même test reproduit quelques jours après produit un résultat différent : 213 ko au lieu de 5 Mo.
103.246.38.196 [2014-04-17T17:43:36+02:00] "GET /5000ko.html HTTP/1.1" 200 213958 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
Nous avons trouvé ici un premier moyen pour « contourner » le système d’analyse : il suffit de placer les données utiles après les premiers octets, la limite devant être encore déterminée (mais 300 ko devrait suffire).
6. Une norme n’est pas une NoRMe
La lecture du User_Agent envoyé par WebPulse indique un navigateur Internet Explorer 7.0 sous Windows 5.1.
Windows 5.1, mais c'est Windows XP ! Est-ce que Blue Coat a payé une extension du support de ce vieil OS à Microsoft ?
Qui dit Windows, dit majuscule = minuscule. Pour rire un peu, j'ai connu une société qui avait ouvert un incident auprès de l'éditeur (français) d'un OS Linux, parce que lorsque le navigateur client (sous Linux donc) demandait une ressource à un serveur (sous Linux aussi), il envoyait des URLs avec des majuscules (telles que demandées par l'application), et donc recevait des erreurs 404, alors que le client Windows renvoyant tout en minuscules pouvait accéder aux ressources sans problème. Bref, au-delà du comportement de l'OS, il s'agit aussi d'un défaut de compétence des développeurs.
Donc, vérifions le comportement de WebPulse concernant la casse des caractères dans les URLs, dont la RFC 3986 précise le comportement attendu à la section 6.2.2 (cf. [RFC3986]), soit pour résumer, respecter la casse des caractères au niveau du chemin d'accès à la ressource.
1.2.3.4 [2014-04-15T18:28:25+02:00] "GET /norme.html HTTP/1.1" 200 11 "curl/7.32.0"
199.19.249.196 [2014-04-15T18:28:25+02:00] "GET /norme.html HTTP/1.1" 200 11 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
1.2.3.4 [2014-04-15T18:28:34+02:00] "GET /NoRMe.html HTTP/1.1" 200 20 "curl/7.32.0"
Les traces précédentes indiquent que WebPulse ne respecte pas cette norme (pas d’appel de la page /NoRMe.html par le robot).
Comme pressenti, WebPulse ne respecte pas la casse des caractères. Ainsi, un attaquant astucieux pourrait élaborer un scénario de contournement (provoquer un premier appel vers une ressource saine, puis utiliser des changements dans la casse des caractères pour pointer vers des pages « malicieuses »).
7. Simplifions
Comme nous l’avons vu, l’attaquant a à sa disposition deux outils pour contourner WebPulse : placer le code actif au-delà des 300 premiers ko, et/ou utiliser à bon escient la casse des caractères dans les URLs.
Mais tout ceci est fastidieux et compliqué (et comme tout adminsys, je suis très fainéant), alors qu’un simple ajustement de la configuration du serveur cible (portant le code malicieux) permet de renvoyer systématiquement une page saine à Blue Coat, tout en se gardant la possibilité d’infecter un utilisateur imprudent.
L’extrait suivant indique un exemple de configuration (toujours pour nginx) :
geo $bluecoat {
default 0;
199.116.168.0/21 1; # CIDR Blue Coat
199.19.248.0/21 1; # CIDR Blue Coat
}
server {
[…]
if ($bluecoat) {
rewrite ^(.*)$ /bluecoat.html break;
}
[…]
}
Si l’appelant provient d’un réseau Blue Coat (voir la liste – mise à jour régulièrement – des adresses IP utilisées pour le service sp.cwfservice.net [WP_IP]), alors le serveur répond par une page saine (/bluecoat.html, d’une taille de 1,9 ko environ), sinon la page demandée est fournie (1 o dans notre exemple).
1.2.3.4 [2014-04-15T18:59:23+02:00] "GET /1o.html HTTP/1.1" 200 2 "curl/7.32.0"
199.19.249.196 [2014-04-15T18:59:23+02:00] "GET /1o.html HTTP/1.1" 200 1914 "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; MS-RTC LM 8; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
Voilà, WebPulse est aveugle (mais heureux).
8. Droit de réponse
Avant de conclure, je vous propose ici une série de questions envoyées à Blue Coat, lequel, même si la réponse est parfois fournie, ne semble pas prendre au sérieux les interrogations de ses clients :
- Étant donné la sensibilité de données (clé de licence, User_Agent, URL, Referer…), pourquoi existe-t-il la possibilité de transmettre ces informations de manière non chiffrée (HTTP au lieu de HTTPS) ? Pas de réponse.
- Comment Blue Coat peut certifier que les données transmises ne sont pas utilisées hors de la fonctionnalité d’analyse de flux ? Il faut nous croire.
- Quelle est la politique de rétention des données transmises ? Le temps nécessaire à l’analyse.
- Pourquoi l’automate effectue parfois deux requêtes au lieu d’une (ancien comportement) ? Pas de réponse.
- Pourquoi l’automate ne respecte pas la RFC 3986 sur le sujet de la casse des caractères (§ 6.2.2.1) ? Pas de réponse.
- Pourquoi l’automate ne récupère que les premiers kilo-octets de la réponse HTTP ? Pas de réponse.
Conclusion
Malgré des fonctionnalités prometteuses, le service WebPulse peut être contourné très facilement par un attaquant. Étant donné les risques induits par cette solution, nous ne pouvons que vous conseiller de ne pas activer ce module. Gageons que les attaquants les plus motivés ont déjà compris comment passer sous le radar de Blue Coat.
L'analyse se veut factuelle, et je n'ai aucun intérêt à critiquer la solution, qui présenterait un intérêt certain pour les utilisateurs avec une implémentation différente.
Le premier objectif est d'avertir les utilisateurs de la fuite d'informations inhérente à ce type d'infrastructure. Le deuxième est de démontrer que la pertinence de ce service est à relativiser, étant donné la facilité avec laquelle nous pouvons le contourner. Le dernier est de provoquer une amélioration du service (si possible), accompagnée d'une communication claire (et d'une vraie réponse aux questions).
Remerciements
Un grand merci au petit scarabée pour sa relecture, et à l'équipe rédactionnelle pour ses conseils avisés.
Références
[WP] https://www.bluecoat.com/security/webpulse
[WP_F] https://kb.bluecoat.com/index?page=content&id=KB3400
[BC_C] https://sitereview.bluecoat.com/sitereview.jsp
[WP_LN] https://kb.bluecoat.com/index?page=content&id=KB4246
[WP_FAQ411] https://kb.bluecoat.com/index?page=content&id=FAQ411
[EFF_UA] https://www.eff.org/deeplinks/2010/01/tracking-by-user-agent
[WP_L] http://www.bestnetworksecurity.com/articles/anti-phishing-and-webfilter-real-time-rating-service
[BC_WHOIS] http://viewdns.info/whois/?domain=199.19.249.196
[CRUD] https://en.wikipedia.org/wiki/Create,_read,_update_and_delete
[RFC3986] https://tools.ietf.org/html/rfc3986#section-6.2.2
[WP_IP] https://kb.bluecoat.com/index?page=content&id=KB3381