记一次腾讯SDK源代码审计后的CSRF攻击

0x00 前言

初进ChaMd5安全团队,应M姐姐之邀写下这篇技术文章,这篇文章主要讲述本人近期代码审计腾讯的第三方登录SDK包时发现的一个漏洞,阅读这篇文章需要读者对OAuth2.0协议的原理和应用特别熟悉,如果读者对此不了解,请参考以下链接:

OAuth2.0协议RFC 文档:

https://tools.ietf.org/html/rfc6749

QQ开放平台的接入说明:

http://wiki.connect.qq.com/oauth2-0%e7%ae%80%e4%bb%8b

这是我之前写的一篇分析OAuth2.0协议安全性的文章:

https://www.anquanke.com/post/id/98392

0x01 攻击模型分析

我在这篇文章里讲的这种攻击方法是针对OAuth协议的一种CSRF攻击,大家都知道,很多网站都有绑定第三方账号的功能,这种攻击手段就是利用了网站的这种功能,为了深入分析漏洞,我先把绑定第三方账号的流程分析一下:

Step 1:某妹子使用账户密码登录XX网站

Step 2:妹子选择绑定QQ账户,在输入凭证信息后,QQ返回如下形式的链接:

http://xx.com/Index.php?Code=XXX

Step 3: 妹子访问上述链接,服务器接收到code参数,进行验证后与当前用户绑定。

为了说明这种攻击方法,我从2012年全国网络与信息安全峰会上知道创宇的一位大佬的PPT里借用一张图:

这种攻击方式看似复杂其实说起来也很简单,主要的问题出现在了上图的第四步中,即攻击者构造链接http://xx.com/Index.php?Code=XXX,其中Code参数绑定的是攻击者的QQ账户,然后发给Victim诱骗点击(CSRF),Victim点击之后,他的账户就与攻击者的QQ账户绑定了,这样攻击者就能通过其QQ登录Victim的账户,实现用户劫持!

当然了,为了防止这种攻击,腾讯在返回的授权登录链接中增加了一个state参数用于防止类似的CSRF攻击。用户在请求使用QQ登录的时候会生成一个与session绑定的不可预测字符串state,并把这个参数发送给授权服务器,授权服务器验证完用户身份后会返回如下形式的链接:

http://xx.com/Index.php?Code=XXX&state=XXX

在接收到此链接时,xx.com会先检测当前session中的state参数和收到的链接中的state参数是否匹配,如果匹配才会进行下一步的操作。这样的话,即使攻击者把自己的授权链接发给Victim,也会因为state验证失败而无法绑定攻击者的账户(攻击者无法预测Victim的session中的state参数,因此就无法构造恶意链接来进行CSRF攻击)。

0x02 漏洞分析

在详细了解了攻击原理之后,我们来剖析一下QQ登录的官方SDK文件。

这里我们废话不多说,直接定位到核心类文件Oauth.class.php

在这个类文件中qq_login方法用于第一步生成state参数并跳转到QQ授权登录接口,可以看到state参数在第36行生成并紧接着调用recorder类的write方法写入到session中,跟进recorder类继续分析:

定位到32行,write方法是把传入的值写到self::$data中,在看到26行,构造函数中self::$data被初始化为一个空数组。

在最后的析构函数中self::$data被存入到session中,这里看上去没有什么大问题,继续向下分析,我们找到Oauth.class.php中的qq_callback方法:

qq_callback方法用于验证state参数并利用传入的code参数获得access_token,我们主要关注state参数的验证阶段,在第57行我们看到有一个if条件判断当前session中的state参数($state)和链接中传入的state参数($_GET['state'])是否匹配,如果不匹配则直接调用showError方法die掉:

但是,问题就出现在这里!之前我们已经分析到,state参数在qq_login方法中生成,但是如果Victim没有调用这个方法,self::$data就会被构造函数初始化为一个空数组,再来看一下recorder类中的read方法:

如果self::$data为空则返回null,因此这里存在一个很明显的逻辑缺陷,只要攻击者把恶意链接的state参数留为空,这时$_GET['state']为空值,$state也为空值,if($_GET['state'] != $state)为false,这样就可以完美的躲过CSRF检测,嘿嘿!

0x04 后记

这个漏洞从确认到修复只用了三个小时的时间,腾讯SRC的响应速度也是非常惊人。

在最新版的SDK文件中,在验证state时会先判断当前的session中是否保存有state参数,即判断当前用户是否调用过qq_login方法,这样就可以成功的阻止类似的CSRF攻击了:

原文发布于微信公众号 - ChaMd5安全团队(chamd5sec)

原文发表时间:2018-03-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏流媒体人生

Yate开发向导

Yate 的设计是为了提供一个可扩展性的电话引擎,试图以最简简洁的代码,在扩展所需功能与性能、稳定性之间达到最佳平衡。

1093
来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

3116
来自专栏Ryan Miao

Git 工作流的正确打开方式

前言 一直在使用git做版本控制,也一直工作很顺利,直到和别人发生冲突的时候。这才注意到git 工作流并不是那么简单。比如,之前遇到的清理历史。百度到的资料很...

3266
来自专栏大前端_Web

nodejs学习一CommonJS和AMD

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

2272
来自专栏为数不多的Android技巧

Android Studio你不知道的调试技巧

写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?或者你知道 Evaluat...

851
来自专栏Golang语言社区

Golang学习-第一篇 Golang的简单介绍及Windows环境下安装、部署

序言 这是本人简书第一篇文章,写的不到位之处,希望各位看客们谅解。 本人一直从事.NET的开发工作,最近在学习Golang,所以想着之前学习的过程中都没怎么好好...

3075
来自专栏Jackson0714

不惧面试:HTTP协议(3) - Cookie

1392
来自专栏Java帮帮-微信公众号-技术文章全总结

Web-第二十天 Redis学习【悟空教程】

rpm -e --nodeps java-1.6.0-openjdk-1.6.0.0-1.66.1.13.0.el6.i686

1905
来自专栏铭毅天下

刨根问底 | Elasticsearch 5.X集群多节点角色配置深入详解

1、问题引出 ES5.X节点类型多了ingest节点类型。 针对3个节点、5个节点或更多节点的集群,如何配置节点角色才能使得系统性能最优呢? ? 2、...

4818
来自专栏非著名程序员

Android Studio你不知道的调试技巧

? 写代码不可避免有Bug,通常情况下除了日志最直接的调试手段就是debug;那么你的调试技术停留在哪一阶段呢?仅仅是下个断点单步执行吗?或者你知道 Eval...

30910

扫码关注云+社区

领取腾讯云代金券