赞
踩
C:\Program Files\Java\jdk1.8.0_111\bin\jarsigner.exe -verify APK 文 件 路 径 -verbose –certs
当输出结果为“jar 已验证”时,表示签名正常
检测签名的 CN 及其他字段是否正确标识客户端程序的来源和发布者身份
如上图,说明测试结果为安全。
要说明的是,只有在使用直接客户的证书签名时,才认为安全。 Debug 证书、第三方(如
开发方)证书等等均认为风险。
把 apk 当成 zip 并解压,得到 classes.dex 文件(有时可能不止一个 dex 文件,但文件名大多类似)
使用 dex2jar 执行如下命令:
dex2jar.bat classes.dex 文件路径
得到 classes.dex.jar
然后使用 jd-gui 打开 jar 文件,即可得到 JAVA 代码。【注: 直接使用 smali2java 或者 APKAnalyser 打开 apk 文件,也可反编译回 Java 代码】
【注:有时用 apktool 能够解包并查看 smali,但 dex2jar 却不行。如果 dex2jar 反编译失败,可以试试看能不能恢复 smali 代码。】
逆向后发现是没混淆的情况,是不安全的。如果代码经过混淆,或者有加壳措施,不能完整恢复源代码的,都可以认为此项安全,混淆
后的代码样例,除了覆写和接口以外的字段都是无意义的名称。如下图已加密混淆,除了覆写和接口以外的字段都是无意义的名称::
使用 apktool 工具可以对 apk 进行解包。具体的解包命令格式为:apktool d <file.apk> [
1.如果只需要修改 smali 代码,不涉及资源文件的修改,可以在解包时加入 -r 选项(也可以直接使用 baksmali 将 dex 反编译为 smali 代码,见 5.3),不解码apk 中的资源。在打包时可以避免资源方面的问题(如 aapt 报的各种错误)。
如果只需要反编译资源文件,可以在解包时加入-s 选项,不对 classes.dex 进行反编译。
如果在 5.6.1 使用 apktool 打包 smali 代码中出现资源相关的错误,可能是需要较新的framework 文件。可参考此处,添加 framework 文件。例如,添加Android 4.4.2 SDK中的 framework 文件,命令如下:
解包时指定相应的 framework(上面命令中的 tag0 是对添加的 framework 的标记,用于标识不同的 framework),如图所示:
解包完成后,会将结果生成在指定的输出路径中,其中,smali 文件夹下就是最终生成的Dalvik VM 汇编代码,AndroidManifest.xml 文件以及 res 目录下的资源文件也已被解码。如图:
odex 是 android 系统中对 dex 文件优化后生成的文件。如果要使用上述反编译方法,
需要先将 odex 转换成 dex。
1. 下载 smali 工具(https://code.google.com/p/smali/)。
2. 将虚拟机中/system/framework/中的 jar 文件复制出来,放到一个文件夹中。所需的虚拟机版本可参考 odex 生成的环境(如 odex 是在 android 4.4 中生成的,就复制 4.4虚拟机,如果在真机中生成,则可以复制真机的)。
3. 运行 baksmali.jar,将 odex 解析为 smali 代码。-x 选项表示输入是 odex 文件,-d 选项指定上个步骤中复制出来的 jar 文件路径,如下图所示。当命令成功执行后,在当前目录会创建一个 out 文件夹,里面就是 smali 代码。
4. 运行 smali.jar,可生成 dex。如下图所示:
apk 解压缩后,将 lib\armeabi\目录下的 so 文件直接拖入 IDA 中,可以对 so 文件进行静态分析。可以看到 so 文件中包含的函数,ARM 汇编代码,导入导出函数等信息。
apk 中的 xml 大部分是经过编译的,无法直接查看和修改。
如果需要查看 xml 文件,可以反编译为 smali 代码部分,使用 apktool 将整个 apk 解包。或者是使用 AXMLPrinter 或 APKParser 工具对要查看的 xml 进行解码。如图:
如果需要将修改后的 xml 重新打包到 apk 中,则可以参考 5.6.1 节,使用 apktool 打包。目前还没有发现可以单独编译一个 xml 文件的方法。对于已经解包的 apk,也可以直接使用 android SDK 中的 aapt 直接编译资源文件(包括 xml)。命令格式如下,apk-src是 apk 的解包目录,output.zip 是输出的 zip 文件(编译好资源文件都会打包到里面),- I 选项指定相应版本的 android.jar。
“ANDROID-SDK\build-tools\20.0.0\aapt.exe" package -f -M -I [apk-src\AndroidManifest.xml] “ANDROID-SDK\platforms\android-19\android.jar” -S [apk-src\res] -F [output.zip]
注:上述 aapt 和 android.jar 的路径为安装 android SDK build-tools rev.20,android4.4.2 SDK platform 后才存在。如果没有安装上述版本的组件,可将路径改为其他版本相应的路径。(通常较新版本的 SDK 出错的可能性会小一些。)
测试客户端程序是否对自身完整性进行校验。攻击者能够通过反编译的方法在客户端程序中植入自己的木马,客户端程序如果没有自校验机制的话,攻击者可能会通过篡改客户端程序窃取手机用户的隐私信息。用 ApkTool 将目标 APK 文件解包,命令如下;
java -jar apktool.jar d -f apk 文件路径 -o 解包目标文件夹
随便找一个解包目录里的资源文件,修改之,推荐找到 logo 之类的图进行修改(因为容易确认结果);
用 ApkTool,将解包目录重新打包成未签名的 APK 文件,命令如下:
java -jar apktool.jar b -f 待打包的文件夹 -o 输出 apk 路径
用 SignApk,对未签名的 APK 文件进行签名,命令如下:
java -jar signapk.jar testkey.x509.pem testkey.pk8 待签名 apk 文件路径 签名后输出 apk 路径
将签了名的 APK 安装、运行、确认是否存在自校验;
需要注意的是,如果之前安装的 APK 和修改后的 APK 签名不同,就不能直接覆盖安装,一般来说,先卸载之前安装的 APP 即可。
【注: APK 必须进行签名后,方可安装和运行。如果开启了“允许未知来源的应用”,那么 Debug 证书、自签名证书、过期证书的签名都是可以的,但是不可以不签名。】
将客户端程序文件反编译,修改源码或资源文件后重新打包安装运行
上图为没有进行自校验的情况,下图为经过自校检的情况,,修改后无法正常启动
推荐修改 apk 中 assets 目录下或 res/raw 目录下的文件。将修改后的 apk 文件导入到/data/app 目录下,覆盖原文件,然后重启客户端,观察客户端是否会提示被篡改
客户端软件 AndroidManifest.xml 中的 android:debuggable="true"标记如果开启,可被 Java 调试工具例如 jdb 进行调试,获取和篡改用户敏感信息,甚至分析并且修改代码实现的业务逻辑,我们经常使用 android.util.Log 来打印日志,软件发布后调试日志被其他开发者看到,容易被反编译破解。
检查 AndroidManifest.xml 文件中的 debuggable 属性(MobSF) – 检查是否能被调试
https://github.com/MobSF/Mobile-Security-Framework-MobSF
Android 2.1 以 上 的 系统 可 为 App 提 供 应 用程 序 数 据 的 备 份 和 恢 复功 能 , 该 由AndroidMainfest.xml 文件中的 allowBackup 属性值控制,其默认值为 true。当该属性没有显式设置为 false 时,攻击者可通过 adb backup 和 adb restore 对 App 的应用数据进行备份和恢复,从而可能获取明文存储的用户敏感信息。
检查 AndroidManifest.xml 文件中的 allowBackup 属性(MobSF) – 检查是否显式设置为 false
打开 AndroidManifest.xml 文件;检查应用 AndoridManifest.xml 文件中的配置是否为:android:allowBackup=“true”,即为 allowBackup 开启。
应用权限分配不合理
1、使用反编译工具反反编译
2、打开源码后,检查应用 AndoridManifest.xml 文件,将应用权限和业务功能需要权限做对比,检查申请应用权限是否大于业务需要权限,有即存在安全隐患。或者
python manitree.py -f AndroidManifest.xml
使用 ApkTool 解包, 打开解包目录中 AndroidManifest.xml,对其中声明的各个组件,根据以下规则判断是否可导出:
显式声明了 android:exported=“true”,则可导出;
显示声明了 android:exported=“false”,则不可导出;
未显示声明 android:exported:
a) 若组件不是 Content Provider:
若组件包含则可导出,反之不可;
b) 若组件是 Content Provider:
若 SDK 版本<17 则可导出,反之不可。
从测试的角度上,只能判断组件是否导出,但能否构成危害需要详细分析源代码后才能得出结论。一般来说,在测试时尽管写清所有的导出组件,由客户开发侧确认相关组件是否确实需要导出即可
由于功能需要,启动 Activity 和 Content Provider 大多是导出组件,一般无须理会。
检查 AndroidManifest.xml 文件中各组件定义标签的安全属性是否设置恰当。如果组件无须跨进程交互,则不应设置 exported 属性为 true。例如,如下图所示, 当MyService 的 exported 属性为 true 时,将可以被其他应用调用。(当有设置权限(permissions)时,需要再考察权限属性。如 android:protectionLevel 为 signature或 signatureOrSystem 时,只有相同签名的 apk 才能获取权限。详情见附录参考资料 API Guides 系统权限简介)
可以使用“组件安全测试工具”来检测组件的 exported 属性(有些应用在代码中动态注册组件,这种组件无法使用“组件安全测试工具”测试,需要通过阅读代码确定是否安全。)点击 Save 按钮可以把检测结果保存在 SD 卡上如下图所示。
凡是列出来的组件都是 exported 属性为 true 的。当发现有可利用的组件导出时,(当然,并不是说所有导出的组件都是不安全的,如果要确定,必须看代码,对代码逻辑进行分析) 可利用 drozer 测试工具进行测试
Android 每一个 Application 都是由 Activity、Service、content Provider 和 BroadcastReceiver 等 Android 的基本组件所组成,其中 Activity 是实现应用程序的主体,它承担了大量的显示和交互工作,甚至可以理解为一个“界面”就是一个 Activity。
检查 AndroidManifest.xml 文件中注册的 Activity(MobSF) – 检查 exported 属性是否被设置为 true,若是则根据业务判断风险
相关 drozer 命令:
>run app.activity.info -a packagename
>run app.activity.start --component com.example.package com.example.package.welcome
1、反编译查看配置文件 AndroidManifest.xml 中 activity 组件(关注配置了 intent-filter的及未设置 export=“false”的)。
2、可使用工具 Drozer 扫描:run app.activity.info -a packagename
3、执行 adb shell 获得一个 shell,使用 am start –n com.isi.testapp/.Welcome 来启动Activity
4、查看是否在未经登录的情况下,该 activity 被正常显示,且形成越权、信息泄露等风险。
一个 Service 是没有界面且能长时间运行于后台的应用组件.其它应用的组件可以启动一个服务运行于后台,即使用户切换到另一个应用也会继续运行.另外,一个组件可以绑定到一个 service 来进行交互,即使这个交互是进程间通讯也没问题.例如,一个 service 可能处理网络事物,播放音乐,执行文件 I/O,或与一个内容提供者交互,所有这些都在后台进行。
检查 AndroidManifest.xml 文件中注册的 Service(MobSF) – 检查有没有 export 的Service
查看 service 类,重点关注 onCreate/onStarCommand/onHandleIntent 方法-- 检测有没有处理不当的方法检索所有类中 startService/bindService 方法及其传递的数据-- 检测是否有数据泄露的可能
相关 drozer 命令:
>run app.service.info -a com.mwr.example.sieve
>run app.service.start --component com.mwr.example.sieve com.mwr.example.sieve.xxx
Broadcast Recevier 广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统代码的──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自 BroadcastReceiver 基类。广播接收器没有用户界面。然而,它们可以启动一个 activity 来响应它们收到的信息,或者用 NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等
等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
检查 AndroidManifest.xml 文件中注册的 Broadcast Receiver – 查找静态 BroadcastReceiver
反编译后检索 registerReceiver()/使用 drozer 命令 run app.broadcast.info -a APP 包名 -i – 查找动态 Broadcast Receiver
注意检索 setPackage 方法与 receiverPermission 变量 – 查找发送广播内的信息检索sendBroadcast 与 sendOrderedBroadcast
查看 onReceive 方法 – 检测是否存在信息泄露或拒绝服务的问题
相关 drozer 命令:
dz> run app.broadcast.info -a com.package.name
dz> run app.broadcast.send --component com.package.name --action android.intent.action.XXX
1、反编译后检索 registerReceiver(),查找动态广播接收器。也可以使用可使用工具 Drozer扫描,命令如下:run app.broadcast.info -a android -i
2、同时留意 android:exported="true"权限的组件。
3、尝试向应用程序的 receiver 组件发送空值,am broadcast -a MyBroadcast -n com.isi.vul_broadcastreceiver/.MyBroadCastReceiver,查看是否能够造成应用程序崩溃,形成拒绝服务。
Android Content Provider 存在文件目录遍历安全漏洞,该漏洞源于对外暴露 ContentProvider 组件的应用,没有对 Content Provider 组件的访问进行权限控制和对访问的目标文件的 Content Query Uri 进行有效判断,攻击者利用该应用暴露的 Content Provider的 openFile()接口进行文件目录遍历以达到访问任意可读文件的目的。在使用 ContentProvider 时,将组件导出,提供了 query 接口。由于 query 接口传入的参数直接或间接由接口调用者传入,攻击者构造 sql injection 语句,造成信息的泄漏甚至是应用私有数据的恶意改写和删除。
检查 AndroidManifest.xml 文件中注册的 Content Provider(MobSF) – Content
Provider 组件在 API-17(android4.2)及以上版本由以前的 exported 属性默认 ture 改为默认 false
使用 drozer 命令 run scanner.provider.injection -a APP 包名测试 Content Provider --检测是否存在 SQL 注入
使用 drozer 命令 run scanner.provider.traversal -a APP 包名测试 Content Provider --检测是否存在目录遍历
1 、 查 看 AndroidManifest.xml 文 件 , 定 位 各 Provider , 尤 其 是 设 置 了android:exported="true"的。
2、可使用工具 Drozer 扫描:run app.provider.info -a cn.etouch.ecalendar
3、可以在反编译后使用关键字:addURI 查找
4 、 执 行 adb shell 获 得 一 个 shell , 使 用 content query --uri content://com.isi.contentprovider.MyProvider/udetails 来查看资源内容
5、如果能够正确访问到共享资源,并且具备敏感信息,则记录漏洞。
Android 应用本地拒绝服务漏洞源于程序没有对 Intent.getXXXExtra()获取的异常或者畸形数据处理时没有进行异常捕获,从而导致攻击者可通过向受害者应用发送此类空数据、异常或者畸形数据来达到使该应用 crash 的目的,简单的说就是攻击者通过 intent 发送空数据、异常或畸形数据给受害者应用,导致其崩溃通过使用 drozer 工具查看对外暴露组件的应用如下:
>run app.activity.info –a com.mwr.example.sieve
grep -rn “get*Extra” ./ | more (在导出组件代码中测试) – 检测在获取 intent数据时是否进行了异常处理
1、使用反编译工具打开应用,反编译出应用源码。
2、在源码中查找以下示例源码(主要查找getAction):
Intent i = new Intent();
if (i.getAction().equals("TestForNullPointerException")) {
Log.d("TAG", "Test for Android Refuse Service Bug");
}
3、如出现像以上代码,getIntent()的intent附带空数据、异常或畸形数据,而且处理
getXXXExtra()获取的数据时没有进行异常捕获,便存在风险。
4、 可使用adbshell验证:adb shell am start -n com.xxx.xxx.pocforrefuseservice/.MainActivity
5、如果服务端出现崩溃界面,则可以证明漏洞存在。记录漏洞,停止测试
6、同样可以造成本地拒绝服务的有:ClassNotFoundException异常导致的拒绝服务源于程序没有无法找到从 getSerializableExtra ()获取到的序列化类对象的类定义,因此发生类未定义的异常而导致应用崩溃。
Intent i = getIntent();
getSerializableExtra("serializable_key");
攻击应用代码片段:
Intent i = new Intent();
i.setClassName("com.alibaba.jaq.pocforrefuseservice","com.alibaba.jaq.pocforrefuseservice.MainActivity");
i.putExtra("serializable_key", BigInteger.valueOf(1));
startActivity(i);
7、IndexOutOfBoundsException异常导致的拒绝服务源于程序没有对 getIntegerArrayListExtra()等获取到的数据数组元素大小的判断,从而导致数组访问越界而导致应用崩溃;漏洞应用代码片段:
Intent intent = getIntent();
ArrayList<Integer> intArray = intent.getIntegerArrayListExtra("user_id");
if (intArray != null) {
for (int i = 0; i < USER_NUM; i++) {
intArray.get(i);
}
}
攻击应用代码片段:
Intent intent = new Intent();
intent.setClassName("com.alibaba.jaq.pocforrefuseservice","com.alibaba.jaq.pocforrefuseservice.MainActivity");
ArrayList<Integer> user_id = new ArrayList<Integer>();
intent.putExtra("user_id", user_id);
startActivity(intent);
)
8、ClassNotFoundException异常导致的拒绝服务源于程序没有无法找到从 getSerializableExtra ()获取到的序列化类对象的类定义,因此发生类未定义的异常而导致应用崩溃。漏洞应用代码片段:
Intent i = getIntent();
i.getSerializableExtra("serializable_key");
攻击应用代码片段:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent i = new Intent();
i.setClassName("com.alibaba.jaq.pocforrefuseservice","com.alibaba.jaq.pocforrefuseservice.MainActivity");
i.putExtra("serializable_key", new SelfSerializableData());
startActivity(i);
}
static class SelfSerializableData implements Serializable {
private static final long serialVersionUID = 42L;
public SelfSerializableData() {
super();
}
}
Android 4.2 版本以下的 webview 组件存在安全漏洞(CVE-2012-6636)。检测客户端是否采取措施避免漏洞被利用。检查应用 AndroidManifest.xml 中的targetSdkVersion是否大于等于 17。
或者使用测试网页进行测试(腾讯的测试页面链接,在被测应用中打开即可。
http://security.tencent.com/lucky/check_tools.html.
android系统通过WebView.addJavascriptInterface方法注册可供JavaScript调用的Java对象,以用于增强 JavaScript 的功能。但是系统并没有对注册 Java 类的方法调用的限制。导致攻击者可以利用反射机制调用未注册的其它任何 Java 类,最终导致 JavaScript 能力的无限增强。攻击者利用该漏洞可以根据客户端执行任意代码。
Webview 代 码 执 行 漏 洞 出 现 在 安 卓 2.1~4.3.1 版 本 , 检 查 targetSdkVersion 、minSdkVersion(MobSF) – 若 targetsdkVersion>=19 或通过minSdkVersion 进行限制则无此问题,否则在低版本上测试,(可使用相关检测代码),检查代码中是否使用addJavascriptInterface()
相关 drozer 命令:
>run scanner.misc.checkjavascriptbridge -a 包名
1、使用反编译工具打开应用,反编译出应用源码。
2、在源码中搜索类似写法:
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.addJavascriptInterface(newJSInvokeClass(), “js2java”);
3、那么该处就可能存在 Web 组件远程代码执行的风险。
4 、 也 可 在 应 用 中 访 问 webview 检 测 页 面 ( 自 行 搭 建 或 者 利 用 现 成 页 面 :http://drops.wooyun.org/webview.html)。webview 检测页面文件见备注。
5、如果存在该风险,将会在改页面中显示出存在问题的接口
调用了 android/webkit/SslErrorHandler 类的 proceed 方法,可能导致 WebView 忽略校验证书的步骤。搜“onReceivedSslError”,看是否调用了 handle.process()方法(在 webview 组件代码中测试)
在使用 WebView 的过程中忽略了 WebView setSavePassword,当用户选择保存在WebView 中输入的用户名和密码,则会被明文保存到应用数据目录的databases/webview.db 中。如果手机被 root 就可以获取明文保存的密码,造成用户的个人敏感数据泄露。
搜”setSavePassword”,看是否显式设置为 false(在 webview 组件代码中测试)
1.使用 mercury 查看那 APP 的组件信息
2.使用 mercury 查找 APP Content Provider 组件漏洞,包括组件暴露,SQL 注入,文件目录遍历
drozer命令方法 :
1.确定包名
run app.package.list
2.查看指定包的基本信息,例如数据存储路径 uid,gid,permissions
run app.package.info -a com.android.browser
3.列出 APP 中的 activity 组件
run app.activity.info -a com.android.browser
4.列出 APP 中的 service 组件
run app.service.info -a com.android.browser
5.列出 APP 中的 Content Provider 组件
run app.provider.info -a com.android.browser
6.查找可以读取的 Content Provider 的 URI
run scanner.provider.finduris -a com.sina.weibo
7.读取 Content Provider 指定 URI 中的内容
run app.provider.query content://settings/secure --selection name=‘adb_enabled’
8.扫描是否存在 content provider 目录遍历的漏洞
run scanner.provider.traversal -a com.android.browser
9.读取 content provider 指定的目录
run app.provider.read content://com.mwri.fileEncryptor.localfile/system/etc/hosts/
10.扫描是否存在 SQL 注入
run scanner.provider.injection -a com.android.browser
11.利用 SQL 注入
run scanner.provider.query content://com.example.bsideschallenge.evilPlannerdb
–projection * from cards –
12.查看指定包的 AndroidManifest.xml 文件
run app.package.manifest com.example.bsidechallenge
13.查看指定包的 AndroidManifest.xml 文件
run app.package.manifest com.example.bsidechallenge
对 android 的每一个应用,android 系统会分配一个私有目录,用于存储应用的私有数据。此私有目录通常位于“/data/data/应用名称/”。在测试时,建议完全退出客户端后,再进行私有文件的测试,以确保测试结果的准确性。(有些客户端在退出时会清理临时文件)
首先查看相关文件的权限配置。正常的文件权限最后三位应为空(类似“rw-rw----” ),即除应用自己以外任何人无法读写; 目录则允许多一个执行位(类似“rwxrwx—x” )。如下图所示,(lib 子目录是应用安装时由 android 系统自动生成,可以略过)
注意:当客户端使用 MODE_WORLD_READABLE 或 MODE_WORLD_WRITEABLE模式创建文件时,shared_prefs 目录下文件的权限也会多出一些,这不一定是安全问题,如下图(Google 已不推荐使用这些模式):
权限检测完整后,再检查客户端程序存储在手机中的 SharedPreferences 配置文件,通常是对本目录下的文件内容(一般是 xml)进行检查,看是否包含敏感信息。
最后在检测 SQLite 数据库文件,在私有目录及其子目录下查找以.db 结尾的数据库文件。对于使用了 webView 缓存的应用,会在 databases 子目录中保存 webview.db 和webviewCache.db,如图所示。其中有可能会记录 cookies 和提交表单等信息用数据库查看工具即可查看这些文件中是否有敏感信息。
客户端程序 apk 包中也是是保存有敏感信息的,比如检查 apk 包中各类文件是否包含硬编码的的敏感信息等(反编译 so 库和 5.逆向 classes.dex,检查 apk包中各类文件是否包含硬编码的的敏感信息。对可执行文件可通过逆向方法寻找,也可以直接使用 16 进制编辑器查找。)。如下图 APP 的相关编码信息将应用存档文件下载到 PC 机上
使用相应格式的编辑器进行操作
adb pull /data/data/ctrip.android.view/[文件名] e:/[文件名]
adb pull /sdcard/CTRIP/[文件名] e:/[文件名]
在应用的私有目录以及 SD 卡中包含应用名称的子目录中进行遍历,检查是否有包含敏感信息的文件。查找应用和文件 IO 相关的系统调用(如 open,read,write 等),对客户端读写的文件内容进行检查
查找保存在应用私有目录下的文件。检查文件中的数据是否包含敏感信息。如果包含非明文信息,在 Java 代码中查找相应的加密算法,检查加密算法是否安全。(例如,采用 base64的编码方法是不安全的,使用硬编码密钥的加密也是不安全的。)或者使用 Dexter 在线检测环境(或 sanddroid)来做,Exported 为对号的是已经导出的组件,可能存在安全问题。(注意:Dexter 对 Content Provider 判断不一定准确。)
注意:不是所有导出的组件都是不安全的,如需确定须看代码,对代码逻辑进行分析
注:有些应用在代码中动态注册组件,这种组件无法使用“组件安全测试工具”测试,需要通过阅读代码确定是否安全于 Android SDK 中对 exported 属性的默认设置说明:对service, activity, receiver,当没有指定 exported 属性时,没有过滤器则该服务只能在应用程序内部使用,相当于 exported 设置为 false。如果至少包含了一个过滤器,则意味着该服务可以给外部的其他应用提供服务,相当于 exported 为 true。对 provider,SDK 小于等于 16 时,默认 exported 为 true,大于 16时,默认为 false。(某些广播如 android.intent.action.BOOT_COMPLETED 是例外)
检查客户端程序存储在手机中的日志。MemSpcetor 中提供了搜索功能,可以将内存 DUMP 到 SD 卡(注意,虚拟机得先配置 SD 卡),然后用 adb 或 monitor 复制到主机上查看。
在这里使用 ADB 进行查看。
使用 adb 工具连接设备:
adb devices //查看安卓设备列表
adb -s 设备名称 其它命令 //当连接了多个设备时,选择操作的目标设备,否则会出错
adb pull 手机目录名 PC 目录名 //从安卓设备中复制文件到电脑中
然后使用 WinHex 打开
这是查看内存遗留的信息,还可以直接使用 adb 查询 logcat 日志:
在 adb shell 中,有下列命令可用:
logcat //持续输出日志,直到 Ctrl+C
logcat -d //一次性输出日志缓存,不会阻塞
logcat -c //清空日志缓存
查看 1.txt:
并未发现有敏感的信息。
1、安装应用后,对应用进行使用。
2、同时使用 androidSDK 中的%ANDROID%/tools/monitor.bat 捕获输出的日志,
3、如果输出的日志中包含敏感信息,记录漏洞,停止测试。
5.密码软键盘安全性测试
测试客户端程序在密码等输入框是否使用自定义软键盘。安卓应用中的输入框默认使用系统软键盘,手机安装木马后,木马可以通过替换系统软键盘,记录手机银行的密码常来说,只有使用系统输入法的编辑框才能够进行键盘码记录。如果是自制的软键盘,则可以尝试进行触摸屏记录。像下图这样,不使用系统输入法,且按键随机分布的软键盘是安全的。
安装安卓按键记录工具(ns_keylogger.apk),在设置中选择我们的输入法,启动 APP,输入框长按空格,选择我们的测试键盘,使用 logcat/DDMS 查看测试键盘记录 – 查看APP 案件能否被测试键盘记录。
安装 android 击键记录测试工具 。然后在“ 语言和键盘设置” 中选择“Sample Soft Keyboard”。然后启动客户端,在输入框长按,弹出提示框后选择“input
method”(输入法),选择我们安装的软键盘。
下图是书写短信息时,使用软键盘输入,在 logcat 日志中可以看到所有的击键
客户端使用的随机布局软键盘是否会对用户点击产生视觉响应。当随机布局软键盘对用户点击产生视觉响应时,安卓木马可以通过连续截屏的方式,对用户击键进行记录,从而获得用户输入。
使用 ADB 进行测试:
adb shell /system/bin/screencap -p 输出 png 路径(安卓设备中)
在/mnt/sdcard/路径下,可以看到 1a.png:
打开:
成功截图, 攻击者可以在用户进入登录页面,在输入密码的同时,进行连续截图,即可记录用户输入的密码。如果没有防截屏,那么即使是随机分布的、没有视觉反馈的软键盘也会被记录.
还有一种验证方式是从代码方面进行验证:
安装安卓屏幕截图程序(screenshoter2.3.3.4.apk),连续截取屏幕内容 – 测试能否记录 APP 软键盘输入(检测需较高安全性的窗口(如密码输入框),看代码中在窗口加载时是否开启 FLAG_SECURE,开启该选项的窗口不能被截屏使用现有的 android 截屏工具,连续截取屏幕内容,测试能否记录客户端软键盘输入。检测需较高安全性的窗口(如密码输入框),看代码中在窗口加载时是否有类似下图的代码。按照 android SDK 的要求,开启 FLAG_SECURE 选项的窗口不能被截屏。
注意:FLAG_SECURE 可能存在兼容性问题,能否防护截图可能与硬件有关。
目前 FLAG_SECURE 测试结果:
N-PASS,可截图,
ZTE 880E, 可截图
ASUS TF300T,可阻止工具及 ddms 截图)
拥有 root 权限后,安卓木马可以通过读取系统文件/dev/input/eventN 得到键盘码,从而获得用户输入。注意:目前很多 android 系统不再向 event 文件输出键盘码,如需测试需先确定键盘输入对应的 event 文件是否存在。运行客户端,在输入密码的同时,在 shell 中使用命令行监控输入。
测试客户端程序是否检查用户输入的密码强度,禁止用户设置弱口令。
人工测试,尝试将密码修改为弱口令,如:123456,654321,121212,888888 等,查看客户端是否拒绝弱口令。也可以阅读逆向后的客户端 java 代码,寻找对用户输入口令的检查方法。
阅读逆向后的客户端 java 代码,寻找对用户输入口令的检查方法。
测试一个帐号是否可以同时在多个设备上成功登录客户端,进行操作。
测试客户端是否限制登录尝试次数。防止木马使用穷举法暴力破解用户密码。
测试对账号某些信息(如单次支付限额)的修改是否有私密问题验证。私密问题验证是否将问题和答案一一对应。私密问题是否足够私密
测试客户端在超过 20 分钟无操作后,是否会使会话超时并要求重新登录。超时时间设置是否合理。
一段时间无操作 – 检测应用是否要求用户重新登陆退出应用再打开 – 检测应用是否要求用户登陆。
检查客户端程序在切换到其他应用时,已经填写的账号密码等敏感信息是否会清空,防止用户敏感信息泄露。如果切换前处于已登录状态,切换后一定时间内是否会自动退出当前会话。
人工检测。在登录界面(或者转账界面等涉及密码的功能)填写登录名和密码,然后切出,再进入客户端,看输入的登录名和密码是否清除。登录后切出,5 分钟内自动退出为安全。输入登陆密码后,切换到其他应用,再切换回来 – 检测是否会将用户输入的密码等敏感信息清空登陆之后,切换到其它应用,过一段时间切换回来 – 检测当前会话是否退出。
检查客户端的各种功能,看是否存在敏感信息泄露问题。
人工测试。使用错误的登录名或密码登录,看客户端提示是否不同。在显示卡号等敏感信息时是否进行部分遮挡。
查看 APP 各界面 – 检测是否对用户的真实姓名、身份证号、银行卡号、手机号等进行适当遮挡
测试客户端在登录和交易时是否使用图形验证码。验证码是否符合如下要求:由数字和字母等字符混合组成;采取图片底纹干扰、颜色变换、设置非连续性及旋转图片字体、变异。体显示样式等有效方式,防范恶意代码自动识别图片上的信息;具有使用时间限制并仅能使用一次;验证码由服务器生成,客户端文件中不包含图形验证码文本内容。观察验证码组成,若简单,可以尝试使用 PKAVHttpFuzzer 的验证码识别工具进行识别也可以使用其它的验证码识别工具
检查客户端在退出时,是否向服务端发送终止会话请求。客户端退出后,还能否使用退出前的会话 id 访问登录后才能访问的页面。
在客户端登出账号之后,继续使用之前的会话 token 进行操作 – 检测用户登出后会话token 是否在服务端被正确销毁
尝试在修改密码时使用错误的旧密码 – 检测服务端是否验证旧密码的正确性
检查是否存在 activity 劫持风险,确认客户端是否能够发现并提示用户存在劫持安装 HijackActivity.apk,使用 activity 界面劫持工具,在工具中指定要劫持的应用进程名称(进程查看和监视 ps/top)。如图所示,从列表中选择被测试的应用,点击 OK。打开应用,测试工具会尝试用自己的窗口覆盖被测的应用。测试工具试图显示自己的窗口时,安全的客户端应该弹出警告提示。如果劫持成功,会出现如下界面:
检查移动客户端的各种功能,看是否存在敏感信息泄露问题。
试使用不存在的用户名登陆,尝试使用存在的用户名及错误密码登陆 – 检测是否可根据界面提示进行用户名枚举
1、使用反编译工具进行反编译
2、打开源码后,查找代码中的敏感数据和敏感函数,使用 DES 弱加密算法,弱加密代码样例:
SecretKeySpec key = new SecretKeySpec(rawKeyData, “DES”);
Cipher cipher = Cipher.getInstance(“DES/ECB/PKCS5Padding”);
cipher.init(Cipher.DECRYPT_MODE, key);
审查代码中以下点
3、RSA 中不使用 Padding:使用 RSA 公钥时通常会绑定一个 padding,原因是为了防止一些依赖于 no padding 时对
RSA 算法的攻击。风险代码样例:
Cipher rsa = null;
try {
rsa = javax.crypto.Cipher.getInstance(“RSA/NONE/NoPadding”);
}
catch (java.security.NoSuchAlgorithmException e) {
}
catch (javax.crypto.NoSuchPaddingException e) {
}
SecretKeySpec key = new SecretKeySpec(rawKeyData, “RSA”);
Cipher cipher = Cipher.getInstance(“RSA/NONE/NoPadding”);
cipher.init(Cipher.DECRYPT_MODE, key);
4、没有安全的初始化向量
初始化向量时,使用了硬编码到程序的常量。风险代码样例:
byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
IvParameterSpec ips = new IvParameterSpec(iv)
5、 使用了不安全的加密模式
SecretKeySpec key = new SecretKeySpec(keyBytes, “AES”);
Cipher cipher = Cipher.getInstance(“AES/ECB/PKCS7Padding”, “BC”);
cipher.init(Cipher.ENCRYPT_MODE, key);
6、 使用了不安全的密钥长度
public static KeyPair getRSAKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(“RSA”);
keyGen.initialize(512);
KeyPair key = keyGen.generateKeyPair();
return key;
}
通过对客户端内存的访问,木马将有可能会得到保存在内存中的敏感信息(如登录密码,帐号等)。测试客户端内存中是否存在的敏感信息(卡号、明文密码等等)。需要 root 权限,可以使用 MemSpector 查看、搜索和修改客户端内存数据,如图所示。用户名、密码等数据通常会在/dev/ashmem/dalvik-heap 内存段。(目前大多数工具都是通过 ptrace 接口修改客户端内存,可以使用 ptrace 机制本身防护。)
击者可通过 ptrace 挂载等方式控制客户端代码执行流程,对金融类 APP 用户的个人财产造成威胁通过注入动态链接库,hook 客户端某些关键函数,从而获取敏感信息或者改变程序执行检测 LD_PRELOAD 环境变量。使用 LD_PRELOAD 环境变量,可以让进程预先加载任意so,劫持函数。如图是劫持 ls 命令__libc_init()函数的效果。或者使用工具动态注入应用进程内存。参考 https://github.com/crmulliner/ddi。
或者使用 hook 框架来进行测试。
通常使用 PF_UNIX、PF_INET、PF_NETLINK 等不同 domain 的 socket 来进行本地 IPC 或者远程网络通信,这些暴露的 socket 代表了潜在的本地或远程攻击面,历史上也出现过不少利用 socket 进行拒绝服务、root 提权或者远程命令执行的案例。特别是 PF_INET 类型的网络 socket,可以通过网络与 Android 应用通信,其原本用于 linux 环境下开放网络服务,由于缺乏对网络调用者身份或者本地调用者 id、permission 等细粒度的安全检查机制,在实现不当的情况下,可以突破Android 的沙箱限制,以被攻击应用的权限执行命令,通常出现比较严重的漏洞
busybox netstat -tuanp|grep -Ei ‘listen|udp*’
Android 系统提供了一种类加载器 DexClassLoader,其可以在运行时动态加载并解释执行包含在 JAR 或 APK 文件内的 DEX 文件。外部动态加载 DEX 文件的安全风险源于:Anroid4.1 之前的系统版本容许 Android 应用将动态加载的 DEX 文件存储在被其他应用任意读写的目录中(如 sdcard),因此不能够保护应用免遭恶意代码的注入;所加载的 DEX 易被恶意应用所替换或者代码注入,如果没有对外部所加载的 DEX 文件做完整性校验,应用将会被恶意代码注入,从而执行的是恶意代码。
搜 DexClassLoader
.风险位置:
public DexClassLoader(String dexPath,String optimizedDirectory, String libraryPath,ClassLoader parent)[2]
. 查 看 AndroidManifest.xml 包 package 值 相 对 应 路 径 下 的 文 件 中 是 否 含 有DexClassLoader()函数调用
检测 so 库中函数是否可被其他应用调用。
尝试使用其他程序调用 APP 的 so 库函数 – 检测 so 库函数能否轻易被其他应用调用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。