CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用

作者:栈长@蚂蚁金服巴斯光年安全实验室

————————

1. 背景

FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器、转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具。2016年末paulcher发现FFmpeg三个堆溢出漏洞分别为CVE-2016-10190、CVE-2016-10191以及CVE-2016-10192。本文对CVE-2016-10190进行了详细的分析,是一个学习如何利用堆溢出达到任意代码执行的一个非常不错的案例。


2. 漏洞分析

FFmpeg的 Http 协议的实现中支持几种不同的数据传输方式,通过 Http Response Header 来控制。其中一种传输方式是transfer-encoding: chunked,表示数据将被划分为一个个小的 chunk 进行传输,这些 chunk 都是被放在 Http body 当中,每一个 chunk 的结构分为两个部分,第一个部分是该 chunk 的 data 部分的长度,十六进制,以换行符结束,第二个部分就是该 chunk 的 data,末尾还要额外加上一个换行符。下面是一个 Http 响应的示例。关于transfer-encoding: chunked更加详细的内容可以参考这篇文章


HTTP/1.1 200 OK

Server: nginx

Date: Sun, 03 May 2015 17:25:23 GMT

Content-Type: text/html

Transfer-Encoding: chunked

Connection: keep-alive

Content-Encoding: gzip

 

1f

HW(/IJ

 

0



漏洞就出现在libavformat/http.c这个文件中,在http_read_stream函数中,如果是以 chunk 的方式传输,程序会读取每个 chunk 的第一行,也就是 chunk 的长度那一行,然后调用s->chunksize = strtoll(line, NULL, 16);来计算 chunk size。chunksize的类型是int64_t,在下面调用了FFMIN和 buffer 的 size 进行了长度比较,但是 buffer 的 size 也是有符号数,这就导致了如果我们让chunksize等于-1, 那么最终传递给httpbufread函数的 size 参数也是-1。相关代码如下:


s->chunksize = strtoll(line, NULL, 16);


av_log(NULL, AV_LOG_TRACE, "Chunked encoding data size: %"PRId64"'\n",

s->chunksize);

 

if (!s->chunksize)

return 0;

        }

        size = FFMIN(size, s->chunksize);//两个有符号数相比较

    }

//...

read_ret = http_buf_read(h, buf, size);//可以传递一个负数过去


而在httpbufread函数中会调用ffurl_read函数,进一步把 size 传递过去。然后经过一个比较长的调用链,最终会传递到tcp_read函数中,函数里调用了recv函数来从 socket 读取数据,而recv的第三个参数是size_t类型,也就是无符号数,我们把size为-1传递给它的时候会发生有符号数到无符号数的隐式类型转换,就变成了一个非常大的值0xffffffff,从而导致缓冲区溢出。


static int http_buf_read(URLContext *h, uint8_t *buf, int size)

{

    HTTPContext *s = h->priv_data;

    intlen;

    /* read bytes from input buffer first */

    len = s->buf_end - s->buf_ptr;

    if (len> 0) {

        if (len> size)

            len = size;

        memcpy(buf, s->buf_ptr, len);

        s->buf_ptr += len;

    } else {

        //...

       len = ffurl_read(s->hd, buf, size);//这里的 size 是从上面传递下来的

static int tcp_read(URLContext *h, uint8_t *buf, int size)

{

    TCPContext *s = h->priv_data;

    int ret;

 

    if (!(h->flags & AVIO_FLAG_NONBLOCK)) {

        //...

    }

    ret = recv(s->fd, buf, size, 0);    //最后在这里溢出 


可以看到,由有符号到无符号数的类型转换可以说是漏洞频发的重灾区,写代码的时候稍有不慎就可能犯下这种错误,而且一些隐式的类型转换编译器并不会报 warning。如果需要检测这样的类型转换,可以在编译的时候添加-Wconversion -Wsign-conversion这个选项。


官方修复方案

官方的修复方法也比较简单明了,把HTTPContext这个结构体中所有和 size,offset 有关的字段全部改为unsigned类型,把strtoll函数改为strtoull函数,还有一些细节上的调整等等。这么做不仅补上了这次的漏洞,也防止了类似的漏洞不会再其他的地方再发生。放上官方补丁的链接


3. 利用环境搭建

漏洞利用的靶机环境

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值