漏洞描述
漏洞发生在Android自带短信应用中updateMessageStatus函数中,该函数用于发送短信完成后更新状态。代码中未对异常进行处理(使用try…finally…,未加catch),且相关的服务对外暴露,恶意程序可以构造恶意的短信发送广播,导致自带的短信应用无法工作。
漏洞代码如下:
当message为null时,访问message对象中的函数或变量就会发生空指针异常,导致短信应用Crash.
函数开始对message是否为空作了判断,因此需要绕过判断。createFromPdu函数是对收到的pdu格式的短信进行解析,返回一个SmsMessage对象,如下图:
该函数根据format的格式(3GPP为GSM,3GPP2为CMDA)去解析PDU,最后返回一个wrappedMessage对象,最后的return没有直接返回wrappedMessage对象,而是通过new的方式返回,导致返回值永不为null。因此,只要wrappedMessage对象为null时,就会绕过”if (message==null)”的检查,触发空指针异常。
漏洞利用
为使wrappedMessage对象为null,只需要构造一个无效的PDU串即可。
>
PDU为发送短信时一种固定的编码格式,一般的PDU编码由A B C D E F G H I J K L M十三项组成。
A:短信息中心地址长度,2位十六进制数(1字节)。
B:短信息中心号码类型,2位十六进制数。
C:短信息中心号码,B+C的长度将由A中的数据决定。
D:文件头字节,2位十六进制数。
E:信息类型,2位十六进制数。
F:被叫号码长度,2位十六进制数。
G:被叫号码类型,2位十六进制数,取值同B。
H:被叫号码,长度由F中的数据决定。
I:协议标识,2位十六进制数。
J:数据编码方案,2位十六进制数。
K:有效期,2位十六进制数。
L:用户数据长度,2位十六进制数。
M:用户数据,其长度由L中的数据决定。J中设定采用UCS2编码,这里是中英文的Unicode字符。
>
考虑到第一个字节为长度标志位,只要将其置0即可够造一个恶意的PDU,参考PDU在线解析,这里伪造的PDU如下:1
0091683108200505F0
为触发漏洞代码,需要找到漏洞代码的调用路径,跟踪短信源码发现updateMessageStatus函数在MessageStatusService服务中,查看menifest文件发现MessageStatusService并没有对外导出。但是短信应用注册了一个recever叫做MessageStatusReceiver,它收到广播后会开启MessageStatusService服务,因此,通过发送“com.android.mms.transaction.MessageStatusReceiver.MESSAGE_STATUS_RECEIVED”广播可以触发漏洞代码。
为保证createFromPdu不会返回null,还需要指定短信的format为3gpp或3gpp2。此外,若要对短信应用进行DOS,需要不停的发送广播。
PoC代码见https://github.com/mabin004/cve-2015-3839_PoC
漏洞修复
由漏洞patch可以看出,google在漏洞代码处加了catch来捕获空指针异常。
##总结
这个漏洞的存在关键在两个地方:
- 没有加catch捕获异常,如果加catch后,任何DoS攻击都无效;
- return的时候没有进行判断,直接new一个对象就return了,这里是绕过null检查的关键