Web安全学习
本文最后更新于:2024年3月3日 晚上
Web安全学习
笔者正在学习渗透测试的途中,此篇博客用于记录学习历程、学习内容。
书单
该仓库内有许多安全方面的书籍:
1 |
|
笔者本人购买了实体书籍《白帽子讲 Web 安全》(第二版),同时正在参阅书单中《渗透测试实战第三版(红队版)》,近期内容将围绕上述两本书展开。
XSS攻击
凡是可以往目标站点注入脚本的攻击行为都可以称为跨站脚本攻击(XSS)
一个简单的例子
对于如下源码:
1 |
|
由于直接将接收到的客户端提交的参数输出到HTML页面,若name参数包含HTML标签,则会当作代码来执行:
1 |
|
如此,便会暴露其 cookie,以提示框形式显示在页面上。
XSS的攻击类型
反射型 XSS 攻击
反射型 XSS 攻击是指服务端应用在收到客户端的请求后,未经过参数检查或安全过滤,直接将参数用于 HTML 中用于页面构建。
最常见的反射型 XSS 攻击方式是将恶意代码包含在 URL 参数中,但是攻击者需要诱使用户点击这个恶意 URL ,攻击才能成功。
反射型 XSS 也被称为“非持久型 XSS”,因为其 Payload 并未持久存储于服务端应用中,每次实施攻击都需要受害者访问带 Payload 的 URL。
存储型 XSS 攻击
在存储型 XSS 攻击中,服务端应用将攻击者提交的恶意代码存储在服务端,受害者每次访问一个“干净”的 URL 时,服务端会在相应页面中嵌入之前存储的恶意代码,这些恶意代码将在受害者客户端执行。由于不需要在受害者的请求中夹带恶意代码,故此种攻击更稳定,危害性也更大。
例如:一个博客系统中存在该类漏洞,攻击者可以写一篇包含恶意 JavaScript 代码的博客文章,当其余用户浏览攻击者发布的博客时,该恶意代码就会执行。
存储型 XSS 漏洞也可能出现在一些更隐蔽、影响面更大的场景中,如社交网站中的个人简介、签名,甚至是昵称。如果网站没有相应的安全策略,就有可能产生这样的漏洞。
基于 DOM 的 XSS 攻击
前两种攻击方法都是与服务端应用的处理逻辑有关系的,恶意 JavaScript 代码在 HTTP 请求中被视为服务端的输入,并且被嵌入返回的 HTML 页面。但是正常应用中的 JavaScript 程序也可以接受外部的输入数据,并直接在客户端渲染和执行,如果处理不当,它就可能将外部数据当代码来执行。
即利用当前页面本身的 JavaScript 代码缺陷,进行恶意代码执行,而不是服务端返回恶意代码给到客户端执行,所以这种攻击称为基于 DOM 的 XSS 攻击。
例如:
1 |
|
JavaScript 代码将当前页面的 URL 当作 HTML 代码插入网页,此时如果 URL 中含有 HTML 标签,就将在当前网页产生新的 DOM 节点,通过特定标签可以引入 JavaScript 代码并执行。
1 |
|
访问此 URL 后,浏览器将执行 URL 中指定的 JavaScript 弹窗代码。此案例看起来很像反射型 XSS ,但是它和反射型 XSS 有着本质的区别,因为服务端返回的 HTML 源码中并没有相应的弹窗代码,弹框代码是客户端原有页面的 JavaScript 代码在执行过程中引入的。它本质上是前端 JavaScript 的漏洞,而不是服务端程序的漏洞。
Self-XSS 攻击
这个类型的 XSS 攻击与前面几种手法不太一样,Self-XSS 是利用社会工程学欺骗用户,让他们复制恶意代码并粘贴到浏览器中,所以称为“Self-XSS”攻击。
但是现在大部分浏览器都有一定的防御措施,如地址栏不支持或不允许粘贴 JavaScript 伪协议的 URL,这种攻击也就失效了。
XSS 攻击进阶
最常见的 XSS Payload 是通过读取浏览器的 Cookie 对象而发起“Cookie 劫持”攻击的。由于 Web 应用通常用 Cookie 作为用户的身份凭证,如果一个用户的 Cookie 被攻击者获取,意味着攻击者获得了该用户的身份。
通常,为了实现复杂的攻击逻辑,可以将 Payload 放在一个 JavaScript 文件中, 然后通过<script>标签载入,这样就可以避免在 URL 中写入大量的代码:
1 |
|
在 evil.js 中,可以通过如下代码读取 Cookie 并将其发送到远程服务器上:
1 |
|
这段代码将 Cookie 作为参数填到一个攻击者指定的 URL 中,然后将 URL 作为一个图像的 src 属性,浏览器向攻击者指定网站(evil.site)发送尝试获取图像请求,实则是将受害者的 Cookie 发送到其指定网站。
攻击者获得 Cookie 之后,则可将其填入自己的浏览器,以受害者身份访问应用。
构造 GET 和 POST 请求
Web 应用通常是通过发送 GET 和 POST 请求与服务端交互的, XSS 攻击能实现在受害者浏览器中执行任意 JavaScript 代码,所以攻击者可以通过 JavaScript 让受害者发送 GET 或 POST 请求来执行 Web 应用中的功能。如博客的发表、删除和点赞等等。
关于构造 GET 请求,最简单的办法就是创建 Image 对象, 将其 src 属性指定为目标 URL,这样浏览器在获取图像时,就在当前页面发送了 GET 请求。
如:
1 |
|
在更多场景里,执行特定功能的操作是通过 POST 请求来实现的。使用 JavaScript 发送 POST 请求也很简单,有两种方法可以做到。
对于提交表单的操作,可以使用 JavaScript 创建一个表单对象,填充表单中的字段,然后提交。
1 |
|
这种方式只能提交表单形式的请求。
对于更复杂的数据格式请求,需要用到 XMLHttpRequest 或 Fetch API,假如删除博客操作需要提交一个 JavaScriptON 格式的数据到服务端,代码如下:
1 |
|
XSS 钓鱼
很多论坛或即时聊天软件都有识别可信 URL 的功能,但如果白名单上的 URL 存在 XSS 漏洞,则攻击者可非常简单地通过 XSS 实现 URL 跳转:
1 |
|
如果受害者以为自己还在 example 这个域名内,很可能会输入账号密码等敏感数据。
XSS 攻击平台
如 BeEF(https://beefproject.com/)
XSS 蠕虫
XSS 蠕虫最早是由 Samy Kamkar 实现并传播,其在短短几小时内感染了百万名用户,它在每位用户的简介后加上了一句话:”but most of all, Samy is my hero.”,这是 Web 安全史上的第一个重量级 XSS 蠕虫,具有里程碑意义。
XSS 蠕虫一般利用存储型 XSS 漏洞,将攻击代码存放在个人签名、站内信上,被感染后执行好友间群发,以具有诱惑力的标题将受害者引入(例如:有人暗恋你哦,你想知道ta是谁吗),成为新的载体。
XSS 攻击技巧
基本变形
最简单的方式是改变字母的大小写。HTML 标签是大小写不敏感的。
如果安全过滤函数只是简单检测 <script> 特征,则可以使用空格、换行符等绕过检测,如:
1 |
|
有些安全检测函数会删掉 script 标签,则提交如下 payload,在其过滤一次后,仍有有效标签:
1 |
|
事件处理程序
很多 HTML 节点都可以绑定事件处理程序,比如 img 标签,指定一个错误或不存在的 src 属性,载入图像失败时就会触发 onerror 事件:
1 |
|
还有很多类似的事件:
1 |
|
构造不同的 HTML 标签并尝试使用不同的事件处理程序,可以绕过一些过滤不严格的安全防御机制。
JavaScript 伪协议
浏览器可以接受内联的 JavaScript 代码作为 URL。
1 |
|
一些安全功能会滤掉 JavaScript 伪协议,可尝试插入空白字符绕过:
1 |
|
当开发者仅仅校验 host 是否为合法域名,而没有校验协议时:
1 |
|
其中的”//example.com”被当作 JavaScript 代码的注释,所以整个代码都是合法可行的。
编码绕过
关于长度限制:
可以利用事件减少字节数,最好的办法是将 XSS Payload 写到别处,再通过简短的代码加载这段 XSS Payload。
最常用藏代码的地方就是“location.hash”。根据 HTTP 协议 ,location.hash 内的内容不会在 HTTP 请求中发送,所以服务端的 Web 日志并不会记录 location.hash 的内容,从而隐藏了攻击者的真实意图。
1 |
|
输出后的 HTML:
1 |
|
因为 location.hash 第一个字符为 #
所以构造的 XSS URL 为:
1 |
|
当有多个变量值时,例如:
1 |
|
可以拼接代码,利用注释,将三行连成一句话。
1 |
|
三个参数被拼接成完成的一句话:
1 |
|
其包含了完整的 JavaScript 代码,可以正常运行。
base 标签
base 标签用于定义该页面上,所有相对路径的 host 地址。
如果 base 标签被攻击者劫持,就可以在远程服务器上伪造图片、链接或脚本,劫持当前页面中所有使用“相对路径”的标签。
在设计 XSS 防御方案时,一定要过滤掉这个非常危险的标签。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!