Initial recon
I was doing recon when I found a static domain that looked empty. It had one image and a disabled HTML form on the left. There were no directories to bust, nothing in Wayback, and nothing useful in search. It looked boring. I almost left, but the disabled form caught my eye. I opened the page source to see the input names because that is a habit. I do this often when I am looking for simple XSS or other client-side issues.
Populating the disabled form
The form had only three inputs: Name, Country and Email. I tried to see if the page would accept those values via the URL. I opened this URL in the browser:
URL
https://sub.domain.com/index.html?name=test&country=test&email=test
The form loaded with the values pre-filled and suddenly a Submit button appeared under the form. I clicked it and got an error message that said Invalid Country Code. I used the word test in the country input so that error made sense. It meant the server expected a country code not a country name. I tried a few country names and still got the same error. Then I used the country code US and the request passed that stage and moved on.
Intercepting validation with Burp
The next message was Invalid Email Address. I wanted to see why that happened so I turned on Burp and intercepted the traffic. The validation flow first called an endpoint called /countryValidate and then it called /emailValidate. The email validator returned a plain JSON response that looked like this:
JSON Response
{
"is_valid": false,
"reason": "domain"
}
At that moment I did a simple test. I edited the response in Burp and changed the value to "is_valid": true and removed the reason field. Then I forwarded the modified response to the client. After that the client sent a registration request to /register. I had spent about one hour building that request and making sure the flow matched what the site expected.
Activation token leaked in the response
After forwarding the registration request I watched the server response in Burp. The response included an activation link in the body. It was plain text in the response. The response looked like this:
JSON Response
{
"activation_link": "https://auth.domain.com/activate?token=eyJhbGci..."
}
I opened the activation link in my browser and it logged me into the account without needing the email inbox. That was the first time I saw the activation token being leaked back to the client.
Escalation to existing account takeover
I then tried a small variation. I used an email that was already registered on the site. I expected an error but instead the server returned an activation link for that existing account. I opened it and I was logged into the other account right away. That means anyone who can trigger the same flow and knows a target email can get the activation link and access that account.
How the static page connects to the main app
There was a valid registration form on the main web application. If you submit a registration there and it fails validation the site redirects you to the static domain where this flow exists. So the static page is reachable from the main site by following an error path.
Full attack chain
So the full story is this. I saw a static page. I populated the form via URL parameters. The page then allowed validation requests to run. I intercepted the validator response in Burp, changed the JSON to pass validation, and forwarded it. The client then submitted the registration and the server replied with an activation link in the response body. Opening that link logs you in. Repeating the same steps for an already registered email leaks the existing account activation token and gives you access to that account.
Key takeaway
It took me about one hour from first spotting the static page to leaking an activation link. The main lesson is do not ignore static domains. Check the source code, try simple URL parameters, and inspect the network calls. Small persistence and muscle memory for these steps will find useful issues that look boring at first.
If you want to talk or give feedback, DM me on Twitter @R29k_. Thanks for reading. I will see you in the next writeup.