APP渗透测试

张天师大约 5 分钟

APK敏感信息收集

使用工具快速扫描

推荐 apkleaks https://github.com/dwisiswant0/apkleaksopen in new window

可以发现比如云主机的key,服务器真实IP、其他服务的密钥等信息。

python apkleaks.py -f  "C:\Users\Administrator\Desktop\app\test.apk"  

img

反编译APK

一个apk包的本质是一个zip格式的压缩包,我们可以直接使用解压缩工具进行解压。

1)检查 classes.dex 硬编码

使用MT管理器open in new window查看apk,检查apk包中是否存在硬编码的敏感信息。

重点查看classes.dex文件反编译后是否有硬编码的敏感信息。

APK文件结构如下

img

2)检查SharedPreferences 配置文件

检查客户端程序存储在手机中的 SharedPreferences 配置文件是否存储、泄露敏感信息。

可以使用MT管理器查看(手机需要root)

• 用MT管理器查看下APK的应用包名

• 查看路径/data/data/<应用包名>/shared_prefs/<应用包名>_preferences.xml

• 可以查看保存的SharedPreferences键值对信息

img

3)检查SQLite数据库

检查客户端程序存储在手机中的SQLite 数据库文件是否保存、泄漏敏感信息。

将路径/data/data/<应用包名>/databases/下的sqlite3类型的数据库文件

用文件管理器导出来用可视化工具查看

img

img

4)检查logcat日志

APP客户端本地 log 运行日志是否打印、泄露用户敏感信息(使用adb即可查看)。

• 按照应用过滤日志

pm list packages -3   #查看非系统的第三方应用包名
logcat | grep <应用包名或者关键字>  

img

然后运行要检查的APP即可实时查看日志。

APP抓包

一、设置代理

1)Burp代理设置为局域网的IP

img

2)模拟器设置桥接模式,和代理工具Burp所在宿主机处于同一局域网

img

设置模拟器的网络代理为Burp的地址

img

3)模拟器访问Burp代理的IP,下载并安装CA证书

img

下载完先把后缀改为cer

夜神模拟器是在WLAN设置中点高级安装证书

img

或者有的模拟器是从设置中搜索安全,打开加密与凭据选项选择从SD卡安装证书

img

img

二、安装系统证书

img

抓到的HTTPS包都是乱码,因为安卓高版本即7.0之后,app可以只信任指定证书和系统内置的证书,后续用户安装的证书是不生效的。所以需要将Burp的CA证书安装到系统内部。

 # 转为pem格式
openssl x509 -inform DER -in cacert.der -out cacert.pem

# 重命名为<hash值>.0
mv cacert.pem `openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1`'.0'

将xxxhash.0证书文件复制到系统根信任证书目录即可

或者直接使用面具的movecert模块

https://github.com/ys1231/MoveCertificateopen in new window

加固绕过

root检测绕过

通过Magiskopen in new window本身的排除列表或者Shamikoopen in new window插件来绕过。

1)用adb将shamiko推送到手机上

adb push Shamiko-v1.0.1-300-release.zip /sdcard/Download/Shamiko-v1.0.1-300-release.zip

2)打开面具,进入模块,选择从本地安装,将zip刷入,点击重启

3)再次打开面具,点击右上角齿轮,配置排除列表,将绕过的APP排除,打开APP就没有提示了

代理检测绕过

使用VPN代理:https://github.com/ys1231/appproxyopen in new window

frida检测绕过

https://github.com/frida/fridaopen in new window 现已经支持自动构建反检测

windows安装客户端

pip3 install Frida 
pip3 install frida-tools
pip3 install objection

ssl Pinning证书绑定绕过

有些APP有预埋证书验证,遇到Burp的证书不能通过验证还是不能抓包。

使用frida进行hook绕过,使用通用的绕过脚本或自己编写。

1)查找设备的arch版本,下载对应的frida

adb shell getprop ro.product.cpu.abi

2)推送frida到手机上

下载后解压,把解压后的文件使用adb命令上传到设备

#推送到设备
adb push C:\frida-server /data/local/tmp

#授予执行权限
adb shell chmod 777 /data/local/tmp/frida-server

#启动firdas-erver
adb shell /data/local/tmp/frida-server &

4)打开新终端,列出服务列表,找到包名

frida-ps -U

3)使用Hook注入脚本

https://github.com/fdciabdul/Frida-Multiple-Bypassopen in new window

#客户端注入
frida -U -f com.package.name --no-pause -l C:\bypass.js

另一个hook脚本

/* 
   Android SSL Re-pinning frida script v0.2 030417-pier 

   $ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
   $ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause

   https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
   
   UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
*/

setTimeout(function(){
    Java.perform(function (){
    	console.log("");
	    console.log("[.] Cert Pinning Bypass/Re-Pinning");

	    var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
	    var FileInputStream = Java.use("java.io.FileInputStream");
	    var BufferedInputStream = Java.use("java.io.BufferedInputStream");
	    var X509Certificate = Java.use("java.security.cert.X509Certificate");
	    var KeyStore = Java.use("java.security.KeyStore");
	    var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
	    var SSLContext = Java.use("javax.net.ssl.SSLContext");

	    // Load CAs from an InputStream
	    console.log("[+] Loading our CA...")
	    var cf = CertificateFactory.getInstance("X.509");
	    
	    try {
	    	var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
	    }
	    catch(err) {
	    	console.log("[o] " + err);
	    }
	    
	    var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
	  	var ca = cf.generateCertificate(bufferedInputStream);
	    bufferedInputStream.close();

		var certInfo = Java.cast(ca, X509Certificate);
	    console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

	    // Create a KeyStore containing our trusted CAs
	    console.log("[+] Creating a KeyStore for our CA...");
	    var keyStoreType = KeyStore.getDefaultType();
	    var keyStore = KeyStore.getInstance(keyStoreType);
	    keyStore.load(null, null);
	    keyStore.setCertificateEntry("ca", ca);
	    
	    // Create a TrustManager that trusts the CAs in our KeyStore
	    console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
	    var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	    var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	    tmf.init(keyStore);
	    console.log("[+] Our TrustManager is ready...");

	    console.log("[+] Hijacking SSLContext methods now...")
	    console.log("[-] Waiting for the app to invoke SSLContext.init()...")

	   	SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
	   		console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
	   		SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
	   		console.log("[+] SSLContext initialized with our custom TrustManager!");
	   	}
    });
},0);