Chrome Téléphone Maison

Fin mars, Google a pris la décision unilatérale de retirer de son magasin de certificats l’autorité chinoise pour avoir frauduleusement émis des certificats au nom de google dans le cadre probable d’une proxyfication SSL.

Le problème reproché à MCS Holdings est que le certificat de sécurité a été généré au nom de Google sans aucune autorisation. Cela est contraire aux bonnes pratiques exigées dans les politiques de certification par le CA Browser Forum. Google aurait pu se limiter à révoquer le certificat intermédiaire (comme l’ont fait Microsoft et Mozilla). Mais finalement, Google a frappé plus fort : il rejette l’ensemble des certificats racines de CNNIC. Cette décision radicale et unilatérale a pour conséquence le rejet par cascade de tous les certificats qui ont été générés par l’entreprise.

L’impact devrait se faire sentir sur le web chinois d’autant plus que le navigateur chrome est particulièrement présent: notamment sur les smartphones.

Au delà de ce débat politico-philosophico-sécuritaire sur cette décision, une autre question se pose : Comment Google a-t-il été mis au courant de cette interception ?

L’utilisation du navigateur Google Chrome sur ces réseaux internes aurait-il permis l’exfiltration de données (une alerte de non conformité de la chaine des certificats utilisés) ? Google aurait-il mis un système en place dans son navigateurs pour s’assurer que ses services ne sont pas proxyfiés ?

La réponse est comme nous allons voir unanimement  : Oui !

Tout d’abord, expliquons ici rapidement la notion de Public Key Pinning.

Le Public Key Pinning ou en bon Français l’épinglage de clé publique est un mécanisme de sécurité.  Il consiste simplement à coder en dur dans un système la valeur que doit avoir telle clé publique. Dans le cas de Chrome, ce système est utilisé afin d’éviter tout usurpation par un tiers (légitime ou non) qui utiliserait un certificat différent (i.e non émis par l’IGC officielle) sur un service de Google et ce, même s’il est reconnu comme valide par le système sous-jacent. (Rappelons que par exemple sous Windows, Chrome utilise le magasin de certificat de l’OS, ce qui est bien différent de Firefox).

Donc Chrome embarque un système qui lui permet de détecter un homme du milieu. Mais cela ne nous dit pas comment la maison mère est informée d’une telle usurpation. Ainsi pour voir de quoi il retourne, nous prenons une grande respiration et nous plongeons dans le code source de Chromium (la version open source de Chrome) :

Une plongée à pic dans le code de Chrome nous conduit tout droit vers le fichier : chrome_fraudulent_certificate_reporter.cc, où nous trouvons des éléments très concrets sur la remontée d’information d’éventuels « certificats frauduleux ».

// TODO(palmer): Switch to HTTPS when the error handling delegate is more
// sophisticated. Ultimately we plan to attempt the report on many transports.
static const char kFraudulentCertificateUploadEndpoint[] =
"http://clients3.google.com/log_cert_error";

Les commentaires dans le code sont également très clairs.

void ChromeFraudulentCertificateReporter::SendReport(
const std::string& hostname,
const net::SSLInfo& ssl_info) {
// Do silent/automatic reporting ONLY for Google properties. For other
// domains (when that is supported), Chrome will ask for user permission.
if (!net::TransportSecurityState::IsGooglePinnedProperty(hostname))
return;

certificate_reporter_->SendReport(
CertificateErrorReporter::REPORT_TYPE_PINNING_VIOLATION, hostname,
ssl_info);
}

Du coup, ca devient assez explicite.

En pratique regardons ce que cela donne…

Dans un premier temps, installons un site web sur une machine de notre réseau, ainsi qu’un accès en SSL avec une chaine « maison » de certificats. Une fois le site en place, configurons une redirection DNS via /etc/hosts.

%> cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       ubuntu
10.10.10.10   www.google.com
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Puis lançons Google Chrome.

Une fois que nous voulons accéder à la page https://www.google.com, Chrome nous affiche directement une erreur :

cert_auth_invalidEn parallèle, si nous observons le trafic avec Wireshark : il n’y a aucune communication vers clients3.google.com.

Si nous nous penchons davantage sur le sujet, nous tombons sur le blog Imperial Violet, qui explique que la mise en place de proxy SSL ne déclenchera pas d’alertes. Le Proxy SSL l’emporte sur l’épinglage de certificat. Il faut donc aller plus loin dans notre investigation.

Si l’on en croit le blog, pour passer outre le PKP, il faut simplement ne pas le faire avec des certificats émis par des ACs reconnues nativement par les navigateurs (comprendre validées par le CA Browser Forum) ou plus précisément ne pas utiliser de clé publique dont le hash est une collision avec l’une d’entre elles.

Ces hashs peuvent être obtenus de la sorte :

%> openssl x509 -inform DER -in GIAG2.crt -noout -pubkey | grep -v "\-\-\-\-" | base64 -d | sha1sum
43dad630ee53f8a980ca6efd85f46aa37990e0ea

Quatres options s’offrent à nous :

  • Monter une AC et la faire valider par le CA Browser forum : Un peu long, un peu chère, un peu chiant pour juste faire un test qui nous fera radier du CA Browser forum
  • Hacker un PSCE : bon, certains l’ont déjà fait… Mais c’est un peu compliqué et illégal.
  • Modifier le code source de Chromium et le recompiler : 22Go de code source, ça fait beaucoup quand même…
  • Et si on modifiait directement le code compilé de Chrome : ça c’est une méthode bien dans l’esprit des gros bourrins que nous sommes.

Nous allons donc tenter cette dernière. Commeçons par rechercher la chaine dans le binaire de Chrome sous linux :

%> xxd -p /opt/google/chrome/chrome | grep -c '43dad630ee53f8a980ca6efd'
1
%> bless /opt/google/chrome/chrome
%> xxd -p /opt/google/chrome/chrome | grep -c '43dad630ee53f8a980ca6efd'
0
%> xxd -p /opt/google/chrome/chrome | grep -c '43dad6ddee53f8a980ca6efd'
1

Notez bien la différence sur la dernière ligne, nous avons modifié via l’éditeur hexadécimal bless le 4ème octet du hash de l’autorité de confiance de Google.

On relance Chrome qui redémarre sous aucun soucis (on notera ici que chrome n’est doc pas protégé en intégrité).

Tentons maintenant d’ouvrir Chrome et d’accéder au vrai http://www.google.com :

  SSL_PINNED_KEY

Chrome nous renvoie cette fois-ci une erreur différente mais qui semble plus convenir à ce que nous recherchons NET:ERR_SLL_PINNED_ KEY_NOT_IN_CERT _CHAIN.

De plus, nous observons une communication vers clients3.google.com : le site de délation pointé plus haut.

wireshark

Voici en détails la communication HTTP entre le serveur et le client (en utilisant l’option « Follow TCP Steam »).

POST /log_cert_error HTTP/1.1
Host: clients3.google.com
Connection: keep-alive
Content-Length: 4684
Content-Type: x-application/chrome-fraudulent-cert-report
User-Agent: Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/41.0.2272.118 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8


.www.google.com..!-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIavTkiJZO79swDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwNDIyMTM0NjQyWhcNMTUwNzIxMDAwMDAw
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAB/W1
HE/ZA8NvB/oOrg6WN4zK6vdt9uqTpk3KAQzQ/e2qwy5WoewNmJgx9RPLIuHReTH+
Orh8vF1jk27rC89Pns9rRsE/FVjpaefNHi3trVFbDHcVdrU6JW0XjsG1+wbL8uSU
vDMiey4ZNqUfopX3MJ6LHpFr5FgrRW1RsemTs/BfXjC4MoBdwnt6xoljh+KHzycy
8OgmCVXPONubyUKUeY/Ui9PaX0GWh5dE5uF72jG8NVPs67K7qpfmrdVSGHvRxH3P
AwA90eKlakelqCSfcrZXD8q7EsMBQvRQbbFeuh/TexdiX+8hA1PXNMEURK5y2EBz
5jAbLuuLbQPN/DqZAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
A1UdDgQWBBSgAQj1VB+R5iA9ZysggEXxg+oRFzAMBgNVHRMBAf8EAjAAMB8GA1Ud
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBlViFXxmddM6J6cVgUBHWw9nsSoJba
SuwHE3Bfo9rrgzV80MazeDaM/tdVSCCA4jD/8jyJr3jl4wtazH9fkn7oBUxYEC22
Xy68txnKMu5LNze+eMbSs7MKSqcPd1ZdUm+3xcsnSc3bmvm/AuOd4WPueMhYdr4c
qwUht+yFSBqEp856JjxsYDlX61h9i7Kq2EAPxA+9GvT2c5j9upUXmUYVnLrx4xjX
LqbbahlsKd+fwvZZ7bFSuyFS8zs5HRfL1kuW1i79cHpuNqQmzC+DrFF2ouJi7uCR
/A6Yfa2DF67oyHZKXuogVwko+cfVe91v+aAQVyltkzAcZy/xaypI8WFj
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID8DCCAtigAwIBAgIDAjp2MA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig
JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF
BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMBcGA1UdIAQQ
MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQUFAAOCAQEAJ4zP6cc7vsBv6JaE
+5xcXZDkd9uLMmCbZdiFJrW6nx7eZE4fxsggWwmfq6ngCTRFomUlNz1/Wm8gzPn6
8R2PEAwCOsTJAXaWvpv5Fdg50cUDR3a4iowx1mDV5I/b+jzG1Zgo+ByPF5E0y8tS
etH7OiDk4Yax2BgPvtaHZI3FCiVCUe+yOLjgHdDh/Ob0r0a678C/xbQF9ZR1DP6i
vgK66oZb+TWzZvXFjYWhGiN3GhkXVBNgnwvhtJwoKvmuAjRtJZOcgqgXe/GFsNMP
WOH7sf6coaPo/ck/9Ndx3L2MpBngISMjVROPpBYCCX65r+7bU2S9cS+5Oc4wt7S8
VOBHBw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
.........*..Rejecting public key chain for domain google.com. Validated chain: sha1/
jF2O7IYbEOOpLdqn7yuS0LThMH8=,sha256/4A1biTdE/o+f3r2TkTIWAVYq/SDuG+Y6bGpiVaMruPY=,sha1/
Q9rWMO5T+KmAym79hfRqo3mQ4Oo=,sha256/7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=,sha1/
wHqYaI2J+6sFZAwRfap9ZbjKzE4=,sha256/h6801m+z8v3zbgkRHpq6L29Esgfzhj89C1SyUCOQmqU=,
expected: sha1/vq7OyjSnqOco9nyMCDGdy77eijM=,sha1/Q9rW3e5T+KmAym79hfRqo3mQ4Oo=


HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Fri, 08 May 2015 12:36:43 GMT
Server: HTTP server (unknown)
Cache-Control: private
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic,p=1
Vary: Accept-Encoding
Transfer-Encoding: chunked
Accept-Ranges: none

Il ne s’agit ni plus ni moins que de la chaine complète des certificats utilisés pour authentifier le site. Donc nous venons de confirmer que Chrome dès lors qu’il  détecte une usurpation de ces services via une AC légitime, transmet immédiatement toutes les informations à un serveur dédié chez Google.

Cependant si nous regardons le certificat présenté par le serveur au navigateur, celui-ci est parfaitement légitime :

vrai_faux_certificatQue s’est-il donc passé ?

Nous avons modifié en hexadécimal dans le code de Google-Chrome la valeur du hash de kSPKIHash_GoogleG2.

Et par défaut, nous avons ceci :

static const char kSPKIHash_GoogleG2[] =
"\x43\xda\xd6\x30\xee\x53\xf8\xa9\x80\xca"
"\x6e\xfd\x85\xf4\x6a\xa3\x79\x90\xe0\xea";

Cette valeur est utilisée plus loin :

static const char* const kGoogleAcceptableCerts[] = {
kSPKIHash_GoogleBackup2048,
kSPKIHash_GoogleG2,
kSPKIHash_GeoTrustGlobal,
NULL,
};

Donc si vous modifiez la valeur du hash du SubjectPublicKeyInfo  de l’AC de Google dans le binaire de Chrome, Lorsque le serveur présente sa chaine légitime de certificat, cette autorité n’est plus considérée comme de confiance en comparaison avec le hash que nous avons modifié.

Or cette AC est signée par GeoTrust Global CA qui est elle-même validé par le CA Browser Forum : Google interpréter cela comme une usurpation illégitime de ces services par un AC tiers non autorisée. Exactement ce qui s’est passé dans le cadre de l’affaire MCS Holdings.

Moralité si vous voulez mettre en place un proxy SSL sur les services de Google et rester discrets et sereins, pensez à faire un peu de filtrage.

A bon entendeur 🙂

A propos JoMendes

Amateur de mathématiques et d'hexadécimal. Je m'intéresse de près ou de loin suivant mon niveau à tous les sujets de sécurité de l'information.
Cet article, publié dans cryptobourrin, Cryptographie Asymétrique, Outils, est tagué , , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire