攻破数百万台智能体重秤:API与硬件黑客实战

admin 2025-12-22 04:23:54 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细介绍了如何通过API和硬件攻击接管数百万台智能体重秤的过程。作者发现了OEM厂商的SQL注入漏洞,能够泄露任意设备信息;在Withings设备上获取了串口调试Shell;最重要的是发现了用户设备关联逻辑中的致命缺陷,允许攻击者将任意设备绑定到自己的账户。文章强调了用户设备绑定流程是智能设备安全的关键环节,建议厂商加强这一环节的安全防护,并对漏洞进行了负责任的披露。 综合评分: 98 文章分类: IoT安全,漏洞分析,硬件安全,渗透测试,API安全


cover_image

攻破数百万台智能体重秤:API 与硬件黑客实战

Spaceraccoon

securitainment

2025年12月15日 17:19 中国香港

通过对智能体重秤用户设备绑定流程的逆向工程和漏洞挖掘,我成功接管了数百万台联网健康设备。硬件安全与 Web 安全是现代智能设备安全的两大支柱,掌握这两方面的攻击技术可以带来令人震撼且细思极恐的成果。本文将从端到端介绍如何攻击联网智能设备的基础知识,重点聚焦于用户设备绑定这一关键环节。

联网的…体重秤???

度假期间,我注意到酒店健身房里一台体重秤的屏幕上出现了一个奇怪的图标——WiFi 图标。我惊恐地发现,现在居然有人认为把体重秤连到互联网上是个好主意 (RIP, Internet of Shit)。在 Amazon 上搜索后,我发现市面上有大量支持 WiFi 或 Bluetooth 连接的体重秤产品,其中许多的移动应用界面可疑地相似。

Weighing Machines on Amazon

事实上,这些产品大多由同一家 OEM 厂商生产。即便是出自不同 OEM、代码库略有差异的产品,查看相关 Android 应用后也会发现,很多都使用了相同的公共库,比如 com.qingniu.heightscale,大概是因为从零开始编写兼容库实在太费事了。

Qingniu Library on Arboleaf App

Qingniu Library on Renpho App

虽然 BLE 协议相关的代码很有意思,让我搞清楚了通过 Bluetooth 与这些设备通信所需的正确操作码,但这些内容大多已被 openScale 项目逆向并记录在案。况且,试图挖掘需要近距离物理接触才能利用的本地漏洞也没什么意思。

更深入的挖掘

如果目标不是攻破一台设备,而是攻破所有设备,那么用户设备绑定流程就是关键靶点。例如,当你第一次购买智能设备并开箱时,通常需要登录移动应用,然后扫描 QR 码或通过 Bluetooth 与设备配对。完成后,你在厂商 Web 服务上的用户账户就会与这台物理设备建立关联。

这个过程的安全防护并不简单。从出厂开始,每台设备都需要一个唯一的设备标识符/密钥,以防止在扫描设备 A 的 QR 码时误配对到设备 B。最不安全的做法是使用静态字符串,如 UUID、MAC 地址或序列号。虽然这些作为标识符尚可接受,但作为认证密钥就很不安全了。即便它们是随机生成的、难以暴力破解,一旦泄露也很难撤销。

更安全的方案是生成加密密钥对,如公钥/私钥对。但这仍然无法抵御物理内存提取攻击,而且如果密钥生成过程存在弱点,攻击者依然有可能为任意设备生成密钥。传统的解决方案是依靠成熟的公钥基础设施和证书体系,这样可以方便地撤销被泄露的证书。

因此,典型的流程如下:

  1. 用户安装移动应用并登录用户账户。
  2. 通过应用连接硬件设备。
  3. 硬件设备的密钥发送到移动应用。
  4. 移动应用将用户的密钥 (如会话令牌) 和设备的密钥一并发送到服务器。
  5. 服务器验证密钥的真实性,并将用户账户与硬件设备建立关联。
  6. 用户此后可通过互联网远程控制设备并获取数据。

看起来挺合理,能出什么问题呢?

OEM 厂商的 SQL 注入漏洞 (BT-WAF 绕过)

这家 OEM 厂商一开始就栽了跟头。我甚至不需要购买实体设备,就枚举出了移动应用中所有可用的 API 端点,其中包括一个有意思的 api/ota/update端点。我原以为这能让我获取固件以便深入了解设备。借助反编译的 Android 应用 Java 代码,我轻松重构出了所需的 JSON 请求体参数。然而即便输入正确,厂商实际上也没提供多少可用的更新。

不幸的是,在探索 API 端点时,我发现有几个端点存在基础的 SQL 注入漏洞。有趣的是,服务器使用了一款名为宝塔云 WAF (BT-WAF) 的国产 WAF,其防护能力远强于我之前遇到的大多数 WAF。其中一个 /api/device/getDeviceInfo端点允许查询设备序列号,而该厂商将序列号同时用作标识符和认证密钥。序列号本身会在 /api/device/bindv2端点中使用,该端点会将请求用户的账户与序列号对应的设备进行绑定!这个”序列号”实际上是一个随机生成的 MAC 地址,存储在设备上。

以下是该漏洞端点的初始请求体:

{
  "serialnumber":"'001122334455"
}

可利用的空间不大。如果有第二个注入点,我或许能构造更巧妙的跨参数 payload。经过大量试错,我最终找到了这个绕过 BT-WAF 的方法:

{
  "serialnumber":"'or\n@@version\nlimit 1\noffset 123#"
}

让我们拆解一下。如果这段内容注入到类似 SELECT * FROM devices WHERE serial = 'INJECTION'的 SQL 语句中,最终的注入 SQL 会是:SELECT * FROM devices WHERE serial = 'INJECTION'or\n@@version\nlimit 1\noffset 123#'。这里有两个关键的绕过技巧:

  1. @@version

    总是求值为真,可以替代更明显的 1=1

  2. \n

    换行符可以用来分隔语句,代替空格。

有了这个漏洞,我现在能够泄露任意设备的信息,包括用作认证密钥的序列号!通过递增 offset参数,我发现设备数量超过了二十万台。

在 Withings WBS06 上获取串口调试 Shell

转向研究其他设备时,我发现了 Withings Body 体重秤。与其他设备类似,它支持 WiFi 和 Bluetooth 连接,并配有专用移动应用。这是个更知名的品牌,有趣的是它似乎还与 Nokia 联合品牌推出了 Nokia Body 秤。

通过应用的 API 拉取固件进行进一步分析相对容易。但与路由器等设备常用的复杂固件 (通常包含完整文件系统和 Linux 操作系统) 不同,这是一个裸机 ARM 固件。我希望能在裸机 ARM 逆向这门艺术上分享更多见解,但经验更丰富的专家在视频和博客中基本都说了同样的话:这非常困难。

尽管如此,我还是尝试了一下,参考 Barun 的博文《在 Ghidra 中分析裸机固件二进制文件》,得到了一个还算不错的分析结果。这包括通过 FCC 认证文档中的内部照片确定 WBS06 的微控制器型号,并设置正确的内存映射。

吸引我注意的是几个零散的字符串,暗示着存在一个… shell?

Connection Manager Shell Command
Usage:
&nbsp; wifi <wifi_sync_flags>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Attempts a Wifi sync with the given flags.
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; wifi_sync_flags is a combination of the following flags:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01 (allow update), 0x02 (store DbLib), 0x04 (send DbLib), 0x08 (send
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rawdata),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x10 (send wlog), 0x20 (send events), 0x40 (send extras)
&nbsp; wifi_no_update <wifi_sync_flags>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Attempts a Wifi sync, no update allowed (even if set in flags).
&nbsp; wifi_update <wifi_sync_flags>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Attempts a Wifi sync, allows update if available (even if not set in
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flags).
&nbsp; bt &nbsp; &nbsp; &nbsp; &nbsp;Attempts a Bluetooth sync
&nbsp; do &nbsp; Attempts a Wifi/Cellular sync and fallback to Bluetooth if it fails.

智能体重秤上为什么会有 shell?经过进一步搜索,我找到了另一位研究人员发布的 Reddit 帖子,他已经找出了早期型号 WBS05 上的 UART 引脚位置。

这看起来很直接,于是我兴奋地开始尝试在 WBS06 上复现。最大的线索是 WBS06 底部也有相同的三个孔,对应 Tx、Rx 和 GND UART 引脚,与 FCC 文档中的内部照片对比后证实了这一点。

Exterior of WBS06 for UART pins

Interior of WBS06 for UART pins

然而,我最初的尝试失败了。尽管用逻辑分析仪正确找出了波特率,我的串口连接始终返回乱码。在痛苦地折腾了好几个小时后,我意识到是便宜的 CP2102 USB 转 TTL 转换器出了问题,换用更可靠的 FT232 后终于得到了我需要的结果。

Logic Analyzer

有了调试 shell 后,我可以探索设备上存储的所有数据,包括证书、密钥等等!当然,虽然这很令人兴奋,但实际意义不大——我只是”攻破”了自己已经拥有的设备,没什么大不了的。

存在缺陷的用户设备关联逻辑

要真正测试远程攻击向量,我需要完全理解设备如何向 API 服务器进行身份验证并执行用户设备绑定。

例如,connection_manager wifi命令会尝试连接到 API 服务器并输出详细的调试日志。

shell>connection_manager wifi

[info][CM] Connection manager request, action = 3, wifi sync flags = 0xffffffff
[VAS] t:15
[info][CM] Start with cnlib action = 3
[VAS] t:15
[CNLIB] Recovered LastCnx from DbLib
[AM] Defuse id 4
[TIME] Current time (timestamp) 0 , 8h 0min 0sec
[TIME] Waking up in 16h 90min 60sec
[TIME] Add random time 0
[AM] Set id 3 at 63060
[AM] Set id 1 at 600
[CNLIB] Try to connect via wifi (1)
[DBLIB][ERASEBANK] Bank 1
[info][DBLIB][SUBSADD] 14 0
[info][CM] Initializ[VAS] t:15
e Wifi
[WIFIM] Request
[WIFIM] init
[VAS] t:15
wifi_chip_enable
bcm43438_request
== Set dcdc_sync ==
bcm43438_request: pwron module
[WIFIMFW] current_fw == FW_2 1
version 1
size 80
[WIFIMFW] wifi_crc: 0
[WIFIMFW] Take current bank
[WIFIMFW] Firmware block 1a8000 : OK
[WIFIMFW] Wifi Offset 21a370, lenght 58d1d
[WWD] HT Clock available in 31 ms
[WWD] mac: a4:7e:fa:19:2c:f6
supported channels: 13
[WIFIM] init OK
[info][CM] Wifi initialized
[WIFIM] join_configured_ap
[VAS] t:15
[WIFIM] ssid = ...
[WIFIM] key &nbsp;= ...
[WIFIM] WPA key already saved
[WWD] join: ssid=<...>, sec=0x00400004, key=<...>
[WDM] wwdm_join_event_handler: state=1, wifim_err=9, stopped=0
[WDM] wwdm_join_event_handler: state=2, wifim_err=9, stopped=0
[WDM] wwdm_join_event_handler: state=2, wifim_err=0, stopped=1
[WDM] wwdm_join_event_handler: stopped
[WWD] join: wiced_res=0, wifim_res=0
[info][WIFIM] join: attempt&nbsp;#0, rc=0
[info][WIFIM] join: SSID <...> join rc=0 after 1 attempts
[VAS] t:15
[VAS] t:15
[info][WIFIM] join: RSSI=-64
[VAS] t:15
[WIFIM] connect: use static ip
[WIFIM] Interface UP (Status : 0xf)
[WIFIM] netif_up: use DHCP
[WIFIM] Interface UP (Status : 0xf)
[WIFIM] netif_up:
[WIFIM] IP=192.168.0.9
[WIFIM] Mask=255.255.255.0
[WIFIM] Gw=192.168.0.1
[WIFIM] DNS[0]=192.168.0.1
[WIFIM] DNS[1]=0.0.0.0
[WIFIM] connect_cfg_ap: success
[info][CM] Joined configured AP successfully
[VAS] t:15
[info][CM] Store DbLib...
[VAS] t:15
[DBLIB][ERASEBANK] Bank 2
[info][CM] Store DbLib done
[HTT[VAS] t:15

S_CLIENT] Init
[HTTPS_CLIENT] Init
[info][CM] Wslib init successful, carry on
[VAS] t:15

[WS] WsLib_StartSession

[WS] __WsLib_Once
[WS] Https_client browsing <https://wbs06-ws.withings.net/once?appliver=1181&appname=WBS06&apppfm=device>
[HTTPS_CLIENT] New connection or Adress/Security Changed
[HTTPS_CLIENT] Close
[HTTPS_CLIENT] Init
[HTTPS_CLIENT] Handshake started
{"status":0,"body":{"user":[{"userid":...,"screens":[{"id":66,"deactivable_status":6,"src":1,"embid":11,"rk":1}]},...]}}
>
[DBLIB][ERASEBANK] Bank 1
[WS] WSLIB_OK
[WS] Https_client browsing <https://wbs06-ws.withings.net/v2/summary?appliver=1181&appname=WBS06&apppfm=device>
[HTTPS_CLIENT] Socket already opened
[WS] Params <action=getforscale&sessionid=...>
{"status":0,"body":[{...}]}
>
[WS] WSLIB_OK
[USLIB] FLUSH STORED MEASURE
[USLIB] 0 measure(s) flushed
[WS] Https_client browsing <https://wbs06-ws.withings.net/v2/weather?appliver=1181&appname=WBS06&apppfm=device>
[HTTPS_CLIENT] Socket already opened
[WS] Params <action=getforecast&sessionid=...short=1&enrich=t>
...

我还尝试替换设备上存储的 mTLS 证书以便更容易拦截 WiFi 流量,但证书机制正常工作,服务器拒绝了我的自签名证书。

尽管如此,通过调试日志和从内存中读取各种状态数据,我理清了大部分身份验证流程:

  1. 通过 Bluetooth 从移动应用接收 WiFi 凭据后,设备可以独立连接到 API 服务器。
  2. 设备出示证书,通过双向 TLS (mTLS) 连接到 API 服务器。
  3. API 服务器返回一个 nonce 值。
  4. 设备用本地私钥对 nonce 签名并发送给服务器。
  5. API 服务器确认签名有效后返回设备会话令牌。
  6. 设备此后可使用设备会话令牌作为身份凭证与 API 服务器交互。

有趣的是,用户设备绑定流程可以通过两种方式完成。第一种方式由用户的移动应用发起:

  1. 移动应用已持有用户的会话令牌。
  2. 应用通过 Bluetooth 获取设备的会话令牌。
  3. 应用使用 Session-Id: USER_SESSION_TOKEN向 API 服务器进行身份验证,并发送请求载荷 userid=USER_ID&sessionidtoken=DEVICE_SESSION_TOKENuserid是一个简单的递增数字。
  4. API 服务器确认 Session-Id和 sessionidtoken均有效后,将 userid与 DEVICE_SESSION_TOKEN对应的设备 ID 关联。

第二种方式由设备发起:

  1. 设备已持有设备会话令牌。
  2. 设备通过 Bluetooth 从应用获取用户的会话令牌。
  3. 设备使用 Session-Id: DEVICE_SESSION_TOKEN向 API 服务器进行身份验证,并发送请求载荷 deviceid=DEVICE_ID&sessionidtoken=USER_SESSION_TOKENdeviceid是一个简单的递增数字。
  4. API 服务器确认 Session-Id和 sessionidtoken均有效后,将 deviceid与 USER_SESSION_TOKEN对应的用户 ID 关联。

这两种方法的验证都做得很严格;尝试在第一个流程中修改 userid,或在第二个流程中修改 deviceid,都会因为与 Session-Id会话令牌不匹配而失败。

然而,业务逻辑中存在一个致命缺陷。我可以用服务器端验证逻辑的近似代码来说明:

if&nbsp;(req.session.isValid) {
if&nbsp;(!validateSession(req.body.sessionidtoken)) {
returnerror
&nbsp; }

consttargetSession=fetchSession(req.body.sessionidtoken)

// user app-initiated flow
if&nbsp;(targetSession.type==='device') {
associate(req.body.userid,&nbsp;targetSession.id)
// device-initiated flow
&nbsp; }&nbsp;elseif&nbsp;(targetSession.type==='user') {
associate(req.body.deviceid,&nbsp;targetSession.id)
&nbsp; }
}

问题出在哪里?设想这样一个请求:攻击者将 Session-Id和 sessionidtoken都设置为自己的用户会话令牌,同时将 deviceid设置为他们不拥有的设备。这时逻辑仍会认为这是设备发起的流程,而且永远不会要求攻击者提供与目标 deviceid对应的会话令牌!花几秒钟时间仔细理解这段代码。

正确的代码应该增加额外的验证:

if&nbsp;(req.session.isValid) {
if&nbsp;(!validateSession(req.body.sessionidtoken)) {
returnerror
&nbsp; }

consttargetSession=fetchSession(req.body.sessionidtoken)

// user app-initiated flow that validates that user to be associated matches the session token header
if&nbsp;(req.body.userid===req.session.id&&targetSession.type==='device') {
associate(req.body.userid,&nbsp;targetSession.id)
// device-initiated flow that validates that devuce to be associated matches the session token header
&nbsp; }&nbsp;elseif&nbsp;(req.body.deviceid===req.session.id&&targetSession.type==='user') {
associate(req.body.deviceid,&nbsp;targetSession.id)
&nbsp; }
}

利用这个缺陷,根据可用的设备 ID,我估计超过 100 万台潜在设备可以被重新绑定到攻击者的用户账户。

漏洞的负责任披露过程进展迅速,即便是在假期期间:

  • 2024 年 12 月 29 日:向厂商报告
  • 2025 年 1 月 3 日:报告确认并修复

这体现了他们对安全问题的重视——漏洞会影响所有厂商,但我清楚自己更愿意从哪家购买产品。

在硬件攻击中,很难将影响范围从单个设备扩大 (双关语) 到完全远程的攻击。用户设备绑定是那些能够绕过许多标准硬件和网络加固措施的关键流程之一,因为漏洞存在于 API 服务器而非设备本身。对于那些优先考虑易用性和便捷设置的消费级硬件,这个环节尤其值得关注。


Pwning Millions of Smart Weighing Machines with API and Hardware Hacking

免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。


查看原文:《攻破数百万台智能体重秤:API 与硬件黑客实战》

评论:0   参与:  3