API


as discovered previously, a virtual host is hosting a webhook api endpoint at http://webhooks-api-beta.cybermonday.htb/webhooks/fda96d32-e8c8-4301-8fb3-c821a316cf77 A webhook is a user-defined HTTP callback mechanism that enables one system to send real-time data to another system when a specific event occurs. It facilitates the automatic exchange of information between applications or services by triggering predefined actions when events like updates, creations, or deletions occur. Webhooks eliminate the need for continuous polling and provide a more efficient and responsive way to communicate data changes. They are commonly used in various contexts, including API integrations, notifications, and automation workflows.

The additional virtual host information has been appended to the /etc/hosts file

The endpoint doesn’t seem to be available, but I will check the webroot

Sending a GET request to the webroot returns a JSON data with various pieces of information, particularly about API routes and their methods and parameters. It looks like a description of different routes and their associated details in a web API. The supported features are;

registration


┌──(kali㉿kali)-[/usr/…/seclists/seclists/Discovery/Web-Content]
└─$ curl -X POST http://webhooks-api-beta.cybermonday.htb/auth/register -H "Content-Type: application/json" -d '{"username": "apiuser", "password": "qwe123"}'               
{"status":"success","message":"success"}                                                                                                                                        

Testing out the /auth/register API endpoint with the username, apiuser, and password, qwe123 It seems to be successful based on the returned data

Not sure where this credential gets registered to

login


┌──(kali㉿kali)-[/usr/…/seclists/seclists/Discovery/Web-Content]
└─$ curl -x post http://webhooks-api-beta.cybermonday.htb/auth/login -H "Content-Type: application/json" -d '{"username": "apiuser", "password": "qwe123"}'   
{"status":"success","message":{"x-access-token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg"}}                                                                                                                                        

Testing the /auth/login API endpoint also succeeded and x-access-token is given The token appears to be the JWT(JSON Web Token) as it’s composed of 3 sections separated by dot (.)

i can confirm that by using an online tool; jwt.io

it indeed is a jwt signed with rs256 another notable point is that the id parameter is set to 2, which indicates that there is an existing user ("id":1)

webhooks


┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ curl http://webhooks-api-beta.cybermonday.htb/webhooks -H "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg"  
{"status":"success","message":[{"id":1,"uuid":"fda96d32-e8c8-4301-8fb3-c821a316cf77","name":"tests","description":"webhook for tests","action":"createLogFile"}]}                                                                                                                                        

The regular GET request to the /webhooks endpoint seems to list the available webhooks This reveals the uuid of the unknown feature; createLogFile

webhooks creation


┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ curl -x post http://webhooks-api-beta.cybermonday.htb/webhooks/create -H "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg" -H "Content-Type: application/json"  -d '{"name": test", "description": "testing", "action": "someTest"}' 
{"status":"error","message":"Unauthorized"}                                                                                     

Attempting to create an arbitrary webhook with the newly created credential fails due to the privileges issue

createLogFile


┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ curl -X POST http://webhooks-api-beta.cybermonday.htb/webhooks/fda96d32-e8c8-4301-8fb3-c821a316cf77 -H "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg" -H "Content-Type: application/json"  -d '{"url":"blah"}'
{"status":"error","message":"\"log_name\" not defined"}                                                                                                                                        

The returned data shows that the log_name parameter is missing I will supply the required parameter and try again

┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ curl -X POST http://webhooks-api-beta.cybermonday.htb/webhooks/fda96d32-e8c8-4301-8fb3-c821a316cf77 -H "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg" -H "Content-Type: application/json"  -d '{"log_name":"blah"}'
{"status":"error","message":"\"log_content\" not defined"}

This time, the error shows that the log_content parameter is missing same thing.

┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ curl -X POST http://webhooks-api-beta.cybermonday.htb/webhooks/fda96d32-e8c8-4301-8fb3-c821a316cf77 -H "x-access-token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJhcGl1c2VyIiwicm9sZSI6InVzZXIifQ.cmh44nhZ-7yjOkacgLB5QOXmks1p50VxqZh_1Yn-VxzUxj64XdtjtZDsQRDxpCTXfnGi2yZ6Fw3xP9DGoY1p75-aJDhlXp0hO7AMb2I87TmDaXUs8kpwaP-akqbCLmSa1tHAFA7ZDz8aX1i-axBcBHdUSgBa1ddGHWkQbp-PiyZ3XwZyS52Pjg-OKbp2ZlFe8y1RyCagolLbro3yv1ghPA_Gpb7Wm1YDOcgD75uD1R2BTtiMc_S03tUy2Kdcv0LVNV4iqYXi6PUQPP5ZKNqbRIlZatdStXQdq5JPeEveoSCV5UfE6SHEigyUTmp1a29gsglCMD7xmFCtWAetKBY1Lg" -H "Content-Type: application/json"  -d '{"log_name": "blah", "log_content": "some content here and there"}'
{"status":"success","message":"Log created"}

The purpose of the feature is still unclear, It went through

Fuzzing


┌──(kali㉿kali)-[~/archive/htb/labs/cybermonday]
└─$ ffuf -c -w /usr/share/wordlists/seclists/discovery/web-content/combined_words.txt -u http://webhooks-api-beta.cybermonday.htb/FUZZ -ic  
________________________________________________
 
 :: Method           : GET
 :: URL              : http://webhooks-api-beta.cybermonday.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
 
[status: 200, Size: 602, Words: 104, Lines: 21, Duration: 103ms]
    * fuzz: .htaccess
 
[status: 200, Size: 447, Words: 7, Lines: 11, Duration: 216ms]
    * fuzz: jwks.json
 
:: Progress: [128338/128338] :: Job [1/1] :: 63 req/sec :: Duration: [0:26:59] :: Errors: 0 ::

ffuf found 2 files; .htaccess and jwks.json

.htaccess


┌──(kali㉿kali)-[/usr/…/seclists/seclists/Discovery/Web-Content]
└─$ curl http://webhooks-api-beta.cybermonday.htb/.htaccess    
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>
 
    RewriteEngine On
 
    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
 
    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]
 
    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

Not much going on with the .htaccess file here

jwks.json


┌──(kali㉿kali)-[/usr/…/seclists/seclists/Discovery/Web-Content]
└─$ curl http://webhooks-api-beta.cybermonday.htb/jwks.json
{
	"keys": [
		{
			"kty": "RSA",
			"use": "sig",
			"alg": "RS256",
			"n": "pvezvAKCOgxwsiyV6PRJfGMul-WBYorwFIWudWKkGejMx3onUSlM8OA3PjmhFNCP_8jJ7WA2gDa8oP3N2J8zFyadnrt2Xe59FdcLXTPxbbfFC0aTGkDIOPZYJ8kR0cly0fiZiZbg4VLswYsh3Sn797IlIYr6Wqfc6ZPn1nsEhOrwO-qSD4Q24FVYeUxsn7pJ0oOWHPD-qtC5q3BR2M_SxBrxXh9vqcNBB3ZRRA0H0FDdV6Lp_8wJY7RB8eMREgSe48r3k7GlEcCLwbsyCyhngysgHsq6yJYM82BL7V8Qln42yij1BM7fCu19M1EZwR5eJ2Hg31ZsK5uShbITbRh16w",
			"e": "AQAB"
		}
	]
}                                                                                                                                        

however, the jwks.json file is a lot more important as it is the private key of the rs256 algorithm used here for JWT Knowing this would allow me to forge a JWT to impersonate other users