The concept is straightforward. You look for refxss in "unkeyed" inputs: those are inputs that alter the output of a cacheable page but aren't themselves part of the cache key. That "unkeyed" property is why his examples are all in things like the X-Forwarded-For header. Caches key on URL parameters (because they key on URLs), but tend not to use that header as a key, so two requests varying only in X-Forwarded-For are, to a cache, the same request. If you can trigger refxss in the unkeyed input, that refxss will be cached and fed to everyone else regardless of whether they use the same unkeyed input. Presto: stored XSS.
While that's super cool, if you're not already familiar with modern web application testing, I think the more interesting part of this post is the tour you get of the methodology Kettle uses to find vulnerabilities in the first place. The XSS examples he's providing aren't "novel"; the novelty is in tricking caches into storing them. But he uses the post as an opportunity to show off some advanced Burp features, which is useful even if you're not going to go test for cache poisoning.
> “To exploit this, we need to go to hubspot.com, register ourselves as a HubSpot client, place a payload on our HubSpot page, and then finally trick HubSpot into serving this response on goodhire.com
> Cloudflare happily cached this response and served it to subsequent visitors. Inflection passed this report on to HubSpot, who resolved the issue by permanently banning my IP address. After some encouragement they also patched the vulnerability.”
This made me chuckle as well as get frustrated with how most teams and organizations react to security issue reports by first going into denial. They then try shutting up or preventing the person/entity reporting the incident from accessing the system, while continuing to proceed with “business as usual” and claiming that their systems are perfect. Good that HubSpot did patch the vulnerability soon after in this case.
If someone were to ask me for comments, I’d say people and organizations need to grow up, own up and work better. Such reactions show a lot of immaturity while keeping their users vulnerable.
P.S.: In the Indian context, this kind of a response reminds me of UIDAI (the organization that manages the biometric based resident ID system), which is permanently in denial mode when vulnerabilities related to security and privacy in its ecosystem and all the entities that link to it are pointed out.
Please note that web caches also enable a different type of attack called Web Cache Deception which should not be confused with cache poisoning.
We were bitten because django's ALLOWED_HOSTS was set to accept anything and django's USE_X_FORWARDED_HOST setting was true.
i.e. The cache looks for:
And caches the request body and other headers as a value with that line as the key. If you can manipulate the same key to have a different value, say by tweaking a cache-specific header, then the body of that GET response (an ad) changes for everyone hitting the same cache. Certainly worth testing with the tools that have been released ;)
EDIT: The tool in question, a plugin for Burp Community + Pro: https://github.com/PortSwigger/param-miner