Web


Nmap discovered a web server on the target port 80 The running service is nginx 1.18.0

Webroot

It’s a login page.


Intercepting the request through Burp Suite, I notice that there are 3 sets of cookies

  • token seems to be either JWT or Flask Token
  • XSRF.TOKEN just a generic XSRF/CSRF prevention
  • intentions_session seems to be a custom session token

token


┌──(kali㉿kali)-[~/archive/htb/labs/intentions]
└─$ jwt_tool 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTAuMTEuMjIwL2FwaS92MS9hdXRoL2xvZ2luIiwiaWF0IjoxNjg4Mzg0MTE0LCJleHAiOjE2ODg0MDU3MTQsIm5iZiI6MTY4ODM4NDExNCwianRpIjoiQW9zMWJnTjNtUjcyNHNTdSIsInN1YiI6IjMyIiwicHJ2IjoiMjNiZDVjODk0OWY2MDBhZGIzOWU3MDFjNDAwODcyZGI3YTU5NzZmNyJ9.6N2yJxp3FEKUqJvKjyUNdJuYUSq6rZCYAtoYy2AcrdY'
 
        \   \        \         \          \                    \ 
   \__   |   |  \     |\__    __| \__    __|                    |
         |   |   \    |      |          |       \         \     |
         |        \   |      |          |    __  \     __  \    |
  \      |      _     |      |          |   |     |   |     |   |
   |     |     / \    |      |          |   |     |   |     |   |
\        |    /   \   |      |          |\        |\        |   |
 \______/ \__/     \__|   \__|      \__| \______/  \______/ \__|
 Version 2.2.6                \______|             @ticarpi      
 
original jwt: 
 
=====================
decoded token values:
=====================
 
token header values:
[+] typ = "JWT"
[+] alg = "HS256"
 
token payload values:
[+] iss = "http://10.10.11.220/api/v1/auth/login"
[+] iat = 1688384114    ==> timestamp = 2023-07-03 13:35:14 (UTC)
[+] exp = 1688405714    ==> timestamp = 2023-07-03 19:35:14 (UTC)
[+] nbf = 1688384114    ==> timestamp = 2023-07-03 13:35:14 (UTC)
[+] jti = "Aos1bgN3mR724sSu"
[+] sub = "32"
[+] prv = "23bd5c8949f600adb39e701c400872db7a5976f7"
 
seen timestamps:
[*] iat was seen
[*] exp is later than iat by: 0 days, 6 hours, 0 mins
 
----------------------
jwt common timestamps:
iat = IssuedAt
exp = Expires
nbf = NotBefore
----------------------

This one is indeed a JWT token It seems that the authentication is made to the API endpoint at /api/v1/auth/login

intentions_session


┌──(kali㉿kali)-[~/archive/htb/labs/intentions]
└─$ echo 'eyJpdiI6ImZacDhOcVlDMWxNcGNMcXYrc0htaXc9PSIsInZhbHVlIjoiYTdOQytGck5iVUZFamkxR1dKMlIzWlc4cDc3SldrZGFYRmdudDBDYUZmY3J0UG1JWXJCcFRGcG0zcGcwMlBPTmkwKzl5cnBFMDN1eGpLdzZIL01WVGE1WnkzZXl4SUw0TjdhZjczUWxPdkgrL1g2ZHVLcWNpR0dNNjFwU2NLWnEiLCJtYWMiOiI1YTM3ODJkNDlkMDljZjhiNTI4ZDk0ZmE3MjdiODY4Mzk5YjUzNWM5NWRiMzMxMmUyNWNiMDcyYzY3ZDc1ZGJkIiwidGFnIjoiIn0%3D' | base64 -d
{"iv":"fZp8NqYC1lMpcLqv+sHmiw==","value":"a7NC+FrNbUFEji1GWJ2R3ZW8p77JWkdaXFgnt0CaFfcrtPmIYrBpTFpm3pg02PONi0+9yrpE03uxjKw6H/MVTa5Zy3eyxIL4N7af73QlOvH+/X6duKqciGGM61pScKZq","mac":"5a3782d49d09cf8b528d94fa727b868399b535c95db3312e25cb072c67d75dbd","tag":""}base64: invalid input

Although incomplete, the string appears to be encoded in the base64 format as it shows some relevant JSON data

Register / Login


Creating a testing account and logging in

The menu bar on the left-hand side consists of a few items

The Gallery button appears to display all the images

Individual images have a tag assigned. There are a total of 4 as far as those those displayed images show

Those images are located in the sub-directories under the /storage directory Names are very much arbitrary yet structural as if those were generated

I seem to be able to set the *Favorite Genres

Which is then reflected on My feed

Fuzzing


┌──(kali㉿kali)-[~/archive/htb/labs/intentions]
└─$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://$IP/FUZZ -ic -e .txt,.php,.html 
________________________________________________
 
 :: Method           : GET
 :: URL              : http://10.10.11.220/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Extensions       : .txt .php .html 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
index.php               [Status: 200, Size: 1523, Words: 415, Lines: 40, Duration: 128ms]
gallery                 [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 106ms]
admin                   [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 113ms]
storage                 [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 192ms]
css                     [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 204ms]
js                      [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 243ms]
logout                  [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 294ms]
robots.txt              [Status: 200, Size: 24, Words: 2, Lines: 3, Duration: 205ms]
fonts                   [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 209ms]

ffuf made a few discoveries.

  • The index.php file is the web root
  • The robots.txt file seems to be rather empty
  • /admin and /storage returns the code 301, likely locked behind the authentication
  • There is the /js directory

JS


Checking the Burp Crawler reveals that the web server keeps loading up 3 JS files

While those JS files appear to be heavily obfuscated for security, little bit of reading suggests that the target web application is running off of these scripts

There are many API endpoints

genres


One of the API endpoints reveals the current sessions user data in the JSON format This is the testing account that I created earlier.

As shown above, I am able to modify the values of the genres parameter

The genres parameter seems to be affecting what gets displayed on to /gallery#/feed

Additionally, /gallery#/feed pulls resources from the API endpoint at /api/v1/gallery/user/feed

This suggests a potential for the 2nd order attack

Fuzzing /js/


┌──(kali㉿kali)-[~/archive/htb/labs/intentions]
└─$ ffuf -c -w /usr/share/wordlists/seclists/discovery/web-content/directory-list-2.3-medium.txt -u http://$IP/js/FUZZ -ic -e .js
________________________________________________
 
 :: Method           : GET
 :: URL              : http://10.10.11.220/js/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Extensions       : .js 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
login.js                [status: 200, Size: 279176, Words: 5446, Lines: 2, Duration: 92ms]
gallery.js              [status: 200, Size: 310841, Words: 6285, Lines: 2, Duration: 92ms]
admin.js                [status: 200, Size: 311246, Words: 6584, Lines: 2, Duration: 91ms]
app.js                  [status: 200, Size: 433792, Words: 7736, Lines: 2, Duration: 236ms]
mdb.js                  [status: 200, Size: 153684, Words: 2246, Lines: 2, Duration: 298ms]

ffuf discovered admin.js and app.js in the /js directory

admin.js


There are some parts within the script with mentions of ReactNative and NativeScript

Here is the most interesting part. It seems that someone left a note in the admin GUI panel

Note

Recently we've had some copyrighted images slip through onto the gallery. This could turn into a big issue for us so we are putting a new process in place that all new images must go through our legal council for approval. Any new images you would like to add to the gallery should be provided to legal with all relevant copyright information. I've assigned Greg to setup a process for legal to transfer approved images directly to the server to avoid any confusion or mishaps. This will be the only way to add images to our gallery going forward.
 
 
Hey team, I've deployed the v2 API to production and have started using it in the admin section.
Let me know if you spot any bugs. This will be a major security upgrade for our users, passwords no longer need to be transmitted to the server in clear text! By hashing the password client side there is no risk to our users as BCrypt is basically uncrackable.
This should take care of the concerns raised by our users regarding our lack of HTTPS connection.
 
the v2 api also comes with some neat features we are testing that could allow users to apply cool effects to the images. i've included some examples on the image editing page, but feel free to browse all of the available effects for the module and suggest some:

The note above mentions the following;

  • Greg might be an admin
  • The second version of the API being already deployed to the admin section of the web app.
  • Passwords no longer need to be transmitted in the cleartext as the v2 API requires hashing on the client side with BCrypt
  • The v2 API also allows users to apply effects to the images
v2 API Authentication

Attempting to authenticate to the v2 API, indeed fails with a message that the hash field is required