【译】SafetyNet:Google对Android的篡改检测 (SafetyNet: Google's tamper detection - Part 1 )

什么是SafetyNet

Android Pay应用程序已于几天前发布。一些使用植根设备的人发现它拒绝工作。这是因为它使用了新的Google Play服务功能:SafetyNet证明

SafetyNet证明是Google告知应用程序有关设备CTS兼容性状态的意见。CTS通常代表兼容性测试套件,它是设备在发布之前必须通过的一组测试,才能包含Google Play服务。这意味着SafetyNet上下文中的内容有所不同,例如“ 设备当前处于未篡改状态 ”。

篡改状态有多个定义,可以包括“被扎根”,“受到监视”或“被恶意软件感染”。

“兼容CTS” 并不意味着没有漏洞。作为SafetyNet服务的一部分,Google不会检查设备是否是最新的容易受到公众利用。它会检查与预期的正常和安全状态相比是否已被篡改。

有人可以说这是应用程序开发人员想要的:设备的漏洞状态对最终用户有用,但对开发人员却无济于事。原因是不切实际的:如果某个应用程序拒绝在易受攻击的设备上运行,那么即使在最新的Android设备上,也几乎没有应用程序可以运行。SafetyNet旨在确保应用程序开发人员该设备“可以安全运行”,而不是确保最终用户该设备“安全”-不同的目标群体,不同的目标。

Google显然不想使用繁琐的术语,例如生根或篡改检测,因此它采用了中性的“兼容CTS”。

使用SafetyNet认证

SafetyNet认证是一项新功能,至少对于第三方应用程序开发人员而言。任何应用程序开发人员都可以在其应用程序中使用它。

该过程包括几个步骤:

  1. 应用程序调用SafetyNetApi.attest()。这是由Google Play服务SDK提供的。该请求用于GoogleApiClient访问Google服务器。
  2. 该请求必须包含一个随机数。这对于防止重放攻击非常重要。最佳实践是服务器生成此随机数并将其发送到设备以在请求中使用。
  3. Google会以证明结果作为回应。这是JSON Web Signature (JWS)格式-一种签名的JSON对象。响应包括各种签名和以下内容:"ctsProfileMatch": true|false
  4. 开发人员需要手动验证响应字段。Google本身也可以使用另一个API调用来验证响应的签名,这是最佳做法。
  5. 假设响应被验证(如果ctsProfileMatch为真),则开发人员可以确定该设备没有被篡改(..与CTS兼容)。

有趣的是,响应也可以在开发人员的服务器上进行验证。应用程序可以获取JWS证明响应并将其发送到通常连接的应用程序服务器。然后,该服务器可以直接要求Google验证JWS签名(或自己做),然后继续对服务器端的结果采取行动,例如拒绝对客户端的API访问。

这是一个好的设计:安全性决定发生在服务器上,而不是客户端上。即使客户端被操纵,服务器也将拒绝提供服务。据我所知,在AndroidPay中,几乎每个wallet&pay API都将证明结果用作参数。话虽如此,这并不意味着证明系统不能被欺骗-恶意环境可能将篡改的数据提供给收集器。而且,这并不意味着证明的结果总是新鲜的。。但是总比没有好。

开发人员可以在这里找到有关使用此功能的说明:https : //developer.android.com/training/safetynet/index.html

但是,这一切如何运作?

SafetyNet系统设计

SafetyNet 是Google用来从10亿台启用Play的Android设备上收集与安全相关的信息的数据收集系统。

这个想法是,Google Play服务(设备上的封闭源程序包)会启动名为的始终运行的服务snet。此服务经常从设备收集各种数据,然后将其发送回Google。

Google将此信息用于多种目的,例如生态系统分析和设备威胁分析。

事实证明,根据收集到的信息,Google可以确定设备是否受到多种方式的篡改。Google会维护此信息,并会随时知道特定设备是否处于可疑状态。

证明是如何将此信息公开给第三方开发人员。当应用程序执行证明请求时,Google会根据对先前从设备中收集的信息的分析,将包含其有关“ CTS兼容性”的决定的已签名响应发送回去。

收集到的数据的实际分析是在服务器端完成的,从而留出了更少的操作空间;再次做好安全设计。

当然,了解收集哪些数据可能意味着某人最终可以开发出一个不断提供snet“非恶意”信息的挂钩系统。

但是,这并不简单:

  • 用于更新的机制snet非常灵活的,如下面所讨论。
  • 谷歌没有透露如何它究竟决定“CTS兼容性”的基础上收集的数据。对于许多此类数据,什么构成“安全”,什么不构成不是很明显。例如,如果Google收集了文件系统中所有文件路径的列表,则攻击者将不得不通过反复试验找出隐藏的内容。即使他能够做出有根据的猜测,他也不知道Google到底在寻找什么。

SafetyNet内部

当第三方应用程序想要发出证明请求时,它将调用com.google.android.gms.safetynet.SafetyNetApi;->attest(mGoogleApiClient, nonce),该应用程序中包含的Play Services SDK的证明方法。该库与com.google.android.gms.safetynet.internal.ISafetyNetService通过Binder在设备上运行的服务进行交易。

SafetyNetService是谷歌游戏服务之一。服务处理代码打包在Google认可的Android设备随附的Google Play服务软件包中,并通过Play商店进行更新。

但是,更深入地揭示一个非常有趣的技巧:

的实际实现snet不在任何APK中。

SafetyNet服务与Google服务器联系,并下载包含代码的二进制程序包。验证软件包的完整性非常费力,例如使用硬编码的证书(固定)。该二进制程序包实质上是一个JAR文件,其中包含classes.dex具有Java字节码的文件。Play Services将其缓存在dalvik-cachesnet.dex)中,并使用反射动态加载。

这对Google来说非常方便:即使不通过Google Play推送应用,也可以非常轻松地更新收集方法的实际实现。

这是该软件包的两个版本:https : //www.gstatic.com/android/snet/12042014-1626247.snet https://www.gstatic.com/android/snet/07172015-2097462.snet

这些文件不会以任何方式混淆(即使使用ProGuard也不会)-尽管使用了Google Play软件包。与Android安全团队的成员交谈之后,看来这是有意为之的:他们想要一个实现,而不是易于审查的实现。我的猜测是,他们希望确保人们知道自己没有收集与敏感/隐私相关的信息。混淆可能会引起怀疑。

从打包日期可以看出,该系统的某些部分根本不是新的-SafetyNet至少从2014年12月开始存在,但是在最新版本中已得到了很大增强。

该JAR文件包含com.google.android.snet.Snet该类的实现。该enterSnet方法是有趣的开始-这就是游戏服务调用通过反射。

Google会在更多情况下下载与安全相关的代码。例如,Android设备还下载了一个名为本机的共享库droidguard并运行它,但让我们将其留给另一篇文章。

EnterSnet

该系统非常模块化:snet可以由Play Services使用配置文件来启动,该配置文件定义将使用哪些收集模块。默认情况下,并非所有功能都启用。

让我们更详细地了解这些模块的每个功能:

default_packages

这将为某些操作创建首选软件包的列表,并报告哪些软件包用于Web浏览和软件包安装。它专门检查首选的Web浏览器是否为 com.android.browsercom.android.chrome。 我可以假设这样做是为了检测用户授权使用非标准浏览器(可能是恶意软件)的情况-Google可以在其后端维护一个列表。

su_files

报告回来,如果这些文件/system/bin/su/system/xbin/su存在。如果这样做,则表明存在篡改迹象。

我确实希望证明结果不仅仅基于此检查-尽管有证据表明它发挥了重要作用。在未感染的,仅已植根的设备上,将这些文件移动到其他位置似乎会产生积极的证明结果。通过“禁用SuperSU”之类的操作也可以达到相同的结果。也许Google格外谨慎。

settings

android.provider.Settings$Secureandroid.provider.Settings$Global取决于操作系统版本收集各种与安全性相关的字段。收集的设置包括的像变量的值adb_enabledinstall_non_market_appsisKeyguardSecure()getNotificationVisibility()lock_screen_lock_after_timeoutlockscreen.password_typelock_pattern_autolock。 显然,所有这些都表明该设备可能“令人感兴趣”。

locale

向后报告设备的当前语言环境配置。 我认为这样做是为了使他们可以根据地区风险对用户进行配置,并根据需要调整其阈值。

ssl_redirect

这是一个有趣的模块。它尝试确定设备是否正确遵循SSL重定向。它收集诸如活动连接的类型,使用中的DNS服务器以及可用连接之类的信息。

然后,它创建到以下主机的请求:http://accounts.google.comhttp://www.google.comhttp://pubads.g.doubleclick.net-使用随机用户代理,甚至模仿一个iPhone,具有“后续重定向”禁用。所有这些主机都重定向到站点的HTTPS版本,并且模块从重定向响应中收集Location HTTP标头。然后,它将再次执行相同的请求,这次是在重定向之后。重定向之后,将报告最终端点主机的IP和主机名。第二个请求甚至是使用ApacheHTTPclient类或HttpURLConnection(!)随机完成的

有人要求提供有关该doubleclick.net域的更多信息。这是一个用于向应用程序投放广告的域,该服务归Google所有。我只能假设这也是尝试检测是否安装了广告拦截器

ssl_handshake

这个另一个非常有趣的模块。它试图确定是否可以通过多种方式来拦截通信,例如通过安装SSL-Kill-Switch应用程序。

该代码试图联系三台主机:accounts.google.comwww.google.compubads.g.doubleclick.net

对于每个主机,遵循以下算法,并捕获每个步骤的所有结果以及任何可能的错误。

  1. 模块尝试使用'accept-all'进行SSL套接字连接TrustAllX509TrustManager
  2. 检索对等证书
  3. 该代码查找系统的所有TrustManager
  4. 找到的每个对象TrustManager都将不使用信任锚进行初始化,并且该checkServerTrusted()方法将在检索到的证书链上执行。通常,这会引发异常,但是在大多数SSL Kill Switch实现中,它不会。该代码验证是否抛出异常(严格检查)
  5. 所述DefaultHostnameVerifier用于验证所述连接的主机名
  6. 然后,模块手动验证证书链,还检查是否有任何证书使用的MD5withRSA算法和公钥短于2048位。
  7. 对于链中收到的每个证书,该模块都会检查发行人是否存在于系统的CA存储中(/system/etc/security/cacerts)或是否已被用户添加(/data/misc/keychain/cacerts-added
  8. 该模块还包括一个用于Google的硬编码固定中间证书,并检查它是否与接收到的链证书之一匹配
  9. 最后,还检索了叶子证书的增强密钥用法对象标识符,并将其与硬编码列表(!)进行比较。

完成所有这些检查之后,所有有关连接是否成功,如果通过了链验证和信任检查都将收到的证书的信息将发送回Google。

mx_record

对于设备上设置的每个DNS服务器,将gmail.com解析主机名并收集MX服务器以及完整的DNS响应。 我认为这是为了检测设备是否配置为使攻击者可以拦截电子邮件。

sslv3_fallback

使用通过和https://www.google.com发起的SSL套接字进行连接。它收集套接字是否已连接以及主机名验证是否通过。如果没有通过连接,则使用而不是上面提到的现代TLS功能重试连接。该模块收集所有产生的工件和错误消息。 该模块显然旨在检测与网络相关的攻击,例如SSL降级。TLSSNI extensionsSessionTicketSSLv3

proxy

收集是否在设备上配置了代理,它们的IP地址是什么以及这些IP是否是设备的本地IP。 这会尝试确定设备上是否存在侦听流量的恶意软件(某些恶意软件-和广告拦截器-使用代理工作)或是否将通信发送到外部已知错误的位置。

selinux_status

收集设备上是否提供SELinux支持(如果/sys/fs/selinux/enforce存在),以及是否处于强制模式(通过读取该文件的内容) 如果在较新的Android版本上SELinux处于非强制模式,则表明存在可疑现象正在进行。

sd_card_test

尝试了解SD卡是否已被篡改。这将gmsnet2.jpg在SD卡上创建一个JPEG文件,并在其中填充一些硬编码的内容。然后,IT部门将分析文件的长度是否与硬编码值匹配,并逐字节验证写入的字节是否与发送的字节匹配。 我不确定我是否理解此检查的原因以及在与安全相关的条件下它将失败的原因。

google_page_info

尝试确定HTML代码的长度是否www.google.com超过某个预先配置的阈值。 我假设这试图确定用户看到的页面上是否发生某种形式的javascript注入。

captive_portal_test

收集的IP地址clients3.google.com。然后,它使用随机用户代理连接http://clients3.google.com/generate_204并捕获响应的返回码和正文长度。 这将尝试确定设备是否使用重定向响应的强制门户。强制门户可以用作执行MitM攻击的方法。

logcat

运行logcat -d命令并查找一组可配置的“有趣的字符串”。 Google可以将所有日志上传到他们的服务器并在其中进行搜索,但是我猜想它采取了这种方法,从而避免了意外泄露用户私人信息。默认情况下,“有趣的字符串”的集合为空,因此我无法确定它们在寻找什么。

event_log

与logcat检查类似,但用于EventLog事件。跳过带有do-not-log-标签前缀的事件。

apps

首先检查设备上是否存在Google帐户。然后,根据Google Play提供的配置开关,它可以收集和报告有关所有非系统应用程序或所有系统应用程序的信息。 默认情况下,此模块未启用。在应用程序测试期间,我们将此类行为标记为隐私问题。但是我想Google已经知道您已经安装了哪些应用程序,因为您最有可能使用Google Play进行了安装,因此泄漏可能不多。我可以理解,为什么Google会对查看设备上还安装了哪些其他应用感兴趣。

google_page

http://www.google.com使用随机用户代理检索页面并存储收到的HTML代码。

suspicious_google_page

这与google_page测试相同,但首先使用ssl_handshakessl_redirect测试的结果,以尝试确定的连接是否安全www.google.com。如果不是,则不会保存任何结果。 这会将检索到的HTML代码发送回Google。我猜他们试图了解某些恶意软件是否在本地拦截流量并将内容注入HTML。

gmscore

收集有关com.google.android.gms设备上的应用程序的信息。这是Google移动服务应用程序,也称为Play服务。收集的信息包括APK和包签名的完整路径。 Google在这里尝试查看是否有某种东西(例如恶意软件)试图静态篡改播放服务。

attest

进行证明请求并收集AttestationInfo响应。 知道在计算较新的响应时要考虑多少过去的认证结果会很有趣。

device_admin_deactivator

检索设备的活动设备管理员(如果有)。将它们与名为的文件的内容进行检查device_admin_blacklist.txt。它包含在下载的snet.jar文件中,包含70多个条目,如下所示:

com.android.vendlng,66fd5cb0,f84d0d9f
org.helpzek.minecraft,1cf1e47b
google.android.xmppm,e39125e5,40c7d1e7
org.zl.zlorg,d2a16633,38d1153c
com.devguru.minecraft,9746f466
com.adobe.flplayer,1c0ec8e1,98837829,08dadccb,b094083a,81565420,76a05ce0,e5f7325e
com.android.pfx12,dc61b3d0
com.cryengine.gplay,61996cf8
com.wikihelp.minecraftwikiversion,2379f1d0
com.xsys.cfgs,749a7f99,3c0a9c89
com.cheatgroup.app,d2ef0ea4

这是一个HashMap,其中的键是程序包名称,值是完整路径名的sha256哈希的前缀。

如果在正确的APK路径上发现任何列入黑名单的应用是活跃的设备管理员,则将removeActiveAdmin()其调用以删除该管理员,并使用停止该软件包forceStopPackage()。收集设备管理软件包的应用程序信息。

显然,这超出了收集范围,实际上尝试使用黑名单方法保护设备免受危险应用的侵害。

system_partition_files

收集有关在下感兴趣的文件的可配置列表的各种信息/system。信息包括所有许可权,文件名,symlink目标,selinux安全上下文,哈希等。当前感兴趣的文件列表似乎为空。有趣的是,该框架利用红色鲱鱼来使攻击者感到困惑:连同感兴趣的文件,可以以相同的方式访问可配置数量的随机文件。 好东西,红鲱鱼方法通常用于高级应用程序保护产品中。但是,默认情况下未启用此功能。

system_ca_cert_store

该模块包含证书的sha256哈希散列的可配置列表。此检查查看试图查找的内容(/system/etc/security/cacerts/system/etc/security/cacerts.bksICS之前的内容),如果找到,则将其返回,或者是完整证书,也可以是主题名称,发行者名称和签名信息(可再次配置)。 这试图通过查找列入黑名单的证书来了解流量是否被拦截。有一种恶意软件会将恶意证书丢弃在证书存储中,从而允许SSL流量在网络层被拦截。

setuid_files

如您所料,此检查将收集有关setuid文件系统中存在的文件的信息。它采用libcore.io.StructStatlibcore.io.OsConstantslibcore.io.OSlibcore.io.Libcore和相关类检索信息。 setuid可执行文件的存在在较新的Android版本中是一个明显的危险信号。

####隐私问题一些人评论说,此博客文章中应单独解决隐私问题。这里有几点:

  • 系统的设计似乎使得收集是透明的:数据收集代码不是故意被混淆的,因此可以像在此分析中那样进行检查
  • 该系统的设计似乎也不会偶然收集私人信息。例如,日志和事件收集器仅收集与正则表达式匹配的某些事件,而不是整个日志。当然,如果没有正则表达式本身,我们将不知道确切收集了什么。
  • 未收集用户敏感的标识符,例如IMEI,IMSI等
  • 默认情况下,几个收集器是禁用的。我想Google只能在特定区域启用这些功能,或者在它首次检测到篡改迹象之后才可以启用这些功能,以收集更多信息。
  • 收集的大多数信息不需要系统特权或许多许可权即可收集。其中一些可以由普通应用收集。我已经看到了嵌入在数百个应用程序中的广告库,这些程序收集了更多的私人信息。

这就是说,我了解有些人会发现SafetyNet的侵入性-每个人对于构成私人/敏感信息的观点都不同。

还必须说,似乎没有退出系统。一旦第三方应用程序开始采用SafetyNet认证,那将产生有趣的含义。

结论

  • 这是一个设计良好的系统,作为安全控制。这是因为它将攻击者的工作从绕过客户端控件转移到试图找出要馈送到收集器的数据,以便Google决定返回true的努力。这是一场军备竞赛,与当前使用的传统反根除控件应用程序相比,攻击者的可见性受到限制。当然,无论设计得多么好,如果付出了足够的努力,具有根特权的攻击者将始终能够绕过此类系统。
  • SafetyNet不会泄漏诸如IMEI / IMSI之类的敏感/私人用户信息-至少不是使用当前默认配置。
  • 如果开发人员使用SafetyNet认证,则应注意:
    • 它不是根检测。根检测系统无法提供任何保证。
    • 他们应该在为SafetyNet设计其应用程序时尝试采用最佳实践:使用以下流程,其中在您的服务器上生成现时现值,由应用程序检索,并将证明响应发送回您的服务器以进行验证和采取措施。
    • 使用结果将其输入到欺诈检测系统中,或拒绝服务器(而非客户端)上的API访问。
    • SafetyNet无法在缺少Google Play的设备(例如各种自定义和第三方ROM)上运行。如果开发人员想要支持非Play设备,则必须围绕此进行设计。即使用户在非Google ROM上间接加载Play服务,SafetyNet也会检测到设备不兼容(遵循原始CTS兼容性定义)。
  • 这不是漏洞检测系统。
    • 漏洞检测系统试图确定设备是否“ 易受攻击 ”(如未打补丁)
    • SafetyNet尝试确定设备“ 当前是否处于被篡改状态 ”(如感染了恶意软件或被MitM感染)
    • 即使安全专业人员倾向于认为“用户安全==无漏洞”,这两种情况对于应用程序开发人员而言还是有很大不同。即使整个系统可能容易受到攻击,开发人员也需要确保设备在运行应用程序时不会处于受损状态。那是SafetyNet可以帮助他们的地方。这与某些应用程序包括生根和篡改检测代码的原因完全相同,尽管大多数人知道只要付出足够的努力就可以绕过这些系统。
  • 我希望SafetyNet周围有一些领域,希望能有时间进行更深入的探索。一个示例是收集的频率:SafetyNet也与“验证应用程序”功能密切相关,并且有一些声称每周进行一次扫描。不要忘记,证明只是Google告诉应用程序其对CTS兼容性的意见,但应用程序不知道该意见形成了多久。

原文地址: https://koz.io/inside-safetynet/

你可能感兴趣的:(Android,Security,Google,Safetynet)