首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
IoT安全
发新帖
2
1
[原创]极路由远程命令执行漏洞-漏洞分析
发表于: 2025-10-27 12:25
12773
[原创]极路由远程命令执行漏洞-漏洞分析
易之生生
4
2025-10-27 12:25
12773
## 简介 本篇主要介绍cloud_token的计算方式和远程命令执行漏洞的代码分析。cloud_token是开启远程ssh的token,如果知道cloud_token就可以远程开启ssh服务。 ## cloud_token计算 按照上文的模拟环境运行方式,打开 <mark class="encrypted">b91K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9J5c8X3I4G2j5$3q4D9i4K6u0V1M7%4y4Z5i4K6u0r3</mark> 连接。出现远程开启ssh服务的页面。  正常情况下local token的输入框显示的是路由器local token的值,因为是模拟环境,没有板载信息,所以显示的为空。这里提供一组历史数据: ``` local_token:RDRFRTA3MjI0MjFFLHNzaCwxNjEyNTA5ODU1NTI4LN/Gtg9ilqUoIsFFNGeHCHIA237Q uuid:f1f01c50-a881-11e4-9b37-d4ee0722421e cloud_token:5Jj4IhbY/K+QpS3n1rGfMFI3A58= ``` uuid就是路由器的固件信息,每个路由器都不同,获取的路径是 <mark class="encrypted">28aK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9J5c8X3y4Y4K9g2)9J5k6r3u0A6L8W2)9J5c8Y4c8#2M7X3u0G2i4K6u0r3M7s2u0G2P5s2W2Q4x3V1k6J5L8%4g2@1k6i4u0Q4y4h3k6A6L8X3k6G2</mark> 通过查看nginx的配置文件,可以找到local_ssh的解析路径为 /usr/lib/lua/luci/local_ssh/local_ssh.lua; ```bash ls /usr/lib/lua/luci/local_ssh local_ssh.lua local_ssh_util.lua ``` 然后使用luadec对local_ssh.lua和local_ssh_util.lua进行反编译,luadec需要使用luadec-openwrt的版本。 可以使用luadec直接反编译,也可以使用luadec -dis 先转为lua的反汇编形式,再使用AI转为lua代码; local_ssh.lua的反编译代码如下: ``` local json = require("hiwifi.json") local utils = require("openapi.utils.utils") local string = string local tostring = tostring module("luci.local_ssh.local_ssh") local function dispatcher(request) local response = "" local result = {} if not request then request = {} end local method = request.method if method == "get" then local cmd_result = utils.exec_cmd("sudo /usr/lib/lua/luci/local_ssh/local_ssh_util.lua get") result["code"] = 0 result["data"] = cmd_result elseif method == "valid" then if request.data ~= nil then local cmd_result = utils.exec_cmd("sudo /usr/lib/lua/luci/local_ssh/local_ssh_util.lua valid " .. tostring(request.data)) if not cmd_result then cmd_result = "" end cmd_result = tostring(cmd_result) if string.find(cmd_result, "Success:") then result["code"] = 0 result["data"] = cmd_result else result["code"] = 1 result["data"] = cmd_result end else -- 当request.data为nil时的处理 result["code"] = 1 result["data"] = "" end elseif method == "stop" then local cmd_result = utils.exec_cmd("sudo /usr/lib/lua/luci/local_ssh/local_ssh_util.lua stop") result["code"] = 0 result["data"] = cmd_result else result["code"] = 1 result["data"] = "Error: Method does not exist" end response = json.encode(result) return response end dispatcher = dispatcher ``` local_ssh_util.lua的反编译代码如下: ``` local tw = require("tw") local auth = require("auth") local socket = require("socket") local util = require("luci.util") local nixio = require("nixio") local protocol = require("luci.http.protocol") local math_floor = math.floor local current_time = math_floor(socket.gettime() * 1000) local mac_address = tw.get_mac() local service_name = "ssh" local token = "" local base_string = tostring(mac_address) .. "," .. service_name .. "," .. tostring(current_time) local encoded_token = "" local timestamp_file = "/tmp/local_ssh_ms" -- 读取时间戳文件 local file_handle = io.open(timestamp_file, "r") local stored_timestamp = 0 if file_handle ~= nil then local timestamp = file_handle:read("*n") if timestamp then stored_timestamp = timestamp else stored_timestamp = 0 end file_handle:close() else -- 文件不存在,创建新文件 file_handle = io.open(timestamp_file, "a") stored_timestamp = 0 file_handle:close() end local command = arg[1] local input_data = arg[2] or "" local popen_handle, port_number if command == "get" then -- 获取SSH状态 file_handle = assert(io.open(timestamp_file, "w")) file_handle:write(current_time) file_handle:close() local hmac_token = auth.lua_hmac_sha1_with_uuid(base_string, string.len(base_string)) if hmac_token then token = hmac_token else token = "" end encoded_token = nixio.bin.b64encode(base_string .. "," .. token) print(encoded_token) os.exit(0) elseif command == "valid" then -- 验证令牌 local validation_string = tostring(mac_address) .. "," .. service_name .. "," .. tostring(stored_timestamp + 1) local hmac_token = auth.lua_hmac_sha1_with_uuid(validation_string, string.len(validation_string)) if hmac_token then token = hmac_token else token = "" end encoded_token = nixio.bin.b64encode(token) if input_data == encoded_token then -- 令牌验证成功,重启SSH服务 os.execute("/etc/init.d/dropbear restart; hwf-at 10 /usr/lib/lua/luci/local_ssh/local_ssh_util.lua check_connected") os.remove(timestamp_file) -- 获取SSH端口号 popen_handle = io.popen("s=`netstat -lntp|grep dropbear | grep '0.0.0.0' | grep -v '127.0.0.1'|awk '{print $4}'`; echo ${s##*:}") if popen_handle == nil then print("Error: port file does not exist") os.exit(1) end port_number = popen_handle:read("*n") if port_number == nil then print("Error: port does not exist") os.exit(1) end popen_handle:close() print("Success: ssh port is " .. port_number) os.exit(0) else print("Error: valid token error") os.exit(1) end elseif command == "stop" then -- 停止SSH服务 popen_handle = io.popen("pidof dropbear | wc -w") local process_count = popen_handle:read("*n") popen_handle:close() if process_count <= 1 then os.execute("/etc/init.d/dropbear stop") else -- 如果还有连接,5秒后重试 os.execute("hwf-at 5 /usr/lib/lua/luci/local_ssh/local_ssh_util.lua stop") end elseif command == "check_connected" then -- 检查SSH连接状态 popen_handle = io.popen("pidof dropbear | wc -w") local process_count = popen_handle:read("*n") popen_handle:close() if process_count <= 1 then -- 没有连接,10秒后再次检查 os.execute("hwf-at 10 /usr/lib/lua/luci/local_ssh/local_ssh_util.lua check_connected") else -- 有连接,180秒后尝试停止 os.execute("hwf-at 180 /usr/lib/lua/luci/local_ssh/local_ssh_util.lua stop") end else print("Error: method does not exist") os.exit(1) end ``` local_token的计算方式是:base64(mac_address,ssh,current_time,hmac_token),主要代码如下: ``` local base_string = tostring(mac_address) .. "," .. service_name .. "," .. tostring(current_time) local hmac_token = auth.lua_hmac_sha1_with_uuid(base_string, string.len(base_string)) encoded_token = nixio.bin.b64encode(base_string .. "," .. hmac_token) print(encoded_token) ``` cloud_token的计算方式是: lua_hmac_sha1_with_uuid(mac_address,ssh,current_time+1),主要代码如下: ``` local validation_string = tostring(mac_address) .. "," .. service_name .. "," .. tostring(stored_timestamp + 1) local hmac_token = auth.lua_hmac_sha1_with_uuid(validation_string, string.len(validation_string)) ``` lua_hmac_sha1_with_uuid 的函数在libauth.so中,主要代码如下: ```c++ int __fastcall sub_830(int a1) { int v2; // $v0 int v3; // $s0 int n20_2; // $v0 int n20; // $s0 int n20_1; // $s2 _DWORD v8[5]; // [sp+18h] [-1Ch] BYREF char v9; // [sp+2Ch] [-8h] v3 = luaL_checklstring(a1, 1, 0); v2 = luaL_checkinteger(a1, 2); memset(v8, 0, sizeof(v8)); v9 = 0; n20_2 = hmac_sha1_with_uuid(v3, v2, v8, 20); n20 = n20_2; n20_1 = 0; if ( n20_2 < 0 ) { n20_1 = -n20_2; LOBYTE(v8[0]) = 0; n20 = 20; } lua_pushlstring(a1, v8, n20); lua_pushinteger(a1, n20); lua_pushinteger(a1, n20_1); return 3; } ``` 调用的hmac_sha1_with_uuid函数在libauth.so中,主要代码如下: ```c++ int hmac_sha1_with_uuid(int a1, int a2, int a3, ...) { int n20; // $v0 int v7; // $v0 int v8; // $v0 _BYTE v9[40]; // [sp+28h] [-40h] BYREF _DWORD v10[5]; // [sp+50h] [-18h] BYREF char v11; // [sp+64h] [-4h] int *va; // [sp+8Ch] [+24h] BYREF va_list va_1; // [sp+8Ch] [+24h] va_list va1; // [sp+90h] [+28h] BYREF va_start(va1, a3); va_start(va_1, a3); va = va_arg(va1, int *); memset(v10, 0, sizeof(v10)); v11 = 0; memset(v9, 0, 38); if ( !a1 ) return -1; n20 = -1; if ( a2 > 0 && a3 ) { if ( (int)va >= 20 ) { tw_get_uuid(v9); v9[37] = 0; v7 = strlen(v9); if ( !v7 ) return -2; if ( !SHA1(v9, v7, v10) ) return -3; v8 = EVP_sha1(); if ( !v8 ) return -4; if ( !HMAC(v8, v10, 20, a1, a2, a3, va_1) ) return -5; n20 = 20; if ( va != &dword_14 ) return -5; return n20; } return -1; } return n20; } ``` tw_get_uuid(v9)是获取固件信息的fac_uuid,也就是固件的uuid。在libtw.so.0.1.0中,代码如下: ```c++ char *__fastcall tw_get_uuid(char *_00000000_0000_0000_0000_d4ee07000000) { _BYTE v3[140]; // [sp+18h] [-8Ch] BYREF if ( !_00000000_0000_0000_0000_d4ee07000000 ) _assert("uuid != ((void *)0)", "libtw.c", 150, "tw_get_uuid"); memset(_00000000_0000_0000_0000_d4ee07000000, 0, 32); memset(v3, 0, 129); if ( bdinfo_get_value((int)"fac_uuid", (int)v3) ) strcpy(_00000000_0000_0000_0000_d4ee07000000, "00000000-0000-0000-0000-d4ee07000000"); else strncpy(_00000000_0000_0000_0000_d4ee07000000, v3, 37); return _00000000_0000_0000_0000_d4ee07000000; } ``` 然后调用SHA1对uuid进行哈希运算做为HMAC的密钥,HMAC使用的是sha1模式进行哈希运算。 根据以上的分析结果生成计算cloud_token的python代码如下: ```python import base64 import hashlib import hmac import sys def main(uuid, local_token): # uuid = 'f1f01c50-a881-11e4-9b37-d4ee0722421e' uuid_sha1 = hashlib.sha1(uuid.encode()).digest() # local_token = 'RDRFRTA3MjI0MjFFLHNzaCwxNjEyNTA5ODU1NTI4LN/Gtg9ilqUoIsFFNGeHCHIA237Q' base64_token = base64.b64decode(local_token) mac_address,ssh,current_time,hmac_token = base64_token.decode("latin1").split(",") local_info = f"{mac_address},{ssh},{int(current_time)+1}".encode("latin1") cloud_token = hmac.new(uuid_sha1, local_info, hashlib.sha1).digest() cloud_token_b64 = base64.b64encode(cloud_token).decode("latin1") # 5Jj4IhbY/K+QpS3n1rGfMFI3A58= print("cloud_token:" + cloud_token_b64) if __name__ == "__main__": total_args = len(sys.argv) if total_args != 3: print("Usage: python3 cloud_token.py uuid local_token") sys.exit(1) uuid = sys.argv[1] local_token = sys.argv[2] main(uuid, local_token) ``` ## 漏洞分析 远程命令执行的漏洞分析比较简单,漏洞代码就位于以上的local_ssh.lua中。漏洞代码如下: ``` local cmd_result = utils.exec_cmd("sudo /usr/lib/lua/luci/local_ssh/local_ssh_util.lua valid " .. tostring(request.data)) ``` 在method=valid时,对于传来的data参数没有做任何的过滤就直接传进了exec_cmd进行了执行。 远程命令执行的POC代码如下: <mark class="encrypted">f38K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9J5c8X3I4G2j5$3q4D9i4K6u0V1M7%4y4Z5i4K6u0r3j5i4m8A6i4K6y4r3L8h3g2@1K9r3!0V1i4K6y4p5N6X3q4D9K9h3c8Q4x3U0k6V1j5i4c8S2i4K6y4p5i4K6N6o6L8s2x3`.</mark> 
登录后可查看完整内容
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2025-10-27 16:11 被易之生生编辑 ,原因:
#固件分析
#漏洞挖掘
#家用设备
收藏
・
2
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
为你点赞!
2026-7-16 11:17
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
2
)
xss
雪 币:
472
活跃值:
(5421)
能力值:
( LV9,RANK:170 )
在线值:
发帖
9
回帖
317
粉丝
5
关注
私信
xss
4
2
楼
不错 cloud_token代码弄出来,不怕网站关闭了。。。
2025-10-29 20:45
0
Pulut
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
8
粉丝
0
关注
私信
Pulut
3
楼
极路由都倒闭了吧
2025-11-12 15:47
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
易之生生
4
19
发帖
11
回帖
257
RANK
关注
私信
他的文章
[原创]挑战 Android 墓碑机制:揭秘某头部社交 APP 永生背后的保活术
9270
[原创]ANDROID 黑科技 : 保活机制深度逆向
35200
[原创] ANDROID 黑科技 : HIDE API 调用
7015
[原创]UNIDBG 环境模拟X音签名算法
20405
[原创]Tenda堆栈缓冲区溢出漏洞 (CVE-2024-2986)
20084
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部