2017-11-20

 作者:大脸猫

前言

据外媒报道,美国媒体机构Zenith发布的最新研究报告预测,在2018年,全球智能手机用户数量将会继续增长。其中,中国智能手机用户数量将位居全球第一,达到13亿,届时将人手一部智能手机。而移动市场份额中,谷歌的Android和苹果的iOS两个操作系统占据了市场份额的98%左右,而其中Android系统的智能设备由于其较高的性价比占据了绝大部分的市场份额。

由此可见,智能终端设备已经占据了人们生活的方方面面。日常生活中,几乎每个人都会接触到智能设备,包括手机、平板、智能手表、智能电视等,其中又以Android系统为主。

移动端应用的开发涉及到许多第三方SDK,而第三方SDK的安全性很难保证。移动端应用的开发为节约成本、快速成型,一般都会使用多种第三方的SDK,包括支付、统计、广告、社交、推送、地图类的第三方SDK。下图所示为经360显危镜后台查询的几款常用SDK使用情况统计数据,从图中可以看出使用了该SDK开发的APP非常多。

1

而第三方的SDK开发侧重于功能性的完善,在安全性方面的投入较少,导致了今年来由第三方SDK引起的安全事件频发。

第三方SDK安全威胁

近两年已被爆出有安全漏洞的第三方SDK主要有FFmpeg、SQLite、pdfium、个信sdk、chrome内核等,且由于其被广泛使用到大量的APP中,造成漏洞的影响范围非常大。

FFmpeg漏洞概况

FFmpeg的是一款全球领先的多媒体框架,支持解码、编码、转码、复用、解复用、流媒体、过滤器和播放几乎任何格式的多媒体文件。

2017年6月,neex向Hackerone平台提交了俄罗斯最大社交网站VK.com的ffmpeg的远程任意文件读取漏洞。该漏洞利用了FFmpeg可以处理HLS播放列表的特性,而播放列表(Playlist)中可以引用外部文件。通过在播放列表中添加本地任意文件的引用,并将该文件上传到视频网站,可以触发本地文件读取从来获得服务器文件内容。同时,该漏洞亦可触发SSRF漏洞,造成非常大的危害。

2

此外,360GearTeam发现的编号CVE-2016-6671漏洞,FFmpeg在对SWF文件解码时,在计算解码后数据大小时可导致写入数据超过申请内存空间的大小,从而造成缓冲区溢出。编号CVE-2016-10190漏洞中发现FFmpeg在处理chunk数据时由于有符号整数到无符号整数类型转换引起的堆缓冲区溢出。

当然,FFmpeg被爆出的漏洞不止上述几种。下图所示为FFmpeg官方的修复记录,从中可以看到每一版本均修复了大量的已分配CVE编号的漏洞,新版本同样会有许多未发掘出的漏洞等待修复。

3

在360显危镜后台根据该第三方库的特征规则搜索查询,在库中40万多个APP中,有月6万多个APP使用了FFmpeg的第三方开源库的代码,如下图所示约占15%。主流的一些视频应用几乎都采用了该开源库用于对多媒体文件的处理。从图中可以看出,该第三方库的使用范围是非常大的,一旦被爆安全漏洞,影响范围将是无法估量的。

4

SQLite安全现状

SQLite是遵守ACID的关系数据库管理系统,实现了大多数SQL标准。它使用动态的、弱类型的SQL语法,包含在一个相对小的C库中。作为一款嵌入式数据库,它因占用的资源非常低,数据处理速度快等优点被Andriod、iOS、WebKit等流行软件采用。

2017年Black大会上来自长亭科技的议题介绍了基于Memory Corruption的SQLite漏洞。基于该漏洞,可以攻击常见的使用了SQLite的浏览器,包括Safari、Chrome、Opera等。同时,由于大部分应用本地数据库的存储几乎都采用了SQLite实现,这些应用同样受到该漏洞的影响。基于该漏洞可以造成大范围的用户信息泄露,包括用户在浏览器中填写的用户名、密码、身份证、银行卡等敏感信息。另外,基于该漏洞可以实现远程代码执行,从而控制用户终端设备,危害是非常大的。

5

此外,SQLite也有许多影响严重的漏洞常常被爆出。SQLite从3.3.6提供了支持扩展的能力,通过sqlite_load_extension API(或者load_extension SQL语句)开发者可以在不改动SQLite源码的情况下,通过加载动态库来扩展SQLite的能力。然而该功能被黑客利用,通过SQL注入漏洞加载预制的符合SQLite扩展规范的动态库,从而实现了远程代码执行,危害非常严重。

当然,SQLite的漏洞并不仅限于这几个。随着版本更新,在功能升级的过程中,每一版本均会被爆出大量的不同级别的漏洞。每一版本均会在上一版本基础上修改一些bug和漏洞,并可能会添加新的功能。由于精力有限,无法保证对每一行代码都经过安全审核,新发布的版本中很可能存在未被发现的漏洞。在现有技术体系下,产品漏洞挖掘的过程将会是长期存在的状况。

6

在Android应用中,只要有本地存储数据的需求,一般均会采用SQLite数据库存储。因此,一旦SQLite被爆安全漏洞,将影响数以万计的Android应用。同时,在某一Android设备中,一般都会预装许多应用或日常使用中安装了许多需要的应用,而这些应用中总会有一款应用使用了SQLite数据库。因此,SQLite的安全漏洞几乎总会影响的该设备。

 

Chromium威胁分析

Chromium是一个由Google主导开发的网页浏览器,以BSD许可证等多重自由版权发行并开放源代码。Chromium是Google的Chrome浏览器背后的引擎,其目的是为了创建一个安全、稳定和快速的通用浏览器。

目前,有许多浏览器是基于Chromium开发的,且提供了Windows、macOS和Android版本的浏览器。国内的主流浏览器均采用了Chromium内核,包括360浏览器、猎豹浏览器、遨游浏览器等。由于终端用户对浏览器均会有硬性需求,PC和移动设备中均会安装各种各样的浏览器,总有一款是基于Chrome内核的。

虽然Chrome是Google开发和维护的,但是也被爆出许多漏洞,影响了基于相当内核版本的其他浏览器。微软于2017年10月18日公布了一款藏匿于Google Chrome的浏览器安全漏洞,编号为CVE-2017-5121。该问题是由V8 JavaScript引擎引起的,通过引起应用崩溃导致攻击者可以在内存地址中放置任意的数据。通过精心构造的攻击,该漏洞可以达到远程代码执行(RCE),影响几乎所有基于Chrome内核的浏览器。Google已于今年9月份中旬在Chrome 61版本修复了相关漏洞。

每年Chrome浏览器都会被爆出许多安全漏洞。如下图所示,每年Chrome均会被爆出大量的多种类型的安全漏洞,影响几乎所有Chrome内核的浏览器。此外,由于漏洞报给Google修复,其他基于Chrome内核的浏览器修复该漏洞需要较长的周期,漏洞的危害还是存在的。同时,其他厂商的浏览器很难跟上Chrome内核的更新速度,以至于很多浏览器还是很久之前的旧版本内核,导致该版本还受以往历史漏洞的影响。

7

8

由于许多浏览器是基于Chrome内核开发的,且Android上许多应用中均会使用到浏览器的功能,一旦被爆漏洞影响将是非常大范围的。

Android系统安全趋势

Android是一种基于Linux的自由及开放源代码的操作系统,由Google公司和开放手机联盟领导及开发,主要设计用于触控荧幕移动设备如智能手机和平板电脑。目前,Android系统已经成为现今最流行的智能设备操作系统。

Android系统中,也使用了大量的第三方SDK组件用于其系统底层的基础服务功能,例如蓝牙协议栈实现、HTTPS协议实现、音视频编解码等。然而,Google使用的这些第三方组件也时常会被爆出有高危漏洞,且鉴于Android系统的广泛流行性,影响也是巨大的。下图所示内容为统计的2017年1月份至11月份Android系统中修复的第三方组件中的漏洞数量情况。从图中可以看出,第三方组件的安全性严重威胁到了Android系统的安全性。

9

下图所示为2017年1月份至11月份每月Android系统修复的第三方组件漏洞数量,平均每月约有80个漏洞影响Android系统的安全性。

10

总结

在软件开发过程中,大量复用第三方SDK加速产品成型成为普遍现状,而第三方SDK的安全漏洞也将影响这些产品。如FFmpeg、SQLite、Chromium、PDFium等开源库,均在安全漏洞的挖掘上投入了非常多的精力,尚且会被爆出许多高危漏洞影响巨大。也有许多优秀的开源产品,重点将精力投入到功能的开发与完善上,而未经过任何的安全审核。这些开源产品中,代码中很难避免地留有大量的安全漏洞,一旦被恶意攻击者利用将对用户造成巨大损失。

目前,国内存在许多提供给第三方用于快速接入的SDK库,然而其安全现状却令人堪忧。绝大部分第三方SDK均缺乏安全审核环节,造成代码中总是有较多的安全漏洞,影响接入该SDK的应用的安全性。对于缺乏安全审核能力的厂商,我们推荐使用360显危镜对Android应用进行线上漏洞扫描,扫描结果报告中将列出风险点供厂商评估修复。同时,针对Android应用中存在较多漏洞,且修复难度较大的问题,360Vulpecker在业内首创了安全SDK。在应用发布时接入该SDK,基于运行时修复技术可以在应用中修复绝大多数常见的通用型漏洞,致力于为缺乏Android应用漏洞修复能力的厂商提供简单通用的漏洞处理方案,使其不再受到常规漏洞的侵扰。目前,该安全SDK尚处于内测阶段,稍后会对外公开。

参考链接

 

团队介绍

360 Vulpecker Team

隶属于360公司信息安全部,致力于保护公司所有Android App及手机的安全,同时专注于移动安全研究,研究重点为安卓APP安全和安卓OEM手机安全。 团队定制了公司内部安卓产品安全开发规范,自主开发并维护了在线Android应用安全审计系统“360显危镜”,在大大提高工作效率的同时也为开发者提供了便捷的安全自测平台。同时研究发现了多个安卓系统上的通用型漏洞,如通用拒绝服务漏洞、“寄生兽”漏洞等,影响范围几乎包括市面上所有应用。

该团队高度活跃在谷歌、三星、华为等各大手机厂商的致谢名单中,挖掘的漏洞屡次获得CVE编号及致谢,在保证360产品安全的前提下,团队不断对外输出安全技术,为移动互联网安全贡献一份力量。

11

2017-09-29

BlueBorne 蓝牙漏洞深入分析与PoC

0x00

前些天,armis爆出了一系列蓝牙的漏洞,无接触无感知接管系统的能力有点可怕,而且基本上影响所有的蓝牙设备,危害不可估量,可以看这里来了解一下它的逆天能力:只要手机开启了蓝牙,就可能被远程控制。现在手机这么多,利用这个漏洞写出蠕虫化的工具,那么可能又是一个手机版的低配wannacry了。我们360Vulpecker Team在了解到这些相关信息后,快速进行了跟进分析。
armis给出了他们的whitepaper,对蓝牙架构和这几个漏洞的分析可以说非常详尽了,先膜一发。不过他们没有给出这些漏洞的PoC或者是exp,只给了一个针对Android的“BlueBorne检测app”,但是逆向这个发现仅仅是检测了系统的补丁日期。于是我来拾一波牙慧,把这几个漏洞再分析一下,然后把poc编写出来:
* CVE-2017-1000250 Linux bluetoothd进程信息泄露
* CVE-2017-1000251 Linux 内核栈溢出
* CVE-2017-0785 Android com.android.bluetooth进程信息泄露
* CVE-2017-0781 Android com.android.bluetooth进程堆溢出
* CVE-2017-0782 Android com.android.bluetooth进程堆溢出

以上PoC代码均在https://github.com/marsyy/littl_tools/tree/master/bluetooth
由于也是因为这几个漏洞才从零开始搞蓝牙,所以应该有些分析不到位的地方,还请各路大牛斧正。

0x01 蓝牙架构及代码分布

这里首先应该祭出armis的paper里的图:
Alt text
图上把蓝牙的各个层次关系描述得很详尽,不过我们这里暂时只需要关心这么几层:HCI,L2CAP,BNEP,SDP。BNEP和SDP是比较上层的服务,HCI在最底层,直接和蓝牙设备打交道,而承载在蓝牙服务和底层设备之间的桥梁,也就是L2CAP层了。每一层都有它协议规定的数据组织结构,所有层的数据包组合在一起,就是一个完整的蓝牙包(一个SDP包为例):
Alt text

虽然协议规定的架构是图上说的那样,但是具体实现是有不同的,Linux用的BlueZ,而现在的Android用的BlueDroid,也就针对这两种架构说一说代码的具体分布。

BlueZ

在Linux里,用的是BlueZ架构,由bluetoothd来提供BNEP,SDP这些比较上层的服务,而L2CAP层则是放在内核里面。对于BlueZ我们对SDP和L2CAP挨个分析。
1, 实现SDP服务的代码在代码目录的/src/sdpxx,其中sdp-client.c是它的客户端,sdp-server.c是它的服务端。我们要分析的漏洞都是远程的漏洞,所以问题是出在服务端里面,我们重点关注服务端。而服务端最核心的代码,应该是它对接受到的数据包的处理的过程,这个过程由sdp-request.c来实现。当L2CAP层有SDP数据后,会触发sdp-server.cio_session_event函数,来获取这个数据包,交由sdp-request.chandle_request函数处理(怎么处理的,后续漏洞分析的时候再讲):

static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
{
    ...
    len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK); //获取SDP的头部数据,获得SDP数据大小
    if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) {
        sdp_svcdb_collect_all(sk);
        return FALSE;
    }

    size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
    buf = malloc(size);
    if (!buf)
        return TRUE;

    len = recv(sk, buf, size, 0);  //获得完整数据包
    ...
    handle_request(sk, buf, len);

    return TRUE;
}

2, L2CAP层的代码在内核里,这里我以Linux 4.2.8这份代码为例。l2cap层主要由 /net/bluetooth/l2cap_core.c和/net/bluetooth/l2cap_sock.c来实现。l2cap_core.c实现了L2CAP协议的主要内容,l2cap_sock.c 通过注册sock协议的方式提供了这一层针对userspace的接口。同样的我们关心一个L2CAP对接受到数据包后的处理过程,L2CAP的数据是由HCI层传过来的,在hci_core.chci_rx_work函数里

static void hci_rx_work(struct work_struct *work)
{

    while ((skb = skb_dequeue(&hdev->rx_q))) {
        /* Send copy to monitor */
        hci_send_to_monitor(hdev, skb);

        ...
        switch (bt_cb(skb)->pkt_type) {
        case HCI_EVENT_PKT:
            BT_DBG("%s Event packet", hdev->name);
            hci_event_packet(hdev, skb);
            break;

        case HCI_ACLDATA_PKT:
            BT_DBG("%s ACL data packet", hdev->name);
            hci_acldata_packet(hdev, skb);
            break;

        case HCI_SCODATA_PKT:
            BT_DBG("%s SCO data packet", hdev->name);
            hci_scodata_packet(hdev, skb);
            break;

        default:
            kfree_skb(skb);
            break;
        }
    }
}

收到数据后,会判断pkt_type,符合L2CAP层的type是HCI_ACLDATA_PKT,函数会走到hci_acldata_packet,这个函数会把HCI的数据剥离之后,把L2CAP数据交给L2CAP层的l2cap_recv_acldata

static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
    ...
    skb_pull(skb, HCI_ACL_HDR_SIZE);
    ...
    if (conn) {
        hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);

        /* Send to upper protocol */
        l2cap_recv_acldata(conn, skb, flags);
        return;
    } else {
        BT_ERR("%s ACL packet for unknown connection handle %d",
               hdev->name, handle);
    }

    kfree_skb(skb);
}

同样的,对于L2CAP层对数据的细致处理,我们还是等后续和漏洞来一块进行分析。

BlueDroid

在现在的Android里,用的是BlueDroid架构。这个和BlueZ架构有很大不同的一点是:BlueDroid将L2CAP层放在了userspace。SDP,BNEP,L2CAP统统都由com.android.bluetooth这个进程管理。而BlueDroid代码的核心目录在Android源码目录下的 /sytem/bt ,这个目录的核心产物是bluetooth.default.so,这个so集成所有Android蓝牙相关的服务,而且这个so没有导出任何相关接口函数,只导出了几个协议相关的全局变量供使用,所以想根据so来本地检测本机是否有BlueDrone漏洞,是一件比较困难的事情。对于BlueDroid,由于android的几个漏洞出在BNEP服务和SDP服务,所以也就主要就针对这两块。值得注意的是,在Android里,不论是64位还是32位的系统,这个bluetooth.default.so都是用的32位的。文章里这部分代码都基于Android7.1.2的源码。
1,BlueDroid的SDP服务的代码,在/system/bt/stack/sdp 文件夹里,其中sdp服务端对数据包的处理由sdp-server.c实现。SDP连接建立起来后,在收到SDP数据包之后呢,会触发回调函数sdp_data_ind,这个函数会把数据包交个sdp-server.csdp_server_handle_client_req函数进行处理:

static void sdp_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
{
    tCONN_CB    *p_ccb;
    if ((p_ccb = sdpu_find_ccb_by_cid (l2cap_cid)) != NULL)
    {
        if (p_ccb->con_state == SDP_STATE_CONNECTED)
        {
            if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
                sdp_disc_server_rsp (p_ccb, p_msg);
            else
                sdp_server_handle_client_req (p_ccb, p_msg);
        }
    ...
}

2,BlueDroid的BNEP服务的代码主要在/system/bt/stack/bnep/bnep_main.c。BNEP连接建立起来后,再收到BNEP的包,和SDP类似,会触发回调函数bnep_data_ind,这个函数包含了所有对BNEP请求的处理,漏洞也是发生在这里,具体的代码我们后续会分析。

0x02 漏洞分析以及PoC写法

蓝牙的预备知识差不多了,主要是找数据包的入口。我们再基于漏洞和PoC的编写过程来详细分析其中的处理过程,和相关蓝牙操作的代码该怎么写。

CVE-2017-1000251

这个是Linux L2CAP层的漏洞,那么就是内核里面的。先不着急看漏洞,先看L2CAP层如何工作。在一个L2CAP连接的过程中,我们抓取了它的数据包来分析,L2CAP是怎么建立起连接的:
Alt text
我们注意这么几个包:
sent_infomation_request , send_connection_request, send_configure_request。抓包可以看到,在一次完整的L2CAP连接的建立过程中,发起连接的机器,会主动送出这么几个包。其中infomation_request是为了得到对方机器的名称等信息,connection_request是为了建立L2CAP真正的连接,主要是为了确定双方的CHANNEL ID,后续的数据包传输都要跟着这个channel id 走(图上的SCID, DCID),这个channel也就是我们所说的连接。在connection_request处理完毕之后,连接状态将变成 BT_CONNECT2 。随后机器会发起configure_request,这一步就到了armis的paper第十页所说的configuration process:
Alt text

这个过程完成后,整个L2CAP层的连接也就建立完成。


从上述过程看,可以发现L2CAP层连接的建立,主要是对上述三个请求的发起和处理。而我们的漏洞,也其实就发生在configuration​ ​ process​。我们先分析接收端收到这三个请求后,处理的逻辑在哪里,也就是我们前文提到的L2CAP对接受到的数据的处理过程:
1,在l2cap_recv_acldata接收到数据后,数据包会传给l2cap_recv_frame
2,l2cap_recv_frame会取出检查L2CAP的头部数据,然后检查根据头部里的cid字段,来选择处理逻辑:

static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
{
    ...
    skb_pull(skb, L2CAP_HDR_SIZE);
    cid = __le16_to_cpu(lh->cid);
    len = __le16_to_cpu(lh->len);

    switch (cid) {
    case L2CAP_CID_SIGNALING:
        l2cap_sig_channel(conn, skb);
        break;

    case L2CAP_CID_CONN_LESS:
        psm = get_unaligned((__le16 *) skb->data);
        skb_pull(skb, L2CAP_PSMLEN_SIZE);
        l2cap_conless_channel(conn, psm, skb);
        break;

    case L2CAP_CID_LE_SIGNALING:
        l2cap_le_sig_channel(conn, skb);
        break;

    default:
        l2cap_data_channel(conn, cid, skb);
        break;
    }

3,底层L2CAP的连接,cid固定是L2CAP_CID_SIGNALING,于是会走l2cap_sig_channell2cap_sig_channel得到的是剥离了头部的L2CAP的数据,这一部将把数据里的cmd头部解析并剥离,再传给l2cap_bredr_sig_cmd进行处理:

static inline void l2cap_sig_channel(struct l2cap_conn *conn,
                     struct sk_buff *skb)
{
    ...
    while (len >= L2CAP_CMD_HDR_SIZE) {
        u16 cmd_len;
        memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);  //取得cmd头部数据
        data += L2CAP_CMD_HDR_SIZE;
        len  -= L2CAP_CMD_HDR_SIZE;

        cmd_len = le16_to_cpu(cmd.len);  //取得cmd的大小
    ...
        err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data); //传给l2cap_bredr_sig_cmd处理
    ...
        data += cmd_len;
        len  -= cmd_len;
    }

drop:
    kfree_skb(skb);
}

到这里,我们应该能得出L2CAP协议的数据结构:

4, 随后数据进入到了l2cap_bredr_sig_cmd函数进行处理。这里也就是处理L2CAP各种请求的核心函数了:

static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                      struct l2cap_cmd_hdr *cmd, u16 cmd_len,
                      u8 *data)
{
    int err = 0;

    switch (cmd->code) {
    case L2CAP_CONN_REQ:
        err = l2cap_connect_req(conn, cmd, cmd_len, data);
        break;

    case L2CAP_CONN_RSP:
    case L2CAP_CREATE_CHAN_RSP:
        l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
        break;

    case L2CAP_CONF_REQ:
        err = l2cap_config_req(conn, cmd, cmd_len, data);
        break;

    case L2CAP_CONF_RSP: 
        l2cap_config_rsp(conn, cmd, cmd_len, data);  //漏洞函数
        break;
    ...
    case L2CAP_INFO_REQ:
        err = l2cap_information_req(conn, cmd, cmd_len, data);
        break;

    case L2CAP_INFO_RSP:
        l2cap_information_rsp(conn, cmd, cmd_len, data);
        break;
    ...
    }

    return err;
}

好了,接下来终于可以分析漏洞了。我们的漏洞发生在对L2CAP_CONFIG_RSP(config response)这个cmd的处理上。其实漏洞分析armis的paper已经写的很详尽了,我这里也就权当翻译了吧,然后再加点自己的理解。那么来看l2cap_config_rsp:

static inline int l2cap_config_rsp(struct l2cap_conn *conn,
                   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
                   u8 *data)
{
    struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
    ...

    scid   = __le16_to_cpu(rsp->scid);   //从包中剥离出scid
    flags  = __le16_to_cpu(rsp->flags);  //从包中剥离出flag
    result = __le16_to_cpu(rsp->result); //从包中剥离出result

    switch (result) {
    case L2CAP_CONF_SUCCESS:
        l2cap_conf_rfc_get(chan, rsp->data, len);
        clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
        break;

    case L2CAP_CONF_PENDING:
        set_bit(CONF_REM_CONF_PEND, &chan->conf_state);

        if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {  //判断conf_state是否是CONF_LOC_CONF_PEND
            char buf[64]; //buf数组大小64字节

            len = l2cap_parse_conf_rsp(chan, rsp->data, len,
                           buf, &result);   //data仍然是包中数据,len也是包中数据。
            ...
        }
        goto done;
    ...

当收到的数据包里,满足result == L2CAP_CONF_PENDING,且自身的连接状态conf_state == CONF_LOC_CONF_PEND的时候,会走到 l2cap_parse_conf_rsp函数里,而且传过去的buf是个长度为64的数据,参数len ,参数rsp->data都是由包中的内容来任意确定。那么在l2cap_parse_conf_rsp函数里:

static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
                void *data, u16 *result)
{
    struct l2cap_conf_req *req = data;
    void *ptr = req->data;
    int type, olen;
    unsigned long val;

    while (len >= L2CAP_CONF_OPT_SIZE) { //len没有被检查,由接收到的包内容控制
        len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);

        switch (type) {
        case L2CAP_CONF_MTU:
            if (val < L2CAP_DEFAULT_MIN_MTU) {
                *result = L2CAP_CONF_UNACCEPT;
                chan->imtu = L2CAP_DEFAULT_MIN_MTU;
            } else
                chan->imtu = val;
            l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
            break;
        case ...

        }
    }
}

static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
{
    struct l2cap_conf_opt *opt = *ptr;
    opt->type = type;
    opt->len  = len;

    switch (len) {
    case 1:
        *((u8 *) opt->val)  = val;
        break;

    case 2:
        put_unaligned_le16(val, opt->val);
        break;

    case 4:
        put_unaligned_le32(val, opt->val);
        break;

    default:
        memcpy(opt->val, (void *) val, len);
        break;
    }

    *ptr += L2CAP_CONF_OPT_SIZE + len;
}

仔细阅读这个函数的代码可以知道,这个函数的功能就是根据传进来的包,来构造将要发出去的包。而数据的出口就是传进去的64字节大小的buf。但是对传入的包的数据的长度并没有做检验,那么当len很大时,就会一直往出口buf里写数据,比如有64个L2CAP_CONF_MTU类型的opt,那么就会往buf里写上64*(L2CAP_CONF_OPT_SIZE + 2)个字节,那么显然这里就发生了溢出。由于buf是栈上定义的数据结构,那么这里就是一个栈溢出。
不过值得注意的是,代码要走进去,需要conf_state == CONF_LOC_CONF_PEND,这个状态是在处理L2CAP_CONF_REQ数据包的时候设置的:

static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
{
    ...
    u8 remote_efs = 0;
    u16 result = L2CAP_CONF_SUCCESS;
    ...
    while (len >= L2CAP_CONF_OPT_SIZE) {
        len -= l2cap_get_conf_opt(&req, &type, &olen, &val);  

        hint  = type & L2CAP_CONF_HINT;
        type &= L2CAP_CONF_MASK;

        switch (type) {
        ...
        case L2CAP_CONF_EFS:
            remote_efs = 1;  //【1】
            if (olen == sizeof(efs))
                memcpy(&efs, (void *) val, olen);
            break;
        ...
    }

done:
    ...
    if (result == L2CAP_CONF_SUCCESS) {
        ...
        if (remote_efs) {
            if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&   
                efs.stype != L2CAP_SERV_NOTRAFIC &&   //【2】
                efs.stype != chan->local_stype) {

                ...
            } else {
                /* Send PENDING Conf Rsp */
                result = L2CAP_CONF_PENDING;
                set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);  //这里设置CONF_LOC_CONF_PEND
            }
        }
}

当收到L2CAP_CONF_REQ的包中包含有L2CAP_CONF_EFS类型的数据【1】,而且L2CAP_CONF_EFS数据的stype == L2CAP_SERV_NOTRAFIC【2】的时候,conf_state会被置CONF_LOC_CONF_PEND


到这里,这个漏洞触发的思路也就清楚了:
1,建立和目标机器的L2CAP 连接,这里注意sock_type的选择要是SOCK_RAW,如果不是,内核会自动帮我们完成sent_infomation_request , send_connection_request, send_configure_request这些操作,也就无法触发目标机器的漏洞了。
2,建立SOCK_RAW连接,connect的时候,会自动完成sent_infomation_request的操作,不过这个不影响。
3,接下来我们需要完成send_connection_request操作,来确定SCID,DCID。完成这个操作的过程是发送合法的 L2CAP_CONN_REQ数据包。
4,接下来需要发送包含有L2CAP_CONF_EFS类型的数据,而且L2CAP_CONF_EFS数据的stype == L2CAP_SERV_NOTRAFICL2CAP_CONF_REQ包,这一步是为了让目标机器的conf_state变成CONF_LOC_CONF_PEND
5,这里就到了发送cmd_len很长的L2CAP_CONN_RSP包了。这个包的result字段需要是L2CAP_CONF_PENDING。那么这个包发过去之后,目标机器就内核栈溢出了,要么重启了,要么死机了。

这个漏洞是这几个漏洞里,触发最难的。

CVE-2017-1000250

这个漏洞是BlueZ的SDP服务里的信息泄露漏洞。这个不像L2CAP层的连接那么复杂,主要就是上层服务,收到数据就进行处理。那么我们也只需要关注处理的函数。
之前说过,BlueZ的SDP收到数据是从io_session_event开始。之后,数据的流向是:

io_session_event–>handle_request–>process_request

有必要介绍一下SDP协议的数据结构:
Alt text
它有一个sdp_pud_hdr的头部,头部数据里定义了PUD命令的类型,tid,以及pdu parameter的长度,然后就是具体的parameter。最后一个字段是continuation state,当一个包发不完所要发送的数据的时候,这个字段就会有效。对与这个字段,BlueZ给了它一个定义:

typedef struct {
    uint32_t timestamp;
    union {
        uint16_t maxBytesSent;
        uint16_t lastIndexSent;
    } cStateValue;
} sdp_cont_state_t;

对于远程的连接,PDU命令类型只能是这三个:SDP_SVC_SEARCH_REQ, SDP_SVC_ATTR_REQ, SDP_SVC_SEARCH_ATTR_REQ。这个漏洞呢,出现在对SDP_SVC_SEARCH_ATTR_REQ命令的处理函数里面 service_search_attr_req 。这个函数有点长,就直接说它干了啥,不贴代码了:
1, extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); 解析service search pattern(对应SDP协议数据结构图)
2,max = get_be16(pdata); 获得Maximu Attribute Byte
3,scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);解析Attribute ID list
4,if (sdp_cstate_get(pdata, data_left, &cstate) maxBytesSent就是由数据包里的数据所控制,而且没有做任何检验,所以这里可以为任意的uint16_t值。那么很明显,这里就出现了一个对pResponse的越界读的操作。而越界读的数据还会通过SDP RESPONSE发送给攻击方,那么一个信息泄露就发生了。


写这个poc需要注意sdp_get_cached_rsp的检验的绕过,那么首先需要得到一个timestamp。当一次发送的包不足以发送完所有的数据的时候,会设置cstate状态,所以如果我们发给服务端的包里,max字段非常小,那么服务端就会给我们回应一个带cstate状态的包,这里面会有timestamp:

if (cstate == NULL) {
        ...
        if (buf->data_size > max) {  //max 可由接收到的包数据指定
            sdp_cont_state_t newState;

            memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
            newState.timestamp = sdp_cstate_alloc_buf(buf); //这里得到一个timestamp

            buf->data_size = max;
            newState.cStateValue.maxBytesSent = max;
            cstate_size = sdp_set_cstate_pdu(buf, &newState); //回应的包中,写上cstate状态。
        } else
            cstate_size = sdp_set_cstate_pdu(buf, NULL);

所以,我们的poc应该是这个步骤:
1,建立SDP连接。这里我们的socket需要是SOCK_STREAM类型,而且connet的时候,addr的psm字段要是0x0001。关于连接的PSM:
Alt text
2,发送一个不带cstate状态的数据包,而且指定Maximu Attribute Byte的值非常小。这一步是为了让服务端给我们返回一个带timestamp的包。
3,接收这个带timestamp的包,并将timestamp提取。
4,发送一个带cstate状态的数据包,cstate的timestamp是指定为提取出来的值,服务端memcpy的时候,则就会把pResponse+maxBytesSent的内容发送给我们,读取这个数据包,则就获取了泄露的数据。

CVE-2017-0785

这个漏洞也是SDP的信息泄露漏洞,不过是BlueDroid的。与BlueZ的那个是有些类似的。我们也从对SDP数据包的处理函数说起。
SDP数据包会通过sdp_data_ind函数送给sdp_server_handle_client_req。与BlueZ一样,这个函数也会根据包中的pud_id来确定具体的处理函数。这个漏洞发生在对SDP_PDU_SERVICE_SEARCH_REQ命令的处理,对包内数据的解析与上文BlueZ中的大同小异,不过注意在BlueDroid中,cstate结构与BlueZ中有些不同:

typedef struct {

    uint16_t​ cont_offset;

} sdp_cont_state_t;

这里主要看漏洞:

①, BE_STREAM_TO_UINT16 (max_replies, p_req);从包中解析出Maximu Attribute Byte

②, for (num_rsp_handles = 0; num_rsp_handles < max_replies; ) 
    {
        p_rec = sdp_db_service_search (p_rec, &uid_seq);

        if (p_rec)
            rsp_handles[num_rsp_handles++] = p_rec->record_handle;
        else
            break;
    }

③, /* Check if this is a continuation request */
    if (*p_req)
    {
        if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
        {
            sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                     SDP_TEXT_BAD_CONT_LEN);
            return;
        }
        BE_STREAM_TO_UINT16 (cont_offset, p_req);  //从包中得到cont_offset

        if (cont_offset != p_ccb->cont_offset)  //对cont_offset的检验
        {
            sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
                                     SDP_TEXT_BAD_CONT_INX);
            return;
        }

        rem_handles = num_rsp_handles - cont_offset;    /* extract the remaining handles */
    }
   else
    { 
        rem_handles = num_rsp_handles;
        cont_offset = 0;
        p_ccb->cont_offset = 0;
    }

④, cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);

    if (rem_handles <= cur_handles)
        cur_handles = rem_handles;
    else /* Continuation is set */
    {
        p_ccb->cont_offset += cur_handles;
        is_cont = TRUE;
    }

⑤, for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
        UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);

①,②中代码可以看出,变量num_rsp_handles的值,一定程度上可以由包中的Maximu Attribute Byte字段控制。
③中代码是对带cstate的包的处理,第一步是对大小的检查,第二步是获得cont_offset,然后对cont_offset进行检查,第三步就到了
rem_handles = num_rsp_handles – cont_offset **
可以思考一种情况,如果num_rsp_handles cont_offset += cur_handles;
,cur_handles是一个固定的值,那么如果这个下溢的过程,发生很多次,p_ccb->cont_offset就会变得很大,那么在5处,就会有一个对rsp_handles数组的越界读的产生。


下面的操作可以让这个越界读发生:
1,发送一个不带cstate的包, 而且Maximu Attribute Byte字段设置的比较大。那么结果就是rem_handles = num_rsp_handles,而由于max_replies比较大,所以num_rsp_handles会成为一个比较大的值。只要在④中保证rem_handles > cur_handles,那么p_ccb->cont_offset就会成为一个非0值cur_handles。这一步是为了使得p_ccb->cont_offset成为一个非0值。
2,接收服务端的回应包,这个回应包里的cstate字段将会含有刚刚的p_ccb->cont_offset值,我们取得这个值。
3,发送一个带cstate的包,cont_offset指定为刚刚提取的值,而且设置Maximu Attribute Byte字段为0。那么服务端收到这个包后,就会走到**rem_handles = num_rsp_handles – cont_offset **从而发生整数下溢,同时p_ccb->cont_offset又递增一个cur_handles大小。
4,重复2和3的过程,那么p_ccb->cont_offset将越来越大,从而在⑤出发生越界读,我们提取服务端返回的数据,就可以获得泄露的信息的内容。

CVE-2017-0781

现在我们到了BNEP服务。BNEP的协议格式,下面两张图可以说明的很清楚:
Alt text

Alt text
BlueDroid中BNEP服务对于接受到的数据包的处理也不复杂:
1,解析得到BNEP_TYPE,得到extension位。
2,检查连接状态,如果已经连接则后续可以处理非BNEP_FRAME_CONTROL的包,如果没有建立连接,则后续只处理BNEP_FRAME_CONTROL的包。
3,去BNEP_TYPE对应的处理函数进行处理。
4,对于BNEP_TYPE不是BNEP_FRAME_CONTROL而且有extension位的,还需要对extension的数据进行处理。
5,调用pan层的回调函数。

值得注意的是,BNEP连接真正建立起来,需要先处理一个合法的BNEP_FRAME_CONTROL数据包。
CVE-2017-0781正是连接还没建立起来,在处理BNEP_FRAME_CONTROL时所发生的问题:

case BNEP_FRAME_CONTROL:
        ctrl_type = *p;
        p = bnep_process_control_packet (p_bcb, p, &rem_len, FALSE);

        if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
            p_bcb->con_state != BNEP_STATE_CONNECTED &&
            extension_present && p && rem_len)
        {
            p_bcb->p_pending_data = (BT_HDR *)osi_malloc(rem_len);
            memcpy((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len);
            p_bcb->p_pending_data->len    = rem_len;
            p_bcb->p_pending_data->offset = 0;
        }

上述代码中,malloc了一个rem_len的大小,这个是和收到的数据包的长度相关的。可是memcpy的时候,却是从p_bcb->p_pending_data+1开始拷贝数据,那么这里会直接溢出一个sizeof(*(p_bcb->p_pending_data))大小的内容。这个大小是8.所以只要代码走到这,就会有一个8字节大小的堆溢出。而要走到这,只需要过那个if的判断条件,而这个if其实是对BNEP_SETUP_CONNECTION_REQUEST_MSG命令处理失败后的错误处理函数。那么只要发送一个错误的BNEP_SETUP_CONNECTION_REQUEST_MSG命令包,就可以进入到这段代码了触发堆溢出了。


所以我们得到poc的编写过程:
1,建立BNEP连接,这个和SDP类似,只是需要指定PSM为BNEP对应的0x000F。
2,发送一个BNEP_TYPE为BNEP_FRAME_CONTROL,extension字段为1,ctrl_type为BNEP_SETUP_CONNECTION_REQUEST_MSG的错误的BNEP包:


CVE-2017-0782

这个也是由于BNEP协议引起的漏洞,首先它是个整数溢出,整数溢出导致的后果是堆溢出。
问题出在BNEP对extension字段的处理上:

UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext)
{
    UINT8       control_type;
    BOOLEAN     bad_pkt = FALSE;
    UINT16      len, ext_len = 0;

    if (is_ext)
    {
        ext_len = *p++; 【1】
        *rem_len = *rem_len - 1;
    }

    control_type = *p++;
    *rem_len = *rem_len - 1;

    switch (control_type)
    {
    ...
    default :
        bnep_send_command_not_understood (p_bcb, control_type);
        if (is_ext)
        {
            p += (ext_len - 1);
            *rem_len -= (ext_len - 1); 【2】
        }
        break;
    }

    if (bad_pkt)
    {
        BNEP_TRACE_ERROR ("BNEP - bad ctl pkt length: %d", *rem_len);
        *rem_len = 0;
        return NULL;
    }

    return p;
}

上述代码中,【1】的ext_len从数据包中获得,没有长度的检查,可为任意值。而当control_type为一个非法值的时候,会走到【2】,那么这里就很有说法了,我们如果设置ext_len比较大,那么这里就会发生一个整数下溢。从而使得rem_len变成一个很大的uint16_t的值。这个值将会影响后续的处理:

    while (extension_present && p && rem_len)
    {
        ext_type = *p;
        extension_present = ext_type >> 7;
        ext_type &= 0x7F;
        ...
        p++;
        rem_len--;
        p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE); 【1】
    }

    p_buf->offset += p_buf->len - rem_len;  
    p_buf->len     = rem_len;  【2】

    ...
    if (bnep_cb.p_data_buf_cb)
    {
        (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf,  fw_ext_present);  【3】
    }
  ...
        osi_free(p_buf);
    }

上面的代码中,【1】处将发生整数下溢出,使得rem_len成为一个很大的值(比如0xfffd),【2】处会将这个值赋值给p_buf->len。【3】处是回调函数处理这个p_buf,在BlueDroid中这个函数是pan_data_buf_ind_cb,这个函数会有一条路径调到bta_pan_data_buf_ind_cback,而在这个函数中:

static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
                                   BOOLEAN ext, BOOLEAN forward)
{
    tBTA_PAN_SCB *p_scb;
    BT_HDR *p_new_buf;

    if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
        /* offset smaller than data structure in front of actual data */
        p_new_buf = (BT_HDR *)osi_malloc(PAN_BUF_SIZE);
        memcpy((UINT8 *)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
               (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
        p_new_buf->len    = p_buf->len;
        p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
        osi_free(p_buf);
    } else {
    ...
}

memcpy用到了我们传进来的p_buf,而p_buf->len是刚刚下溢之后的很大的值,所以主要保证sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset,这里就会发生一次很大字节的堆溢出。


代码首先要走到extension的处理,这个的前提是连接状态是BNEP_STATE_CONNECTED。而这个状态的建立,需要服务端先接收一个正确的BNEP_SETUP_CONNECTION_REQUEST_MSG请求包,同时要想pan_data_buf_ind_cb调用到bta_pan_data_buf_ind_cback产生堆溢出,需要在建立连接的时候指定UUID为UUID_SERVCLASS_PANU可以阅读这两个函数来找到这样做的原因,这里就不再贴代码了。清楚这一点之后,我们就可以构造我们的poc了:
1,建立BNEP连接,这里只是建立起初步的连接,conn_state还不是BNEP_STATE_CONNECTED,这一步通过connect实现
2,发送一个正确的BNEP_SETUP_CONNECTION_REQUEST_MSG请求包,同时指定UUID为UUID_SERVCLASS_PANU。这个包将是这样子:

3,发送一个extension字段可导致整数下溢的包,而且注意控制pbuf->offset变得比较小:

这样PoC就完成了。
CVE-2017-0781和CVE-2017-0782导致了堆溢出,一般会使得com.android.bluetooth崩溃,但是这个进程崩溃系统不会有提醒,需要去logcat来找崩溃的日志。这是两个很有品质的堆溢出漏洞,结合前面的信息泄露漏洞,是完全可以转化为远程代码执行的。

0x03

这篇分析到这里也就结束了,蓝牙出漏洞是个比较危险的事情,希望没有修补的能尽快修补,补丁链接如下:

CVE-2017-1000250

CVE-2017-1000251

CVE-2017-0785

CVE-2017-0781

CVE-2017-0782

确定自己是否有漏洞可以用我们提供的poc呀,关于蓝牙漏洞的研究,也希望能和各位多多交流。

参考文档:

1,https://www.armis.com/blueborne/

2,http://blog.csdn.net/rain0993/article/details/8533246

3,https://people.csail.mit.edu/albert/bluez-intro/index.html

0x04

360Vulpecker Team:
隶属于360公司信息安全部,致力于保护公司所有Android App及手机的安全,同时专注于移动安全研究,研究重点为安卓APP安全和安卓OEM手机安全。 团队定制了公司内部安卓产品安全开发规范,自主开发并维护了在线Android应用安全审计系统“360显危镜”,在大大提高工作效率的同时也为开发者提供了便捷的安全自测平台。同时研究发现了多个安卓系统上的通用型漏洞,如通用拒绝服务漏洞、“寄生兽”漏洞等,影响范围几乎包括市面上所有应用。
该团队高度活跃在谷歌、三星、华为等各大手机厂商的致谢名单中,挖掘的漏洞屡次获得CVE编号及致谢,在保证360产品安全的前提下,团队不断对外输出安全技术,为移动互联网安全贡献一份力量。

2016-12-09

本月一共有79个安全漏洞,其中Critical 12个,High 46个,Moderate 20个,Low 1个其中属于Aosp部分的有23个,驱动和kernel的有56个。

 

下面是与10月份的漏洞数量对比图:

 

漏洞分布情况对比图:

漏洞详细情况分析整理

  • Aosp高风险安全漏洞

下图是这个月aosp漏洞的整理

A)以下高风险安全漏洞在mediaserver组件中,可以被任意app触发。

CVE-2016-3862是一个Critical级的mediaserver漏洞。影响framework.jar。

Mediaserver的远程代码执行漏洞能够通过精心构造一个媒体文件来破坏内存,达到远程利用的效果。

CVE-2016-3862这次的更新是对一个旧的漏洞的升级。这次更新是在使用ExifInterface加载大量的图片时,如果I/O出现问题后可以返回。

 

CVE-2016-6761、CVE-2016-6760、CVE-2016-6759、CVE-2016-6758、CVE-2016-6704是五个High级别的mediaserver漏洞。分别影响libOmxVenc.so、libOmxVdec.so、libvisualizer.so,libqcomvisualizer.so四个文件。

Mediaserver的提权漏洞可以被手机里的任意app利用,来获取更高的权限,并在特权进程执行任意代码。

CVE-2016-6761是在omx_video::allocate_input_buffer()方法里使用m_sInPortDef.nBufferCountActual申请了一段内存。这段可以被通过使用一个畸形binder请求修改,导致堆溢出。

CVE-2016-6760是omx_vdec::allocate_output_headers()申请了一段内存,大小是drv_ctx.op_buf.actualcount。但是drv_ctx.op_buf.actualcount可以通过一个畸形的binder访问修改,导致堆溢出。

CVE-2016-6759是omx_vdec::empty_this_buffer()没有验证要清空buffer的index,可能导致越界写。

CVE-2016-6758是omx_vdec::empty_this_buffer_proxy()没有校验buffer。如果一个buffer是在secure memory申请的,在memcpy之前调用了omx_vdec::empty_this_buffer_proxy()可能导致堆溢出。

CVE-2016-6704的补丁是对上一次补丁的一次升级。修补的问题是在编译的debug版本中会返回一个null引用。

 

B)以下高风险安全漏洞在curl和libcurl模块中。

CVE-2016-5419、CVE-2016-5420、CVE-2016-5421是三个High级的远程代码执行漏洞。

这三个漏洞是可能导致中间人攻击。被评为High是因为需要一个伪造的证书。Patch位于https://curl.haxx.se/changes.html#7_50_1

 

C)其他High级别的漏洞

CVE-2016-6762是libziparchive一个权限提升的漏洞。问题的根源是两个32位的整型相加可能产生溢出并且和第三个32位整型相比较。最终在控制mmaped的内存使用一个被控制的offset。解引用的地址是可以被控制的,最终导致内存破坏或权限提升。

 

D)其他风险级别较低的受影响文件

TeleService.apk、libstagefright.so、services.jar、libstagefright.so、libchromium_net.so、libframesequence.so、libwifi-service.so、libstagefright_soft_avcdec.so

 

  • kernel高风险安全漏洞

CVE-2016-4794 是内核内存子系统中一个可以在内核上下文中任意执行远程代码的漏洞.在Linux内核4.6版本中,有一个潜在的UAF漏洞存在于mm/percpu.c当中.它允许本地用户通过构造mmap和bpf系统调用导致拒绝服务.补丁中的代码将大多数非原子分配置于pcpu_alloc_mutex下,以与pcpu_balance_work同步,并将异步映射扩展操作转储到pcpu_balance_work,以防止UAF漏洞.A).Critical级提权的漏洞

 

CVE-2016-5195 是内核内存子系统中一个可以在内核上下文中任意执行远程代码的漏洞(脏牛漏洞).由于内存子系统处理私有只读存储器映射的写时复制时存在竞争条件.本地攻击者可以使用它来获得对只读存储器的写入访问,例如可执行文件的内存缓存版本,并且可能在特权进程的上下文中获得任意代码执行.补丁中的代码增加了一个FOLL_COW的标识,然后使用pte的dirty标识来验证FOLL_COW是否有效,以此来防止潜在的任意代码执行.

 

CVE-2015-8966 是内核中一个可以在内核上下文中任意执行远程代码的漏洞.在sys_oabi_fcntl64函数中,KERNEL_DS如果没有被及时设置回USER_DS就会导致任意内存读写的问题.补丁中的代码是在返回之前设置回USER_DS来阻止潜在的问题.

 

CVE-2016-9120 是内核ION驱动中可以在内核上下文中任意执行任意代码的漏洞.在涉及ion_handle结构有个竞争问题导致了UAF漏洞的出现.补丁中的代码增加了适当的锁来阻止潜在的UAF漏洞.

 

B).High级提权的漏洞

CVE-2014-4014 是内核文件系统中的提权漏洞.可以导致本地恶意应用程序绕过与其他应用程序隔离的系统保护.在3.14.8之前的Linux内核中实现的功能中没有正确地考虑命名空间不适用于inode,这允许本地用户通过首先创建用户命名空间来绕过预期的chmod限制,如通过设置带有组的文件的setgid位所示root权限.补丁修复程序在更改inode_capable以检查uid和gid映射,以防止权限绕过.

 

CVE-2015-8967 是内核中一个可以在内核上下文中任意执行远程代码的漏洞.sys_call_table可写导致了潜在的任意代码执行.补丁中的代码标记了放在rodata段的sys_call_table常量,这可以导致尝试修改它失败,在严格的页表权限控制下,防止了潜在的任意代码执行.

 

CVE-2016-6786和CVE-2016-6787是内核performance子系统中的一个可以在内核上下文中任意执行远程代码的漏洞.在涉及perf_event结构中的一个竞争问题,导致了潜在 的UAF漏洞出现.补丁中的代码增加了合适的锁来防止潜在的UAF漏洞出现.

 

CVE-2015-7872 是内核安全子系统中的一个可以在内核上下文中任意执行远程代码的漏洞.在Linux4.2.6版本中security/keys/gc.c文件中的key_gc_unused_keys函数中允许本地用户通过恶意构造keyctl命令来执行代码.补丁中的代码增加了检查来阻止潜在的代码执行问题.

 

CVE-2016-1583 是内核加密文件系统中的一个可以在内核上下文中任意执行远程代码的漏洞.原始修复是通过实现仅打开文件的mmap操作来引入对较低文件系统的依赖.更新的补丁设计具有mmap处理的实例来替换.

 

C).Moderate级漏洞

CVE-2016-8399 是内核网络子系统中的一个可以在内核上下文中任意执行远程代码的漏洞.在ping_common_sendmsg函数中,传递的icmph_len变量的长度没有校验充分导致潜在的数据溢出.补丁中的代码增加了额外的检查来防止溢出.

 

CVE-2016-8401,CVE-2016-8402,CVE-2016-8403,CVE-2016-8404,CVE-2016-8406,CVE-2016-8407都是内核组件中的可以导致恶意应用程序使用权限之外的数据的漏洞.%p可以导致泄漏内核地址,补丁中的代码使用%pK来替换%p,防止泄漏内核地址.

 

CVE-2016-8405 是内核组件中的可以导致恶意应用程序使用权限之外的数据的漏洞.fb_cmap_to_user函数中,没有考虑to->start变量小于0的情况,因此导致了信息泄漏问题的出现.补丁中的代码加强了边界检查来避免这个问题.

 

D). Low级提权的漏洞

CVE-2016-6690 是内核音频驱动中的一个可以导致设备重启的漏洞.原来的固定使用EIO作为错误返回代码但函数签名有unsigned int作为返回类型.补丁中的代码用-1替换掉了原来的-EIO来修正这个问题.

 

  • 驱动漏洞

A).高通驱动漏洞

CVE-2016-8411 是高通MSM接口中一个可以在内核上下文中任意执行远程代码的漏洞.在处理QMI QOS NSTD过滤器或NW支持的QOS配置文件TLV时,没有对过滤器或配置文件缓冲区索引进行边界检查.当我们从调制解调器获得QOS指示,并且配置文件数量大于QMI_QOS_MAX_PROFILES或者如果过滤器规格缓冲区大于QMI_QOS_MAX_FLOW_FILTER,则发生缓冲区溢出.

 

CVE-2016-6755 是高通照相机驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在msm_actuator_parse_i2c_params函数中,有一个不正确的边界检查导致潜在的堆缓冲区溢出.补丁中的代码修复了边界检查来阻止潜在的堆缓冲区溢出问题.

 

CVE-2016-6791,CVE-2016-8391和CVE-2016-8392都是高通音频驱动中的可以在内核上下文中任意执行远程代码的漏洞.在涉及到audio_aio_ion_region结构中存在竞争问题,因此导致了潜在的UAF漏洞.补丁中的代码增加了适当的锁来修复UAF问题的出现.

 

CVE-2016-8410 是高通音频驱动可以导致恶意应用程序使用权限之外的数据的漏洞.%p可以导致泄漏内核地址,补丁中的代码使用%pK来替换%p,防止泄漏内核地址.

 

B).MediaTek驱动漏洞

CVE-2016-6492 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.传递给MT6573FDVT_SetRegHW函数的a_pstCfg变量没有经过校验,导致潜在的内存破坏问题出现.补丁中的代码增加了边界检查来修复这个问题.

 

CVE-2016-6781 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在rgidle_state_store函数中,由于拷贝的数据没有约束导致了潜在的栈溢出问题.补丁中的代码增加了临界检查来防止这个问题的出现.

 

CVE-2016-6782 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在mt_gpio_store_pin 函数中,由于拷贝的数据没有约束导致了潜在的栈溢出问题.补丁中的代码增加了临界检查来防止这个问题的出现.

 

CVE-2016-6783 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在__enable_ssc函数中,传递的变量pll_id没有经过校验,从而导致了潜在的内存破坏问题的出现.补丁中的代码增加了临界检查来阻止潜在的问题.

 

CVE-2016-6784 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在__disable_ssc函数中,传递的变量pll_id没有经过校验,从而导致了潜在的内存破坏问题的出现.补丁中的代码增加了临界检查来阻止内存漏洞.

 

CVE-2016-6785 是MediaTek驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在TMP103_HW_Write_Proc函数中,由于拷贝的数据没有约束导致了栈溢出问题的出现.补丁中的代码增加了边界检查来防止这个问题.

 

CVE-2016-6788 是MediaTek I2C驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在set_config函数中,由于拷贝的数据没有约束导致了潜在的溢出问题.补丁中的代码限制了拷贝的大小来阻止潜在的溢出问题.

 

CVE-2016-8396 是MediaTek视频驱动中的一个可以导致恶意应用程序使用权限之外的数据的漏洞.VAL_VCODEC_CPU_LOADING_INFO_T结构没有初始化就拷贝给用户导致了潜在的信息泄漏问题.补丁中的代码在初始化的时候将该结构清零来阻止潜在的信息泄漏问题.

 

C). NVIDIA 驱动漏洞

CVE-2016-6775 是英伟达GPU驱动中可以在内核上下文中任意执行任意代码的漏洞.在涉及到nvmap_handle_info的结构中存在一个竞争条件的问题会导致UAF漏洞的出现.补丁中的代码使用nvmap_get_dmabuf_fd函数替换了nvmap_create_fd函数来阻止潜在的UAF风险.

 

CVE-2016-6776 是英伟达GPU驱动中可以在内核上下文中任意执行任意代码的漏洞.在涉及到vm_gk20a的结构中存在一个竞争条件的问题会导致UAF漏洞的出现.补丁中的代码是确保VM对象的至少有一个通道的使用,防止UAF的漏洞出现.

 

CVE-2016-6777 是英伟达GPU驱动中可以在内核上下文中任意执行任意代码的漏洞.存在一个和ch->error_notifier变量存在条件竞争的问题导致了UAF漏洞的出现.补丁中的代码增加了适当的锁来防止潜在的问题.

 

CVE-2016-6915 和 CVE-2016-6916 是英伟达视频驱动中可以在内核上下文中任意执行任意代码的漏洞.num_syncpt_incrs变量在传递给nvhost_ioctl_channel_submit函数中就使用导致了栈溢出问题.补丁中的代码增加了对输入参数的校验来防止这个问题的出现.

 

CVE-2016-6917 是英伟达视频驱动中可以在内核上下文中任意执行任意代码的漏洞.在32位体系的机器上,在job_size函数中,由于num_unpins变量的设置存在整形溢出问题.补丁中把变量类型全部设置成u64来防止这个问题.

 

CVE-2016-8397 是英伟达视频驱动中的一个可以导致恶意应用程序使用权限之外的数据的漏洞.在nvmap_ioctl_get_param函数中,由于没有检验参数而导致了潜在的信息泄漏问题.补丁中的代码检查了nvmap_get_handle_param的返回值来判断是否信息泄漏.

 

CVE-2016-8395 是英伟达照相机驱动中拒绝服务漏洞.regmap_read函数在写入数据的时候是一个整形指针的变量,没有检查直接使用导致了潜在的溢出问题.补丁中的代码在读入数据前增加了校验防止拷贝越界.

 

CVE-2016-8408 和CVE-2016-8409都是英伟达视频驱动中的可以导致恶意应用程序使用权限之外的数据的漏洞.%p可以导致泄漏内核地址,补丁中的代码使用%pK来替换%p,防止泄漏内核地址.

 

D). 其他驱动漏洞

CVE-2016-6778 和CVE-2016-6779 是HTC音频codec驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.由于没有验证cmd变量是否小于sizeof(struct tfa9895_i2c_buffer)导致了潜在的堆溢出问题.补丁中的代码增加了边界检查来阻止潜在的堆溢出问题.

 

CVE-2016-6780 是HTC音频codec驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在rt5506_ioctl函数中,有一个涉及rt5506_cfg_data.cmd_data变量的竞争条件问题导致了潜在的UAF漏洞.补丁中的代码增加了适当的锁来避免UAF问题的出现.

 

CVE-2016-8393 是Synaptics触摸屏驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在fwu_get_image_firmware_id函数中,由于没有限制索引导致了潜在的堆缓冲区溢出问题.补丁中的代码增加了边界检查来阻止潜在的堆缓冲区溢出问题.

 

CVE-2016-8394 是Synaptics触摸屏驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在fwu_sysfs_image_name_store函数中,由于拷贝没有约束而导致了潜在的堆缓冲区溢出问题.补丁中的代码增加了边界检查来阻止潜在的堆缓冲区溢出问题.

 

CVE-2014-9909 是博通wifi驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在wl_android_priv_cmd函数中,由于priv_cmd.total_len变量没有考虑到负数的情况而导致了潜在的堆溢出漏洞.补丁中的代码增加了额外的检查来修复潜在的堆溢出漏洞.

 

CVE-2014-9910 是博通wifi驱动中的一个可以在内核上下文中任意执行远程代码的漏洞.在wls_parse_batching_cmd函数中,由于拷贝的数据没有约束导致了潜在的溢出问题.补丁中的代码限制了拷贝的大小来阻止潜在问题的出现.

 

  • 高通组件漏洞

CVE-2016-5341 是高通GPS组件中一个能被远程攻击者导致系统崩溃或者重启的漏洞.部分文件通过HTTP传输,由于该通信协议缺乏安全性,恶意攻击者可能能够使用中间人攻击提供任意数据.此修复程序旨在将XTRA客户端版本修改为包括签名,将端点更改为使用HTTPS或同时使用两者的版本.

 

CVE-2016-6756 是高通组件中的一个可以导致恶意应用程序使用权限之外的数据的漏洞.在msm_cpp_subdev_ioctl函数中,如果_IOC_DIR(cmd)是_IOC_NONE就会导致信息泄漏问题的出现,补丁中的代码增加了边界检查来阻止潜在的信息泄漏问题.

 

CVE-2016-6757 是高通组件中的一个可以导致恶意应用程序使用权限之外的数据的漏洞.%p可以导致泄漏内核地址,补丁中的代码使用%pK来替换%p,防止泄漏内核地址.

  • 受影响进程列表

2016-11-08

11月安全补丁风险评估

本月一共有91个安全漏洞,其中Critical 26个,High 44个,Moderate 21个,其中属于Aosp部分的有34个,驱动和kernel的有57个。

 

 

下面是与10月份的漏洞数量对比图:

漏洞详细情况分析整理

  • Aosp高风险安全漏洞

下图是这个月aosp漏洞的整理。

 

A)以下高风险安全漏洞在mediaserver组件中,可以被任意app触发。

CVE-2016-6699、CVE-2016-3862是两个Critical级的mediaserver漏洞。分别影响libstagefright.so、framework.jar两个文件。Mediaserver的远程代码执行漏洞能够通过精心构造一个媒体文件来破坏内存,达到远程利用的效果。

CVE-2016-6699是在MediaHTTP.cpp中,重连方法调用mLastURI.c_str()得到URI,并且在没有检查是否和mData相等就free,可能导致use after free。

CVE-2016-3862 这次的的补丁是对8月份的补丁的一个升级,上次的补丁在调用ExifInterface#saveAttributes()后可能导致PNG图片内存被破坏。

CVE-2016-6704、CVE-2016-6705、CVE-2016-6706是三个High级别的mediaserver漏洞。分别影响libvisualizer.so、libradio.so、libstagefright_omx.so三个文件。Mediaserver的提权漏洞可以被手机里的任意app利用,来获取更高的权限,并在特权进程执行任意代码。

CVE-2016-6704是一个无效replySize在effect_descriptor_t gVisualizerDescriptor可能导致堆溢出。

CVE-2016-6705 service interface 使用一个指针引用代替强指针可能导致在竞争条件下service指针已经释放,但是有另一个线程正在使用。这能触发一个use-after-free漏洞。

CVE-2016-6706是在IOMXNodeInstance.cpp,enableNativeBuffers接受一个任意的portIndex,没有校验的情况下,在IOMXNodeInstance结构里一个可以控制的偏移写一个dword值为0或者1。

 

B)以下高风险安全漏洞在libzipfile中。

CVE-2016-6700是Critical级的提权漏洞,android系统很多地方使用到了libzipfile(STATIC_LIBRARY)。entry->uncompressedSize和entry->data的值可以修改超出缓冲区边界的值,可能导致代码执行。

 

C)其他High级别的漏洞

CVE-2016-6702是libjpeg一个远程代码执行漏洞。可以使用一个特殊构造的文件来达到任意代码执行的目的。一个特殊构造的JPEG文件(size大于2的32次方)可以调用jpeg_open_backing_store在ashmem导致整数溢出。可能导致远程代码执行。

CVE-2016-6703是一个Android Runtime的远程代码执行漏洞。攻击者可以使用特制的payload在低权限进程执行任意代码。64位的IDN.toASCII()函数,一个很长的域名可能栈溢出,导致任意代码执行。

CVE-2016-6707当进程间共享bitmap时,android.graphics.Bitmap类设定的ashmem的大小是由用户提供的。并用它来匹配实际bitmap的大小。Bitmap构造器需要查询ashmen的大小。

CVE-2016-6708是一个SystemUI的提权漏洞,任意app可以用来绕过安全性提示。

CVE-2016-3912是对9月份补丁的一次再升级,修改了一处可能造成ActivityManagerService死锁的情况。

CVE-2016-3911是对9月份补丁的一次再升级,最初的补丁只是修复了受影响目标的文件描述符。经过讨论发现,这个问题会影响从Zygote到它的子进程泄露所有的文件描述符。恶意程序可以修改文件描述符的seek,而其他进程会使用这些。

 

D)其他风险级别较低的受影响文件

services.jar、Launcher3.apk、libmedia.so、Settings.apk、libstagefright_omx.so、libstagefright.so

 

  • kernel高风险安全漏洞

A).Critical级提权的漏洞

CVE-2016-6728 是内核ION子系统中一个导致本地程序在内核上下文中执行任意代码的漏洞.恶意程序可以通过ION来分配堆创建特定的内存块,对物理硬件进行攻击.

CVE-2016-6828 是内核networking子系统中一个导致本地程序在内核上下文中执行任意代码的漏洞.当tcp_sendmsg函数分配一个新的skb结构时,把它放入写入队列的尾部.在失败的条件判断下,遗留下的空指针会导致UAF问题.

CVE-2016-2184 是内核sound子系统中一个导致本地程序在内核上下文中执行任意代码漏洞.create_fixed_stream_quirk,snd_usb_parse_audio_interface,和create_uaxx_quirk函数分配了audioformat对象,并且在返回之前错误地释放了它,因此导致内存破坏.补丁中的代码在释放之前取消了audioformat对象的关联,防止潜在的内存破坏.

CVE-2016-7910 是内核文件系统中的一个导致本地程序在内核上下文中执行任意代码的漏洞.一个失败的条件判断可以导致潜在的UAF漏洞,补丁中的代码把私有指针设置为NULL,来避免野指针的复用.

CVE-2016-7911 是内核文件系统中的一个导致本地程序在内核上下文中执行任意代码的漏洞.在访问task->io_context时出现竞争就会导致UAF漏洞的出现,因此补丁中的代码在访问task结构的前后都进行了锁的操作.

CVE-2016-8961 是内核文件系统中的一个导致本地程序在内核上下文中执行任意代码的漏洞.在函数__ext4_journal_stop中,jbd2_journal_stop函数释放掉handle指针后又被复用,因此造成了UAF问题.补丁中的代码把handle的值提前存储到本地变量中来避免复用.

CVE-2015-8962 是内核SCSI驱动中的一个导致本地程序在内核上下文中执行任意代码的漏洞.在函数sg_common_write中,如果设备在SG_IO的ioctl中被分离,块设备请求被释放掉并且返回-ENODEV.然而在sg_finish_rem_req函数在返回之前也释放了srp->rq,在释放rq对象后rq->cmd中再次释放,造成了double free的问题.补丁中的代码把srp->rq的值设置为NULL,防止在失败返回的分支中再次释放.

CVE-2016-7912 是内核USB驱动中的一个导致本地程序在内核上下文中执行任意代码的漏洞.当在使用USB上异步读取或写入操作的时候,通过调用ki_complete()回调通知IO请求的发出者在完成时提交kiocb.然而ki_complete()函数会提前释放掉kiocb,因此导致了UAF漏洞的出现.补丁中的代码保证kiocb在释放后不再使用,避免了这个问题.

CVE-2016-7913 是内核media驱动中的一个导致本地程序在内核上下文中执行任意代码的漏洞.在xc2028_set_config函数中,如果没有固件名的校验,直接传递xc2028_config结构有可能出现UAF的问题.补丁中的代码把固件名的值最后设置为NULL,来防止释放后再重用.

CVE-2016-6737 是内核ION子系统中的一个导致本地程序在内核上下文中执行任意代码的漏洞.竞争条件导致了潜在的UAF漏洞,补丁中的代码禁用了某种类型的堆.

CVE-2013-7446 是内核Networking子系统中的一个导致本地程序在内核上下文中执行任意代码的漏洞.原来的修复设计是把unix_dgram_poll函数中,移除sock_poll_wait的第二次调用来阻止UAF漏洞.新更新的的补丁中,修复了不正确的原始校验.

 

 

B).High级提权的漏洞

CVE-2016-6136 是内核系统调用审计子系统中的一个可能使本地恶意应用程序中断内核中的系统调用审计的提权漏洞.在Linux内核4.7版的auditsc.c文件中的audit_log_single_execve_arg函数中的一个竞争条件导致本地用户通过修改某个字符串绕过限制或系统调用审计.补丁中的代码把参数的数据存入缓冲区中.并且记录到审计记录中防止竞争条件.

CVE-2016-7914 是内核组件中的一个信息泄漏的漏洞.在assoc_array_insert_into_terminal_node函数中compare_object方法在所有的非空slot中调用,传递指针给给compare_object,导致了越界读的问题.补丁中的代码只有在slot 处于leave状态的时候才能调用compare_object来避免越界读的问题.

CVE-2015-8963 是内核performance子系统中一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在释放SWEVENT结构的哈希数组后,由于CPU中的线程有竞争关系的存在因此会导致UAF问题.补丁中的代码在最后一个SWEVENT结构结束后会自动释放来避免这个问题.

CVE-2015-8964 是内核组件中的一个信息泄漏的漏洞.滥用ldisc字段会导致信息泄漏,补丁中的代码在tty_set_termios_ldisc函数初始化时把tty结构清零防止信息泄漏.

CVE-2016-7915 是内核组件中的一个信息泄漏的漏洞.在补丁的代码中,hid_input_field函数增加了边界的检查,来防止潜在的越界读漏洞.

CVE-2016-7916 是内核组件中的一个信息泄漏的漏洞.如果在envp数组完全设置之前读取了/proc/pid/environ,则会出现潜在的信息泄露漏洞,因为可以读取的字节数比实际写入的字节多.补丁中的代码增加了对env_end变量地校验,防止信息泄漏.

 

C).Moderate级漏洞

CVE-2016-6753 是内核组件中的信息泄漏漏洞.在没有设置kptr_restrict情况下,%p都导致了信息泄漏,补丁中的代码把%p改为%pk来防止信息泄漏.

CVE-2016-7917 是内核组件中的信息泄漏漏洞.在nfnetlink_rcv_batch函数中,如果length校验出现问题,就会导致越界读的问题.补丁中的代码增加了临界校验来避免潜在的越界读问题.

 

  • 高通和MTK的驱动漏洞

A).高通驱动漏洞

 

CVE-2016-6727 是高通GPS子系统中一个可以在内核上下文中任意执行远程代码的漏洞.当通过http下载和处理XTRA blobs的时候,使用loc_xtra_download_bin没有校验需要读取的值,如果没有考虑到负数的情况,就可能导致整数溢出,从而缓冲区溢出.

CVE-2016-6725 是高通加密驱动中一个可以在内核上下文中任意执行远程代码的漏洞.在_qcrypto_process_aead函数中,由于判断的定义是ULONG,但是变量的类型是UINT,所以导致了整形溢出.补丁中用UINT_MAX替换掉了ULONG_MAX来保证整数溢出的校验.

CVE-2016-6726 是高通radio中一个可以在内核上下文中任意执行远程代码的漏洞.在某种情况下,为SubjectAltName分配的扩展内容不足,无法包含NULL终止符,容易导致内存破坏.补丁中增加了空间的分配来避免这个问题.

CVE-2016-6729 是高通bootloader中一个导致本地程序在内核上下文中执行任意代码的漏洞.在更新设备树中添加/更新DT节点之前,没有检查存储器范围不与上述存储器区域是否重叠.补丁中的代码修复添加了一个错误的条件判断是否是更新DT节点入口时会导致内存区重叠.

CVE-2016-6738 是高通加密引擎驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在qcedev_vbuf_ablk_cipher函数中,可以绕过对目标地址的校验,导致内存破坏.补丁中的代码各自校验了目标地址和源地址来防止内存破坏.

CVE-2016-6739 是高通照相机驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在msm_cpp_cfg_frame函数中,new_frame->num_strips变量由于没有被校验,所以会导致潜在的堆溢出问题.代码中的设计加强了边界检测来防止堆溢出漏洞.

CVE-2016-6740 是高通照相机驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在msm_camera_qup_i2c_write_seq函数中,由于变量的大小是用户态可控的,所以会导致潜在的栈溢出问题.补丁中的代码增加了对边界的校验来防止这个问题.

CVE-2016-6741 是高通照相机驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在msm_camera_qup_i2c_read和msm_camera_qup_i2c_read_seq函数中栈的变量都是用户可控所以容易导致栈溢出.补丁中的代码都加强了对边界的校验来防止这个问题.

CVE-2016-3904 是高通bus驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.由于字符串的长度没有进行校验,所以当读入到缓冲区时可能会造成栈溢出.补丁中的代码加入了最大值读取的限制来避免这个问题.

CVE-2014-9874 是高通音频驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.原始的修复是给整数变量增加边界检查,但是导致在电话通话期间音频录制导致中断.新补丁中的代码对这些问题进行了修复.

CVE-2016-3850 是高通bootloader驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.原始的修复是为了linux镜像设计的,而不是安卓.在新的补丁中增加了整数溢出的检查.

 

B).英伟达驱动漏洞

CVE-2016-6730,CVE-2016-6731,CVE-2016-6732,CVE-2016-6733,CVE-2016-6734,CVE-2016-6735和CVE-2016-6736是英伟达GPU驱动中能导致本地程序在内核上下文中执行任意代码的漏洞.涉及到tegra_drm_context的调用中出现了竞争条件的问题,因此导致了UAF漏洞的出现.补丁中增加了适当的锁来阻止资源的竞争,避免了UAF漏洞.

CVE-2016-6746 是英伟达GPU驱动中的一个信息泄漏漏洞.有个涉及到tegra_drm_context结构的竞争问题会出现信息泄漏.补丁中添加了锁,来防止潜在的问题.

 

C).其他驱动漏洞

CVE-2016-6742 和 CVE-2016-6743 是Synaptics触摸屏驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在fwu_sysfs_store_image函数中,没有对count变量进行检验,所以导致了潜在的堆溢出漏洞.补丁中的代码增加了边界检查来避免这个问题.

CVE-2016-6744 是Synaptics触摸屏驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.在synaptics_rmi4_reg_control_store函数中由于偏移值没有考虑到负数的情况,因此导致了栈溢出.补丁中的代码把无符号数转换成了有符号数来修复问题.

CVE-2016-6745 是Synaptics触摸屏驱动中的一个能够让本地恶意程序在内核上下文中执行任意代码的漏洞.全局变量fwu在函数fwu_sysfs_image_size_store和函数fwu_sysfs_store_image都可以使用,在没有加锁的情况下很容易造成竞争条件的漏洞.补丁中的代码加入了锁来阻止竞争问题.

 

  • 高通组件漏洞    CVE-2016-6748,CVE-2016-6749,CVE-2016-6750和CVE-2016-6751 都是高通组件中的信息泄漏漏洞.在没有设置kptr_restrict情况下,%p都导致了信息泄漏,补丁中的代码把%p改为%pk来防止信息泄漏.CVE-2016-3906 是高通组件中的信息泄漏漏洞.在msm_core_ptable_read函数中,有潜在的越界读漏洞,补丁中的代码增加了边界检查来防止潜在漏洞.CVE-2016-3907 是高通组件中的信息泄漏漏洞.对于msm_audio_wmapro_config_v2_32结构在开始的时候没有进行初始化,因此导致了信息泄漏问题.补丁中的代码在该结构初始化的时候全部置为0来防止信息泄漏.

    CVE-2016-6698 是高通组件中的信息泄漏漏洞.对于msm_audio_wmapro_config_32结构在开始的时候没有进行初始化,因此导致了信息泄漏问题.补丁中的代码在该结构初始化的时候全部置为0来防止信息泄漏.

    CVE-2016-6752 是高通组件中的信息泄漏漏洞.params_value数组没有初始化,因此在使用的时候会导致信息泄漏问题.补丁中的代码在初始化的时候全部置为0来避免这个问题.

受影响进程列表