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

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

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

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

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

Категории

Все категории
Loading categories
cve-2010-4221-lab — От патча к RCE: собственноручно собранный эксплойт для CVE-2010-4221 (переполнение стека TELNET IAC в ProFTPD), с полным описанием пути, продиктованного ошибками | Kitploit
Инструменты/GitHubGitHub/diegslva/cve-2010-4221-lab
Фреймворки для эксплойтовАнализ уязвимостейЭксплуатацияОбратная инженерияТестирование на ПроникновениеОбучение и ОбразованиеЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubdiegslva/cve-2010-4221-lab

cve-2010-4221-lab

От патча к RCE: собственноручно собранный эксплойт для CVE-2010-4221 (переполнение стека TELNET IAC в ProFTPD), с полным описанием пути, продиктованного ошибками

Репозиторий
12 ч 14 мин назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2010-4221 — Переполнение стека TELNET IAC в ProFTPD: от патча до RCE

Полностью воспроизводимый лабораторный стенд и написанный вручную эксплойт на сырых сокетах для CVE-2010-4221 — переполнение стекового буфера до аутентификации в pr_netio_telnet_gets() ProFTPD — созданный как учебное упражнение по исследованию уязвимостей и разработке эксплойтов.

Каждая неудача задокументирована. Прямой путь — ложь; обходные пути — и есть урок.


Правовое и этическое уведомление — прочтите сначала

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

Работа Red Team — настоящая, профессиональная наступательная безопасность — определяется одним словом: авторизация. Всё, что делает профессионал, происходит в рамках письменного соглашения: подписанного документа о правилах взаимодействия, в котором указаны объём, цели, разрешённые техники, временное окно и люди, которые это одобрили. Без этого документа те же самые нажатия клавиш — это не профессия, а преступление практически в любой юрисдикции на Земле.

Итак, вот контракт для этого репозитория, без права обсуждения:

  • Запускайте это только против прилагаемой Docker-лаборатории или систем, которыми вы владеете.
  • Никогда не запускайте против чего-либо без явного письменного разрешения.
  • Если вы учитесь: добро пожаловать, это создано для вас.
  • Если вы ищете оружие для использования против других: закройте эту вкладку. Эта ошибка из 2010 года; она не принесёт вам ничего, кроме судимости.
  • Ремесло стоит того, чтобы его изучать. Ремесло чего-то стоит только с дисциплиной, которая приходит вместе с ним.


    Уязвимость

    ProFTPD обрабатывает TELNET escape-последовательности на управляющем канале FTP. В TELNET байт 0xFF (IAC, «Interpret As Command») является escape-байтом; литеральный 0xFF передаётся как 0xFF 0xFF.

    pr_netio_telnet_gets() копирует байты клиента в стековый буфер (char buf[PR_DEFAULT_CMD_BUFSZ+1] из pr_cmd_read, 4104 байта при MAXPATHLEN=4096 в glibc), отслеживая оставшееся место в buflen — переменной типа size_t, беззнаковой.

    Уязвимый путь (1.3.3a, netio.c):

    root@kitploit:~
    case TELNET_IAC:
      switch (cp) {
        ...
        default:
          *bp++ = TELNET_IAC;   // запись №1
          buflen--;             // уменьшение №1
          telnet_mode = 0;
          break;
      }
      break;
    ...
    *bp++ = cp;                 // запись №2
    buflen--;                   // уменьшение №2  <-- нет проверки между ними
    

    Две записи, два уменьшения, без проверки нуля между ними. Когда buflen равно ровно 1, пара уменьшает его до 0, а затем происходит переполнение до SIZE_MAX (18 квинтиллионов). Теперь цикл считает, что буфер бесконечен, и продолжает записывать управляемые атакующим байты вверх по стеку — поверх сохранённых регистров, сохранённого RBP и адреса возврата.

    До аутентификации. Функция выполняется до того, как USER/PASS вообще обрабатываются.

    Патч

    Исправление (коммит 3cc69b8388, «Bug#3521 - Telnet IAC processing stack overflow», выпущено в 1.3.3c) состоит из двенадцати строк. Вся граница безопасности — это:

    root@kitploit:~
    if (buflen == 0) {
      break;
    }
    

    См. patch.diff. Чтение патча показывает, где была рана — это и есть навык.

    Лаборатория

    Dockerfile компилирует ProFTPD 1.3.3a из исходников исторического снимка Debian, намеренно небезопасно (так выглядел 2010 год):

    • -fno-stack-protector — без канарейки
    • -z execstack — исполняемый стек (без NX)
    • -no-pie — фиксированные адреса бинарника
    • запуск под gdb, который отключает ASLR по умолчанию → детерминированный стек
    root@kitploit:~
    docker build -t proftpd-133a .
    docker rm -f lab133 2>/dev/null
    docker run -d --name lab133 --cap-add SYS_PTRACE \
      --security-opt seccomp=unconfined -p 127.0.0.1:2122:21 \
      proftpd-133a sh -c 'gdb -batch -ex "set follow-fork-mode child" \
      -ex "run" -ex "continue" --args /usr/local/sbin/proftpd -n -d1 \
      > /tmp/gdb.txt 2>&1; sleep 600'
    python3 exploit.py
    

    Ожидаемый вывод:

    root@kitploit:~
    [S] 220 ProFTPD 1.3.3a Server (lab-iac) ...
    [S] THE SERVER SAID: b'PWNED!!PWNED!!'
    

    (Шеллкод пишет в файловые дескрипторы 0, 1 и 2, потому что мы не хотели зависеть от знания того, какой из них несёт управляющий канал — два из них отвечают.)

    Архитектура эксплойта

    root@kitploit:~
    "SITE " + NOP-слайд + шеллкод + [\xff\xff флуд] + паддинг + [ret] + "\n"
     ^^^^^^^^^^^^^^^^^^^^                             ^^^^
     шеллкод живёт ВНУТРИ буфера               хвост переполнения доставляет
     команды — область, которую никто          только ОДИН адрес
     не трогает
    
    1. «SITE » поддерживает FTP-парсер в живых — команда обрабатывается чисто.
    2. Шеллкод — это содержимое команды. Буфер — самое безопасное место в стеке: после чтения затрагивается только buf[4102] (завершающий NUL). Всё ниже живых локальных переменных фрейма спокойно.
    3. IAC-флуд доводит buflen до переполнения (см. «Путь» о проблеме чётности).
    4. Слот ret (buf + 4152) получает адрес середины NOP-слайда. Когда pr_cmd_read достигает return 0 после разбора, CPU попадает в слайд и соскальзывает в шеллкод.

    Эта инвертированная архитектура — сначала полезная нагрузка, затем флуд, адрес в конце — была проверена против канонического модуля Metasploit (proftp_telnet_iac), который использует ту же компоновку. Их цели имели NX, поэтому им требовалась ROP-цепочка с «четверным разыменованием» указателя res; в нашей лаборатории исполняемый стек, поэтому достаточно одного прямого возврата.

    Путь (собственно, смысл этого репозитория)

    Финальный эксплойт — 60 строк. Во что это обошлось:

    1. Слепой \xff флуд → ничего. Сервер вежливо закрыл сессию. Корневая причина: buflen начинается с 4102 (ЧЁТНОЕ), и каждая пара IAC уменьшает на 2 — он попадает ровно на 0, никогда на 1. Для переполнения нужна нарушенная чётность. Урок: чтение конечного автомата лучше, чем распыление.

    2. Неверный размер буфера. Первая калиброванная попытка предполагала буфер в 1024 байта. Реальный — MAXPATHLEN+8 = 4104 в Linux/glibc. Флуд остановился на 3 КБ раньше цели. Урок: измеряйте цель, не предполагайте.

    3. Первый SIGSEGV. Циклический узор де Брёйна (Aa0Aa1...) поместил слот возврата на buf+4152, перекрёстно проверенный дважды (математика фрейма + смещение узора). Урок: циклический узор — это измерительная лента, а не эксплойт.

    4. Контроль RIP. Установка слота в 0x4141414141414141 вызвала сбой самой инструкции ret — x86-64 отвергает неканонические адреса, и ошибка происходит на ret, а наше значение ожидает в обратной трассировке. Урок: сбой на ret с вашим значением во фрейме = контроль.

    5. Шеллкод выше слота ret → затёрт. 8 байт перезаписаны указателем кучи (0x4d7838 — позже идентифицирован как выделение пула cmd_rec). Стек-фреймы выше слота принадлежат функциям, которые всё ещё работают между приземлением и перехватом. Урок: переполнение — не последняя запись; программа продолжает жить в стеке, который вы только что испортили.

    6. «Мёртвая зона» ниже слота → тоже исписана. Собственные локальные переменные pr_cmd_read (cmd, buflen, cp) живут прямо там и продолжают сохраняться во время разбора.

    7. Криминалистика аппаратной точкой останова. watch *(long*)ADDR в gdb превратил загадку в камеру: каждая запись в затёртый адрес, с обратной трассировкой, по порядку. Урок: когда вопрос «кто записал эту память?», ответ — в одной команде gdb.

    8. Прочтите эталон, затем поймите его. Канонический модуль подтвердил инвертированную архитектуру. Чтение чужого эксплойта после построения собственной мысленной модели — это изучение; до — это копирование.

    Извлечённые уроки

    • size_t никогда не становится отрицательным — он становится гигантским. Целочисленное переполнение в счётчике оставшегося места — это переполнение стека с дополнительными шагами.
    • Чётность — это оружие. Когда примитив уменьшает по 2, вы управляете переполнением, контролируя чётность/нечётность, а не только размер.
    • Плохие символы — это вопрос протокола. Наш шеллкод избегает \x0a (завершает чтение) и переживает \xff (TELNET escape) по замыслу.
    • Prefork-серверы прощают сбои. Дочерний процесс умирает, родитель продолжает принимать: бесконечные попытки. Инженерия надёжности — часть эксплойта.
    • Измеряйте и эксплуатируйте один и тот же артефакт. Разница в 11 байт в argv[0] (бинарник из дерева сборки против установленного) сдвинула весь стек на 0x40 и молча аннулировала идеальный эксплойт.
    • Обработчик сигнала признаётся. ProFTPD перехватывает SIGSEGV и пишет в лог «terminating (signal 11)» — цель сообщает вам, что она умерла, даже когда ядро молчит.

    Ссылки

    • Коммит с исправлением: https://github.com/proftpd/proftpd/commit/3cc69b8388
    • CVE: https://nvd.nist.gov/vuln/detail/CVE-2010-4221
    • Канонический модуль: modules/exploits/linux/ftp/proftp_telnet_iac.rb (rapid7/metasploit-framework)
    • Смежная лаборатория (логическая ошибка, тот же демон): CVE-2015-3306 mod_copy

    Автор

    Создано diegslva, обучение на публике — от «никогда не писал эксплойты» до RCE до аутентификации с шеллкодом ручной работы за один задокументированный день. Если этот репозиторий чему-то вас научил, передайте это дальше.

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