Saison | Épisode |
---|---|
1 | 11 |
- Spotify
- Deezer
- Youtube
- Youtube Music
- Amazon Music
- Apple Podcast
- Podcast Index
- podCloud
- Podchaser
- podtail
- Podcasts Français
- Vodio
- Spreaker
Notes#
Vocabulaire#
- IC : intégration continue (CI : continuous integration en anglais)
- DC : déploiement continue (CD : continuous deployment en anglais)
- Github Action : nom de l'outil de IC/DC intégré de Github
- ECD : exécution de code à distance (RCE : remote code execution en anglais)
- fusiodemande : demande de fusion d'un changement de code dans un dépôt git (merge request en anglais)
- tube ou bitoduc : conduits transportant des bits (pipeline en anglais)
Partie 1 - Aperçu#
- Introduction
- Contexte GitHub
- Contextes intéressant pour un attaquant :
env
,secrets
,github
,steps
,needs
- Exemple d'ECD :
${{ github.event.issue.title }}
et$(id)
dans le titre d'un ticket
- Contextes intéressant pour un attaquant :
- Secrets Github
- Permissions des flux de travaux
github.token
ousecrets.GITHUB_TOKEN
: jeton d'authentification spécifique à chaque tâche- Par défaut, le jeton à accès en lecture seule au dépôt
- Avant 2022, le jeton avait aussi le droit d'écriture par défaut
- Le changement n'est pas forcé, les organisations créées avant cette date ont toujours le droit d'écrite par défaut
- Peut être défini de manière granulaire
- Nouveaux contributeurs
- Par défaut, les flux de travail déclenchés par des fusiodemandes des nouveaux contributeurs externes à des dépôts publics demandent une approbation pour s'exécuter automatiquement
- Le flux de travail sera mis en pause en attendant
- Facilement contournable : faire 1ère contribution anodine et une 2ième malveillante
- Déclenchements des flux de travail
push
- peu utile pour l'attaquantpull_request
- pour cet évènementGITHUB_TOKEN
est restreint : il ne peut pas avoir de droit en écriture, sinon tout le monde pourrait modifier le code du projet, et ne peut pas lire les secretspull_request_target
- lors d'activité sur une fusiodemande, ex : quand la branche a été mise à jour, à accès en écriture et aux secrets, peut être configuré de manière granulaire sur les types d'évènementsworkflow_run
- quand un flux de travail est demandé ou en cours ou complété, permet de chainer plusieurs flux de travail, n'hérite pas des droits, le flux fils (celui avecworkflow_run
) est privilégié (écriture + accès aux secrets)action/checkout@v2
+ref: ${{ github.event.workflow_run.head_sha }}
: se base sur lecommit
qui a déclenché le flux de travail, peut exécuter le code de l'attaquant, ex : dans un des étapes suivantes est exécutée la commandenpm run script-perso
et que l'attaquant a modifiépackage.json
pour contenir sa commande malveillante dansscripts.script-perso
.- Téléchargement d'un artefact et fait quelque chose avec, il suffit alors d'écrire par dessus
Partie 2 - Exemples de cas réels#
- Injection d'expressions - Éléments contrôlables par un attaquant
github.event.issue.{title,body}
,github.event.pull_request.{title,body}
,github.event.{comment,review}.body
,github.event.commits.*.message
,github.event.commits.*.author.{email,name}
,env.*
, etc.- Apache Superset : évènement
issue_comment
+github.event.comment.body
dans unrun
- AutoGPT : évènement
pull_request_target
sur plusieurs branches +github.event.pull_request.head.ref
concaténé dans un script bash, ex. de charge utile";{echo,aWQK}|{base64,-d}|{bash,-i};echo"
en nom de branche puis fusiodemande - Microsoft Generative AI for Beginners : évènement
pull_request_target
+actions/checkout@v3
avecref: ${{ github.event.pull_request.head.sha }}
dont on peut abuser avec un fichier Markdown spécifiquement conçu - ant-design : évènement
workflow_run
+actions/checkout@v4
+dawidd6/action-download-artifact@v2
et un fichier JS est exécuter, il suffit de créer un flux de travail avec le même nom et d'utiliseractions/upload-artifact@v3
- Bascules (git) dangereuses
- Cypress : évènement
pull_request_target
+actions/checkout@v3
avecref: ${{ github.event.pull_request.head.ref }}
puisnpm install
, il suffit d'éditerpackage.json
- AutoGPT : évènement
pull_request_target
+actions/checkout@v3
avecref: ${{ github.event.pull_request.head.ref }}
puispip install -r requirements.txt
, il suffit d'éditerrequirements.txt
- excalidraw : évènement
issue_comment
+ … +actions/checkout@v2
où est récupéré l'identifiant de la fusiodemande puis utilisation deyarn
, il suffit de créer un fichier.yarnrc.yml
- Apache Doris ou FreeRDP ou Angular : évènement
pull_request_target
+actions/checkout@v3
avecref: ${{ github.event.pull_request.head.sha }}
et applique un correctif suractions/action-sh-checker
- Cypress : évènement
Partie 3#
- Détournement de dépôt (repository hijacking en anglais)
- Je créé des mots-valises : détournepôt ou dépônement (repojacking en anglais)
- Quand un flux de travail fait référence à une action sur une organisation ou un utilisateur GitHub inexistant (similaire aux prises de contrôle d'un sous-domaine)
- Il suffit de réclamer l'organisation et de créer un dépôt pour l'action mentionnée pour avoir une ECD dans le flux de travail
- Pour se protéger contre le détournement de dépôt, GitHub utilise un mécanisme de sécurité qui interdit l'enregistrement de dépôts ayant déjà existés avec plus de 100 clones au cours de la semaine précédant le changement de nom ou la suppression du compte du propriétaire
- Cela est arrivé sur un dépôt Azure
- Écriture dangereuse
- Des variables d'environnement crées par défaut
- Les variables d'environnement sont partagées entre les étapes
- On peut ECD avec
LD_PRELOAD
ouNODE_OPTIONS
si on peut contrôler cette variable dans une autre étapeNODE_OPTIONS="--experiment --experimental-loader=data:text/javascript,console.log('injection');"
- Exemple d'un cas un peu plus sofistiqué pour swagger-editor
NODE_OPTIONS
mis sur liste noire dans les versions récentes de GitHub runner
- Commande de flux de travail
- Commande pour interagir directement avec la machine
- Avant 2020 il était facile d'injecter
set-env
pour ECD - Si le dev. active
ACTIONS_ALLOW_UNSECURE_COMMANDS
, on peut utiliserset-env
- Il y a toujours
set-output
, déprécié, vuln. dans un dépôt Firebase- Test si
pr_number.txt
contient bien un nombre - La valeur du fichier est stocké dans
echo "::set-output name=pr_number::$pr_number"
- Puis utilisé dans une autre étape
${{ steps.unzip.outputs.pr_number }}
- La commande
unzip
va afficher le nom du fichier dans STDOUT - Avec un nom de fichier malveillant dans le Zip on peut donc contrôler la valeur de
pr_number
qui sera executé - Exemple de nom de fichier dans le Zip :
steps/Hello ##[set-output name=pr_number;]'end'}); console.log('pwn') ; console.log({console
pr_number
='end'}); console.log('pwn') ; console.log({console
- Test si
Références#
Synacktiv
- Partie 1 - Synacktiv - 🇬🇧 GitHub Actions exploitation: introduction
- 🇫🇷 Exploitation des GitHub Actions : introduction
- Partie 2 - Synacktiv - 🇬🇧 GitHub Actions exploitation: untrusted input
- 🇫🇷 Exploitation des GitHub Actions : entrée non fiable
- Partie 3 - Synacktiv - 🇬🇧 GitHub Actions exploitation: repo jacking and environment manipulation
- 🇫🇷 Exploitation des GitHub Actions : détournement de dépôt et manipulation de l'environnement
Legit Security
- Partie 1 - Legit Security - 🇬🇧 Vulnerable GitHub Actions Workflows Part 1: Privilege Escalation Inside Your CI/CD Pipeline
- 🇫🇷 Flux de travail Github Action vulnérables partie 1 : Élévation de privilèges à l'intérieur de votre bitoduc IC/DC
- Partie 2 - Legit Security - 🇬🇧 Vulnerable GitHub Actions Workflows Part 2: Actions That Open the Door to CI/CD Pipeline Attacks