android 服务端 漏洞,安卓漏洞 CVE 2017-13287 复现详解-

0105cf91814a842b89050889fef7998b.png

2018年4月,Android安全公告公布了CVE-2017-13287漏洞。

与同期披露的其他漏洞一起,同属于框架中Parcelable对象的写入(序列化)与读出(反序列化)的不一致所造成的漏洞。

在刚看到谷歌对于漏洞给出的补丁时一头雾水,

在这里要感谢heeeeen@MS509Team在这个问题上的成果,启发了我的进一步研究。

原理

谷歌在Android中提供了Parcelable作为高效的序列化实现,用来支持IPC调用中多样的对象传递需求。

但是序列化和反序列化的过程依旧依靠程序员编写的代码进行同步。

那么当不同步的时候,漏洞就产生了。

Bundle

传输的时候Parcelable对象按照键值对的形式存储在Bundle内,Bundle内部有一个ArrayMap用hash表进行管理。

反序列化过程如下:

/* package */ void unparcel() { synchronized (this) { final Parcel parcelledData = https://www.solves.com.cn/it/cxkf/ydd/Android/2020-02-16/mParcelledData; int N = parcelledData.readInt(); if (N < 0) { return; } ArrayMapmap = mMap; try { parcelledData.readArrayMapInternal(map, N, mClassLoader); } catch (BadParcelableException e) { } finally { mMap = map; parcelledData.recycle(); mParcelledData = null; } } }

首先读取一个int指示里面有多少对键值对。

/* package */ void readArrayMapInternal(ArrayMap outVal, int N, ClassLoader loader) { if (DEBUG_ARRAY_MAP) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Log.d(TAG, "Reading " + N + " ArrayMap entries", here); } int startPos; while (N > 0) { if (DEBUG_ARRAY_MAP) startPos = dataPosition(); String key = readString(); Object value = https://www.solves.com.cn/it/cxkf/ydd/Android/2020-02-16/readValue(loader); outVal.Append(key, value); N--; } outVal.validate(); }

之后的每一对先是Key的字符串,然后是对应的Value。

public final Object readValue(ClassLoader loader) { int type = readInt(); switch (type) { case VAL_NULL: return null; case VAL_STRING: return readString(); case VAL_INTEGER: return readInt(); case VAL_MAP: return readHashMap(loader); case VAL_PARCELABLE: return readParcelable(loader); case VAL_SHORT: return (short) readInt(); case VAL_LONG: return readLong();

值内部先是一个int指示值的类型,再存储实际值。

当Bundle被写入Parcel时:

void writeToParcelInner(Parcel parcel, int flags) { final ArrayMap map; synchronized (this) { if (mParcelledData != null) { if (mParcelledData =https://www.solves.com.cn/it/cxkf/ydd/Android/2020-02-16/= NoImagePreloadHolder.EMPTY_PARCEL) { parcel.writeInt(0); } else { int length = mParcelledData.dataSize(); parcel.writeInt(length); parcel.writeInt(BUNDLE_MAGIC); parcel.appendFrom(mParcelledData, 0, length); } return; } map = mMap; } }

先写入Bundle总共的字节数,再写入魔数,之后是指示键值对数的N,还有相应的键值对。

LaunchAnyWhere

弄明白Bundle的内部结构后,先来看看漏洞触发的地方:

173753964e95443a69efcfe8082724e3.png

这个流程是AppA在请求添加一个帐号:

AppA请求添加一个帐号

System_server接受到请求,找到可以提供帐号服务的AppB,并发起请求

AppB返回了一个Bundle给系统,系统把Bundle转发给AppA

AccountManagerResponse在AppA的进程空间中调用startActivity(intent)调起一个Activity。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值