0×01 漏洞简介
9月7号 趋势科技发布了一篇《CVE-2017-0780: 拒绝服务漏洞可以导致Android Message App 崩溃》的文章。目前已经确认该漏洞对最新版本的Nexus 和 Pixel 设备有影响,攻击者可以通过发送恶意彩信到受害人手机实现攻击。很多彩信客户端会在启动的时候自动恢复加载之前的记录,包括彩信,这导致受害人无论是重启手机还是进入安全模式都无法解除恶意彩信对Message app的影响,自动成为一个可持续的漏洞。 该漏洞目前针对 Android 6.0 --- 8.0 版本均有影响。
漏洞代码在AOSP 第三方扩展模块 framesequence 的FrameSequenceDrawable类的acquireAndValidateBitmap 函数。在函数内因为没有捕获 Java-level Null Pointer Exceptions 异常,从而会导致此异常沿着调用栈一直向上回溯直到被捕获处理,如果在APP内部也没有处理,最终会被系统处理,通常系统会让APP Crash。
0×02 漏洞分析
public FrameSequenceDrawable(FrameSequence frameSequence, BitmapProvider bitmapProvider) {
`if (frameSequence == null || bitmapProvider == null) throw new IllegalArgumentException();
mFrameSequence = frameSequence;
mFrameSequenceState = frameSequence.createState();
final int width = frameSequence.getWidth();
final int height = frameSequence.getHeight();
mBitmapProvider = bitmapProvider;
mFrontBitmap = acquireAndValidateBitmap(bitmapProvider, width, height);
mBackBitmap = acquireAndValidateBitmap(bitmapProvider, width, height);
mSrcRect = new Rect(0, 0, width, height);
mPaint = new Paint();
mPaint.setFilterBitmap(true);
mFrontBitmapShader
= new BitmapShader(mFrontBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBackBitmapShader
= new BitmapShader(mBackBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mLastSwap = 0;
mNextFrameToDecode = -1;
mFrameSequenceState.getFrame(0, mFrontBitmap, -1);
initializeDecodingThread();
`
}
Android 使用FrameSequenceDrawable 类来展示gif 文件,首先要基于GIF 文件构造Bitmap对象,然后FrameSequenceDrawable 类展示GIF。
FrameSequenceDrawable 构造函数中会调用 acquireAndValidateBitmap 创建 Bitmap对象。
private static Bitmap acquireAndValidateBitmap(BitmapProvider bitmapProvider,
` int minWidth, int minHeight) {
Bitmap bitmap = bitmapProvider.acquireBitmap(minWidth, minHeight); // 实现在应用中,可能返回 null
if (bitmap.getWidth() < minWidth
|| bitmap.getHeight() &lt; minHeight
|| bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
throw new IllegalArgumentException("Invalid bitmap provided");
}
return bitmap;
`
}
下面这个 class 可以在任何 APP 中自定义。
private class CheckingProvider implements FrameSequenceDrawable.BitmapProvider {
` HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>();
@Override
public Bitmap acquireBitmap(int minWidth, int minHeight) {
Bitmap bitmap =
Bitmap.createBitmap(minWidth + 1, minHeight + 4, Bitmap.Config.ARGB_8888);
mBitmaps.add(bitmap);
return bitmap;
}
`
}
bitmapProvider 是FrameSequenceDrawable.BitmapProvider 的子类对象,Sample 代码中中实现一个 class, 重写 BitmapProvider 的抽象函数 acquireBitmap。
构造POC 可以 直接在 此函数中返回null, 因为在 acquireAndValidateBitmap 中没有检测 bitmap 对象是否为null ,而且此函数也没有 catch 空指针异常,最终在调用 bitmap 对象时 会导致 使用此模块(android-common-framesequence)的上层应用 crash。
当FrameSequence尝试从格式不正确的GIF构建位图时,我们看到"acquireBitmap"函数可能会失败并返回null。 因此,如果有变量引用此空对象,则会触发NPE。
0×03 构造Exploit
exp-1:
通过构造特殊的gif 文件验证漏洞。
趋势给的demo 截图将 width 和 height 设置为 0xffff 可以触发漏洞。
exp-2:
通过构造一个 app 验证漏洞。
此方法可以直接从aosp 代码中获取FrameSequenceSample 案例,修改FrameSequenceTest.java。
public class FrameSequenceTest extends Activity {
...
private class CheckingProvider implements FrameSequenceDrawable.BitmapProvider {
` HashSet<Bitmap> mBitmaps = new HashSet<Bitmap>();
@Override
public Bitmap acquireBitmap(int minWidth, int minHeight) {
return null;
// Bitmap bitmap =
// Bitmap.createBitmap(minWidth + 1, minHeight + 4, Bitmap.Config.ARGB_8888);
// mBitmaps.add(bitmap);
// return bitmap;
}
...
`
}
...
}
0×04 漏洞利用
笔者的测试环境:
Nokia 6 手机
型号 TA-1000
Android 7.1.1
利用条件:
目标机的手机号码
目标机 Android版本
通过构造恶意的gif从一台手机中发送到目标机,目标机上的 Android Messages App 会自动接受,并且导致应用卡死。
0×05 相关的移动平台GIF/PNG解析器导致的RCE与DoS漏洞
通过整理 发现了 3个关注过的gif 的远程漏洞。
l CVE-2017-0780 Android DOS 漏洞
l CVE-2017-2416 iOS RCE 漏洞
l CVE-2017-0478 Android FrameSequence_webp 漏洞
CVE-2017-0780 和 CVE-2017-2416 漏洞的相似性非常高,都是在处理GIF文件中LOGICALSCREENDESCRIPTOR段的Width 和 Height 字段时出现错误,这2个字段是GIF图片的宽度和高度。只是在Android平台对应的漏洞在Java层通过NPE造成APP Crash,在iOS平台漏洞在GifPlugin模块中,因为width 和 Height 对应short 类型攻击者可以设置为负数造成内存越界访问,精心构造文件可以造成远程代码执行利用。
Poc可参考:
https://blog.flanker017.me/cve-2017-2416-gif-rce-chn/
https://github.com/JiounDai/CVE-2017-0478
0×06 参考: