Why X-FRAME-OPTIONS matters on API endpoints
As a security researcher, I try to identify area’s of potential abuse before bad people do. Once in a while, you stumble upon an attack scenario that is so incredibly stupid yet genius at the same time, that it deserves a name and a logo. Introducing GOTCHA:
GOTCHA is a UI redressing attack that allows attackers to extract valuable information from API endpoints. It requires a significant amount of user interaction, but could end up compromising a user’s plaintext password when executed successfully.
I invented GOTCHA at a HackerOne live hacking event last year. The target was a password & identity provider, so we knew stakes were high. Our mission was to get access to a victim’s plaintext password, by whatever means. We knew it wouldn’t be easy: password managers are known for their robust security, with bounties ranging up to $100,000. We’d have to get creative.
The password manager’s UI did not show plaintext passwords right away. In order to view the password, you had to press a button that would trigger an xhr request to the endpoint /api/reveal-password/APP_ID, which would reveal the password to the user.
I noticed that the AJAX call did not have any X-FRAME-OPTIONS headers set, and started thinking of possible security implications. Technically, this would allow users to display a user’s password within an iframe:
Due to CORS, other websites can not extract the password from the iframe. So unless we could find a way to visually extract the password from the iframe, this would be a dead-end.
I started playing around with the iframe for a bit and set the width to 30px:
Then I came to the conclusion that every character had exactly the same size of 8 x 15px. Using some neat CSS positioning tricks, we could isolate every character from the response.
I knew the first 17 characters did not contain the user’s password, so I skipped those and put the rest next to each other in separate iframes, all of which contained one isolated character of the password:
At this point, we can isolate a victim’s password and show it to them. It may seem a little bit threatening, but unless we find a way to extract the password, it’s useless. But what would happen if we built a captcha form around the password?
This could work for people that use randomly generated passwords, but in other cases this wouldn’t have much success (I mean — what kind of idiot would fall for that?).
The cool thing about having every character isolated, is that you can scramble them in whatever order you like:
As a finishing touch, we could apply some neat CSS filters to blur and rotate the captcha. Seems pretty darn realistic, huh?
I actually tried this one (with permission) on a befriended hacker.
He fell for it, and frankly I would probably also fill in the password-captcha without blinking twice. Captcha’s are annoying enough, it not like we want to spend any extra time verifying if we’re not typing our scrambled passwords, do we?
This issue can be remediated by implementing the X-FRAME-OPTIONS to prevent API responses from being embedded on external webpages.
I was awarded a $100 bounty for this discovery and a $1000 bonus for creativity. This must have been the report where the bonus was tens times as high as the actual bounty!