Activity漏洞初步介绍
Activity基本介绍
Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。
Activity生命周期
当用户浏览、退出和返回应用时。应用中的 Activity 实例会在其生命周期的不同状态间转换,例如。我们在界面A使用了视频播放器,当我们切换到下个界面B的时候,那么界面A就必须释放视频播放器,这样才不会导致界面B无法使用。当我们在界面之间进行导航切换的时候,其实就是在切换Activity。当界面在不同状态之间进行切换的时候,也就是Activity状态的切换,就会回调activity相关的方法。例如当界面不可见的时候会回调onStop方法,恢复的时候会回调onReStart方法等。为了在 Activity 生命周期的各个阶段之间导航转换,Activity 类提供六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()。当 Activity 进入新状态时,系统会调用其中每个回调。
onCreate:首次创建 Activity 时触发,调用后Activity进入ON_CREATE状态。
onStart:Activity 进入“已开始”状态时,然后Activity会进入ON_START状态
onResume:Activity准备与用户交互的时候调用。调用之后Activity进入ON_RESUME状态。
onPause:activity窗口失去焦点的时候,会调用此方法。调用后activity进入ON_PAUSE状态,并进入后台。
onStop:activity不可见的时候进行调用。调用后activity进入ON_STOP状态
onRestart :从另一个activity切回到该activity的时候会调用。调用该方法后会立即调用onStart方法,之后activity进入ON_START状态
onDestroy:当activity被系统杀死或者调用finish方法之后,会回调该方法。调用该方法之后activity进入ON_DESTROY状态
Intent 调用Activity
Activity以实现不同组件之间的交互需要一个重要的组件,即Intent Intent(意图)是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent虽然不是四大组件,但却是连接四大组件的桥梁。
Intent通常用于启动Activity、启动Service、发送广播等场景。Intent具有多个构造函数的重载 Intent的用法大致可以分为两种,显式Intent和隐式Intent:
显示Intent打开Activity:
先构造一个Intent对象(两个参数的构造方法),传入MainActivity.this作为上下文,传入MainActivity2.class作为目标Activity,这样我们的“意图”就非常明显了,即在MainActivity这个活动的基础上打开MainActivity2这个Activity然后通过startActivity()方法来执行这个Intent。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.btn1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
startActivity(intent);
}
});
}
}
隐式Intent打开Activity:
隐式Intent并不指明启动哪一个Activity,而是指定了一系列更为抽象的action(动作)和category(类别)等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动,action和category一般在AndroidManifest中指定
<activity
android:name=".MainActivity2"
android:exported="false"
android:label="这是第二个Activity">
<intent-filter>
<action android:name="com.example.test.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.test.MY_CATEGORY" />
</intent-filter>
</activity>
在
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.test.ACTION_START");
startActivity(intent);
}
}
重新运行程序,在界面点击一下跳转按钮,同样成功启动第二个页面了,不同的是,这次你是使用了隐式Intent的方式来启动的。值得注意的是我们只传入了ACTION_START,并没有传入category这是因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()时会自动将这个category添加到Intent中,注意:Intent中只能添加一个action,但是可以添加多个category。对于含多个category情况,我们可以使用addCategory()方法来添加一个category。
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.test.ACTION_START");
intent.addCategory("com.example.test.MY_CATEGORY");
startActivity(intent);
}
}
然后 在AndroidManifest 中的
<activity
android:name=".MainActivity2"
android:exported="false"
android:label="这是第二个Activity">
<intent-filter>
<action android:name="com.example.test.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.test.MY_CATEGORY" />
</intent-filter>
</activity>
再次重新运行程序同样成功启动到第二个页面了。
隐私Intent打开其他应用Activity:
使用隐式Intent,我们不仅可以启动自己程序内的activity,还可以启动其他程序的activity,这便是Android多个应用程序之间的功能共享。例如我们调用系统拨号界面:修改点击事件如下:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
}
当然也可以调用浏览器去打开网址:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.baidu.com"));
startActivity(intent);
}
}
这样我们就通过隐式Intent的方法打开外部Activity。
Activity 漏洞类型
越权绕过 Activity劫持 隐式启动intent包含敏感数据 拒绝服务
越权绕过
在 AndroidManifest.xml 中配置 Activity 时,如果设置了 exported="true" 这样的关键值或添加了
Google 在 Android 12 中引入了更加严格的规定,以增强应用的安全性。特别是关于导出属性 android:exported 的设置,以确保开发者明确声明其 Activity 是否可以被其他应用访问。在 Android 12 中,如果应用的 Activity 包含了
元素,那么开发者必须显式地设置 android:exported 为 true 或 false。如果没有明确指定导出属性,而又带有 ,那么这样的 Activity 在应用安装时会被 PackageManager 拒绝
比如在业务过程中会有一些敏感的界面是需要用户输入密码才能查看的,但是如果没有对调起此activity的组件进行权限验证,那么就会造成验证的越权问题,导致恶意的攻击者不需要输入密码等信息也可以打开这个界面。还有通过Intent给Activity传输畸形数据使得程序崩溃拒绝服务影响用户体验或Activity界面被劫持产生欺诈等安全事件。
示例-小试牛刀:
我们来写一个简单的登录样本:
public void onClick(View v) {
String username = editTextUsername.getText().toString();
String password = editTextPassword.getText().toString();
// 在这里添加验证逻辑,比如检查用户名和密码是否匹配
if (username.equals("test") && password.equals("123456")) {
Intent intent = new Intent(LoginActivity.this, MainActivity2.class);
startActivity(intent);
Toast.makeText(LoginActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
} else {
// Toast.makeText(LoginActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
// 登录失败,弹出 Snackbar
showFailedSnackbar();
}
} //只贴出部分代码,可以拿样本直接使用
新建一个MainActivity2 并添加一个TextView:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="恭喜你 登录成功!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
在AndroidManifest中指定MainActivity2 的 exported 属性设置为 true
<!-- LoginActivity - 初始活动 -->
<activity
android:name=".LoginActivity"
android:exported="true"> <!-- 将 LoginActivity 的 exported 属性设置为 true -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <!-- MainActivity2 -->
<activity
android:name=".MainActivity2"
android:exported="true"> <!-- 将 MainActivity2 的 exported 属性设置为 true -->
<intent-filter>
<action android:name="com.example.test.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity> <!-- MainActivity -->
我们来看下效果:
MainActivity2 的 exported 属性设置为 true 我们可以通过其他应用构造隐式Intent调用该Acivity来绕过登录验证。我们在写一个尝试越权的demo app :
/*
*
* 说明:
* 使用隐式 Intent启动另一个应用的 Activity
* 在使用隐式 Intent 时,请确保目标 Activity 设置了适当的 android:exported 属性,以确保安全性。
*
*/
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("com.example.test.action.VIEW");
intent.setPackage("com.example.test"); // 目标应用的包名
startActivity(intent);
}
});
成功的实现了越权绕过登录验证。
注意:(1)私有Activity不应被其他应用启动相对是安全的,创建activity时:需要设置exported属性为false (2)公开暴露的Activity组件,可以被任意应用启动,创建Activity:设置export属性为true,有返回数据不应包含敏感信息,也要小心处理接收的intent。
为了感恩新老用户对我们的支持,我们特别推出了一张迄今为止最大的知识星球优惠券我们深知在安全路上,知识对于晋升和成长的重要性,所以这个超值的优惠券它来了。
通过使用这张优惠券,您将享受到前所未有的折扣,并且获得一年内无限制访问我们星球中所有的知识内容以及最新的技术文档、问题解答和行业动态等资源的特权。
原文始发于微信公众号(移动安全星球):Android-Activity漏洞初步介绍
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论