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

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

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

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

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

Категории

Все категории
Loading categories
ExecASLR-ekoparty — Эксплойт класса proof-of-concept, который обходит ASLR на процессорах Intel, злоупотребляя буфером целевых переходов (branch target buffer) и спекулятивным выполнением для утечки рандомизированных адресов через побочный канал. | Kitploit
Инструменты/GitHubGitHub/es0j/execaslr-ekoparty
Анализ уязвимостейЭксплуатацияАппаратная БезопасностьОбучение и ОбразованиеRed TeamingСостязательная АтакаЭксплуатация Бинарных Файлов
GitHubes0j/execaslr-ekoparty

ExecASLR-ekoparty

Эксплойт класса proof-of-concept, который обходит ASLR на процессорах Intel, злоупотребляя буфером целевых переходов (branch target buffer) и спекулятивным выполнением для утечки рандомизированных адресов через побочный канал.

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

Популярное

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

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

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

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

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

ExecASLR — злоупотребление предсказателями переходов Intel для обхода ASLR

Что такое ASLR

Address Space Layout Randomization (рандомизация адресного пространства) — это механизм защиты, используемый для усложнения эксплуатации уязвимостей повреждения памяти. Например, в сценарии с уязвимостью переполнения буфера атакующий, пытающийся построить эксплойт на основе Return Oriented Programming, должен знать адреса гаджетов в цепочке. Если сегмент кода эксплуатируемого бинарного файла рандомизирован, атакующему становится гораздо сложнее выбрать правильный адрес для эксплойта, что делает эксплуатацию нецелесообразной.

Следующий пример показывает, как рандомизируется адрес:

root@kitploit:~
#include <stdio.h>
void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){}

int main(int argc,char **argv){

    printf("Destination %p\n",codePtr);
    DoNothing();
}


При каждом запуске значение рандомизируется:

root@kitploit:~
Destination 0x563714256149
Destination 0x556d8e2f1149
Destination 0x5618c8bdd149
Destination 0x55ee623b0149

Последние 12 бит 149 всегда одинаковы, но расположение функции может находиться примерно где угодно в диапазоне от 0x550000000000 до 0x570000000000, что означает, что рандомизируются 29 бит, занимая возможное адресное пространство размером 0x200 0000 0000, или 2,2 ТБ.

Конвейер процессора

Обработка каждой инструкции — сложная задача. Некоторые этапы обработки отдельной инструкции:

  • выборка инструкции;
  • декодирование инструкции;
  • выполнение операций в арифметико-логическом устройстве.

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

Выполнение инструкций A, B и C в течение тактов 1-5. Например, в такте 3 блоки выборки, декодирования и исполнения одновременно активны

Однако инструкции не полностью независимы друг от друга. Например, следующая последовательность:

root@kitploit:~
A. add ax,[bx]
B. jz $+1
C. mov dl,[rsi]  
D. nop

В этом случае инструкция A в лучшем случае завершится только на такте 3 исполнения. Однако блок выборки должен решить, какую следующую инструкцию выбирать из памяти: должна ли инструкция C (mov dl,[rsi]) быть пропущена. В этом сценарии у процессора есть возможность дождаться завершения инструкции A, которое произойдёт только на третьем такте, чтобы затем выбрать из памяти правильную инструкцию, если, например, операция add вернёт 0:

Это приводит к задержке в конвейере, поскольку процессор должен ждать выполнения инструкции. В этом примере задержка составляет один такт, но инструкция add ax,[bx] требует операции с памятью, которая, как уже упоминалось, может занимать до сотен тактов, что влечёт за собой значительные потери производительности процессора.

Более быстрый вариант — попытаться «угадать» правильный путь выполнения. Процессор может спекулятивно предположить, выполнится переход или нет. После этого выполнение продолжается по предположенному пути, и значения фиксируются только в том случае, если путь оказывается правильным после завершения инструкции A. Если путь оказывается неверным, результаты отбрасываются, а состояние откатывается к моменту до точки спекуляции.

Единственная проблема при откате выбранного пути заключается в том, что микроархитектурное состояние процессора не может быть откачено. Поэтому, если процессор спекулятивно выполнит инструкцию C (mov dl,[rsi]), данные, на которые указывает rsi, будут перемещены в кэш. Этот эффект впоследствии можно измерить с помощью атаки по побочному каналу.

2-битный условный предсказатель переходов. https://en.wikipedia.org/wiki/Branch_predictor

Spectre V2 (инъекция адреса перехода)

Предсказываться должны не только условные инструкции, но и косвенные переходы. Процессор должен иметь механизм для угадывания адресов назначения таких инструкций, как call [rdi].

Уязвимость Spectre v2 показывает, что можно эксплуатировать предсказатель косвенных переходов для достижения транзиентного выполнения в других процессах: Извлечено из https://spectreattack.com/spectre.pdf

Размещая инструкцию call в контексте A по тому же виртуальному адресу, что и другую инструкцию call в контексте B, атакующий может обучить процессор выполнять код в выбранной атакующим позиции в контексте B — это атака с повторным использованием кода, аналогичная Return Oriented Programming (ROP).

Целевая жертва должна содержать фрагмент кода, известный как «spectre-гаджет», способный утечь секрет с помощью атаки по побочному каналу. Для успешной атаки Spectre атакующий также должен знать местоположение spectre-гаджета. Поэтому при атаках «пользователь-пользователь» защита жертвы с помощью ASLR ранее считалась смягчающей мерой для такого рода атак. Однако существуют также методы извлечения ASLR с помощью микроархитектурных атак, таких как Jump Over ASLR. Однако у этого метода есть ограничения по количеству утекаемых битов, поскольку он использует коллизии в предсказателе прямых переходов для обхода ASLR.

Внутренние механизмы этого предсказателя показаны ниже:

Извлечено из https://spectreattack.com/spectre.pdf

Некоторые из этих компонентов:

  • Буфер целевых адресов переходов (Branch Target Buffer, BTB);
    • BTB — это кэш-подобный компонент, который хранит адреса назначения для предсказаний. BTB хранит полный 64-битный адрес назначения, а количество доступных записей BTB зависит от архитектуры.
  • Буфер истории переходов (Branch History Buffer, BHB);
    • BHB хранит «хэш» недавнего потока выполнения. Каждая инструкция перехода записывает данные в BHB. На процессорах Skylake и более ранних BHB может хранить контекст последних 29 переходов. На Icelake BHB хранит до ~100 переходов. Обратите внимание, что BHB использует только 20 младших битов (20LSBs) адресов переходов для создания хэша, из которых 12 не рандомизированы.
  • Предсказатель косвенных переходов;
    • Использует только 12 младших битов инструкции косвенного перехода для определения полного 64-битного адреса назначения. Exec ASLR утекает 64-битный указатель из BTB, чтобы полностью восстановить адреса ASLR.
  • Предсказатель прямых переходов;
    • Использует 30 младших битов исходного адреса для предсказания 32-битного значения. Другая половина адреса берётся из исходного адреса. Атака Jump Over ASLR эксплуатирует коллизии в этом предсказателе, чтобы найти исходный адрес, который совпадает с другим контекстом, поэтому она ограничена утечкой только 30 младших битов контекста жертвы.

Классическая схема атаки Spectre v2 выглядит так:

  • Атакующий размещает косвенный переход в той же позиции, что и переход жертвы, но адрес назначения указывает на spectre-гаджет в контексте жертвы
  • Когда жертва выполняет переход, происходит неверное предсказание, и spectre-гаджет загружает секрет и выполняет условный доступ к области общей памяти, такой как библиотека. Например, spectre-гаджет, выполняющий getenv + secret[0]*4096, может утечь значение секрета в позиции 0, используя libc в качестве общей памяти.
  • Затем атакующий извлекает утёкший секрет, определяя, какие части общей памяти были перемещены в кэш, с помощью атаки flush+reload

Exec ASLR

Exec ASLR (также известный как Reverse Branch Target Buffer Poisoning — обратное отравление буфера целевых адресов переходов) — это новая техника обхода ASLR с использованием уязвимости Spectre-BTI. Эта атака использует тот факт, что не только атакующий может отравить BTB в классическом сценарии Spectre-BTI, но и жертва может вызвать неверное предсказание перехода в процессе атакующего, заставляя атакующего спекулятивно перейти по адресу, защищённому ASLR. Затем, используя побочный канал, который раскрывает, какой адрес исполняется, атакующий может получить полный адрес назначения, обходя ASLR для целевого процесса.

Схема атаки Exec ASLR выглядит так:

  • Жертва выполняет косвенный переход, который записывает свой рандомизированный указатель назначения (0x55aabbeef456) в BTB
  • Атакующий размещает косвенный переход по адресу, выровненному по 12 младшим битам. Поскольку эти 12LSB не рандомизированы, эта часть тривиальна.
  • Атакующий заполняет все возможные области памяти «leak-гаджетом», который сообщает атакующему: «Я исполняюсь по этому адресу!», используя probeArray в качестве побочного канала.
  • Когда атакующий выполняет косвенный переход, происходит неверное предсказание на один из множества leak-гаджетов в памяти
  • Атакующий использует атаку flush+reload, чтобы определить, был ли доступ к ProbeArray во время спекулятивного выполнения.

В таком виде атаки нет необходимости искать spectre-гаджет или иметь общую память для побочного канала; единственное требование — эксплуатируемый косвенный переход, а все необходимые гаджеты Spectre v2 размещаются внутри процесса атакующего. Единственное новое требование для этой атаки — возможность отобразить адрес назначения жертвы в собственный процесс, поэтому, например, эта атака не работает против KASLR. Это также не атака перебором: за одну попытку можно проверить несколько адресов одновременно, однако существует предел того, сколько «leak-гаджетов» память может вместить одновременно. Это значительно сокращает время выполнения атаки по сравнению с Jump Over ASLR: от ~100 адресов в секунду до нескольких сотен миллиардов адресов в секунду.

Leak-гаджет

Leak-гаджет использует probeArray, чтобы сообщить атакующему, где исполняется сам гаджет. Он принимает probeArray и индекс бита RIP, который нужно утечь, в качестве аргументов и выполняет своего рода программирование без ветвлений, чтобы решить, должен ли быть доступен probeArray[0] или probeArray[4096].

root@kitploit:~
lea rax,[rip - 7]      ;load current address
shr rax,cl             ;selects the bit using cl arg
and rax,1
shl rax,12             ;loads probearray
mov dl,[rsi+rax]       ;or probearray+4096

Управление BHB и кодом целевой жертвы

Как было показано ранее, BHB используется для выбора записи BTB. Чтобы найти коллизию BTB и эксплуатировать эту уязвимость, атакующий должен знать последние N выполненных переходов (29 для процессоров старше Skylake). В наших тестах мы использовали цикл for, чтобы установить состояние BHB в известное значение перед косвенным вызовом. Вот уязвимый пример кода жертвы:

root@kitploit:~
#include <stdio.h>

void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){
    return;
}

int main(){
    printf("Destination = %p\n",codePtr);
    while(1){
	for(int i=0;i<200;i++){}
    	codePtr();
    }
}

Чтобы гарантировать одинаковое состояние BHB в обоих контекстах, атакующий копирует байты, соответствующие циклу for и вызову жертвы, в виде шелл-кода. Шелл-код копируется во все возможные 256 позиций, которые могут соответствовать выравниванию по 20 младшим битам, необходимому для одинакового состояния BHB.

root@kitploit:~
Victim Code

0x5594c566a152 <+28>:    mov    eax,0xc8
0x5594c566a157 <+33>:    dec    eax
0x5594c566a159 <+35>:    jne    0x1157 <main+33>
0x5594c566a15b <+37>:    nop
0x5594c566a15c <+38>:    nop
0x5594c566a15d <+39>:    nop
0x5594c566a15e <+40>:    lea    rdi,[rip+0x2ecb]
0x5594c566a165 <+47>:    call   QWORD PTR [rdi]

--> Executes to
0x5594c5669135:    ret

root@kitploit:~
Attacker Code

… //eax=200 rsi=probeArray, cl=0 
0x6a157    dec    eax
0x6a159    jne    0x455555500157
…
0x6a165    jmp    QWORD PTR [rdi]

--> Misspredicts to
0x5594c566a135:    lea rax,[rip - 7]
0x5594c566a13c:    shr rax,cl
0x5594c566a13f:    and rax,1
0x5594c566a133:    shl rax,12
0x5594c566a137:    mov dl,[rsi+rax]

Сложности

Есть проблема при попытке разместить гаджет во всех возможных позициях одновременно. В наших тестах ASLR помещает адрес назначения где-то между 0x550000000000 и 0x570000000000. Это означает, что необходимо отобразить 2,2 ТБ возможного виртуального адресного пространства, или 537 миллионов leak-гаджетов. Но в системе всего 8 ГБ ОЗУ. Несмотря на то, что можно отобразить 2 ТБ ОЗУ с помощью COW, у нас не было особого успеха с этим подходом. Предполагаю, что это создаёт слишком большую нагрузку на буфер трансляции (Translation Lookaside Buffer, TLB), из-за чего спекулятивное обращение к нетранслированному адресу становится слишком медленным. В тестах мы создали страницу размером 1 ГБ в памяти и заполнили её утекающими гаджетами. Затем мы сдвигали страницу по диапазону 2 ТБ с помощью системного вызова remap. Другой наблюдённой проблемой был тот факт, что спекулятивный адрес, вероятно, отсутствовал в TLB, поскольку он никогда фактически не исполнялся. Но в руководстве Intel сказано:

  • «Процессор может кэшировать трансляции, необходимые для предвыборок и для обращений, являющихся результатом спекулятивного выполнения, которое никогда реально не произойдёт в исполняемом пути кода» — ISA

Поэтому, чтобы увеличить шансы на «спекулятивно вызванный» обход страниц (pagewalk), мы старались сделать разрешение правильного адреса как можно более трудным. Это делается с помощью цепочки указателей для адреса назначения. Идея в том, что фронтенд процессора спекулятивно предскажет адрес назначения перехода, а блок переупорядочивания выполнит leak-гаджет до завершения чтения цепочки указателей.

root@kitploit:~
Improved Caller - Frontend fetched instructions
mov rcx,%1       ;mask arg for gadget
lea rsi,[%2]     ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx]    ;pointer chain
mov rdx,[rdx]
mov rdx,[rdx]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx]      ;mispredicts to gadget

lea rax,[rip - 7];speculative execution
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]

root@kitploit:~
Improved Caller - Reorder unit scheduled instructions
mov rcx,%1    ;mask arg for gadget
lea rsi,[%2]  ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx] ;pointer chain
mov rdx,[rdx]
; <pagewalk occurs some where here>
... ;Out of order + speculation
lea rax,[rip - 7]
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx] ;the execution path reverted

Эта техника внеочередного выполнения + спекулятивного исполнения показала улучшение желаемых показателей неверных предсказаний в атаке

Планирование и STIBP

Для выполнения атаки Spectre V2 атакующий должен исполнять код на том же ядре, что и жертва, чтобы они разделяли один и тот же блок предсказания переходов (Branch Prediction Unit, BPU). На процессорах <= Skylake мы наблюдали, что можно добиться размещения на одном ядре с помощью Hyper-Threading. Процессоры Icelake и Cascade Lake реализуют смягчающую меру под названием Single Thread Indirect Branch Predictor, которая разделяет BPU между потоками. Поэтому необходимо исполнять жертву и атакующего в одном потоке и использовать usleep для чередования процессов жертвы и атакующего, что замедлило бы атакующего на этих процессорах, если бы не тот факт, что кэши (и, вероятно, TLB тоже) в этих поколениях очень хороши, позволяя кэшировать одновременно гораздо больше гаджетов.

Результаты

Эта техника была протестирована на всех процессорах Intel, доступных в Google Cloud, как в поколениях N1, так и N2:

  • Sandy Bridge
  • Ivy Bridge
  • Haswell
  • Broadwell
  • Skylake
  • Cascadelake
  • Icelake

Несмотря на некоторые различия в эксплойтах для Cascade и Ice Lake, все тесты способны восстановить адреса с точностью >99% менее чем за 10 секунд.

Меры защиты

Меры защиты такие же, как для Spectre V2 при защите от атак «пользователь-пользователь». Барьер предсказания косвенных переходов (Indirect Branch Prediction Barrier, IBPB) позволяет сбрасывать BPU и может использоваться при переключении контекста. В Linux IBPB можно использовать через системный вызов prctl с опцией PR_SET_SPECULATION_CTRL. Понятия не имею, какая эквивалентная мера защиты существует для Windows, пожалуйста, сообщите мне.


Статья:

https://cos.ufrj.br/uploadfile/publicacao/3061.pdf

Доклад на Ekoparty:

https://www.youtube.com/watch?v=Qj4z-KvnkxU

Слайды:

https://docs.google.com/presentation/d/10t-oo-c26x9ydx1_FYgmhy204rxfmQ92eboPlCnA2y4/edit?usp=sharing

Ссылки:

https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html https://eprint.iacr.org/2013/448.pdf https://spectreattack.com/spectre.pdf https://www.cs.ucr.edu/~nael/pubs/micro16.pdf http://download.vusec.net/papers/bhi-spectre-bhb_sec22.pdf https://www.kernel.org/doc/html/latest/userspace-api/spec_ctrl.html Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3. Santa Clara, USA: Intel Corporation, 2016, iSBN 325384-060US

Скачать инструмент
Операция \ такт12345
ВыборкаABC
ДекодированиеABC
ИсполнениеABC
Операция \ такт123456
ВыборкаABD
ДекодированиеABD
ИсполнениеABD
Операция \ такт123456
ВыборкаAB(S) C
ДекодированиеAB(S) C
ИсполнениеAB(S) C