Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

XSS are possible when the user input is used somewhere on the web application

output without proper protection, and as a result attack users of the vulnerable
application.

XSS attacks can: (Anatomy of XSS)

Steal your cookies (which may have login info).

Control your browser actions secretly.

Take over your device.

Record what you type (keylogging).

Change website appearances (defacing).

There are 3 primary types of XSS:

•Stored XSS

•Reflected XSS

•DOM-based XSS

Reflected XSS is probably the most common form of XSS. It occurs when untrusted
user data is sent to a web application, and it is immediately echoed back in the
page source.
Then the browser renders received from server code.
Clearly, this type of vulnerability deals with server-side code.

Persistent (or Stored) XSS are similar to Reflected, however, rather than the
malicious input being directly reflected into the response, it is stored within the web
application and echoed somewhere else within the web application and might be
available to all visitors.

This type of XSS occur also in server-side code, but more useful for attacker than
Reflected XSS.

It is because with a page persistently affected, we are not bound by having to trick a
user. We just exploit the website, and then any visitor that visits will run the malicious
code and be affected.
The last one is DOM XSS which is a form of cross-site scripting that exists only
within client-side (JavaScript) code.
This vulnerability lives within DOM environment, thus within a page’s client-side
script itself and does not reach server-side code.
This is similar to our Reflected XSS example, but without interacting with the server
side.

In XSS attacks, the sneaky script code can reach all the info in your browser, like
URLs, history, cookies, and more. But you can't just send users to your page to read
cookies from another site (like auth.y.com). That's because of the Same Origin
Policy, which only lets code access data from its own site.

A payload is the harmful code or script that the attacker injects into a vulnerable
website. It's the part of the attack that carries out the malicious actions, such as
stealing information or taking control of the victim's browser.

In Reflected XSS, victims bring the payload in their HTTP request to the vulnerable
website. This payload will be inserted into the webpage and executed by their
browsers. So, attacker has to trick the victim to bring the payload with them to
website. For example victim need to click on a link with payload in order for the
attack to be successful. When this occurs, the malicious payload is run in the victim’s
browser within the context of the vulnerable website.

Persistent XSS are attacks that lead to the execution of


code in all the user’s web browsers visiting a vulnerable (and exploited)
web page. The injected code is saved by the application in unsanitized form and
then rendered on either the same or another web page in the same website. Hence,
the malicious code can be injected, by the attacker, directly into web application.
This is the most important difference between Reflected and Persistent XSS.
Therefore it is the most dangerous form of XSS as it can target all the
visitors of a website, and in a matter targeting the website itself (although
indirectly).

Persistent XSS attacks are more dangerous because they store the harmful code in
the vulnerable website's database. This means the code gets shown to every visitor
of the website, not just the victim who triggered the attack. It's like a hidden trap that
affects anyone who visits the compromised page. This makes it a big threat because
it can harm many users and even compromise the entire website indirectly.

Difference:
● Reflected XSS: In this type, the malicious code is included in the URL or input
field, and it's reflected back to the user. The attacker needs to trick the victim
into clicking on a crafted link or submitting a form with the malicious code.
● Persistent XSS: In this type, the malicious code is stored in the website's
database and gets displayed to every visitor who views the affected page.
The attacker doesn't need to trick individual users; instead, they exploit a
vulnerability to inject the code directly into the website.

In this scenario submitted parameter is not sanitized for illegal characters and saved
in the database for later use. The hacker constructs his exploit,
carrying XSS payload, which will be stored in the
database. The web application is designed so that parameter, submitted by the
hacker, is given on output on page page_out.php without any sanitization. This
scenario is both very common and applies to a number of situations, like either
commenting scripts or personal community members that accept an input.

By visiting page_out.php in which malicious payload is rendered, all the visitors of


the webpage execute the malicious payload that was submitted by the hacker. Note
that this type of attack is as asynchronous as the exploitation and actual execution
of the code happens at different times. While in the case of reflected XSS targeted
user could defend himself (at least by not visiting strange link), in the case of
Persistent XSS is so covert and neat that as soon as the user browses the infected
page, the code gets executed.

DOM (Document Object Model) is the object (more like a tree) built by the web
browser upon parsing the web page content provided by the server. This object
makes it easy to navigate through the different HTML tags and the hierarchy of
elements.

Functions like getElementsByTagName are SOME functions that let us navigate


through the page elements through a hierarchical view. You can look at the
DOM-tree with help of "Inspect element" feature, available in every browser.

DOM-based XSS is different from Reflected and Persistent XSS because it doesn't
rely on server-side vulnerabilities. Instead, it happens when JavaScript code uses
user input without proper validation. If the input isn't sanitized, attackers can inject
malicious code. JavaScript can get user input from the URL (querystring) or other
methods like prompt(). However, we won't focus on prompt() because it's harder to
exploit. When user input is part of the querystring and displayed on the page using
methods like document.write, attackers can inject harmful content into the webpage.
It is important to note that this attack does not require any interaction with the server.
DOM-based XSS can be persistent if the malicious code is saved in a cookie or web
storage by the web application. This means that every time a new request is sent to
the vulnerable page, the victim's browser will execute the malicious payload.

Also, it's important to note that the part of the URL after the # sign (hash or pound)
isn't sent to the server by the browser. This makes it harder to detect DOM-based
XSS because it doesn't show up in server logs. Despite having similar steps to
Reflected XSS, it's more challenging to identify from server logs.

•There is one type of XSS that you can find – Self-XSS.

•Self-XSS can be stored, reflected or DOM, but considering “self” in the name we
can only attack ourselves with this XSS, for example user can insert payload in the
user’s cabinet which only this user can access.
Obviously, we can try to use social engineering to exploit this issue, but it is hard to
force user to type some strange data into web application.
Therefore self-XSS usually do not pose a risk.
But in some cases, it can be exploited with use of chain of vulnerabilities.

Blind XSS vulnerabilities are a type of persistent XSS problem. Here's how it
works:

1. Attacker inserts harmful code into a part of the website, like a feedback page.
2. The website saves this code.
3. Later, when someone like an administrator views the feedback, the harmful
code executes.
4. The attacker might not directly see the effects, as it could happen in a part of
the website they can't access, like an admin panel or a separate application.
5. To check for this, testers use payloads that make requests to their own
server, allowing them to see if the attack works, even if they can't directly see
the results.
In black box testing, finding Reflected XSS is relatively simple:

1. We don't have access to the application's source code.


2. We input some data into the application.
3. Then, we check if the data we input appears in the output from the
application.
4. If the data we entered shows up in the output, there might be a chance for a
Reflected XSS attack.
5. It's important to note that modern browsers often have filters for Reflected
XSS, so we might use browsers like Firefox or older versions of Chrome
which don't have these filters for testing.

Once we find where our input shows up in the output, we try putting in HTML or
JavaScript code. We can inject this code into various places like GET/POST
parameters, cookies, or HTTP headers (like User-Agent).

● GET method is easiest: Just craft a bad link, and when someone clicks it, the
browser runs the code.
● POST method is trickier: It involves forms, so the attack method is different.

When testing a website's input fields, especially in the URL, we try putting HTML or
JavaScript code in them to see if it works. For XSS attacks, we can use a payload
like "<plaintext>". This makes the browser treat the rest of the page as plain text,
messing up the appearance. It's handy because if the injection works, the page
layout breaks, showing the injected code right away without needing to check the
source. But be careful: when testing for Stored XSS, this payload might break the
entire page.

We successfully injected the plaintext tag in the HTML source code. When this
happens, any tags coming after the injection point won't be shown by the browser;
they'll be treated as plain text.

But injecting <plaintext> doesn't guarantee we can inject JavaScript because the
application might have input validation to prevent script injection. So, the next step is
to check if we can inject scripts using the <script> tag or DOM events.

Input validation might allow plaintext tag but deny others like IFRAME or IMG. So,
just using the plaintext tag isn't enough to confirm XSS.

In a white-box approach (having the source code), we look for all the points where
the application shows user-supplied data and trace it back to where it's first retrieved.
If there's proper sanitization or type conversion along this path, then it's usually safe
from XSS.
This trick helps us get around basic checks for symbols like "<" and ">". However, it
relies on the user interacting with our component by moving their mouse over it. If we
need to get past more checks, we can use different tags like svg, button, or body
onload event, or combine onfocus with autofocus attribute.

To bypass other checks, we use the String.fromCharCode function, which avoids


needing additional quotation marks.

For research purposes, it's sometimes easier to use numbers instead of words in
alert windows. This helps simplify things and understand how the system reacts to
different inputs.

Another useful payload is one with the img tag.

With this tag we can use onerror event. And to successfully trigger this event we will
place a corrupted src attribute.

In this case our payload will look like this:

<img src=0 onerror=alert(“image not loaded”)/>

To identify a user session, applications often use cookies, which are automatically
sent to the server based on the domain and path. Sometimes, applications use
tokens submitted with JavaScript. In the next steps, we'll see how we can steal
cookies through XSS. For cases with tokens, our steps will be similar, but with some
differences in the payload.

Browser's Same Origin Policy (SOP) prevents reading cookies/data from other
domains. So, we need the ability to run our code in the targeted domain. Fortunately,
we can achieve this with XSS.

First of all, user must be logged into application and have a valid session cookie.
After login browser will receive cookie with Set-Cookie response header and will
save it.

In each subsequent request to this domain, this cookie will be sent and server will
use it to identify that it indeed that user. For that purpose server will create some
sort of database of data with key value matching session cookie. Now it should be
clear that if we make a request with a valid cookie from another user, we will access
his data.
Firstly, we need to find an XSS vulnerability. Sometimes, if a cookie is set on the
entire domain, including subdomains, we can even attack applications on other
subdomains, which might be less secure. However, we should remember that cookie
scope can also be limited by the path attribute. Fortunately, this limitation is more
about performance than security, and we'll find a workaround for it later.

If a cookie doesn't have any restrictions, it's better for us. For instance, if we see
'domain=.example.com' in a cookie, it's like having a wildcard symbol set:
'*.example.com'. This means the web browser will send the installed cookie to all
example.com subdomains, broadening our attack surface to include them as well.

The other parameter is path.

When it is set to ‘path=/’ then it will be sent to all directories of the domain.

When it is set to ‘path=/auth/’ it will be limited to auth directory and it’s subdirectories.

When it is set to ‘path=/auth’ it, surprisingly, will limit to all directories which name
starts from auth: /authorization, /authentication and so on.

To steal cookies through XSS, it's crucial that the httpOnly flag is not set on the
cookie. This flag prevents reading cookies with JavaScript and restricts their use
only to the HTTP protocol.

Let's say we found an XSS vulnerability on the http://example.com/search page.


Here's how we exploit it:

1. Read the cookie with JavaScript: We use the XSS vulnerability to execute
JavaScript code that reads the cookie.

2. Send the cookie to our server: We send the stolen cookie to a server that we
control.

3. Retrieve the cookie from our server: We retrieve the stolen cookie from our server
and install it in our browser, giving us access to the victim's session.

To demonstrate the risks of XSS to a client, simply showing an alert window might
not be enough since it's not very informative or visibly damaging. Defacing the
website can be a more effective way to show the dangers of XSS and emphasize the
need for patching the vulnerability.

In the previous example, we attacked a user by trying to steal their cookie. With
defacement, we attack the application itself. Having a persistent XSS vulnerability
instead of a reflected one can enhance the impact of the attack.

To achieve defacement, we typically search for Stored XSS vulnerabilities in the


database. If we find a Persistent XSS vulnerability, we can manipulate the
appearance of the webpage by changing the DOM (Document Object Model) using
JavaScript.

For example, the simplest way to change the DOM is by using JavaScript like this:

document.body.innerHTML = "<h1>LOL, haxxed</h1>";

This line of JavaScript replaces the entire content of the webpage's body with our
own content.

XSS can also be used for advanced phishing. Normally, when a website asks for
your password, you'd probably type it in without thinking much, even if you're in the
middle of a session. Attackers can exploit this by injecting a fake login form into the
legitimate website. This fake form will send your credentials directly to the attacker's
server.

What's tricky about this type of phishing is that it works on a real website, not a fake
one. Since the phishing website is actually the legitimate site with an XSS
vulnerability, usual phishing defenses won't work. Creating a valid-looking login form
is easy for attackers—they can just copy the real site's login form and change the
action URL to send the data to their server.

BeEF (The Browser Exploitation Framework) was created to simplify XSS


exploitation. It allow to redirect the victim, perform Man-In-The-Browser attack,
control web camera, incases with old vulnerable browsers run Metasploit Browser
Autopwn and achieve remote shell on the machine.

XSS vulnerabilities relate to Data Validation vulnerabilities. They arise when user
input is
not validated and copied in the output.
To mitigate an XSS we need to validate an input and perform context-aware output
encoding.

Validating an input can dramatically reduce chances of XSS. For example if we have
cost field, then we probably need to accept only numbers.

If URL is outputted on the page, then probably we need to check protocol to match
only HTTP/HTTPS and drop others, especially JavaScript.
Output, obviously need to be encoded. In cases when data printed between tags, it’s
probably good idea to use HTML-entity, so no new tags are appeared. But
sometimes input can accept tags like img or spoiler, so we need to encode data
depending on context.

If data printed in URL attribute of tag or in attribute in general, then we can use URL-
encoding or quotes sanitization.

Luckily most of libraries have default sanitization functions and it’s better to use one
instead of creating them manually.

You might also like