*本文阐述的漏洞已被上报锤子科技并已确认修补。

Smartisan OS是锤子科技推出基于Android定制的移动操作系统。该系统于去年3月27日在国家会议中心由罗永浩首次公布。在2014年4月11日发布V0.9.9.7 alpha版本中,系统新增了云服务功能用来同步联系人、日历以及便签到云服务器。

 

 

在该测试版本中存在重大安全隐患。由于2014年5月20日的发布会临近,锤子科技选择默默的将漏洞修补并采取不声张策略。


上述云服务使用基于Nginx定制的scws/2.4.9作为Web服务器。scws即Smartisan Cloud Web Server之意。同时,上述云服务使用锤子科技自行颁发的X.509证书 以及TLS 1.2协议对访问流量进行加密。

1) TSL以及中间人攻击

TLS,即Transport Layer Security,传输层安全协议,是SSL(安全套接字)的继任者,二者均使用公开密钥技术对网络流量进行非对称加密。

中间人攻击,即Man-in-the-middle Attack,是指攻击者分别与通信的两端建立连接,转发两者之间的流量,从而窃听通信内容的攻击方式。而TLS和SSL有防范中间人攻击的机制。在本次测试过程中,实际上更多地使用了中间人转发通信内容的方式获取锤子科技云服务的加密流量的明文以进行分析,而并非窃听他人的通信。

由于锤子科技云服务采用了TLS加密其HTTP流量,因此,在中间人代理服务器与锤子科技云服务通信时,流量采用锤子科技的X.509证书加密,而在云服务客户端程序与中间人代理服务器通信时,流量采用代理服务器自行生成的X.509证书加密。于是,中间人代理服务器便能够监听并篡改云服务客户端程序和云服务服务器之间的通信。

 

2) 云服务器漏洞发现过程

本次测试中用到的工具主要有Poster,Android模拟器和mitmproxy。

本次测试中使用的Android模拟器由锤子科技论坛网友使用Google Android SDK中的模拟器,通过打包Smartisan OS的系统文件并替换模拟器中的system.img,定制而成,运行早期Smartisan OS。

通过修改设置中移动网络的APN(接入点名称),配置HTTP代理服务器,可以实现流量转发,从而达到分析流量的目的。

2.1 反编译关键应用

在本次测试的第一部分,由于受限于硬件条件,无法进行真机调试,因此从静态分析入手,即通过分析云服务客户端程序的代码,而不是通过实际运行程序,来获得云服务系统的相关信息。

下载锤子科技官方网站上的V0.9.9.7 alpha版压缩包后,解压system目录下的CloudServiceSmartisan.apk,并使用通用的apk反编译工具对其进行反编译,生成jar文件。而后使用Java Decompiler 查看由字节码反编译而成的源代码。

 

 

在名为CommonHttpUtils的类中可以看到一些反编译错误,以及认证用的名为Ticket的HTTP头,如下图所示。

 

 

而在NoteTask类中,可以看到更新、新建、删除便签的操作细节。如下图所示,创建便签操作的请求是一个发往api.sync.cloud.smartisan.cn/USER_ID/notes.json的HTTPS的PUT请求。

 

 

2.2 模拟器环境下的加密流量劫持

上文所述Android模拟器即“锤子系统电脑版”,被用来运行第一部分中所提到的云服务客户端程序,即CloudServiceSmartisan.apk。同时,一台运行Ubuntu操作系统的虚拟机被用来运行mitmproxy,作为Android模拟器的HTTP代理服务器以劫持云服务客户端程序与服务器的通信。

启动“锤子系统电脑版”后发现,这款Android模拟器的所载入的Smartisan OS发布于2013年7月,并不具有V0.9.9.7 alpha版本的云服务功能。由于在使用最新版的Smartisan OS重新打包system.img文件后,模拟器并不能正常启动,因此转而使用Android系统调试工具adb安装CloudServiceSmartisan.apk。安装成功后可在“设置”中选择“添加账户”来登录或注册云服务账户。

根据第一部分中对云服务客户端程序反编译获得的源代码的分析,以及概述中对中间人攻击的介绍,由于中间人代理服务器与云服务客户端之间的通信会使用代理服务器自行生成的X.509证书,因此必须要将该证书导入Android模拟器所加载的操作系统中。

导入过程并不复杂,既可以将BASE64编码的证书文件直接复制到/etc/security/cacerts目录,并设置权限为644;也可以将相应证书文件复制到/sdcard目录后,在“设置”中的“安全”菜单选择“从SD卡安装”。作为Android内建安全措施之一,导入证书时采用后者将会强制用户设置锁屏密码。

在安装并第一次运行mitmproxy后,mitmproxy生成的X.509证书可在当前用户home目录下的.mitmproxy下找到。将其中的mitmproxy.cer通过adb复制到模拟器的/sdcard目录下,进行安装。

此外,还需要设置恰当的APN来配置操作系统使用中间人代理服务器作为HTTP代理。打开“设置”菜单,选择“无线和网络下”的“更多”,选择“移动网络”,“接入点名称(APN)”。“名称”任意设置,“APN”设置为“Internet”,并将代理服务器地址和端口设置为运行mitmproxy的虚拟机的IP地址和端口,默认为8080端口。

使用任意账号密码测试登录,在mitmproxy界面可以看到请求的URL以及JSON请求格式,与第一部分中登录部分相关代码相符。

 

 

 

2.3 针对JSON API的黑盒测试

根据前两部分获得的云服务相关信息可以发现,云服务接口实际上是一系列JSON API。而这些API分为两台服务器:api.account.smartisan.cn和api.sync.cloud.smartisan.cn。其中前者负责账户相关API请求,后者负责实际同步内容相关API请求。下表列出了部分常用API以及用途:

api.account.smartisan.cn/tickets.json POST方法;登录
api.account.smartisan.cn/user/prereg.json POST方法;短信验证相关
api.account.smartisan.cn/user/USER_ID.json GET方法;用户基本信息
api.account.smartisan.cn/user/USER_ID/avatar GET方法;用户头像
api.sync.cloud.smartisan.cn/USER_ID/notes/list.json GET方法;便签同步列表
api.sync.cloud.smartisan.cn/USER_ID/notes.json GET/PUT方法;便签操作
api.sync.cloud.smartisan.cn/USER_ID/ contacts/list.json GET方法;联系人同步列表
api.sync.cloud.smartisan.cn/USER_ID/contacts.json GET/PUT方法;联系人操作
api.sync.cloud.smartisan.cn/USER_ID/calendars/list.json GET方法;日历同步列表
api.sync.cloud.smartisan.cn/USER_ID/calendars.json GET/PUT方法;日历操作

其中用户基本信息、便签、联系人以及日历API均需要验证身份。身份验证是通过验证HTTP请求头中的“Ticket”字段进行的。

通常对于计算机程序和系统的测试都是从用户输入开始的。根据以上的信息,云服务的API主要有三类用户可控的输入:URL参数,即用户ID,HTTP请求头中的字段,即“Ticket”等,以及JSON格式的请求主体。

经过一系列检测,在第一类用户输入中并没有发现云服务API响应异常,推测原因为API过滤了所有非数字字符。

而HTTP请求头中,版本参数,User-Agent等字段均不能导致API响应异常。真正有趣的地方在身份认证使用的“Ticket”字段上。下表列出了针对用户基本信息API的“Ticket”字段部分测试输入以及响应。

测试输入 API响应

999' # {"code":404125}
999' or 1=1 # {"code":401}
999' order by 6# {"code":500013}
999' order by 5# {"code":404125}
999' union select 3,3,3,3,3# {"code":404122}

由此,用户基本信息API被确认在“Ticket”字段部分存在SQL注入漏洞,并且可以确认检查令牌的SQL查询返回字段数为5。可以推测出,响应中的“401”意为找到了令牌但是用户ID与URL中的USER_ID参数不符,因此认证失败;“404125”意味着没有找到相应令牌记录;而“404122”则意味着并未找到相应的用户。

此外,在针对登录和短信验证相关API的测试中发现,请求的JSON格式数据中的“email”字段也存在注入。由于云服务API在处理“email”字段时过滤了部分不符合电子邮件地址命名规则的字符(如空格,逗号,全角字符等),因此此处SQL注入点威胁并不大。下表列出了针对登录API的部分Email输入测试以及响应。

qqq'/**/order/**/by/**/3#@ qq.com {"code":404123}
qqq'/**/order/**/by/**/4#@ qq.com {"code":500013}
qqq'@ qq.com {"code":500013}

令人感到奇怪的是,提交到api.sync.cloud.smartisan.cn服务器的所有请求的HTTP请求头中的“Ticket”字段均经过了良好的过滤,并不存在SQL注入漏洞。而提交到api.account.smartisan.cn服务器的请求头中的“Ticket”字段并未经过过滤。这意味着两台服务器运行着完全不同的用户身份认证模块,而这对于一个有着如此预期用户规模的云服务来说,是不可想象的。

 

3) 安全缺陷

由于用于获取用户头像的API并没有身份认证,因此可以根据用户ID任意下载用户头像。下图展示了用户ID小于200的部分内部测试用头像。

 

 

用户ID大于1000000的为公开测试用户,目前约3000名用户中有707人设置了头像。

如果从安全缺陷的严格定义出发,用户头像并不是重要的隐私信息,并且用户头像本身就存在一定的社交属性。因此不经身份认证也可访问用户头像并不属于安全缺陷。

 

用户个人信息泄露

经过针对用户个人信息API的测试,已经确定用户基本信息API请求头中的“Ticket”字段存在SQL注入漏洞。通过闭合“Ticket”字段查询条件,并加入OR条件指明“uid”字段取值,可以绕过用户身份认证,获取用户电话号码,邮箱地址,注册时间,以及是否通过短信和邮件认证等信息。

 

 

用户同步令牌泄露

用户基本信息API在未找到请求中“Ticket”字段对应的令牌时,返回代码“404125”,即令牌未找到;而在找到令牌,但用户ID与URL中请求的USER_ID参数不符时,返回代码“401”,即认证失败。由此,可在用户基本信息API请求中“Ticket”字段后加入OR条件来测试任意SQL表达式。如果表达式为真,用户基本信息API则返回代码“401”,如果表达式为假,用户基本信息API则返回代码“404125”,从而使SQL盲注成为可能。

经过针对用户基本信息API的SQL盲注测试发现,可以通过提交精心构造“Ticket”字段的API请求来获取SQL表名,字段名,以及当前运行SQL版本等信息。经过检测,数据库名为cloud_account,存在用户表7个,分别是account_cellphone_uid,account_email_uid,account_failedlogin,account_seccode,account_seccodes,account_tickets以及account_users。其中account_tickets表存在5个字段,分别是id,ticket,uid,create_time以及expire_time。

通过利用这一安全缺陷,可以获取指定用户ID的同步令牌,从而进一步获取该用户的便签,联系人和日历信息,此外还可以修改用户昵称,头像,甚至添加、修改联系人电话号码,实施电信诈骗。

 

4)小编总结

小编认为,这里的漏洞修补了,不见得别的地方就没漏洞,历史告诉我们,某些厂商注定继续悲剧,希望锤子科技越做越好。

顺便小编问一句,老罗的手机通讯录在黑市值多少钱?

//silic.wiki