type
status
date
slug
summary
tags
category
icon
password
0x01 引言
这道题目利用的是
Parcel MisMatch
进行漏洞利用,和直接在系统上通过AddAcount
利用造成LaunchAnyWhere
原理一样,但是有些细节还是不太一样,需要记录一下。0x02 题目分析
1. Parcel MisMatch
点
存在
Parcel MisMatch
问题的Parcelable
位于MainActivity类中,作为一个子类存在,这个点需要注意,因为如果是这种情况,在构造序列化数据时parcelable数据的数据类名应当为com.de1ta.broadcasttest.MainActivity$Message
而不能将$
改为.
问题主要出在
this.rttSpread = in.readLong();
和dest.writeInt((int) this.rttSpread);
类型不匹配,导致在两次序列化和两次反序列化过程中出现问题。2. 三个广播接收器
题目中有三个继承自
BroadcastReceiver
的接收器,其中只有MyReceiver1
是导出的,并且action
为com.de1ta.receiver1
,另外两个均为非导出,仅能构造恶意序列化数据,构成MyReceiver1
.onReceive->
MyReceiver2
.onReceive->
MyReceiver3
.onReceive
的调用顺序,在MyReceiver2
.onReceive
中绕过对command
的检测,在MyReceiver3
.onReceive
中使得command = getflag
从而拿到flag。3. 两次序列化两次反序列化
这里需要格外注意题目中关于序列化和反序列化点的分析
- 第一次序列化是攻击者构造恶意
Bundle
并且将其序列化的过程,实际上可以直接简化为构造parcel
序列化数据的过程,构造完成后通过base64
传入第一个广播接收器
- 第一次反序列化 是在
MyReceiver2
中String command = bundle.getString("command");
时进行的,而非在MyReceiver1
的时进行bundle.readFromParcel(dest);
,实际上在readFromParcel
时仅仅将序列化数据放入Bundle
实例的mParcelledData
中,直到此时序列化数据并未被反序列化,而当getString
时需要读取实际的数据而非序列化数据,所以才会取出mParcelledData
中数据反序列化并且将反序列化结果(一个map数据结构)
放入Bundle
实例的mMap
中。
- 第二次序列化 是在
MyReceiver2
的sendBroadcast
时进行,因为在MyReceiver2
通过command
校验后需要再次将数据广播,但是实际上在进程间传递的信息只能是序列化数据,所以此时需要进行序列化操作,将mMap
中的数据再次进行序列化以进行信息传递。
- 第二次反序列化 是在
MyReceiver3
的getString
时进行,和第一次反序列化类似。
0x03 解题
关于这种漏洞的利用方法,之前已经写blog记录过了,详细的方法和细节请看之前的文章
Android反序列化漏洞-Bundle风水
,因此在这里不再赘述,直接给出poc。原理就是第一次反序列化时会读取两个四字节Long,但是第二次序列化会写入一个四字节Int,第二次反序列化又会读取两个四字节Long,中间有四个字节的差,造成偏移后能够隐藏后面的数据。给出第一次反序列化时被攻击APP的视角,发现第二个键值对中隐藏了command,第三个键值对给了假的command绕过,第二个键值对通过字节数组类型绕过
给出第二次反序列化时被攻击APP的视角,发现第三个键值对中出现了
command = getflag
,第四个键值对不再读取,因为mapSize = 3
,和上面的图对比发现就是0xD8
位置的07 00 00 00
被吞掉,造成解析偏移。0x04 总结
其实关键点还是分析两次序列化两次反序列化的具体位置信息,分析出来然后配合着调试就很容易做。构造方法不止一种,可以自己尝试。
0x05 题目
官方在Github上传了题目原件和对应的Docker环境以及WP,有兴趣可以复现
- 作者:LLeaves
- 链接:https://lleavesg.top//article/De1CTF-2020-Pwn-BroadCastTest
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章