Як відомо, код, що виконується в анклаві, серйозно обмежений у своїй функціональності. Він не може здійснювати системні виклики. Він може здійснювати операції вводу-вывода. Він не знає базової адреси сегмента коду хост-додатку. Він не може jmp'ити та call'ити код хост-додатку. Він не має уявлення про структуру адресного простору, якою керується хост-додаток (наприклад, які саме сторінки промапени або які дані розміщені на цих сторінках). Він не може просити операційну систему промаппіть йому шматок пам'яті хост-програми (наприклад, через /proc/pid/maps). Наївні спроби прочитати наосліп довільну область пам'яті хост-додатки, – не кажучи вже про спроби запису, – рано чи пізно (скоріше перше) призведуть до примусового завершення анклавної програми. Так відбувається щоразу, коли область віртуального адресного простору, що запитується анклавом, виявляється недоступною хост-додатку.
Чи зможе вірусописач за таких суворих реалій задіяти SGX-анклави для реалізації своїх зловмисних цілей?
З усього перерахованого вище, прийнято вважати, що анклав здатний лише те що, щоб обслуговувати хост-додаток, і що анклав неспроможна виявляти власну ініціативу, зокрема зловмисну. Отже, для вірусописачів анклави не мають практичної цінності. Це поспішне припущення є однією з причин того, чому SGX-захист несиметрична: код хост-програми не може отримувати доступ до анклавної пам'яті, тоді як анклавний код може читати та писати за будь-якою адресою пам'яті хост-програми.
Тому, трапись так, що зловмисному анклавному коду вдасться робити довільні системні виклики від імені хост-додатка, виконувати від його імені довільний код, сканувати пам'ять хост-додатки та знаходити в ній придатні для зловживання ROP-ланцюжка, він зможе захопити повний контроль над хост-додатком, у стелс-режимі. Зможе не тільки красти і шифрувати файли користувача, але і діяти від імені користувача. Наприклад, відправляти від його імені фішингові листи або проводити DoS-атаки. Не боячись при цьому навіть найсучасніших захисних механізмів, таких як стікові канарки та санітарна обробка адрес.
Ми покажемо кілька хаків, за допомогою яких лиходії долають вищеописані обмеження, прагнучи скористатися благами SGX у своїх зловмисних цілях: проведення ROP-атак. Або для виконання довільного коду замаскованого під процес хост-пікладання (аналогічно process hollowing, який часто використовується малвар'ю), або для маскування вже готової малварі (щоб позбавити свого зловреда від переслідувань з боку антивірусів та інших захисних механізмів).
Хак для зондування адрес щодо можливості їх зчитування
Оскільки анклав не знає, які діапазони віртуального адресного простору доступні хост-додатку і оскільки при спробі читання недоступної адреси анклав примусово завершується, - перед лиходієм постає завдання знайти спосіб сканування адресного простору. Знайти спосіб складання карти доступних віртуальних адрес. Лиходій вирішує це завдання за допомогою нецільового використання Intel'івської технології TSX. Використовує один з побічних ефектів TSX: якщо функцію доступу до пам'яті помістити в TSX-транзакцію, то винятки, що виникають через звернення до неприпустимих адрес, пригнічуються TSX, не доходячи до операційної системи. При спробі доступу до недійсної адреси пам'яті – переривається лише поточна транзакція, а не вся анклавна програма. Т.о. TSX дозволяє анклаву безпечно отримати доступ до будь-якої адреси, зсередини транзакції - без ризику обвалення.
Якщо вказана адреса доступна хост-додатку, TSX-транзакція найчастіше завершується успіхом. В окремих випадках вона може зазнати невдачі через зовнішні впливи, такі як переривання (наприклад, переривання планувальника), витіснення з кешу або одночасна зміна осередку пам'яті кількома процесами. У цих рідкісних випадках TSX повертає код помилки, що вказує на те, що збій, що виник, носить тимчасовий характер. У таких випадках потрібно просто перезапустити транзакцію.
Якщо вказана адреса недоступна хост-додатку, TSX пригнічує виняток (ОС не повідомляється) і скасовує транзакцію. Анклавному коду повертається код помилки, щоб він міг зреагувати на факт скасування транзакції. Ці коди помилок вказують на те, що адресу, що розглядається, недоступний хост-додатку.
У такого маніпулювання TSX'ом зсередини анклава є приємна для лиходія особливість: оскільки на момент виконання анклавного коду більшість апаратних лічильників продуктивності не оновлюються, за ними неможливо відстежувати TSX-транзакції, що виконуються всередині анклаву. Таким чином, зловмисні махінації з TSX' залишаються повністю невидимими для операційної системи.
Крім того, оскільки вищеописаний хак не покладається на якісь системні виклики, його не можна ні виявити, ні запобігти простим блокуванням системних викликів; що зазвичай дає позитивний результат при боротьбі з "полюванням на яйця".
Лиходій застосовує вищеописаний хак для пошуку в коді хост-додатку гаджетів, придатних для формування ROP-ланцюжка. При цьому йому не потрібно зондувати кожну адресу. Достатньо прозондувати за однією адресою з кожної сторінки віртуального адресного простору. Зондування всіх 16 Гб пам'яті займає близько 45 хвилин (на Intel i7-6700K). У результаті лиходій отримує список виконуваних сторінок, які придатні для конструювання ROP-ланцюжка.
Хак для зондування адрес на предмет можливості запису
Для здійснення анклавного варіанту ROP-атаки лиходій потребує можливості шукати доступні для запису ділянки пам'яті хост-додатка, що не використовуються. Лиходій використовує ці ділянки пам'яті для інжектування підробленого стекового кадру та для інжектування корисного навантаження (шелкода). Суть у тому, що зловмисний анклав не здатний вимагати від хост-програми виділити собі пам'ять, але натомість може використовувати не за призначенням вже виділені хост-додатком ділянки пам'яті. Якщо, звичайно, йому вдасться знайти такі ділянки, не обваливши анклав.
Лиходій здійснює цей пошук, експлуатуючи ще один побічний ефект TSX'а. Спочатку він, як і в попередньому випадку, зондує адресу щодо його існування, а потім перевіряє, чи доступна для запису відповідна цій адресі сторінка. Для цього лиходій задіює наступний хак: поміщає функцію запису в TSX-транзакцію, і після того, як вона виконалася, але ще до того, як завершилася - примусово обриває транзакцію (explicit abort).
Дивлячись на код повернення з TSX-транзакції, лиходій розуміє, чи вона доступна для запису. Якщо це «explicit abort», лиходій розуміє, що запис був би успішним, якби він довів його до кінця. Якщо ж сторінка доступна лише читання, то транзакція завершується помилкою, – відмінною від «explicit abort».
У такого маніпулювання TSX'ом є ще одна особливість, приємна для лиходія (крім неможливості відстеження через апаратні лічильники продуктивності): оскільки всі команди запису в пам'ять фіксуються тільки якщо транзакція пройшла успішно, примусове завершення транзакції гарантує, що зондується комірка пам'яті.
Хак для перенаправлення потоку керування
При здійсненні ROP-атаки з анклаву, - на відміну від традиційних ROP-атак, - лиходій може отримати контроль над регістром RIP без експлуатування будь-яких багів в програмі, що атакується (переповнення буфера або щось в цьому роді). Лиходій може безпосередньо перезаписувати значення регістра RIP, що зберігається на стеку. Зокрема він може замінити значення цього регістру своїм ROP-ланцюжком.
Однак якщо ROP-ланцюжок довгий, то перезапис великого шматка стека хост-програми може призвести до пошкодження даних і несподіваної поведінки програми. Лиходія, який прагне проводити свою атаку потай, такий стан речей не влаштовує. Тому він створює собі підроблений тимчасовий кадр стека і зберігає свій ROP-ланцюжок у ньому. Підроблений кадр стека розміщується в довільному місці пам'яті, доступному для запису, завдяки чому справжній стек залишається недоторканим.
Що дають лиходію три перераховані вище хаки
(1) Спочатку зловмисний анклав за допомогою хака для зондування адрес на предмет можливості їх зчитування, - Шукає в хост-додатку ROP-гаджети, придатні для зловживання.
(2) Потім за допомогою хака для зондування адрес на предмет можливості запису, – зловмисний анклав ідентифікує у пам'яті хост-додатки ділянки, придатні для інжектування корисного навантаження.
(3) Далі, анклав створює ROP-ланцюжок з гаджетів, виявлених на кроці (1), і інжектує цей ланцюжок у стек хост-додатку.
(4) Нарешті, коли хост-додаток натикається на створений у попередньому кроці ROP-ланцюжок, починається виконання зловмисного корисного навантаження – з привілеями хост-додатка та з можливістю звертатися до системних викликів.
Як лиходій задіяє ці хакі для створення ранзомварі
Після того як хост-додаток передає анклаву керування через якийсь із ECALL'ів (не підозрюючи, що цей анклав зловмисний), зловмисний анклав шукає в пам'яті хост-додатку вільне місце для інжектування коду (за вільні місця приймає ті послідовності осередків, які заповнені нулями). Потім за допомогою хака для зондування адрес на предмет можливості їх зчитування, - анклав відшукує в хост-додатку виконувані сторінки і генерує ROP-ланцюжок, який створює новий файл з ім'ям «RANSOM» в поточній директорії (при реальній атаці анклав шифрує існуючі файли користувача) і відображає повідомлення з вимогою викупу. При цьому хост-додаток наївно вважає, що анклав просто складає два числа. Як це виглядає у коді?
Для зручності сприйняття введемо через дефайни деяку мнемоніку:
Зберігаємо вихідні значення регістрів RSP та RBP, щоб після виконання корисного навантаження відновити нормальну роботу хост-додатку:
Шукаємо відповідний кадр стека (див. код з розділу «хак для перенаправлення потоку управління»).
Знаходимо відповідні ROP-гаджети:
Знаходимо місце для інжектування корисного навантаження:
Будуємо ROP-ланцюжок:
Ось таким чином Intel'овська технологія SGX, покликана протистояти шкідливим програмам, експлуатується лиходіями для реалізації протилежних цілей.
Джерело: habr.com