NahamCon 2021 CTF: Imposter

Westar
6 min readMar 16, 2021

This was a Medium challenge with 71 solves. Created by congon4tor#2334

Walkthrough

Upon loading the challenge, we get greeted with an invalid session message. Weird, but alright, let’s make an account.

Trying to create an account with the username admin fails since there already exists a user with that username. This admin user could be our target.

Now creating a user westar and after pressing sign-up we get greeted with a QR code to scan with google authenticator. So I scanned it to my google authenticator.

Looking at the request we see the qr code gets generated client side, so I take note of the otpauth url.

otpauth://totp/2Password:westar?secret=O5SXG5DBOIYTEMZUGU3DOOBZ&issuer=2Password

Then, to get a better understanding of the sign-up flow, I wanted to see what the url would look like when we create a second account. So I created an account with the name “test”

So again I take note of the otpauth url and scan the presented QR code with google authenticator

otpauth://totp/2Password:test?secret=ORSXG5BRGIZTINJWG44DS%3D%3D%3D&issuer=2Password

However, google authenticator gave me an error. “Invalid barcode”. That should not happen. Let’s investigate.

Note: the creator of the box told me this error message only pops up on iPhone with the google authenticator application.

Comparing the two optauth urls the main difference was %3D%3D%3D, these are three equal signs url encoded.

Equal sings are often used as padding with encoded data. Let’s see what encoding it’s using with CyberChef.

Just with the automatic wand, it was able to detect url encoding and Base32 encoding. Resulting in test123456789, this does not seem like a random secret. Let's check westar's secret.

westar123456789. So it seems to just append 123456789 to one of the user's properties. Lets create a new user with easily distinguishable properties. Then we can easily find what it uses.

I added one of the sing-up requests to the repeater in burp suite and edited the values.

otpauth://totp/2Password:username?secret=OVZWK4TOMFWWKMJSGM2DKNRXHA4Q%3D%3D%3D%3D&issuer=2Password

Now we check the decoded value of OVZWK4TOMFWWKMJSGM2DKNRXHA4Q%3D%3D%3D%3D to see what part of the user's info is used as part of the secret.

It’s the username! A username is no secret! Since we know a user “admin” exists we can generate the OTP and maybe login. So we encode the predictable secret and create a new otpauth url.

Omitting the padding (=) to prevent the invalid barcode error

I also updated the username within the otpauth url itself.

otpauth://totp/2Password:admin?secret=MFSG22LOGEZDGNBVGY3TQOI&issuer=2Password

We can make this a QR code in the terminal with:

echo -n "otpauth://totp/2Password:admin?secret=MFSG22LOGEZDGNBVGY3TQOI&issuer=2Password" | qr

Now we scan the QR code with google authenticator.

Let’s try to login as the admin user with admin:admin and the OTP we just got.

admin is not the password we're looking for. Back to some recon.

On the login page, we can also see a “Forgot your password?” button, clicking on that we get a new screen with a username input field.

So I just entered admin in there since that is our target.

It leaks the user’s email address to us! This sure is weird, but let’s click confirm.

Looking at the request it then sends out, the email address stood out here. Why would the email address be given back to the server? So I decided to just put my email address in there and look what happens.

Within burp suite, I send the request to the repeater and replace the email address with my own.

My email address is censored out.

The request turned from a json response into a html response. Looking into the html it errors out that it expects the user’s email address to “contail” in the provided email. I took this as a typo for “contain” and tried a couple of payloads. Separating the email addresses with , or ; returned a success but I didn't receive an email.

During the CTF ; worked, however when writing this writeup it no longer did. Talking to the creator, the array is the intended solution.

After some tries, simply putting the email addresses in an array worked perfectly.

I got an email with a reset url in my inbox, clicking on that url we go to a password reset form.

Then I just filled in the form and pressed “Change password”

Success!

Now with my newly set password and OTP from my google authenticator, we can log in as the admin user.

There we see a single stored secret.

Clicking on that requires us to fill in the OTP again.

And then pressing “Show secret” shows us our flag! Which we can submit for ~492 points.

flag{9cd73159b385acb823ad1b4d3f9a924c}

Thanks for reading!
Please follow me on twitter

Edit: Added some clarification around the email address injection

--

--