基于libupnp的upnp安全
字数 1643 2025-08-06 20:12:41
基于libupnp的UPnP协议安全分析
0x00 UPnP协议概述
协议栈
UPnP(Universal Plug and Play)即插即用协议,设计目的是让设备接入网络后能自动发现并相互通信。基于TCP/UDP和HTTP协议,协议栈如下:
- 底层:IP、TCP、UDP
- 传输层:HTTPU(基于UDP的HTTP)、HTTPMU(组播HTTP)、HTTP(常规HTTP)
- 协议层:SSDP(简单服务发现协议)、SOAP(简单对象访问协议)、GENA(通用事件通知架构)
- 描述层:XML格式的设备和服务描述
libupnp在传统UPnP实现基础上集成了HTTP处理、XML处理、HTTP服务器、SSDP处理等功能。
关键标识
- UUID:通用唯一识别码,格式为8-4-4-16的十六进制数
- UDN:单一设备名,基于UUID,表示一个设备
- URN:统一资源名称,唯一标识实体但不提供位置信息
- Mx:1-5之间的值,表示最大等待应答秒数
- ST:Search Target,表示搜索的节点类型
SSDP协议
SSDP(简单服务发现协议)是UPnP的发现协议,设备加入网络时会发送广播包:
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 10
ST: ssdp:all
响应包示例:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=120
ST: uuid:75802409-bccb-40e7-8e6c-40a5ef100e92
USN: uuid:75802409-bccb-40e7-8e6c-40a5ef100e92
LOCATION: http://192.168.100.1:24795/rootDesc.xml
...
SCPD描述
LOCATION字段指向的XML文件描述设备信息,包含:
- 设备类型、友好名称、制造商信息
- 服务列表(serviceList):
- serviceType:服务类型
- SCPDURL:服务描述文件
- controlURL:控制URL
- eventSubURL:事件订阅URL
SOAP控制
基于TCP的XML格式控制协议,请求示例:
POST /control/url HTTP/1.1
CONTENT-TYPE: text/xml;charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:serviceType:v#actionName"
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
<argumentName>in arg value</argumentName>
</u:actionName>
</s:Body>
</s:Envelope>
GENA订阅&事件
订阅请求格式:
SUBSCRIBE publisher_path HTTP/1.1
HOST: publisherhost:publisher_port
CALLBACK: <deliveryURL>
NT: upnp:event
事件通知格式:
NOTIFY delivery_path HTTP/1.1
NT: upnp:event
NTS: upnp:propchange
SID: uuid:subscription-UUID
...
0x01 攻击面分析
常见漏洞类型
-
数据包处理漏洞:
- 边界检查不严格导致缓冲区溢出
- 如CVE-2012-5958在strncpy时长度计算错误
-
变量过滤不严格:
- 直接传入system等危险函数导致命令注入
- 如CVE-2017-17215、CVE-2020-15893
-
XML解析问题:
- XML递归错误
- XXE注入
-
信息泄露和越权控制:
- 缺乏身份验证机制
- 任意设备可控制网络中的所有UPnP设备
libupnp漏洞分析
CVE-2016-6255
- 影响版本:libupnp < 1.6.21
- 漏洞描述:通过未注册处理程序的POST请求实现任意文件写入
- 漏洞位置:webserver回调函数中的文件处理逻辑
- 修复方式:添加全局宏限制POST操作权限
CVE-2016-8863
- 影响版本:libupnp < 1.6.21
- 漏洞描述:gena_device.c中create_url_list函数的堆溢出
- 触发方式:发送包含无效URI的SUBSCRIBE请求
- 漏洞原理:URL计数与分配空间不一致导致越界写入
其他UPnP实现漏洞
CVE-2020-9373
- 影响设备:Netgear R6400等
- 漏洞类型:SSDP处理中的栈溢出
- 漏洞位置:strcpy到固定大小缓冲区
- 利用方式:构造超长SSDP请求触发溢出
CVE-2021-27239
- 影响设备:Netgear设备
- 漏洞类型:MX头处理中的缓冲区溢出
- 漏洞原理:strncpy长度参数可控
0x02 安全建议
- 及时更新libupnp到最新版本
- 对UPnP服务进行严格的输入验证
- 避免在UPnP服务中使用危险函数(system等)
- 在网络边界禁用UPnP服务
- 实施最小权限原则,限制UPnP服务的文件系统访问
0x03 测试工具
- Miranda:轻量级UPnP测试工具
- CallStranger:测试CVE-2020-12695漏洞
- upnpclient:Python3 UPnP通信客户端
- 自定义Python脚本:模拟SSDP发现和SOAP请求
示例发现脚本:
import socket
ANY = "0.0.0.0"
DES_IP = "239.255.255.250"
PORT = 1900
xml_str = b'M-SEARCH * HTTP/1.0\r\n' \
+ b'HOST: 239.255.255.250:1900\r\n' \
+ b'MAN: "ssdp:discover"\r\n' \
+ b'MX: 3\r\n' \
+ b'ST: ssdp:all\r\n\r\n'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((ANY, PORT))
s.sendto(xml_str, (DES_IP, PORT))
while True:
try:
data, address = s.recvfrom(2048)
print(address, data)
except:
pass
0x04 参考资源
- UPnP协议官方文档
- libupnp源码和漏洞公告
- 设备厂商安全公告
- 漏洞利用数据库(Exploit-DB)
- 相关技术博客和分析文章