Категория > Новости > Флуктуация шелл-кода. Пишем инжектор для динамического шифрования полезной нагрузки в памяти - «Новости»

Флуктуация шелл-кода. Пишем инжектор для динамического шифрования полезной нагрузки в памяти - «Новости»


19-06-2022, 00:01. Автор: Goldman
smbexec.py, wmiexec.py, dcomexec.py, scshell.py и Evil-WinRM. Но, во‑пер­вых, это чер­тов­ски неудоб­но, во‑вто­рых, ты потен­циаль­но стал­кива­ешь­ся с проб­лемой double-hop-аутен­тифика­ции (как, нап­ример, с Evil-WinRM), а в‑треть­их и далее — ты не можешь поль­зовать­ся объ­ективно полез­ными фичами C2, как, нап­ример, исполне­ние .NET из памяти или под­нятие прок­си через ском­про­мети­рован­ную тач­ку.

Ес­ли не рас­смат­ривать сов­сем уж инва­зив­ные под­ходы типа пат­чинга RDP при помощи Mimikatz (AKA ts::multirdp), оста­ется работа из аген­та С2. И вот здесь ты стол­кнешь­ся с проб­лемой бай­паса средств защиты. Спой­лер: по моему опы­ту, в 2022-м при активнос­ти любого «уво­жаемо­го» анти­виру­са или EDR на хос­те твой агент C2, которо­го ты так дол­го пытал­ся получить (и все же получил, зак­рипто­вав наг­рузку миль­ён раз), про­живет в луч­шем слу­чае не боль­ше часа.


Все­му виной баналь­ное ска­ниро­вание памяти запущен­ных про­цес­сов анти­виру­сами, которое выпол­няет­ся по рас­писанию с целью поис­ка сиг­натуры извес­тных злов­редов. Еще раз: по­лучить аген­та с активным AV (и даже нем­ного из него порабо­тать) нет­рудно; сде­лать так, что­бы этот агент про­жил хотя бы сут­ки на машине‑жер­тве, бес­ценно уже слож­нее, потому что, как бы ты ни крип­товал и ни энко­дил бинарь, PowerShell-стей­жер или шелл‑код аген­та, вре­донос­ные инс­трук­ции все рав­но ока­жут­ся в памяти в откры­том виде, из‑за чего ста­нут лег­кой добычей для прос­того сиг­натур­ного ска­нера.



KES поднимает тревогу!


Ес­ли тебя спа­лят с вре­доно­сом в сис­темной памяти, который не под­креп­лен подоз­ритель­ным бинарем на дис­ке (нап­ример, ког­да име­ла мес­то инъ­екция шелл‑кода в про­цесс), тот же Kaspersky Endpoint Security при дефол­тных нас­трой­ках не опре­делит, какой имен­но про­цесс заражен, и в качес­тве решения нас­той­чиво пред­ложит тебе перезаг­рузить машину.


Да‑да, мы поняли

Та­кое поведе­ние вызыва­ет еще боль­шее негодо­вание у пен­тесте­ра, потому что испу­ган­ный поль­зователь сра­зу побежит жаловать­ся в IT или к безопас­никам.



Есть два пути решить эту проб­лему.



  1. Ис­поль­зовать C2-фрей­мвор­ки, которые еще не успе­ли намозо­лить гла­за блю­тиме­рам и чьи аген­ты еще не попали в спи­сок лег­кодетек­тиру­емых. Дру­гими сло­вами, писать свое, искать малопо­пуляр­ные решения на гит­хабе с уче­том реги­ональ­ных осо­бен­ностей AV, который ты соб­рался бай­пасить, и тому подоб­ное.

  2. При­бег­нуть к прод­винутым тех­никам сок­рытия инди­като­ров ком­про­мета­ции пос­ле запус­ка аген­та C2. Нап­ример, под­чищать ано­малии памяти пос­ле запус­ка потоков, исполь­зовать связ­ку «неис­полня­емая память + ROP-гад­жеты» для раз­мещения аген­та и его фун­кци­они­рова­ния, шиф­ровать наг­рузку в памяти, ког­да вза­имо­дей­ствие с аген­том не тре­бует­ся.


В этой статье мы на при­мере пос­мотрим, как воору­жить прос­той PoC флук­туирующе­го шелл‑кода (ком­бинация треть­его и час­тично вто­рого и пун­кта из абза­ца выше) для его исполь­зования с поч­ти любым опен­сор­сным фрей­мвор­ком C2. Но для начала нем­ного экскур­са в исто­рию.


 

A long time ago in a galaxy far, far away...


 

Флипы памяти RX → RW / NA


Пер­вым опен­сор­сным про­ектом, пред­лага­ющим PoC-решение для укло­нения от ска­ниро­вания памяти, о котором я узнал, был gargoyle.


Ес­ли не углублять­ся в реали­зацию, его глав­ная идея зак­люча­ется в том, что полез­ная наг­рузка (исполня­емый код) раз­меща­ется в неис­полня­емой области памяти (PAGE_READWRITE или PAGE_NOACCESS), которую не ста­нет ска­ниро­вать анти­вирус или EDR. Пред­варитель­но заг­рузчик gargoyle фор­миру­ет спе­циаль­ный ROP-гад­жет, который выс­тре­лит по тай­меру и изме­нит стек вызовов таким обра­зом, что­бы вер­хушка сте­ка ока­залась на API-хен­дле VirtualProtectEx, — это поз­волит нам изме­нить мар­киров­ку защиты памяти на PAGE_EXECUTE_READ (то есть сде­лать память исполня­емой). Даль­ше полез­ная наг­рузка отра­бота­ет, сно­ва передаст управле­ние заг­рузчи­ку gargoyle, и про­цесс пов­торит­ся.


Ме­ханизм работы gargoyle (изоб­ражение — lospi.net)

www


Прин­цип работы gargoyle мно­го раз допол­нили, улуч­шили и «пере­изоб­рели». Вот нес­коль­ко при­меров:




  • Bypassing Memory Scanners with Cobalt Strike and Gargoyle


  • Bypassing PESieve and Moneta (The “easy” way....?)


  • A variant of Gargoyle for x64 to hide memory artifacts using ROP only and PIC


Так­же инте­рес­ный под­ход про­демонс­три­рова­ли в F-Secure Labs, реали­зовав рас­ширение Ninjasploit для Meterpreter, которое по кос­венным приз­накам опре­деля­ет, что Windows Defender вот‑вот запус­тит про­цеду­ру ска­ниро­вания, и тог­да «фли­пает» область памяти с аген­том на неис­полня­емую пря­мо перед этим. Сей­час, ско­рее все­го, это рас­ширение уже не «взле­тит», так как и Meterpreter, и «Дефен­дер» обно­вились не по одно­му разу, но идея все рав­но показа­тель­на.


Из это­го пун­кта мы заберем с собой глав­ную идею: изме­нение мар­киров­ки защиты памяти помога­ет скрыть факт ее зараже­ния.


Флуктуация шелл-кода. Пишем инжектор для динамического шифрования полезной нагрузки в памяти - «Новости»
Вот что на самом деле про­исхо­дит под капотом этой тех­ники 

Cobalt Strike: Obfuscate and Sleep


В далеком 2018 году выш­ла вер­сия 3.12 куль­товой C2-плат­формы Cobalt Strike. Релиз называл­ся «Blink and you’ll miss it», что как бы намека­ет на глав­ную фичу новой вер­сии — дирек­тиву sleep_mask, в которой реали­зова­на кон­цепция obfuscate-and-sleep.


Эта кон­цепция вклю­чает в себя сле­дующий алго­ритм поведе­ния бикона:



  1. Ес­ли маячок «спит», то есть без­дей­ству­ет, выпол­няя kernel32!Sleep и ожи­дая коман­ды от опе­рато­ра, содер­жимое исполня­емо­го (RWX) сег­мента памяти полез­ной наг­рузки обфусци­рует­ся. Это меша­ет сиг­натур­ным ска­нерам рас­познать в нем Behavior:Win32/CobaltStrike или похожую бяку.

  2. Ес­ли маяч­ку пос­тупа­ет на исполне­ние сле­дующая коман­да из оче­реди, содер­жимое исполня­емо­го сег­мента памяти полез­ной наг­рузки деоб­фусци­рует­ся, коман­да выпол­няет­ся, и подоз­ритель­ное содер­жимое маяка обратно обфусци­рует­ся, прев­раща­ясь в нераз­борчи­вый циф­ровой мусор на радость опе­рато­ру «Кобы» и на зло бдя­щему анти­виру­су.


Эти дей­ствия про­ходят проз­рачно для опе­рато­ра, а про­цесс обфуска­ции пред­став­ляет собой обыч­ный XOR по исполня­емой области памяти с фик­сирован­ным раз­мером клю­ча 13 байт (для вер­сий CS от 3.12 до 4.3).


Про­демонс­три­руем это на при­мере. Я возь­му этот про­филь для CS, написан­ный @an0n_r0 как PoC минималь­но необ­ходимо­го про­филя Malleable C2 для обхо­да «Дефен­дера». Опция set sleep_mask "true" акти­виру­ет про­цесс obfuscate-and-sleep.


По­лучи­ли маячок

Да­лее с помощью Process Hacker най­дем в бинаре «Кобы» сег­мент RWX-памяти (при задан­ных нас­трой­ках про­филя он будет один) и пос­мотрим его содер­жимое.


Циф­ровой мусор или?..

На пер­вый взгляд, и прав­да, выг­лядит как ничего не зна­чащий набор бай­тов. Но если уста­новить инте­рак­тивный режим маяч­ка коман­дой sleep 0 и «пок­лацать» нес­коль­ко раз на Re-read в PH, нам откро­ется исти­на.


Мас­ки прочь!
Де­обфусци­рован­ная наг­рузка маяч­ка

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


PURE EVIL

Од­нако на любое дей­ствие есть про­тиво­дей­ствие (или наобо­рот), поэто­му люди из Elastic, недол­го думая, за­пили­ли YARA-пра­вило для обна­руже­ния пов­торя­ющих­ся пат­тернов, «зак­сорен­ных» на одном и том же клю­че:


{meta:
author = "Elastic"
description = "Identifies deobfuscation routine used in Cobalt Strike Beacon DLL version 4.2."strings:
$a_x64 = {4C 8B 53 08 45 8B 0A 45 8B 5A 04 4D 8D 52 08 45 85 C9 75 05 45 85 DB 74 33 45 3B CB 73 E6 49 8B F9 4C 8B 03}
$a_x86 = {8B 46 04 8B 08 8B 50 04 83 C0 08 89 55 08 89 45 0C 85 C9 75 04 85 D2 74 23 3B CA 73 E6 8B 06 8D 3C 08 33 D2}condition:
any of them}


Перейти обратно к новости