2016-09-01

appscan

0x1 libupnp简介

libupnp 是一个便携、可移植的 UPnP 的 C 语言开发包,UPnP是一种网络协议,允许设备自动搜寻和设定。Libupnp最新版本是1.6.20,编译时间为2016年7月7日,上一个版本为1.6.19,编译时间为2013年11月15日,编译间隔很长,有漏洞的版本为1.6.17及以下版本,编译时间为2012年12月以前。

0x2 漏洞原理

在1.6.17以及以下版本中存在多个缓冲区溢出漏洞,漏洞函数出现在upnp/src/ssdp/ssdp_server.c的unique_service_name中:

对于输入参数cmd未做安全检测,导致strncpy时发生缓冲区溢出。

由于漏洞类型比较老,攻击难度不大,使用一个构造的UDP数据包就能触发漏洞。早在漏洞刚出现时,Rapid7就推出了扫描工具ScanNow,其构造的数据包为:

测试ssdp包
M-SEARCH * HTTP/1.1
HOST:239.255.255.250:1900
MAN:"ssdp:discover"
MX:3
ST:uuid:rootdevice

 

通过数据包返回的结果中查看是否是有漏洞的upnp库。下面是一段python发送udp的代码:

 

发送ssdp数据包
import socket
 
SSDP_ADDR = '172.21.192.2' 
#SSDP_ADDR = '10.18.25.50' 
SSDP_PORT = 1900 
 
MS = 'M-SEARCH * HTTP/1.1\r\nHost:239.255.255.250:1900\r\nST:upnp:rootdevice\r\nMan:\"ssdp:discover\"\r\nMX:3\r\n'
__s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
__s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
local_ip = socket.gethostbyname(socket.gethostname())
__s.bind((local_ip, 50000))
__s.sendto(MS, (SSDP_ADDR, SSDP_PORT))

 

0x3 漏洞修复

判断数据大小,防止数据越界,常规的缓冲区溢出修复方法。下图为

0x4 漏洞扫描方法

360显危镜现已支持libupnp漏洞的扫描,其扫描方式为判断libupnp的版本,一般来说,libupnp在编译的时候都会将版本号编译进去,通过扫描so文件的字符串拿到版本号,如果小于1.6.18则判断为有漏洞的版本,扫描代码如下:

 

扫描代码
def detect_so_upnp(apkinfo,native_dir,logger=logger):
    r_rets = {'scan_version':scan_version,'scan_tag':scan_tag}
    ret_ = []   
    rets = detect_so_strings(apkinfo,native_dir,logger)
    if len(rets['result']) > 0:
        for r in rets['result']:
            if 'data' not in r.keys():
                continue
            rr = r['data'].split('\n')
            for __r in rr:
                if 'Portable SDK for UPnP' in __r:
                    vers = __r.split("/")
                    ver = vers[3].split(".")
                    real_ver = int(ver[2])
                                               sub_ver = int(ver[1])
                    if sub_ver<=6 and real_ver < 18:
                        r_ = {'vul_file':r['vul_file']}
                        r_.update({'vul_id':vul_id})
                        r_.update({'md5':apkinfo['md5']})
                        if r_ not in ret_:
                            ret_.append(r_)
    if len(ret_) == 0:
        r_rets.update({'risk':0,'result':[{'vul_id':vul_id,'md5':apkinfo['md5']}]})
    else:
        r_rets.update({'risk':1,'result':ret_})      
	return r_rets  

 

0x5 市场状况

直到2015年12月,QQ音乐才修复了这个漏洞,替换了有漏洞的libupnp库,当时使用的库版本为1.6.17。

 

通过对appscan大数据中的13w款app的扫描,发现受此漏洞影响的产品数量为60款。

虽然说比重几乎可以忽略不计,但是仍然要提醒开发者,开发时关注第三方库的安全状况,及时使用官方最新的安全版本库。

 

0x6 参考

  1. https://community.rapid7.com/community/infosec/blog/2013/01/29/security-flaws-in-universal-plug-and-play-unplug-dont-play
  2. https://security.tencent.com/index.php/blog/msg/99