- Critical Thinking - Bug Bounty Podcast
- Posts
- [HackerNotes Ep. 62] Frontend Language Oddities
[HackerNotes Ep. 62] Frontend Language Oddities
Justin and Joel are back with some additional research resources that didn’t make the Portswigger Top-Ten: HTML quirks, CSS injection, XSS, and JS analysis.
Hacker TLDR;
Cool HTML Sh*t
The form attribute on an input element can be used to emulate nested forms, or place it outside a form but still be posted with it
The target field in a form can be set to an iframe outside of the form instead of a page
Input tags can function as an image tag via
type=image
which can also be abused to hitonerror
handlers
Documented Bounty Journeys: Ajxchapman and Monke have been documenting their bug bounty journeys for us, covering bugs found and lessons learned here and here.
Dealing with JS: 0xDevAlias has made a huge seriously good gist for dealing with obfuscated JavaScript - decompilers, tools to use, how they work, and more. Check it out here.
Spots to find cool research: r/websecurityresearch, Nahamsec’s bug bounty repo, PortSwigger top 10.
Abusing Perspectives & CSS: PortSwiggers CSS Exfiltration repo has a huge number of CSS exfil POCs, along with extensive research on CSS injection and blind CSS injection.
Cool HTML Sh*t
The form attribute on an input element can be used to emulate nested forms, or to place it outside a form but still be posted with it:
You can have an input outside of that form, and if you have the form attribute to that correlates it to the ID of the form itself, it will also be submitted to the form.
This could be a good way to smuggle data into a form if you have a HTMLi or something similar. The original thread from above can be found here.
Its also possible to use target on form and post inside an iframe instead of the page:
Useful if, again, you have an HTMLi or if you want to interact with an iframe outside of the iframe context. The original thread can be found here.
Input tags can function as an image with type=image
specified as the input type :
Useful in contexts where you attribute injection and you need error handlers to trigger which aren’t triggering, or redefine input as an image and use associated handlers with that. It does trigger the onerror handlers too. The original intended purpose is to create graphical submit buttons.
Frame hijacking
Justin had a page that he needed to clickjack a button, to get a user to login to the page and he could then exfil data from that page using postMessage.
The problem was the user wasn’t being logged in automatically, the state was being stored in JS - if you refresh, it logged you out, no local storage, etc.
The user clicks a link or button on the page, which Justin could clickjack as it was frameable, and then it opens up a new tab the authorization flow of that page.
From that page, the user would automatically be logged in, and the original page that opened it up would reach into that frame, grab the authorization header and log the user in.
Justin noticed when window.open was happening, it was actually pointing the name of the target frame, to a frame with a name associated to it.
Justin then iframed two frames (sounds like a riddle) into the page, one of them was the page to do the iframe hijacking from, and the other one was a page on the same origin as the page he was attacking.
The second frame however had the same name as what was specified in the window.open call.
When the window.open happened, it would open into that iframe as it has the same origin and the same name. As it has a reference to the frame, he could redirect the location of that page.
Both of these iframes are iframed in using Justin's attacker-controlled page, meaning Justin controls both of the iframes sources.
This is important as it affected what the original tab was looking for in the (referenced) page, meaning Justin could redirect the frame away and feed it different data as to what it was expecting and use it to exfil from a tasty postMessage he was targeting.
Documented Bounty Journeys
Two hunters, Ajxchapman and Monke have been documenting their bounty journeys weekly providing statistics and some lessons learned.
It’s always good to see other hackers’ statistics for staying motivated, and seeing other hackers (regardless of who) also get duped!
AJxchapman does a weekly Twitter thread, so check that out here: https://twitter.com/ajxchapman/status/1762101366057525521
Monke posts in a blog format on beehiiv, so check that out here: https://monkehacks.beehiiv.com/p/monkehacks-02
Equally, if you want to stay motivated on your bug bounty journey, make sure to document gadgets. Documenting gadgets makes you a step closer to being able to abuse them for a real bug, and eventually, if you find enough gadgets it will probably lead to a bug.
This is a really interesting bug disclosed by a researcher on Yelps program on HackerOne.
So, it started when the researcher noticed that you can create an account and its possible to put an XSS payload before the @
symbol in the flow and it will pop - so it starts as a self XSS.
However, there’s functionality in Yelp which is used to translate and localize the Yelp app, ie the UK version, the US version and so on. So say for example if you log in on yelp.com but you need to be redirected to your localised version, ie to yelp.co.uk, these are different origins. So how will it transfer sessions over to log you in automatically?
Yelp uses cookie bridges for this and there are two endpoints involved in the process, the store endpoint and the retrieve endpoint. When a user uses the store endpoint it takes all your cookies and returns a unique token.
When you use that unique token and send it to the retrieve endpoint, it will set all your cookies for the new domain you’re trying to access, ie store cookies from yelp.com and set on yelp.co.uk.
This happens by hitting the /store
endpoint with the locality you want, which in turn then generates a one-time use token for the target domain which can be consumed to then retrieve the cookies from the original domain. Interesting gadget.
The researcher used a self XSS to force someone to log in using the cookie bridge onto a different domain, into my account which has a self XSS, and can then pop an XSS in their user context instead. So now we have an XSS in the victim context but now what?
How do you take this further? You cookie bomb the retrieve endpoint and send hundreds of cookies which causes Openresty to fail. This results in the flow failing and the unique token used to retrieve the cookies from another domain staying in the URL.
So to exploit this, we have two tabs. The victim is logged into .com, they open the link, it hits the cookie bridge which then logs them into the attacker account on the new domain. So now, we have two sessions - the victim session on the original domain, and the attacker session (via xss) on the new domain.
Now, taken from the report… ‘Now Tab B can access Tab A's location via window.opener.location.href
since they share the same origin biz.yelp.dk
. Tab B can now leak the retrieve url for the victims session cookies, and the attacker can simply visit this url to be signed in as the victim. This works for both business accounts and regular yelp accounts.’
Functionality like this is always interesting because the devs are trying to punch holes in existing security controls which more often than not, leaves room for error.
This was a pretty awesome writeup, with full POCs, videos and exploits used detailed within: https://hackerone.com/reports/2089042. One to add to the reading list.
Dealing with JS
Dealing with JS across different targets can sometimes be a cumbersome process due to things like packed JS, minified, and hard to read - if you’ve spent any time reading JS, you know it’s painful sometimes.
This gist is a giant list of resources, tools and tips for deobfuscating, and depacking any kind of JS you might encounter:
One of the tools mentioned in this is https://github.com/pionxzh/wakaru - a ‘JS decompiler for modern frontend’. Check out the whole Gist and expand your JS toolbelt.
Another good example when having to deal with a lot of JS is if you want to implement monitoring on a target, so you can check out new endpoints, and new params as they come online.
0xdevalias made an excellent repo with a lot of information on how this is done for ChatGPT - If you’re looking for a good example of target-specific JS monitoring check it out here:
Spots to find cool research
If you’re looking to keep up to date or tap fresh sources of research for inspiration, these resources could help you out:
Web security research subreddit - modded by Gareth Hayes + James Kettle
Nahamsecs’ Git repo for bug bounty - SO many resources in here, even including Twitter accounts to follow
PortSwiggers top 10. Always a good fresh resource to use - equally, checking out prior year’s research is equally as valuable:
Abusing Perspectives & CSS
Abusing perspectives in bug bounty can find you some pretty nice bugs. When approaching a target, or a piece of functionality, think about how you can leverage the victim’s position in the application to break that context or escape out of it.
Having good notes and a list of gadgets to refer to is a good way to identify what you can do in a given perspective, and figure out how it could be abused.
CSS Container Queries
They allow you to select elements and affect elements specifically based off of the size of an element. Justin’s idea was if to use CSS along with traditional methods of sequential import chaining and so on, to leak the size of a container or the size of a specific entity, you could technically read arbitrary data off of the page.
You could apply a font to different characters to then get the width of the characters on the page for every single character, and adjust the size of the container to include breakpoints on specific characters, if we can leak the size of the container, we can get a step by step by step what the character is using the oracle of the width of the container.
Unfortunately, when you define something as a container using these methods, it applies attributes to it that won’t allow it to be fit to the child element so it didn’t seem feasible.
PortSwigger CSS Exfiltration Repo
PortSwigger have an entire repo with different CSS exfiltration POCs: https://github.com/PortSwigger/css-exfiltration
It’s an entire repo dedicated to exfiltration data in certain contexts solely via CSS, definitely worth checking out.
If I’m being honest, this was a bug class that was on my radar but I never really gave much attention to it. Seeing some of this research by Gareth Hayes @ PortSwigger has certainly put it up on my list of things to research. Check out these posts:
This episode certainly grew my reading list; lots of cool research I hadn’t seen before. If you do decide to go into the rabbit hole of CSS injection and find some cool gadgets, throw them in the Critical Thinking Discord channel!
As always, keep hacking