挖洞经验 | 记一次针对Twitter(Periscope)API 的有趣挖洞经历
近期,我在Twitter的Periscope服务中发现了一个漏洞。这是一个CSRF(跨站请求伪造)漏洞,虽然这个漏洞并不算是高危漏洞,但是发现该漏洞的整个过程我认为是非常值得跟大家分享的。
就在几天之前,我发现Twitter发布了一个名叫ProducerAPI的接口,该接口目前仅提供给Twitter的合作伙伴使用,Twitter的第三方合作伙伴可以在特定的应用(例如外部相机设备)中利用该API与Periscope账号同步流媒体视频。
注:在此之前,Periscope曾是一家流媒体直播服务运营商。广大用户不仅可以通过Periscope与其他人进行视频直播,而且还可以分享视频或进行评论。Twitter在2015年3月份以接近亿美金的架构收购了Periscope,并将其融入了自己现有的社交平台服务中。
这样看来,Twitter应该在这里需要使用到一些与OAuth相关的东西,而就我过去所积累的经验来看,OAuth的实现过程中一般都会存在安全问题,因此我决定要深入分析一下这个API接口。
在分析过程中,我遇到的第一个问题就是Twitter似乎并没有提供Periscope API的开发文档。不过Twitter在一篇官方博客中列举出了能够使用这个API的第三方厂商,所以我感觉可以看看这些厂家是怎样跟这个API交互的,然后也许还能从中找出一些端倪。但不幸的是,大多数的这些厂商或服务都需要订阅之后才能使用Periscope的功能,即便是我愿意为服务付费也没用。
不过我后来发现有一个移动端应用程序(Mevo for iOS)也在使用这个API。在这个移动应用中,OAuth请求都是直接从客户端发送的,这样我们就有可能通过拦截并分析网络流量来了解API的调用情况了。与OAuth 1.0a不同的是(OAuth 1.0a使用了签名来隐藏类似consume_secret这样的重要信息,并防止流量被拦截),OAuth 2.0会通过HTTPS来发送所有流量。因此,除非应用程序使用了某种安全系数非常高的证书机制(可以使用SSL Kill Switch2来解决),否则这些还是难不倒我们的。
我遇到的第二个问题是,为了使用这个App,我首先得要有一个Mevo摄像头才行…在亚马逊上逛了一圈之后,最便宜的Mevo摄像头要399.99美金,穷哭在厕所的我当然不会为了测试而去买这么贵的东西了,而且这里还不一定存在漏洞。
于是乎,我决定通过另一种方法来进行测试,即逆向工程分析。首先,我需要一台已越狱的iPhone和Clutch来解密IPA文件,然后用class-dump来生成Objective-C头文件,最后再用Hopper来对代码进行反汇编。
一开始我尝试在头文件中搜索字符串“Periscope”,因为那些负责处理Periscope交互逻辑的类很有可能会包含这个字符串。
搜索之后,这些类似PeriscopeBroadcastCreateOperation.h或PeriscopeBroadcastPublishAPIOperation.h的文件名吸引了我的注意,因为这些头文件看起来似乎与Periscope API的调用有关。通过对这些文件进行分析之后,我发现它们都继承了PeriscopeAPIOperation类,所以接下来我就要重点分析这个PeriscopeAPIOperation类了。
PeriscopeAPIOperation类的代码如下所示:
//
// Generated by class-dump 3.5 (64 bit).//// class-dump is Copyright (C) 1997-1998,2000-2001, 2004-2013 by Steve Nygard.// #import "GroupOperation.h" @class NSDictionary, NSMutableURLRequest,PeriscopeOAuthOperation,PeriscopeRefreshTokenAPIOperation,URLSessionTaskOperation; @interface PeriscopeAPIOperation :GroupOperation{NSDictionary *_JSON;URLSessionTaskOperation *_taskOperation;PeriscopeRefreshTokenAPIOperation *_refreshTokenOperation;PeriscopeOAuthOperation *_oauthOperation;NSMutableURLRequest *_request;} + (void)removeCookies;+ (void)logout;+ (id)userID;+ (id)refreshToken;+ (id)accessToken;+ (void)updateAccessToken:(id)arg1;+ (void)setAccessToken:(id)arg1refreshToken:(id)arg2 forAccount:(id)arg3;+ (_Bool)isUserAuthorized;+ (id)buildRequestForPath:(id)arg1params:(id)arg2 query:(id)arg3 queryItems:(id)arg4 HTTPMethod:(id)arg5accessToken:(id)arg6; @property(retain, nonatomic)NSMutableURLRequest *request; // @synthesize request=_request;@property(retain, nonatomic)PeriscopeOAuthOperation *oauthOperation; // @synthesizeoauthOperation=_oauthOperation;@property(retain, nonatomic)PeriscopeRefreshTokenAPIOperation *refreshTokenOperation; // @synthesizerefreshTokenOperation=_refreshTokenOperation;@property(retain, nonatomic)URLSessionTaskOperation *taskOperation; // @synthesizetaskOperation=_taskOperation;@property(retain) NSDictionary *JSON; //@synthesize JSON=_JSON; - (void).cxx_destruct;- (void)repeatOperation;- (_Bool)operationHas401Code;- (_Bool)shouldHandle401Code;- (void)operationDidFinish:(id)arg1withErrors:(id)arg2;- (void)finishWithError:(id)arg1;- (id)initWitMethod:(id)arg1params:(id)arg2;- (id)initWitMethod:(id)arg1params:(id)arg2 HTTPMethod:(id)arg3;- (id)initWitMethod:(id)arg1queryItems:(id)arg2;- (id)initWitMethod:(id)arg1params:(id)arg2 HTTPMethod:(id)arg3 queryItems:(id)arg4; @end
大家可以从上面这段代码中看到,其中包含了很多很多的属性和方法。从这些方法名中可以看出,这个类应该就是负责处理Periscope API调用的类了。
接下来,我打开了Hopper来验证我的想法。果然没错,这些方法都会调用initWitMethod并通过传递各种参数来实现API的初始化。
这样一来,我只需要找出其他调用了这个方法的地方,我就能够列出所有的Periscope API调用以及相关的参数名。通过对相关类进行深入分析之后,我还可以从静态字符串中提取出Mevo的API root、clinet_id以及client_secret了。
接下来,我们就可以检查Periscope的OAuth实现中的漏洞了,而Periscope初始的身份认证节点并没有部署CSRF保护机制。如果一个第三方应用可以请求获取用户Periscope账号信息的完整权限,那么攻击者就有可能创建一个恶意第三方应用来伪装成用户执行恶意操作了。
总结
1.从今以后,我都会时刻关注Twitter的更新情况,并在第一时间对Twitter新上线的功能进行安全测试。 2.将功能开放给特定的第三方(或在公开API之前)不意味着你就不用对该功能的安全性进行测试了,有时我们只需要找到一个访问API的方法,我们也许就能轻松地找出其中存在的安全问题。当然了,如果厂商给特定服务设立了漏洞奖励计划的话,你也许就不必绕弯路了。 3.最后一点,当你没钱的时候,不要立刻放弃,你应该想办法绕过或避免那些需要你花钱的东西。不过你也可以换个角度考虑,人们一般都不喜欢去投资那些所谓的“不确定性”,这也就意味着如果某个服务需要收费,说明会有一部分人不愿意花钱去测试,那你就很有可能从中发现一些别人无法发现的漏洞了。如果这个服务又有漏洞奖励计划的话,那你估计就要发财了。
参考资料
关于该漏洞的详细技术分析以及PoC,请参考发布在HackerOne上的原始报告。
- EF基础知识小记七(拆分实体到多个表以及拆分表到多个实体)
- Android 进程回收之LowMemoryKiller原理篇
- 邮件发送功能开发
- Vuejs和其他前端框架的对比
- 详述 IntelliJ IDEA 中恢复代码的方法
- C# 通过IEnumberable接口和IEnumerator接口实现自定义集合类型foreach功能
- 微信小程序之picker组件
- 详述 IntelliJ IDEA 中恢复代码的方法「进阶篇」
- mac环境下mongodb的安装和使用
- C# 终极基类Object介绍
- EF基础知识小记五(一对多、多对多处理)
- 字符串的方法汇总
- Kotlin和anko融合进行Android开发
- EF基础知识小记六(使用Code First建模自引用关系,常用于系统菜单、文件目录等有层级之分的实体)
- 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 数组属性和方法
- 再也不怕面试官问java中的goto关键字了?
- 死磕Java之分析short类型
- 死磕Java之Java数据类型的来龙去脉
- 请不要再使用判断进行参数校验了
- 检测假新闻:比较不同的分类方法的准确率
- SpringBoot下载xlsx模板,导出excel数据
- 如何利用机器学习和Gatsby.js创建假新闻网站
- Spring Security 实战干货: 401和403状态
- Spring Data R2DBC响应式操作MySQL
- 项目端口可以设置为 6666 吗?
- 【JS】666- window.reqeustIdleCallback方法详解
- 一个无聊的宏定义
- windows的Ubuntu子系统ssh和ftp
- 面试官问:如何设计一个安全的对外接口?
- [树莓派公网远程监控]autossh反向代理