CVE-2016-10191 FFmpeg RTMP Heap Buffer Overflow 漏洞分析及利用

本文深入分析了FFmpeg中CVE-2016-10191 RTMP Heap Buffer Overflow漏洞,解释了漏洞成因,即在chunk size字段未做一致性校验导致的缓冲区溢出。通过示例代码展示了如何利用此漏洞,包括漏洞环境的搭建、利用脚本编写以及漏洞利用过程。最终,利用堆溢出控制RTMPPacket结构体数组,通过ROP技术执行shellcode,实现远程代码执行。
摘要由CSDN通过智能技术生成

CVE-2016-10191 FFmpeg RTMP Heap Buffer Overflow 漏洞分析及利用

一、前言

FFmpeg是一个著名的处理音视频的开源项目,使用者众多。2016年末 paulcher 发现FFmpeg三个堆溢出漏洞分别为CVE-2016-10190、CVE-2016-10191以及CVE-2016-10192。网上对CVE-2016-10190已经有了很多分析文章,但是CVE-2016-10191尚未有其他人分析过。本文详细分析了CVE-2016-10191,是学习漏洞挖掘以及利用一个非常不错的案例。

二、漏洞成因分析

在 RTMP协议中,最小的发送数据包的单位是一个 chunk。客户端和服务器会互相协商好发送给对方的 chunk 的最大大小,初始为 0x80 个字节。一个 RTMP Message 如果超出了Max chunk size, 就需要被拆分成多个 chunk 来发送。在 chunk 的 header 中会带有 Chunk Stream ID 字段(后面简称 CSID),用于对等端在收到 chunk 的时候重新组装成一个 Message,相同的CSID 的 chunk 是属于同一个 Message 的。

在每一个 Chunk 的 Message Header 部分都会有一个 Size 字段存储该 chunk 所属的 Message 的大小,按道理如果是同一个 Message 的 chunk 的话,那么 size 字段都应该是相同的。这次漏洞的起因是对于属于同一个 Message 的 Chunk的 size 字段没有校验前后是否一致,导致写入堆的时候缓冲区溢出。

漏洞发生在rtmppkt.c文件中的rtmp_packet_read_one_chunk函数中,漏洞相关部分的源代码如下

    size = size - p->offset;    //size 为 chunk 中提取的 size 字段
    //没有检查前后 size 是否一致
    toread = FFMIN(size, chunk_size);//控制 toread 的值
    if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
        ff_rtmp_packet_destroy(p);
        return AVERROR(EIO);
    }

在 max chunk size 为0x80的前提下,如果前一个 chunk 的 size 为一个比较下的数值,如0xa0, 而后一个 chunk 的 size 为一个非常大的数值,如0x2000, 那么程序会分配一个0xa0大小的缓冲区用来存储整个 Message,第一次调用ffurl_read_complete函数会读取0x80个字节,放到缓冲区中,而第二次调用的时候也是读取0x80个字节,这就造成了缓冲区的溢出。

官方修补方案

非常简单,只要加入对前后两个 chunk 的 size 大小是否一致的判断就行了,如果不一致的话就报错,并且直接把前一个 chunk 给销毁掉。

+    if (prev_pkt[channel_id].read && size != prev_pkt[channel_id].size) {
 +        av_log(NULL, AV_LOG_ERROR, "RTMP packet size mismatch %d != %d\n",
 +                size,
 +                prev_pkt[channel_id].size);
 +        ff_rtmp_packet_destroy(&prev_pkt[channel_id]);
 +        prev_pkt[channel_id].read = 0;
 +    }
 +

三、漏洞利用环境的搭建

漏洞利用的靶机环境

操作系统:Ubuntu 16.04 x64

FFmpeg 版本:3.2.1 (参照https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu编译, 需要把官方教程中提及的所有 encoder编译进去。)

官方的编译过程由于很多都是静态编译,在一定程度上降低了利用难度。

四、漏洞利用脚本的编写

首先要确定大致的利用思路,由于是堆溢出,而且是任意多个字节的,所以第一步是观察一下堆上有什么比较有趣的数据结构可以覆盖。堆上主要有一个RTMPPacket结构体的数组,每一个 RTMPPakcet 就对应一个 RTMP Message, RTMPPacket 的结构体定义是这样的:

/**
 * structure for holding RTMP packets
 */
typedef struct RTMPPacket {
    int            channel_id; ///< RTMP channel ID (nothing to do with audio/video channels though)
    RTMPPacketType type;       ///< packet payload type
    uint32_t       timestamp;  ///< packet full timestamp
    uint32_t       ts_field;   ///< 24-bit timestamp or increment to the previous one, in milliseconds (latter only for media packets). Clipped to a maximum of 0xFFFFFF, indicating an extended timestamp field.
    uint32_t       extra;      /
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值