Reflected XSS with AngularJS sandbox escape and CSP
The website in this lab uses CSP and AngularJS.
Since Chrome 109 the path property has been removed. The workaround is to use
composedPath() instead. That goes for Firefox as well.
According to MDN, all major browsers support composedPath as of January 2023. Chrome (and other Chromium-based browsers) supported both path (it was a Chrome innovation) and composedPath until v109 when path was removed. (The obsolete browsers IE11 and Legacy Edge didn’t support either of them).
Reproduction and proof of concept
Go to the exploit server and paste the following code, replacing
0a5a009b039d93c0c0374b3300ea00c7with your lab ID:
<script> location='https://0a5a009b039d93c0c0374b3300ea00c7.web-security-academy.net/?search=<input id=x ng-focus=$event.composedPath()|orderBy:'(z=alert)(document.cookie)'>#x'; </script>
<script> location='https://0a5a009b039d93c0c0374b3300ea00c7.web-security-academy.net/?search=%3Cinput%20id=x%20ng-focus=$event.composedPath()|orderBy:%27(z=alert)(document.cookie)%27%3E#x'; </script>
Click Store and Deliver exploit to victim.
The exploit uses the ng-focus event in AngularJS to create a focus event that bypasses CSP. It also uses
$event, which is an AngularJS variable that references the event object. The path property is specific to Chrome and contains an array of elements that triggered the event. The last element in the array contains the window object.
orderBy filter. The colon signifies an argument that is being sent to the filter. In the argument, instead of calling the
alert function directly, we assign it to the variable
z. The function will only be called when the
orderBy operation reaches the window object in the
$event.composedPath() array. This means it can be called in the scope of the window without an explicit reference to the window object, effectively bypassing AngularJS’s window check.