TP-Link Kasa 相机泄露家庭坐标:145 字节离线样本复现 UDP 9999 协议
一、这次披露的重点,不只是一个 GPS 字段
7 月 16 日,安全研究者 Christopher Childress(BadChemical)公开了 TP-Link Kasa Spot EC71 的完整协调披露记录。官方随后确认,Kasa EC70 v4 与 EC71 v4 同时受两个漏洞影响:CVE-2026-9770 是固件内共享私钥导致的通信机密性问题,CVSS 4.0 为 8.6 High;CVE-2026-13230 是本地发现响应无认证暴露地理位置,CVSS 4.0 为 5.3 Medium。
HN 讨论把标题概括成“一个 UDP 包返回家庭坐标,而且这个协议族的问题公开了约 6 年”。这个说法容易让人误以为设备直接在公网广播 GPS。官方 CVSS 向量里的 AV:A 很关键:攻击者首先要进入同一二层或邻接网络,并不是隔着互联网随手查询。但研究者又验证了一个更实际的边界——二手设备恢复出厂后仍可能残留旧主人的数据,连接设备配网热点后,旧坐标就可能跨越原来的家庭网络边界。
我没有 Kasa EC71 实机,所以没有对任何网络设备发送探测包。我具体做了两件事:先交叉核对 TP-Link FAQ 5192、NVD 两个 CVE 条目和研究者原始报告;再把 2016 年 softScheck 公开的 XOR Autokey 算法抽成一个纯离线 Python 测试,用 145 字节的脱敏 JSON fixture 验证加密与解密能否 round-trip。这样可以把协议层讲清楚,又不会把文章变成扫描陌生设备的操作手册。
二、两个 CVE 分别解决什么
| 项目 | CVE-2026-9770 | CVE-2026-13230 |
|---|---|---|
| 根因 | 只读文件系统里存在跨设备共享的静态私钥 | 本地发现响应无认证返回敏感位置字段 |
| 官方评分 | CVSS 4.0 8.6 High | CVSS 4.0 5.3 Medium |
| 前置条件 | 同一邻接网络,并能取得固件中的密钥 | 同一邻接网络,可向发现服务发送请求 |
| 影响 | 被动解密或主动 MITM,破坏机密性与完整性 | 暴露经纬度等信息,官方认定只影响机密性 |
| EC70/EC71 v4 修复版本 | 2.4.0 Build 20260520 rel.4191 | 2.4.1 Build 20260621 rel.76536 |
这里必须把两个版本号分开看。只升级到 2.4.0 Build 20260520 rel.4191,解决的是共享私钥问题;要覆盖地理位置泄露,还需要到 2.4.1 Build 20260621 rel.76536 或更高。NVD 目前对两条记录都还没有给出自己的 CVSS 复评,页面展示的是 CNA(TP-Link)评分。
研究者对 GPS 泄露给出的独立评分是 7.1 High,高于厂商的 5.3。他认为精确家庭坐标不应只算低机密性影响;TP-Link 则按“同一网络、无完整性和可用性影响”给出 Medium。这个分歧没有一个可以脱离场景的标准答案:家庭可信 LAN 内风险较低,酒店 Wi-Fi、访客网、共享办公网和二手设备市场的风险明显更高。
三、为什么 0xAB XOR 不能叫加密保护
softScheck 在 2016 年逆向 TP-Link HS110 智能插座时,已经记录了 9999 端口上的 JSON 协议:初始 key 是 0xAB,每个明文字节与前一个明文字节派生出的 key 做 XOR。2017 年公开仓库又提供了 Python 客户端与 Wireshark dissector。智能插座当时主要使用 TCP 9999;本次 Kasa 相机报告描述的是向 UDP 9999 发送本地发现请求。传输层不同,但研究者报告确认相机仍使用同类可逆 XOR 包装。
下面这段只对内存里的脱敏 fixture 做运算,不创建 socket,也不接收 IP 地址:
import json
INITIAL_KEY = 0xAB
def encrypt(plaintext: bytes) -> bytes:
key, out = INITIAL_KEY, bytearray()
for byte in plaintext:
out.append(byte ^ key)
key = byte
return bytes(out)
def decrypt(ciphertext: bytes) -> bytes:
key, out = INITIAL_KEY, bytearray()
for byte in ciphertext:
plain = byte ^ key
out.append(plain)
key = plain
return bytes(out)
fixture = {
"system": {"get_sysinfo": {
"model": "EC71(US) ver:4.0",
"sw_ver": "2.4.1 Build 20260621 rel.76536",
"alias": "lab-camera",
"longitude": 0,
"latitude": 0
}}
}
plain = json.dumps(fixture, separators=(",", ":")).encode()
cipher = encrypt(plain)
assert decrypt(cipher) == plain
print(len(plain), len(cipher), "round_trip=PASS")
我在 Python 3.11 下实际运行了这个文件,输出是:
fixture_bytes=145 encrypted_bytes=145 round_trip=PASS
cipher_prefix=d059510a0a0711084f184159
结果说明两点。第一,包装后长度仍是 145 字节,没有认证标签、随机 nonce 或完整性校验;第二,拿到固定初始 key 后可以逐字节恢复。它最多算“混淆”,不能承担加密保护。也因此,真正的修复不能只换一个 XOR key,而应当同时处理认证、设备唯一密钥和响应字段最小化。
四、从 2016 到 2026:问题为什么能跨产品线存活
研究者给出的时间线比单个 CVE 更值得看:
- 2016 年 7 月:softScheck 公开 TP-Link Smart Home Protocol,无认证的 9999 端口协议与
0xABXOR 已可复现。 - 2020 年 8 月:独立研究者在同协议族的 KC100 相机响应中记录了
longitude/latitude等字段。 - 2020 年 11 月:研究者报告称,TP-Link 在智能插座产品线处理过同类问题,但相机产品线没有同步覆盖。
- 2024 年 4 月:本次分析的 EC71 2.3.26 固件仍可观察到问题。
- 2026 年 1 月到 7 月:协调披露持续约 6 个月;期间一版 beta OTA 还把研究者的测试设备永久变砖。
- 2026 年 6 月 21 日:2.4.1 构建完成,研究者在 6 月 24—25 日确认三个主要发现已修复。
这不是“密码算法太弱”这么简单,而是一个典型的跨产品线安全需求没有进入回归测试的问题。协议在插座上被研究过,不代表相机团队会自动继承修复;相机固件升级了 Web 管理层,也不代表本地 discovery 响应会自动做字段最小化。安全测试若只盯 CVE 对应函数,而不把“未认证发现接口不得返回位置、账号、设备唯一标识”写成产品族级 invariant,同类问题就会在下一条硬件线复活。
五、我会怎样做资产自检与网络隔离
1. 先核对型号与固件,不先扫端口
在 Kasa App 的设备信息页记录硬件版本和固件版本。官方公告当前明确点名的是 EC70 v4 / EC71 v4,目标版本至少是 2.4.1 Build 20260621 rel.76536。不要因为型号名字相近,就把 EC70 v1-v3 或 KC 系列直接写成“已确认受影响”;研究报告里提到协议复用,只能作为继续排查的线索。
2. 在自己的 IoT 网桥上被动抓包
下面命令只监听自己管理的 br-iot,不主动发请求:
sudo tcpdump -ni br-iot 'udp port 9999' -w kasa-9999.pcap
tshark -r kasa-9999.pcap -Y 'udp.port == 9999' \
-T fields -e frame.time -e ip.src -e ip.dst -e udp.length
如果网络里没有相机或 App 没有触发 discovery,抓不到包是正常现象。这里的目标是确认资产与流量边界,不是扫描邻居设备。softScheck 的旧 Lua dissector面向 Smart Home Protocol;Wireshark 3.5.0 之后已经内置相关 dissector,但是否能直接识别 EC71 当前的 UDP 变体仍需在自己的设备上验证。
3. 用 VLAN 把“访客”和“IoT”拆开
最小策略不是把摄像头 DMZ 到公网,而是让主 LAN 可以按需访问 IoT,访客网完全不能访问 IoT,并禁止 IoT 主动横向进入主 LAN。下面是 nftables 思路示例,接口名要按自己的 OpenWrt / Linux 网关修改:
table inet filter {
chain forward {
type filter hook forward priority filter; policy accept;
iifname "br-iot" oifname "br-lan" ct state established,related accept
iifname "br-iot" oifname "br-lan" drop
iifname "br-guest" oifname "br-iot" drop
}
}
如果业务不依赖厂商云端,再进一步禁止摄像头访问 WAN;如果依赖 Kasa 云服务,则需要抓取实际目的地址后做最小放行,而不是照抄一条“一刀切”规则。对普通家庭,升级固件 + 独立 IoT SSID/VLAN + 禁止路由器端口转发,已经比改 UA、藏设备名之类表面动作有效得多。
六、目前的局限与待验证项
- 没有 EC71 实机(不足):我运行的是 145 字节脱敏离线 fixture,只验证 XOR round-trip,没有声称复现真实设备回包。
- UDP 变体的 Wireshark 支持(待验证):旧仓库与内置 dissector 的成熟路径主要来自智能插座协议,EC71 UDP discovery 是否完整解析还要以当前抓包为准。
- 受影响范围(还在调研):官方只确认 EC70 v4 与 EC71 v4。KC100 等旧型号共享协议历史,不等于已经获得本次 CVE 的产品确认。
- 二手设备残留链路(待验证):恢复出厂后不清 jffs2 数据来自研究者实机报告,TP-Link FAQ 没有单独描述这一点,我也没有购买二手机做独立验证。
- 评分争议(局限):5.3 与 7.1 的差异依赖部署场景;不能把“同 LAN”误写成“公网任意攻击”,也不能因此忽略访客网和二手市场。
- 共享私钥实际利用(坑点):NVD 确认固件中存在跨设备共享私钥以及 MITM 风险,但这不代表拿到任意一台设备就能直接攻破云端;攻击仍受本地网络和具体服务边界约束。
- 在野利用证据(不足):截至 NVD 7 月 15 日的 SSVC 记录,两条 CVE 都是
exploitation: none,没有观测到在野利用。
七、如何判断优先级
如果你管理 EC70 v4 或 EC71 v4,优先级很明确:先升级到 2.4.1 及以上,再检查是否有端口转发、DMZ、访客网与 IoT 网互通。企业或共享办公场景还应把摄像头纳入 CMDB,记录型号、硬件 revision、固件 build 和 VLAN,而不是只登记一个 MAC 地址。
如果你没有这两个型号,这次披露仍然提供了一条通用检查方法:发现协议是否需要认证、响应是否遵循字段最小化、设备证书是否逐台唯一、factory reset 是否真正清除用户数据。四条里任何一条没有自动化回归测试,都可能在产品线迁移时重新出现。
参考资料
- BadChemical,Security Advisory: Kasa Spot EC71 (Firmware 2.3.26):https://github.com/BadChemical/IoT-Vulnerability-Research-Public/blob/main/TP-Link_Kasa_EC71/Kasa_EC71.md
- TP-Link FAQ 5192,CVE-2026-9770 / CVE-2026-13230 官方公告:https://www.tp-link.com/us/support/faq/5192/
- NVD CVE-2026-9770:https://nvd.nist.gov/vuln/detail/CVE-2026-9770
- NVD CVE-2026-13230:https://nvd.nist.gov/vuln/detail/CVE-2026-13230
- softScheck,Reverse Engineering the TP-Link HS110:https://www.softscheck.com/en/blog/tp-link-reverse-engineering
- softScheck/tplink-smartplug(Apache-2.0,约 1.2k stars):https://github.com/softScheck/tplink-smartplug
- HN 讨论(141 points / 42 comments):https://news.ycombinator.com/item?id=48952565
浙公网安备 33010602011771号