
CVE-2023-29478 - эксплойт BiblioCraft, осуществляющий манипуляцию файлами/удаленное выполнение кода, поражающий версии BiblioCraft до v2.4.6
Для этого метода требуется только BiblioCraft! Не нужно слишком много ухищрений, и никакие другие моды не требуются для выполнения кода!
Оригинальное описание, посвященное CoreTweaks, можно найти здесь. Рекомендую сначала прочитать его, так как ниже я могу пропустить некоторые важные детали.
Выполнение кода возможно несколькими способами. Это затрагивает BiblioCraft 1.7.10 v1.11.7 и BiblioCraft 1.12.2 v2.4.5 (подтверждено) и, вероятно, все версии BiblioCraft до v2.4.6 (не подтверждено, не протестировано)
Существующие исправления, устраняющие ошибку обхода пути, по-прежнему предотвращают этот новый путь выполнения кода.
На этот раз мы сосредоточимся на сохранении ванильных написанных книг.
Написанные книги сохраняются в world/books/<author-name>, <book-title>.
Формат этих книг построчно:
Продолжая с начала, страницы книги начинаются с маркера , и от следующей строки до следующего маркера содержится часть этой страницы. BiblioCraft всегда добавляет новую строку в конце строк, даже если ничего не следует.
#pgx<page-number>Как и раньше, мы можем контролировать как название книги, так и имя автора через NBT-тег книги, а также выполнять обход пути.
Место, в которое мы будем записывать, — это папка mods/. Моды в этой директории чаще всего хранятся в виде JAR-файлов. Замечательное свойство JAR-файлов в том, что на самом деле это просто ZIP-файлы под маской.
Итак, почему это нам помогает?
ZIP-файлы имеют интересное свойство: они могут оставаться валидными, даже если в начало/конец добавлены мусорные данные.
Запись EOCD (End of central directory — конец центрального каталога) в ZIP-файле размещается в конце.
Она (грубо) состоит из магической сигнатуры/подписи 0x06054b50, а также количества, размера и смещения записей центрального каталога внутри архива.
Последнее поле в записи EOCD — это комментарий с префиксом длины, который может быть практически любой последовательностью байтов, кроме магической (не проверено).
(Я думаю, что парсеры ZIP-файлов начинают с конца и ищут сигнатуру EOCD для разбора архива, но я не совсем уверен.)
Если парсеру ZIP нужно только найти записи EOCD, и если любые данные (с ограничениями) могут следовать за записью EOCD, то мы можем создать валидный ZIP, даже если внутри файла есть другие данные.
(Огромная благодарность https://github.com/c0ny1/ascii-jar! Я активно использовал эти инструменты!)
Сначала нам нужно структурировать нашу полезную нагрузку. Forge загружает классы как моды, если у них есть специальная аннотация @Mod, поэтому мы будем использовать это здесь.
Наша черновая полезная нагрузка:
@Mod(modid = "payload-mod")
public class Payload {
// ...
static {
System.out.println("Hello World!");
}
// ...
}
Чтобы избежать проблем с кодировкой, мы используем скрипт для создания ASCII-только JAR-файла, содержащего только наш класс полезной нагрузки.
Мы дополняем начало PK\3\4.jar\n../../mods/\nprivate\n#pgx0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Причина, по которой мы добавляем PK\3\4 (сигнатура локального заголовка файла ZIP) в начало заполнения, связана со странной особенностью Forge, которую я не смог воспроизвести вне среды, где JAR-файлы проверяются на начало с этой сигнатуры, несмотря на то, что это не является требованием ZIP? Возможно, это ошибка Forge.
Мы используем длинную строку из 'A' и 'a', чтобы убедиться, что смещение больше 255, гарантируя, что 2-байтовое целое число, кодирующее смещение, не имеет байтов вне диапазона ASCII.
Мы дополняем конец \n, чтобы избежать проблем с добавлением новых строк BiblioCraft.
С нашим новым дополненным JAR мы берем все байты, следующие за последней новой строкой данных, которыми мы дополнили начало, и создаем из них новую строку (назовем ее <jar-data>) и создаем новую написанную книгу с NBT-данными:
TAG_Compound(''): 2 entries
{
TAG_String("author"): "../../mods/"
TAG_String("title"): "PK\3\4.jar"
TAG_List("pages"): 1 entry
{
TAG_String(None): "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + <jar-data>
}
}
Когда мы сохраняем эту книгу на диск через BiblioCraft, все данные заполнения будут «регенерированы» его форматом, что сделает наш JAR снова валидным.
И теперь, при следующей перезагрузке сервера (даже обычный перезапуск, или если вы вызовете сбой) наш JAR-мод будет загружен, и наш код будет выполнен.
В BiblioPOC/tools/ находится скрипт Python3, помогающий сгенерировать валидную полезную нагрузку.
Аргументы:
python3 create_payload.py [java_file] [forge_jar_location] [class_name] [output_dir]
Затем, находясь в игре и держа атлас BiblioCraft, выполните /jarpoccommand [completed_jar_path], где [completed_jar_path] — это путь к [output_dir]/completed.jar.