Fun with header and forget password, with a twist:

3 years ago 142
BOOK THIS SPACE FOR AD
ARTICLE AD

Vuk Ivanovic

Image for post

Image for post

Headers are quite something to play with. The most usual ones are X-Forwarded-For (usually used for waf bypass), and X-Forwarded-Host (personally, interesting one for achieving dns/http pingbacks, sometimes ssrf).

This article will cover the case where I was able to use one of those headers to trick the website to send a forget password link that included the domain of my choosing.

X-Forwarded-Host and forgot password link, with a not so fun twist:

Spoiler alert, the twist, together with the nature of this bug, resulted in a lower payout, much lower than if it weren’t for the said twist.

The initial phase:

This one is easy to test for, but easy to miss testing for. To be honest, without going through twitter and finding this through #BugBountyTip

---For waf bypass, and similar---X-Forwarded-HostX-Forwarded-PortX-Forwarded-SchemeOrigin: nullOrigin: [siteDomain].attacker.comX-Frame-Options: AllowX-Forwarded-For: 127.0.0.1X-Client-IP: 127.0.0.1Client-IP: 127.0.0.1

And actually applying its wisdom I would have probably missed it. At least on the first go. Maybe days, weeks, months later, bored or whatever I would have read through my notes and having a House MD moment of clarity I would have given it a go :)

Image for post

Image for post

Note the Match and Replace rule for X-Forwarded-Host

I had that set up while messing around on this website let’s call it website.com, and it had sign up and with it Forgot password.

As per usual, I first registered in order to get further insight into how this website functions, what additional access it provides to registered users, and whether it can be leveraged for idor-s, or even getting admin functions via false2true (as per my other article)

During clicking around, and finding nothing, there was this one “last” thing to test for. I tend to leave it for the end because I’m logging out.

Therefore, I logged out, and went for the Forgot password page.

The forgot password testing:

The thought behind it, at the time (I learned more afterwards), was to see how the whole forgot password link looked like: whether there was something that indicated a way to guess the reset link parameter that associated the link with the user. But, there has always been another thing to keep an eye for: the base domain of the link itself.

Pre-PoC step:

After entering my email, I clicked the Submit button, and waited.

A few moments later as the narrator voice of Sponge Bob Square Pants :)

I checked my email, and pretty much immediately noticed that the reset password link had a very unusual base domain, hard to miss really:

instead of expected

https://website.com/resetpassword?email=email@website.com&id=1234&hash=randomstuff

I got:

https://localhost/resetpassword?email=email@website.com&id=1234&hash=randomstuff

I think you can already see the potential.

But, it’s not as obvious as it appears to be.

PoC:

I went for the obvious content of the X-Forwarded-Host:

Image for post

Image for post

but I got BAD REQUEST

WTH?

This is where experience/memory/notes come handy. I remembered from the earlier list this part:

Origin: [siteDomain].attacker.com

Which gave me this thought:

If attacker.com is blacklisted, but localhost is whitelisted, => localhost.attacker.com is the answer (and you also see now why the lower bounty amount)

This one resulted in 200 OK, and the email was sent with the localhostattacker.com as the base domain:

Image for post

Image for post

Note that it accepted localhostattacker.com, didn’t even require the dot.

Now, using burp collaborator or even your own vps, you get to log the randomstring required for password reset, as long as the user/victim clicks the link. Thus you get the account takeover of the user’s/victim’s account. That is, as long as the user doesn’t mind clicking on a link with localhost string as part of its name, and not to mention not having memory of ever requesting to reset their password :)

Interestingly enough, whatever parser they used, it actually accepted any base domain as long as it contained localhost, meaning junklocalhostjunk.com was being accepted as well.

Read Entire Article