前言:本文主要介绍了目前App数据传输过程中几种常见的加密方式,以及一些常规的解密手段,并不涵盖并应对所有情况,在实战过程中还须具体情况具体分析,随机应变;同时,也十分欢迎与希望各路大神提出宝贵建议和思路,一起学习和研究。(注:全文中所提到的App仅针对Android App)
随着App移动应用的广泛应用及移动开发技术的飞速发展,移动应用的安全也越来越被重视;在App服务端渗透中,我们在抓包时经常会发现App在数据传输过程中做了加密(如图1),以防止数据被查看或被篡改;而渗透过程中的很多时候我们都需要抓包修改,这就要求我们需要先对App数据包进行解密了。
一、一些常见的加密方式
对于App传输数据加密,一般会考虑三个方面
1) 可用性:客户端和服务端都可逆向破解
2) 较高的安全性:不容易被破解
3) 效率性:加密性能及资源占用方面不是很高
针对以上三个方面需求,目前用得最多有以下几种加密方式(当然,有时候会掺杂一些其他的小算法,具体情况自行识别和解码即可),其特点及优缺点分别阐述如下。
1)对称性加密。如DES、AES、3DES等。这些加密方式的算法基本已公开,因此其特点为密钥/生成密钥的方法固定,因此这种加密方式的优点为性能效率较好,而且也较大的提升了解密的成本;但由于密钥固定,因此缺点也很明显了,则是在客户端和服务端上都能找到密钥或密钥的生成方法。因此其突破口为通过逆向客户端来寻找密钥。另外,这种加密方式可同时用于请求包和返回包。
2)非对称性加密。如RSA、Rabin等。这些加密方式的算法基本也已经公开,因此其特点为有一对公钥和私钥:客户端上保存公钥,用于加密;服务端上保存私钥,用于解密。因此这种加密方式的优点为安全性较高,客户端上只有用于加密的公钥,而没有用于解密的私钥;而弱点则为加解密效率不高,性能资源占用较大,所以目前很多App还是选用对称性加密。由于客户端上没有解密数据包的私钥,因此需要使用其他方法获取数据包明文才能进行数据包篡改。(获取方法后续详述)另外,由于只有一对公钥和私钥,所以这种加密方式一般只会出现在请求包,而返回包则一般为明文返回。
3)自定义算法加密。有少数App开发的技术人员还会使用自定义算法来对数据包进行加密,算法五花八门,大多为各种常见的编码(如Base64)和字节位移运算等混杂。这种加密方式的优点为效率较高,但缺点为算法硬编码在客户端中,只要通过逆向即可解密出来。
以上三种加密方式各有优缺点,对于第一和第三种,虽说可通过逆向App获取密钥/算法来进行解密,但是开发者往往会通过其他手段来增强安全性,如App加固或把密钥/算法硬编码在so文件中等;这样就更进一步地提高了逆向与解密的难度和成本了。
二、常规的解密手段
1、判断加密方式
对于解密,首先我们须要先大概判断使用的是什么样的加密方式,不管是对称还是非对称加密,从这些加密算法的密文形式可知,一般只有以下三种:
1)原始格式。也就是字节数组了,这种展现在数据包中就是乱码了。(如图2)
2)十六进制,亦即Hex编码。对称/非对称加密后,做了Hex编码处理(如图3)
3)Base64编码样式,对称/非对称加密后,做了Base64编码处理(如图4)
综上,如果发现数据包是这三种形式,而且尝试过Base64反编码后是乱码的,那很大概率就是使用了对称/非对称性加密了;而对于自定义算法加密的,一来并不常见,二来很多时候密文形式会比较奇葩,所以最后考虑。
当判断出是对称/非对称加密时,我们可以进一步判断用的是对称还是非对称。判断方法比较多,最简单的一个方法是,对于同一个数据请求包,重复触发时,密文是一模一样的则为对称性加密,而密文不一样的则为非对称性加密了。
2、定位密钥/算法代码
接着,我们需要通过逆向App来寻找对称/非对称性加密的密钥(而关于如何破壳和逆向则非本文讨论范围了,此处略过)。逆向后,得到的是java代码及对应的Smali代码。一般地,前者用于分析,后者用于调试。
我们先在java代码中查找并定位到加密过程的代码。如何定位?一言以蔽之:全靠眼和经验。比如可以在整个class包中查找含有加密数据包的url接口所在的位置,然后一步步跟踪查看其加密数据是通过什么函数生成的,最终定位到加密函数,当然中间的函数跳转可能会很多;又如可以暴力地直接在整个class包中查找加密函数的一些关键字,如AES、DES之类的,当然这样返回的结果可能会很多,只要一个个验证过去就可以了。至于如何验证,我们可以通过经验去判断,也可以通过下面所讲的调试。
3、调试
正如开发编程一样,调试往往是程序定位的最好方法。而调试有两种方法,一为日志输出,二为动态调试。
举个例子,比如我们在java代码查找中找到一段DES的加密函数代码,不确定是否数据包加密时所调用的,这时我们可以在Smali代码里该函数中插入日志输出代码,如
const-string v0, "Log here!!!!!!!"
invoke-static {v0, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
保存后编译回apk文件,并在手机/模拟器中安装后打开App触发加密数据包,并通过adb logcat输出日志,查看是否有“Log here!!!!!!”。如果有则说明加密函数代码定位成功;反之则失败。
当然,我们也可以使用动态调试法来解决上面的例子。将反编译后的App文件夹载入到开发环境中(如Eclipse等),记得先修改AndroidManifest.xml开启调试模式,然后在Smali代码里该函数开头处设置断点,并在开发环境所连接的Android模拟器中启动App触发加密数据包,即可通过查看是否停在断点出来进行判断。
4、获取密钥/算法
当定位到加密函数后,算法已经展示在面前了。而密钥的话,我们可以继续使用调试方法来获取密钥。如果使用日志输出法的话,有时候密钥不一定是字符串格式,直接日志输出时会报错,所以我们切记一定要在Smali代码中把密钥的对应参数类型转换为字符串格式;如果使用动态调试法的话,开发环境中走到密钥寄存器那一步时会则自动显示出来。
对于对称性加密和自定义算法加密的,当获取到加密密钥/算法时,我们已经可以直接解密数据包获取明文–篡改明文数据包(如加入注入/xss攻击字符串)–加密明文数据包为密文–发送了;而对于非对称性加密,由于客户端中只有公钥,因此只能做篡改数据包后的加密动作,而无法直接解密数据包;此时,我们可以使用其他方法来获取数据包明文,比如使用调试同理把加密前的数据包明文参数获取即可~
三、防御手段
没有绝对的安全,预防往往是建立在不断提高攻击成本和难度的基础上。针对上述常规的解密手段,我们可以从以下方面来增强App加密的安全性。
1)App加固。使用加壳、混淆等手段,增强App被反编译的难度和成本。
2)使用So文件来保存密钥/算法。由于So文件是c编译的,因此反编译的难度无疑增大了很多。
3)重要的核心业务App考虑使用加密WAF。一般经过加密后的App,WAF基本已经失去检测和防御作用了;因此,对于重要的核心业务App,可考虑把加密模块加到WAF中,以保持检测防御效果。