1.基础分析
1.1.基础分析
工作中经常会对一些app进行安全审计,一般在拿到应用后可以使用APK Helper工具对应用做个简单分析,了解目标的包名,版本号,名称等基础信息,之后再安装到手机上熟悉下应用的业务,该应用属于哪类app,之后就是思考业务上可能存在的攻击点。
本次目标是一个电商应用,简单使用后可知应用存在登录,购买,支付等众多攻击点,这里我们就从登录入手。
登录逻辑的常见审计思路有:
1.审计客户端与服务端交互时是否直接将用户名密码进行明文传输。
2.客户端是否将用户登录的错误分开提醒如单独提示密码错误、单独提示账号错误。
3.服务端没对客户的登录次数进行限制导致用户名/密码可被爆破。
4.是否对用户的token做了校验,不存在校验可能导致任意用户登录等。
5.是否对验证码的输入次数做了限制,如果验证码为4,6位的纯数字则可以被爆破。
6.服务端是否验证注册手机和提交的验证码是否对应。
7.验证码获取的次数、频率是否有限制。
有了审计思路后就可以进行更深入的分析,在分析之前还需要确定该app是否有保护机制,比如应用是否加固,是否存在反抓包机制。如果存在的保护机制的话还需要把这些保护机制给过掉。
1.2.抓包
第一步,抓包,在实际的测试过程中发现该应用做了反抓包策略,只要我们一挂上代理或开启VPN就会在请求服务器时提示以下的错误。
这时候有两种选择
- 1.分析apk代码,找到证书检查的位置,hook绕过
- 2.采取通用方案:Xposed+JustTrustMe插件+SSLUnpinning2.0插件
这里为了方便就选择第二种了,首先需要在手机上安装Xposed环境,Xposed是一个hook框架,它支持安装别的模块,每个模块都是基于hook实现的小工具。比如这里用于绕过SSL证书校验的模块JustTrustMe和SSLUnpinning2.0,将Xposed和模块安装完成后需要重启一下系统,这是因为Xposed 的原理是对zygote进程进行劫持,每个apk启动都是由zygote进程fork出来的,所以每次新加一个模块都需要重启下系统使得zygote进程重启进而加载我们新添加的模块。
这里再补充说下这两个插件的原理,都是对APK中可能用到的校验SSL证书的API进行hook,从而绕过证书检查这么一步的。
等待系统启动完成后再次进行抓包,可以发现再次请求时就没有了之前的错误提示,并且fiddler也顺利抓到了数据包。
POST https://www.100hhr.com/App/Login/phoneCode HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 217
Host: www.100hhr.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.9.1
data=%7B%22type%22%3A%2220%22%2C%22phone%22%3A%2213711111111%22%2C%22countries_code%22%3A%22%2B86%22%2C%22p%22%3A%22android%22%2C%22v%22%3A%2271%22%2C%22time%22%3A1622530633%7D&apisign=a6874abaa4ff4bc156563b07589d93fe
能够顺利捕获数据包后,我们可以在抓包工具中对请求的数据进行修改,之后点击发送来检查应用是否做了数据包完整性的校验,如果不存在完整性校验那就可以利用数据包重放攻击来对服务端进行测试,这里是重放测试是失败了的,所以确定服务端是检查了数据包的完整性。
其实除了修改数据包来确定,还可以分析发送的数据包来确定,数据包中有个apisign字段,每次请求这个apisign值都会变化,一般sign字段表示签名值,通过计算除sign之外的其他字段算出来的,这叫做参数签名。
所以如果要实现模拟请求那就需要分析这个apisign值的生成,下面开始分析apisign值的生成。
1.3.脱壳
将应用丢到反编译工具中进行反编译时发现应用做了加固,有经验的小伙伴一眼应该就能看出这个哪家的壳子
不清楚的小伙伴也没关系,可以使用查壳工具(PKID)来检测。
工具检测出使用了360加固,知道使用的哪家加固后脱壳就可以有针对性的进行,不过这里找了几款通用的脱壳工具进行脱壳。
1.3.1.内存搜索法脱壳
第一款Frida-dexdump,是基于Frida的一款脱壳工具,它的原理是在内存中暴力搜索dex开头的标志性字符(dex035/dex036/dex037),如果找到了就会将这个dex文件给dump下来,对于将头部抹掉的dex还支持dex文件的模糊查找。使用时是默认对顶层activity所在进程的内存进行搜索。
E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump
λ python main.py -n com.ljhhr.mobile
05-31/10:32:32 INFO [DEXDump]: found target [6717] com.ljhhr.mobile
[DEXDump]: DexSize=0x7324, DexMd5=d4f38621321e74cf8b44a79549af028e, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xca69c000.dex
[DEXDump]: DexSize=0x647424, DexMd5=a56baf750eecd3d744feb795fe3f71b2, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcb490000.dex
[DEXDump]: DexSize=0x2399f0, DexMd5=6b784fda24a96e6e415a503c4cbbb418, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcc0bf000.dex
[DEXDump]: Skip duplicate dex 0xcc880000<d4f38621321e74cf8b44a79549af028e>
[DEXDump]: DexSize=0x11c, DexMd5=f1771b68f5f9b168b79ff59ae2daabe4, SavePath=E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump/com.ljhhr.mobile/0xcd0498b0.dex
[DEXDump]: Skip duplicate dex 0xcd38701c<d4f38621321e74cf8b44a79549af028e>
/...skip.../
E:\FRIDA-DEXDump\FRIDA-DEXDump\frida_dexdump
使用后一共dump出了4个dex,简单看了下0xcb490000.dex文件比较大,使用反编译工具可以看到确实存在ljhhr相关代码,其中还有一些sdk的代码。
那么该如何确认代码是否完整呢?
打开登录页面拿到顶层activity,看这个dex中是否存在这个activity的处理代码。
λ adb shell
bullhead:/ $ dumpsys activity top | grep ACTIVITY
ACTIVITY com.google.android.googlequicksearchbox/com.google.android.launcher.GEL cb0b9c6 pid=3519
ACTIVITY com.ljhhr.mobile/.ui.login.register.RegisterActivity b215e63 pid=4469
当前顶层activity"com.ljhhr.mobile/.ui.login.register.RegisterActivity",那我们去找下看能找到这个activity的java逻辑不
尴尬 ̄□ ̄||并没有,说明dump出来的不完整,换个脱壳工具。
1.3.2.关键函数hook法脱壳
第二款Frida-Apk-Unpack,该工具也是基于Frida实现的,原理则是对libart.so中的一些关键函数进行hook,比如OpenMemory和OpenCommon函数,通过这些函数可以拿到内存中的dex地址,之后就可以计算出dex文件大小并从内存中对dex进行导出。话不多说,奥利给,直接淦
E:\Frida-Apk-Unpack\Frida-Apk-Unpack
λ frida -U -f com.ljhhr.mobile -l dexDump.js
Spawning `com.ljhhr.mobile`...
[04:06:36:441] Android Version: 9
[04:06:36:455] index 3406 function name: _ZN3art16ArtDexFileLoader10OpenCommonEPKhjS2_jRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS_13DexFileLoader12VerifyResultE
[04:06:36:460] processName com.ljhhr.mobile
[04:06:36:460] Android Version: 9
[04:06:36:460] hookFunction: 0xeec28765
Spawned `com.ljhhr.mobile`. Use %resume to let the main thread start executing!
[AOSP on walleye::com.ljhhr.mobile]-> %resume
[04:06:42:263] hookFunction onEnter
[04:06:42:263] hookFunction onLeave
[04:06:42:266] hookFunction onEnter
[04:06:42:266] magic : dex
/...skip.../
035
[04:06:42:580] dex_size :6160852
[04:06:42:596] dump dex success, saved path: /data/data/com.ljhhr.mobile/6160852.dex
[04:06:42:596] hookFunction onLeave
[04:06:42:598] hookFunction onEnter
[04:06