深入Android组件安全攻防(揭秘手Q强制下线提示原理)

2020-11-23 15:05:47 浏览数 (1)

本文继续Android安全话题,继续说道第四篇,继续对具体安全漏洞做具体的防止实践。本篇介绍组件劫持攻防。本文让你明白手机QQ强制登录提示功能的原理。

ps: 安全漏洞详细 可点这里

Activity

Activity是android最基本的组件,也是最常用的组件,基本运行原理请见:https://developer.android.com/reference/android/app/ActivityManager.html, activity的启动模式(四大启动模式自行找文看)决定了安全存在风险。于是存在了劫持风险。Activity劫持主要的表现是自己的Activity被恶意攻击,或者仿冒的恶意Activity界面进行攻击和非法用途。此漏洞的存在允许执行网络钓鱼攻击,以及用户在相关活动中处理的信息泄露。此外,此漏洞允许攻击者修改数据,从而危及其完整性。

轻度劫持

原理:

恶意被第三方程序启动,绕过本身的业务逻辑,造成数据泄露。主要体现在自己的首页被非法启动,绕过登录界面,导致可直接进行数据浏览和查看,或者携带对本app有害的指令,造成其他问题。

可以参考以前本号发布的安全要点与规范 中权限的描述。由于android所有组件通讯都会是基于intent来实现的,对于Intent的处理都有相关的action 中的 permission 进行过滤,所以如果开发者不严谨就会造成acivity被恶意开启。

解决方案: 第二篇安全要点中已经说明组件权限,具体属性请自行阅读,这里不过多解释!

代码语言:javascript复制
<activity android:name=".MainActivity"   
    android:label="@string/title_activity_single" 
    android:exported="false"
    android:permission="自定义权限"      
    android:protectionLevel="normal" />

如果还需要做加固,Android 提供各种 API 来在运行时检查、执行、授予和撤销权限。这些 API是 ContextWraper的一部分,这个类提供有关应用程序环境的全局信息。

代码语言:javascript复制
    if (context.checkCallingOrSelfPermission("自定义权限") 
          != PackageManager.PERMISSION_GRANTED) { 
    // The Application requires permission to access the // Internet"); 
    } else { 
      // handler 
    }

深度劫持

原理: 启动一个Activity时,给它加入一个标志位FLAG_ACTIVITY_NEW_TASK,就能使它置于栈顶并立马呈现给用户。如果不加以区别就能获取用户的相关信息,如果伪造出一个登录界面,搜集后发往云端,那么就会造成账户秘密泄露。被恶意程序截获 ,产生恶意程序的界面或者假冒伪造的界面覆盖在最上层,导致非法采集用户信息,盗取账号和密码。俗称钓鱼。 常用攻击要体现在登录和支付。

解决方案: 没有直接的解决方案, 只能引导用户!通过遍历系统当前最上层Activity,来判断是否是自己应用的界面,来做友好提示,防止用户被钓鱼程序劫持。下面就请来姿势砸我吧!

代码语言:javascript复制
public static boolean checkMyself(Context context) { 
   PackageManager pm = context.getPackageManager();    
   List<ApplicationInfo> listAppcations =   
       pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);

   Collections.sort(listAppcations, new        
         ApplicationInfo.DisplayNameComparator(pm));    
      // 排序 
     List<ApplicationInfo> appInfos = new ArrayList<ApplicationInfo>(); 
     // 保存过滤查到的AppInfo 
    for (ApplicationInfo app : listAppcations) {        
     //这个排序必须有. 
     if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 
        //appInfos.add(getAppInfo(app));     
        safePackages.add(app.packageName); 
       } 
     }    //得到所有的系统程序包名放进白名单里面.
    ActivityManager activityManager = 
          (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); String runningActivityPackageName; 
     int sdkVersion;     try { 
           sdkVersion =   
                   Integer.valueOf(android.os.Build.VERSION.SDK); 
         } catch (NumberFormatException e) {
            sdkVersion = 0;
         } 
       if (sdkVersion >= 21) {       
        //获取系统api版本号,如果是5x系统就用这个方法获取当前运行的包名 
       runningActivityPackageName = getCurrentPkgName(context); 
        } else { 
             runningActivityPackageName = 
                 activityManager.getRunningTasks(1).get(0).topActivity.getPackageName(); 
        } 

       //如果是4x及以下,用这个方法. 
       if (runningActivityPackageName != null) {        
        //有些情况下在5x的手机中可能获取不到当前运行的包名,
         所以要非 空判断。
         if(runningActivityPackageName.equals(context.getPackageName())  ) { 
         safe = true; 
        } 
       // 白名单比对 
        for (String safePack : safePackages) { 
           if (safePack.equals(runningActivityPackageName)) {
            
               safe = true;
             }
          } 
       } 
      return safe;
}

因此在需要的检测的Activity中调用代码检查!

代码语言:javascript复制
@Override protected void onStop() { 
     super.onStop();     if (checkMyself(this)){ 
        //todo 
    } else { 
       //todo
   } 
}

目前,QQ强制登录下线就利用这种原理,无论你停留在任何应用,当QQ账号在其他设备登陆时,当前总会提示对话框告知用户, 虽然很烦人,但用户无法阻止,手机QQ的service在收到推送时 立即在actiivity启动一个用来展示重新登录的透明activity, 用来伪造对话框覆盖在其他activity栈顶。为什么不直接提示Dialog?Android因为限制了dialog的show, dialog的初始化必须依赖acitvity的context, 因此这种组件攻击就成了手机QQ强制提示登录下线的实现原理。需要代码的朋友可以关注留言来索要。

Service

本地服务(Local)

该服务依附在主进程上,不是独立的进程。本地服务在一定程度上节约了资源,由于是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。

远程服务(Remote)

该服务是独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。但由于独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。一些提供系统服务的Service通常是常驻的。

拒载服务

由于Service于外界也是通过Intent机制来协助应用间的交互与通讯,因此Intent的信息和描述就可能对Service发起攻击,造成自己的服务被停止服务漏洞.

1) 漏洞位置: 处理getIntent()的intent附带的数据 2) 漏洞触发前提条件: getIntent()的intent附带空数据、异常或畸形数据; 处理getXXXExtra()获取的数据时没有进行异常捕获. 3) 漏洞原理: Android系统中提供了Intent机制来协助应用间的交互与通讯,其负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,系统则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成组件的调用。调用的组件在处理Intent附加数据的时候,没有进行异常捕获,因此当处理空数据、异常或者畸形数据时,导致应用崩溃。

  • 空指针异常;
  • 类型转换异常;
  • 数组越界访问异常;
  • 类未定义异常;
  • 其他异常;

外界劫持

service也需要在manifest注册,因此权限属性和activity一样,出于安全考虑,应将不必要的组件设置私有,防止引起拒绝服务,尤其是杀毒、安全防护、锁屏防盗等安全应用; 在AndroidMenifest.xml文件中,将相应组件的“android:exported”属性设置为“false”,如下示例:

代码语言:javascript复制
<service android:name="MyService"
         android:exported="false"> 
     <intent-filter> 
          <action android:name="android.intent.action_tamic"/>
     </intent-filter>
 </service>

Content Provider和Receiver

Content Provider和Receiver同上,具体我们也需要加入权限和声明为内部使用。干货文章有啥理由不关注呢?

猜你喜欢

Andrroid安全要点与规范

Android安全漏洞大全

技术 - 资讯 - 感悟

END

0 人点赞