• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Что такое анклав, пример тестового проекта и анализ применения анклава в блеке

X-Shar

(L2) cache
Пользователь
Регистрация
17.05.2020
Сообщения
473
Реакции
354
Всем привет, решил скопировать сюда тоже свою статью с васма:https://wasm.in/threads/chto-takoe-...ta-i-analiz-primenenija-anklava-v-bleke.33910

Изначально писал сюда под конкурс, но понял что на данный момент у меня знаний нехватает для написания статей под конкурс, т.к. получаются сборные статьи из нескольких статей, которые уже есть в паблике, либо частичные переводы, что может как минимум нарушать правила конкурса, ну и если сравнивать с другими статьями, к сожалению недотягивает что-бы конкурировать с ними...:(

Но тем не менее кому-то такие статьи могут быть интересны.)))

Мотивация написать такую статью, было то-что часто слышу, что есть такой самый крутой анклав, который может прятать данные ваших программ от реверсера, антивирусов и даже операционной системы.

Звучит как в сказке, а действительно было-бы не плохо прятать какие-то данные от лишних глаз реверсера, или еще кого.

Я начал разбираться, а как можно создать такой анклав и что-то сделать с ним ?

Кому интересно, предлагаю прочитать эту статью.

Хочу отметить, что статья направлена больше для новичков, которые мало понимают что такое SGX и даёт поверхностные знания, что это за технология.

Итак, что-же такое анклав ?

Если кратко, то весь смысл Intel SGX (А мы будем говорить именно про него) по сути сводится к тому-что, в процессоре есть какая-то защищенная область памяти, которая доступна только процессору, больше никто даже операционная система доступ туда получить не может, по сути это и есть анклав.

В модели SGX приложение делится на доверенную и ненадежную часть. Недоверенная часть - это та часть, которая взаимодействует с остальной системой, а также создает анклав, который считается безопасной частью приложения (Это доверенная часть).

Внутри анклава хранятся важные данные, доступные только процессору.

Все экземпляры анклава изолированы друг от друга, поэтому они могут взаимодействовать только через свою ненадежную часть.

Доверенный и недоверенный код жестко связываются между собой ключами шифрования с использованием протокола Диффи-Хеллмана.

За процедуру подписи отвечает процессор, где и хранится ключ обмена информации, обновляющийся каждый раз при перезагрузке системы. Содержимое анклавов хранится в общей памяти, используемой пользовательскими приложениями, однако хранение происходит в зашифрованном виде. Расшифровать содержимое может только процессор.

Вообще по теме много публикаций есть, цель этой статьи дать начальное представление о SGX, также показать как сделать каркас проекта для дальнейших экспериментов.

Ещё пару строк про функции ECALL и OCALL:


Доверенная часть представляет из себя набор функций и процедур, называемых ECALL (Enclave Call). Сигнатура таких функций должна быть прописана в специальном header-файле, а их реализация в файле с исходным кодом доверенного приложения, которое будет выполняться в процессоре.
Enclave Call – Это реализация программы в анклаве.

Также необходимо прописать прототипы тех функций, которые можно будет вызвать изнутри анклава в недоверенное приложение, такие функции называются OCALL (Outside Call). Прототипы прописываются в том же заголовочном файле, где и ECALL-функции, а реализация, в отличие от ECALL, прописывается соответственно в недоверенной части приложения.

Давайте перейдем к реализации простого примера:

Итак предлагаю написать демонстрационный пример, который просто передаст какие-то защищенные данные из анклава в наше приложение.

Ну например, пусть в анклаве у нас будет хранится какой-то буфер:
сhar* enclave_secret = "I am enclave !";

Этот буфер нам и нужно передать в наше приложение, в будущем эти наработки можно использовать как каркас, для написания более сложных приложений, например внутри анклава можно реализовать алгоритмы шифрования/расшифрования, ну тогда вы будете уже передавать приложению расшифрованные данные и т. д.

Итак, что-же нам нужно для работы:

1)Скачать и установить Visual Studio, я использую 2019 версию...
2)Cкачать и установить SDK для работы с SGX:https://software.intel.com/content/www/us/en/develop/topics/software-guard-extensions/sdk.html

В процессе скачки, будет предложена утомительная регистрация, но думаю вы справитесь...)))

На этапе установки будет предложено интегрировать пакет разработки в имеющуюся на компьютере версию VS, сделайте это.

1602567221217.png


Итак запускаем вижуалку и создаём проект:

1602567240930.png


1602567249678.png


Далее такое окно:

1602567265310.png


Тут я оставил всё как есть:

1602567281521.png


Затем добавим к созданному решению, ещё один проект: обычное консольное приложение C++.

1602567306789.png


В результате у нас должно быть что-то такое в обозревателе решений:

1602567328357.png


Теперь необходимо связать анклав с нашей программой консоли (Это недоверенная часть), для этого жмем правой кнопкой на проекте «Console_demo»:

1602567345367.png


1602567353935.png


Теперь нужно изменить некоторые свойства проекта «Console_demo» и «Enclave_demo»:

ОБЯЗАТЕЛЬНО СДЕЛАЙТЕ ЭТИ НАСТРОЙКИ ДЛЯ ДВУХ ПРОЕКТОВ:

1602567371347.png


1602567379077.png


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

1602567398064.png


Всё мы закончили настройки, теперь давайте кодить…)

У нас два решения:
«Console_demo» и «Enclave_demo»:

Из сгенерированных файлов, нам будет интересно три файла:

1) Enclave_demo.edl – Это по сути заголовочный файл, туда мы пропишем имена и прототипы ECALLs и OCALLs функций (Проект «Enclave_demo»).
2) Enclave_demo.cpp – Это доверенная часть приложения (Проект «Enclave_demo»). Тут будет реализация ECALLs.
3) Console_demo.cpp – Это недоверенная часть приложения (Проект «Console_demo»). Тут будет реализация OCALLs.

Пропишем реализацию Console_demo.cpp:
C:
#define ENCLAVE_FILE "Enclave.signed.dll" //Библиотека, через которую осуществляется подпись анклава
#define BUFFER_LEN 256 //Размер буфера данных, которые мы отправляем в анклав
 
#include "sgx_urts.h"  //Базовый заголовочный файл, в котором реализованы функции управления анклавом
#include "Enclave_demo_u.h" //Подключение автоматически сгенерированного файла
#include "stdio.h"
 
void ocall_function(char* buf) //OCALL функция для вывода текстовой строки - секрета из анклава. Вызов из анклава.
{
    printf("+++ OCALL output: %s\n", buf);
}
 
static sgx_enclave_id_t enclave_id = 0; // id анклава, в проекте может быть несколько анклавов, каждый со своим id
static sgx_status_t enclave_ret = SGX_SUCCESS; //Статус выполнения операции
static sgx_launch_token_t enclave_token = { 0 }; //Массив нициализации токена запуска для анклава
static int enclave_token_updated = 0; // Флаг, что токен запуска не был изменен
static char buffer[BUFFER_LEN]; // Буфер, в который будет записан секрет из анклава
 
int main()
{
    sgx_status_t ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &enclave_token, &enclave_token_updated, &enclave_id, NULL); //Функция создания анклава
 
    if (ret != SGX_SUCCESS)
    {
        printf("+++ Failed to create enclave with error number: %#x\n", ret);
        return 0;
    }
 
    ecall_function(enclave_id, buffer, BUFFER_LEN); //Вызов ECALL функции
 
    printf("\n+++ ECALL Output: %s\n", buffer); //Вывод полученного секрета
 
    system("pause");
}

Реализация Enclave_demo.cpp:
C:
#include "Enclave_demo_t.h"
#include "sgx_trts.h"
#include <cstring>
 
void ecall_function(char* str, size_t len)
{
    char* secret = "I am enclave !"; // Наша секретная фраза
 
    memcpy(str, secret, len); //Копируем секрет по адресу, которую получили
 
    ocall_function(secret); //Вызов OCALL-функции
}

Реализация заголовочного файла Enclave_demo.edl:
C:
enclave {
    from "sgx_tstdc.edl" import *;
 
    trusted {
        /* define ECALLs here. */
        public void ecall_function([out, size=len] char* str, size_t len);
    };
 
    untrusted {
        /* define OCALLs here. */
        void ocall_function([in, string] char* buf);
    };
};

В итоге после запуска консольного приложения, отрабатывает функция анклава ecall_function доверенного приложения, которая вызывает функцию в недоверенное приложение ocall_function и будет вывод: +++ OCALL output: I am enclave !

Далее функция ecall_function, копирует данные из анклава в буфер недоверенного приложения и этот буфер мы и распечатываем.
И будет вывод: +++ ECALL Output: I am enclave !

Выводы:

Как видите если использовать SDK от интела и Visual Studio, то работать с анклавами достаточно не сложно, нужно просто реализовать ECALLs/OCALLs функции для обмена с анклавом из вашего приложения.
Пример проекта можно глянуть в гите:https://github.com/XShar/Enclave_demo

Теперь можно-ли это применять в малваре ?

С одной стороны не плохо-бы делать так криптовку/раскриптовку строк, или самого зверька, реализовав весь алгоритм в ECALL функции.
Но тут есть негативные моменты:
1. Не все процессоры поддерживают SGX.
А поддерживают только новые компьютеры, начиная с 2016-2017 годов.
2. На некоторых компьютерах поддержку нужно включать в биос.

Ну и самый распространенный миф, что эта технология может обойти детект в памяти, при работе например крипторов, увы, но думаю что нет, т.к. память процесса должна-быть видна в системе, а раз она видна в системе, значит будет видна и антивирусу.
В целом плюсы этой технологии в том-что вы можете сами реализовывать ECALL - функции и то-что реализовано в этой функции не должно-быть доступно антивирусу и реверсеру.)

Надеюсь данная статья даст объяснение новичкам что такое SGX, также приведенный тут проект можно использовать для экспериментов и дальнейшего изучения технологии.)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
мифы мифами, но по-моему это никто не проверял)
Если sgx поддерживался бы не с 2к17 компов, то давно разработали технологию такую.
Хотя сами intel не дают однозначного ответа может ли это пропустить скана аверов, а лишь ссылаются на то, чтоб юзер не запускал такое ПО.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ну и самый распространенный миф, что эта технология может обойти детект в памяти, при работе например крипторов, увы, но думаю что нет, т.к. память процесса должна-быть видна в системе, а раз она видна в системе, значит будет видна и антивирусу
Так а что значит, что должна быть видна системе? Насколько я понимаю эту технологию, теоретически можно разместить в sgx анклаве динамическую библиотеку полностью, но нужно, чтобы она все внешние апи вызывала через OCALL. Не уверен, можно ли это сделать универсально (чтобы это можно было бы делать, скажем, в крипторах), вероятно придется все равно делать исполняемый файл какой-то определенной стурктуры.

Кстати есть еще и VBS анклавы, если в системе включена виртуализация.
 
Вот есть интересная статья на хакере:https://xakep.ru/2019/04/04/sgx-attack/

Ну как я понял эту технологию, что мы можем делать доверенное приложение, которое не будет видна никому, где можно реализовывать какие-то приватные алгоритмы и использовать скрытые данные, но если говорить о крипторах, мы-же не можем сделать какой-то "невидимый" для ядра поток, сам поток будет будет виден антивирусам и ядру, но какую-то часть криптора, например как-раз процедуру расшифровки и что-то ещё, можно скрыть...

Т.е. как многие думают, типо расшифровал пейлоад в эту скрытую память и потом запустил его, а как это сделать-то ?

Если мы создадим поток, то антивирус проверит его, ну-да до каких-то данных в защищенной памяти он недоберется просто, но проблема что расшифрованный пейлоад придётся передавать хост-приложению и тут антивирус его и проверит, собственно и будет детект.)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Если мы создадим поток, то антивирус проверит его, ну-да до каких-то данных в защищенной памяти он недоберется просто, но проблема что расшифрованный пейлоад придётся передавать хост-приложению и тут антивирус его и проверит, собственно и будет детект.)
Та память, которую будет исполнять поток после ECALL до выхода его через OCALL недоступна даже для ядра операционной системы.
 
Ну мы-же будем внешние апи вызывать через OCALL, а туда передавать как-раз уже расшифрованный пейлоад, который уже будет "виден" антивирусам ?

Или там от реализации зависит ?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
кста, авер же делает дамп памяти процесса? Можно ли отловить этот момент дампа и выгрузить малварь из виртуальной памяти? А после антиэмуля снова загрузить туда?
 
кста, авер же делает дамп памяти процесса? Можно ли отловить этот момент дампа и выгрузить малварь из виртуальной памяти? А после антиэмуля снова загрузить туда?
Как идея можно удалять PE заголовки и нужную служебную информацию как у своей программы, так и у пейлоада.

А заголовки PE хранить в какм-то месте.

Тогда для реверсера и антивирусов, это будет просто набор каких-то данных в оператосе, ну это как идея, сделать такое не сложно и реально.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Как идея можно удалять PE заголовки и нужную служебную информацию как у своей программы, так и у пейлоада.

А заголовки PE хранить в какм-то месте.

Тогда для реверсера и антивирусов, это будет просто набор каких-то данных в оператосе, ну это как идея, сделать такое не сложно и реально.
но как отловить?) Как похукать?)
С тем, что PE заголовки удалять проблем впринципе нету.
В крипторе параллельно можно тред запустить, чтоб он чекал и в случае чего скрывал нашу малварь.

Хотя смотри, авера же сигнатурный анализ. Не думаю, что удалив PE заголовок можно это обойти. Хотя можно поробовать удалить PE заголовок и посмотреть, детектит ли авер по сигнатурному. Прост суть в том, чтоб в памяти скрыть. Могу ошибаться...
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Ну мы-же будем внешние апи вызывать через OCALL, а туда передавать как-раз уже расшифрованный пейлоад, который уже будет "виден" антивирусам ?
Зачем во внешние апи передавать расшифрованный пейлоад?
 
Зачем во внешние апи передавать расшифрованный пейлоад?
Может что-то не понимаю, но если мы говорим о криторе, то пейлоад должен исполняться в хостовом потоке ?
Мы-же незнаем какие апи будет вызывать пейлоад ?

В теории может и можно загнать основной функционал в ECALL, но мне кажется с крипторами вряд-ли такое получится.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Мы-же незнаем какие апи будет вызывать пейлоад ?
Ну опять же чисто теоретически, когда мы настраиваем пейлоуду таблицу импорта, для каждого импорта мы можем сделать ассемблерный стаб, который сконвертирует исходный вызов в вызов OCALL(хеш-имени-длл, хеш-имени-функции, аргумент1, аргумент2, аргумент3, ...). Но да, в таком случае пейлоад не должен иметь динамических импортов, только статические.
 
но как отловить?) Как похукать?)
Где-то на факкаве по моему, была ещё старая статья от Мультика, по реверсу детекта нода в памяти.

Так-вот нод анализировал регистры и определял что пейлоад распакован и на него переходит управление и соотвественно был детект.

Вряд-ли из юзермода можно отловить чтение памяти.

К тому-же как показало исследование хуков апи, нод не хукает в юзермоде никакие апи.)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Вряд-ли из юзермода можно отловить чтение памяти.
Можно самому себе брейкпойнт поставить на чтение памяти, но это канеш бред наверное.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Можно самому себе брейкпойнт поставить на чтение памяти, но это канеш бред наверное.
заинжектиться в каспер, поставить хук на чтение памяти NtReadVirtualMemory, посмотреть какой процесс читает, а если наш, то завершать. Не ну а хуль. Каспер на инжект не детектит. Или вообще, лучшая защита - нападение. Инжектимся в службу каспера и оттуда уже выполняем код.
Мокрые мечты конечно...

А вообще, можно ли обойти проактивку, с хуками понятно, что нужно в ring0. Тут с драйверами заморочки. Ну мной выше описанный вариант мб поможет, прост сложно отловить когда авер дампает память. А так можно вообщем-то. Для криптора идеал вариант. В два треда: 1. Выгружаем код в память. 2. Смотрим, читает ли авер нашу память.

Я предпологаю, чтоб отлавить дампер авера не так-то сложно.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх