谷歌最近在2016年10月发布了Nexus安全公告,其中包含360MobileGuardAlphaTeam(AlphaTeam)提交的电子邮件信息泄露漏洞(CVE-2016-3918),谷歌将此漏洞评为高风险级别。该漏洞可以让恶意应用程序获取电子邮件中的数据,这些数据可能是电子邮件内容、电子邮件附件,甚至是帐户密码。目前,谷歌已经修复了该漏洞,并向OEM厂商推送了补丁。本文将对该漏洞进行分析。本文测试环境及代码版本如下:SDKVersion:23,Android6.0.1Build:MOB30YBranch:android-6.0.1_r60漏洞产生原因在AndroidAOSPEmail应用的源代码中,我们可以看到在AndroidManifest.xml文件中存在一个名为AttachmentProvider的ContentProvider。其主要属性如下:exportedtrue表示对外开放权限com.android.email.attachmentprovider表示URI唯一标识readPermissioncom.android.email.permission.READ_ATTACHMENT表示read需要这个权限。通过查询我们可以知道com.android.email.permission.READ_ATTACHMENT权限的protectionLevel是危险的,可以通过第三方应用获取。确认这个ContentProvider可以被第三方应用访问后,我们定位到AttachmentProvider的源码。源码路径如下:/packages/apps/Email/provider_src/com/android/email/provider/AttachmentProvider.java通过阅读源码我们可以发现在AttachmentProvider中实现了一个publicopenFile接口,返回调用者打开文件的ParcelFileDescriptor类型对象。publicParcelFileDescriptoropenFile(Uriuri,Stringmode)throwsFileNotFoundException{进入openFile接口会立即判断mode值是否为“w”,若为w则返回一个可写的文件描述符。但在返回之前,函数的实现代码会检查权限。如果调用者没有com.android.email.permission.ACCESS_PROVIDER权限,则会抛出异常。权限的声明如下:/permission_access_provider_desc"/>可见这个权限是第三方应用无法获取到的,所以获取可写权限是不可行的。继续往下分析代码。Listsegments=uri.getPathSegments();StringaccountId=segments.get(0);Stringid=segments.get(1);Stringformat=segments.get(2);if(AttachmentUtilities.FORMAT_THUMBNAIL.equals(format)){intwidth=Integer.parseInt(segments.get(3));inheight=Integer.parseInt(segments.get(4));...}else{returnParcelFileDescriptor.open(newFile(getContext().getDatabasePath(accountId+".db_att"),id),ParcelFileDescriptor.MODE_READ_ONLY);}接下来的一系列代码会从uri.getPathSegments()中分离出不同的字段,并从中读取相应的配置参数。当格式参数不等于“THUMBNAIL”时,代码会直接返回getDatabasePath()目录下名为id的文件的文件描述符。id参数是从上面的uri.getPathSegments().get(1)中获取的,获取之后没有任何处理。uri.getPathSegments()方法的作用是将字符串以“/”进行分割,但是由于它没有对url编码后的字符串进行解码,所以在处理过程中,/encoding之后的%2f不会做处理,从而绕过getPathSegments的分段。漏洞利用根据我们对上面代码的分析,我们可以得出AttachmentProvider的uri如下:content://accountId/id/format/width/height如果我们想利用这个漏洞读取数据,为了使程序流成功运行到目标位置需要构造如下uricontent://com.android.email.attachmentprovider/1/file_position/1/1/1getDatabasePath()的目录为/data/user/0/com.android.email/databases/,如果我们要读取邮件数据,需要跳转到目标目录/data/data/com.android.email/读取Email的sqlite数据库文件应用程序,我们需要构造以下uri:content://com。android.email.attachmentprovider/1/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fdata%2Fdata%2Fcom.android.email%2Fdatabases%2FEmailProvider.db/1/1/1和EmailProvider.db存放的是我们登录账号的账号名和密码,对应的结构体就是loginHostAuth表和密码字段。我们构建的PoC截图如下:综上所述,CVE-2016-3918漏洞的分析利用已经完成。经过我们的测试,该问题存在于小米Note、华为P9、三星S5等多款主流手机内置的邮件客户端中。为了账户安全,使用存在漏洞的手机用户应暂停使用邮件客户端并清除账户信息,切换至其他邮件客户端。