I solved this gitlab box the unintended way by exploiting the
- Use creds to gain access to the profile repo and modify it to get PHP RCE
- Get root access using the unintended method of git post-merge hooks
The portscan shows SSH and HTTP ports open along with entries from
robots.txt indicating this is a Gitlab service. I’ll check out a couple of the URIs mentioned below in the next section.
root@kali:~/htb/bitlab# nmap -sC -sV -T4 10.10.10.114 Starting Nmap 7.80 ( https://nmap.org ) at 2019-09-08 09:49 EDT Nmap scan report for bitlab.htb (10.10.10.114) Host is up (0.022s latency). Not shown: 998 filtered ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 a2:3b:b0:dd:28:91:bf:e8:f9:30:82:31:23:2f:92:18 (RSA) | 256 e6:3b:fb:b3:7f:9a:35:a8:bd:d0:27:7b:25:d4:ed:dc (ECDSA) |_ 256 c9:54:3d:91:01:78:03:ab:16:14:6b:cc:f0:b7:3a:55 (ED25519) 80/tcp open http nginx | http-robots.txt: 55 disallowed entries (15 shown) | / /autocomplete/users /search /api /admin /profile | /dashboard /projects/new /groups/new /groups/*/edit /users /help |_/s/ /snippets/new /snippets/*/edit | http-title: Sign in \xC2\xB7 GitLab |_Requested resource was http://bitlab.htb/users/sign_in |_http-trane-info: Problem with XML parsing of /evox/about Service Info: 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 13.33 seconds
I already knew that the box was going to contain a Gitlab service based on the box name and the logo. The box was originally submitted as Gitlab but was renamed to Bitlab before launch.
I clicked the Explore link at the bottom of the page to look for repos but I didn’t see any repositories that are publicly accessible.
I checked a few links from the
robots.txt file and found a profile page for Clave:
That’s not a default page in Gitlab so I’ll keep that in mind for later.
Hardcoded Gitlab credentials
I initially skipped the Help section but when I went back and clicked on the link, I got the following page:
I can now log in to the Gitlab portal and I see two repositories that I have access to:
I have read/write access to the
Profile repo but only read access to
As per Gitlab’s documentation, these are the permissions available:
Guest - No access to code Reporter - Read the repository Developer - Read/Write to the repository Maintainer - Read/Write to the repository + partial administrative capabilities Owner - Read/Write to the repository + full administrative capabilities
Getting RCE through the Profile page
The Profile repository contains the webpage for the Profile page I found earlier. I see that it’s running PHP so if I can modify this page I should be able to gain remote code execution by adding a reverse shell on the page.
The Deployer repo code is a simple PHP script that expects a specific JSON message then does a
git pull. I assume this’ll be used to deploy the Profile page when I commit changes to the repo.
The repo is deployed in the root of the directory and I can access it with
I’ll add a PHP reverse shell in the Profile
index.php page that triggers when I have a
shell parameter present. Then I submit the merge request and merge it after.
I’ll craft the proper POST request with the Repeater function in Burp Suite. The JSON message has to match the exact format from the code I found in the repo.
Now that the profile page has been updated, I can trigger the reverse shell by sending a request with the
Unintended privilege escalation to root
www-data user can execute
git pull as root:
$ sudo -l Matching Defaults entries for www-data on bitlab: env_reset, exempt_group=sudo, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User www-data may run the following commands on bitlab: (root) NOPASSWD: /usr/bin/git pull $
Git has hooks that can be used to execute code after commit, push, merge, etc. I’ll use that to get remote execution as root through the
git pull command. The https://www.git-scm.com/docs/githooks#_post_merge documentation says:
This hook is invoked by git-merge, which happens when a git pull is done on a local repository.
First, I’ll create two local repos:
foo will be merged into the
bar repo. I’ll add a reverse shell in the
post-merge hook of the
bar repo where
bar will be merged into.
Then I’ll do an initial commit in the
foo repo and set up
bar to pull from the
And finally I’ll do a new commit in
foo so I can initiate a merge from
foo and trigger the reverse shell: