Write-up author: jon-brandy
- Source Code Review.
- Bypassing SSRF Filter (filter for localhost IP usage).
- Execute Server-Side Request Forgery.
HauntMart, a beloved Halloween webstore, has fallen victim to a curse, bringing its products to life. You must explore its ghostly webpages, and break the enchantment before Halloween night. Can you save Spooky Surprises from its supernatural woes?.
- NONE
- In this challenge we're given the source code of the webapp.
WEBAPP
- Noticed there's a register option, hence the objective is to not bypass the login page or achieved admin role with bypassing the DB logic.
- Upon registering an account, we're redirected to
/home
endpoint.
- After clicking every available feature, turns out only one feature accessible. The sell product.
- Interesting! Let's review the source code handling the logic behind this endpoint.
- The first step involves employing the @isAuthenticated middleware, followed by an endpoint that anticipates a JSON body containing specific keys.
- Subsequently, the
downloadManual
function is invoked, taking the manualUrl value from the JSON body as an argument. - Should this call yield a False result, the request is halted with a status of 400.
- Conversely, if it returns True, the addProduct function is triggered, accepting parameters such as name, description, and price. Upon successful execution of this function, the request is terminated satisfactorily.
- Let's review the
@isAuthenticated
middleware code.
- Based from the code, the middleware checks if a session token exists. If it does, it verifies it and passes the user information to the decorated function. If it does not exist, it returns a 401 HTTP error indicating unauthorized access.
- Next, let's review the
downloadManual
function.
- This code, checks whether the url does contain a blocked host, then it returns false. Otherwrise, it makes a request to the specified url.
- Let's review the
isSafeUrl
function.
- It filtered for localhost, interesting.
- Reviewing the other code, found a code that to make an admin user and seems the flag shall rendered if our role is admin. The flag itself shall rendered at the
/home
endpoint. - The
/addAdmin
endpoint should be our interest.
- Noticed there is a middleware called -->
@isFromLocalhost
, which handle that the/addAdmin
endpoint is only reachable from localhost request. - However, noticing there is a filter which blocks several localhost form, it's not quite robust. We can easily bypass it using
0
. - Seems now we're clear, the objective for this challenge is to do Server-Side Request Forgery.
Manual URL:
http://0:1337/api/addAdmin?username=vreshco
- Remember to use port 1337, based from the Dockerfile, that port is reachable.
Also the run.py code specified that the port for localhost is 1337.
- WHY adding /api/ at the manual URL? Because /addAdmin endpoint is one of api.route.
api = Blueprint('api', __name__)
...
...
...
@api.route('/addAdmin', methods=['GET'])
@isFromLocalhost
def addAdmin():
username = request.args.get('username')
if not username:
return response('Invalid username'), 400
result = makeUserAdmin(username)
if result:
return response('User updated!')
return response('Invalid username'), 400
EXECUTION
- Great! Now logout then login again, our user account shall upgraded to admin.
- Got the flag!
HTB{s5rf_m4d3_m3_w3t_my_p4nts!}