April 2, 2024

Ослепить Sysmon полностью. Манипулируем объектами ETW, чтобы обойти мониторинг

  1. Event Tracing for Windows
  2. Sysmon && ETW
  3. Манипулируем с ETW и ломаем Sysmon
  4. Выводы

По­лучив дос­туп к сис­теме, зло­умыш­ленник пер­вым делом пыта­ется вывес­ти из строя средс­тва ауди­та, что­бы как мож­но доль­ше оста­вать­ся незаме­чен­ным. В этой статье я покажу, как ата­кующий может осле­пить средс­тва монито­рин­га Windows путем манипу­ляций с под­систе­мой Event Tracing for Windows (ETW).

Приз­наюсь чес­тно, в прош­лом матери­але, ког­да я ска­зал, что у ата­кующе­го получи­лось осле­пить Sysmon путем манипу­ляций с дес­крип­тором безопас­ности устрой­ства \Device\SysmonDrv, я нем­ножеч­ко слу­кавил. На самом деле пос­ле про­делан­ных манипу­ляций Sysmon перес­танет фор­мировать лишь часть событий, но не все. Перес­тают генери­ровать­ся события, получен­ные от драй­вера SysmonDrv (это, кста­ти говоря, основная часть: события запус­ка и завер­шения про­цес­сов, заг­рузка DLL в адресное прос­транс­тво про­цес­са, заг­рузка драй­вера, манипу­ляций с клю­чами реес­тра и дру­гие). Но есть еще один пос­тавщик информа­ции, на осно­ве которо­го Sysmon фор­миру­ет свои события, — это ETW. Сегод­ня мы пос­мотрим на этот механизм со сто­роны ата­кующе­го и попыта­емся помани­пули­ровать его работой, что­бы «до кон­ца осле­пить Sysmon».

EVENT TRACING FOR WINDOWS

Event Tracing for Windows (ETW) — механизм опе­раци­онной сис­темы Windows, пред­назна­чен­ный для регис­тра­ции событий, про­исхо­дящих в сис­теме.

В ETW есть нес­коль­ко основных понятий: про­вай­деры, сес­сии, кон­трол­леры и пот­ребите­ли.

  • Про­вай­деры (providers, пос­тавщи­ки событий) — это при­ложе­ния (нап­ример, DLL), в которых реали­зова­ны фун­кции регис­тра­ции событий. Про­вай­дер дол­жен быть обя­затель­но зарегис­три­рован в под­систе­ме ETW и иметь GUID. По сути, имен­но про­вай­дер отсле­жива­ет сос­тояния при­ложе­ний (или сис­темы) и отправ­ляет события в сес­сию.
  • Сес­сии (sessions, сеанс трас­сиров­ки, лог­гер) — сущ­ности, которые собира­ют события от про­вай­деров и переда­ют их пот­ребите­лям. Одна сес­сия может пот­реблять события от одно­го или нес­коль­ких про­вай­деров. Сес­сии, как и про­вай­деры, тоже име­ют свой иден­тифика­тор (GUID).
  • Кон­трол­леры (controllers) — это при­ложе­ния (нап­ример, logman), которые управля­ют сес­сиями. Могут соз­давать или уда­лять сес­сии, а так­же изме­нять их парамет­ры.
  • Пот­ребите­ли событий (consumers) — при­ложе­ния, которые могут получать и как‑то обра­баты­вать события от одной или нес­коль­ких сес­сий, а так­же из фай­лов.

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

Де­ло в том, что один про­вай­дер может генери­ровать мно­жес­тво пре­доп­ределен­ных типов событий, часть из которых нуж­на одним пот­ребите­лям, а дру­гая часть — дру­гим. Имен­но на уров­не сес­сии про­исхо­дит филь­тра­ция событий. Кро­ме того, одной груп­пе пот­ребите­лей могут пот­ребовать­ся события не от одно­го, а сра­зу от груп­пы про­вай­деров, поэто­му сеанс трас­сиров­ки может собирать события сра­зу от нес­коль­ких про­вай­деров и отда­вать их нес­коль­ким пот­ребите­лям.

Да­вай пос­мотрим, как это выг­лядит в ядре ОС. За общее сос­тояние под­систе­мы ETW отве­чает струк­тура _ETW_SILODRIVERSTATE, адрес которой мож­но получить из гло­баль­ных перемен­ных ядра.

В этой струк­туре есть два инте­рес­ных нам поля: EtwpLoggerContext и EtwpGuidHashTable.

Ос­тановим­ся на них под­робнее.

Сессии ETW

По­ле EtwpLoggerContext — ука­затель на мас­сив струк­тур типа _WMI_LOGGER_CONTEXT, каж­дая из которых опи­сыва­ет сес­сию сбо­ра событий. Адре­са для этих струк­тур мож­но получить спо­собом, изоб­ражен­ным ниже.

Об­рати вни­мание, что пер­вые адре­са рав­ны 0x00000000 00000001. Ско­рее все­го, это свя­зано с тем, что два сеан­са трас­сиров­ки пре­доп­ределе­ны сис­темой и не могут быть изме­нены, поэто­му они име­ют такие зна­чения.

Да­вай пос­мотрим на опре­деле­ние струк­туры _WMI_LOGGER_CONTEXT.

На скри­не выведе­ны толь­ко наибо­лее инте­рес­ные нам детали:

  • По­ле LoggerId — иден­тифика­тор сеан­са трас­сиров­ки.
  • Па­раметр LoggerName содер­жит имя сес­сии в фор­мате _UNICODE_STRING.
  • InstanceGuid — иден­тифика­тор сес­сии трас­сиров­ки в фор­мате GUID.
  • Па­раметр SecurityDescriptor — ука­затель на дес­крип­тор безопас­ности сес­сии.
  • По­ле Consumers пред­став­ляет собой спи­сок струк­тур _ETW_REALTIME_CONSUMER, каж­дая из которых содер­жит ука­затель на струк­туру _EPROCESS. Сама струк­тура _ETW_REALTIME_CONSUMER опи­сыва­ет отдель­ный объ­ект — пот­ребитель событий.

По­ле ProcessObject — это ука­затель на струк­туру _EPROCESS про­цес­са‑пот­ребите­ля.

Для при­мера давай пос­мотрим на сес­сию 0xFFFFBA05E862D040.

Тут мы видим, что у сес­сии EventLog-Microsoft-Windows-Sysmon-Operational есть толь­ко один пот­ребитель и это про­цесс с иден­тифика­тором 1528. Инте­рес­но, что же это за про­цесс?

Да, это служ­ба жур­нала событий Windows, которая берет события Sysmon-про­вай­дера и записы­вает их в файл . evtx. Но об этом чуть поз­же. А пока давай вер­немся к струк­турам ядра.

ETW-провайдеры

На­вер­ное, было бы логич­но, если бы в _WMI_LOGGER_CONTEXT был ука­затель на мас­сив про­вай­деров, которые пишут события в сес­сию. Но нет, все устро­ено нем­ного ина­че.

Каж­дый зарегис­три­рован­ный в сис­теме про­вай­дер опи­сыва­ется струк­турой _ETW_GUID_ENTRY.

При­чем пос­тавщик событий может пре­дос­тавлять события не более чем в восемь сеан­сов трас­сиров­ки. Эти све­дения хра­нят­ся в поле EnableInfo, которое пред­став­ляет собой мас­сив струк­тур типа _TRACE_ENABLE_INFO. Эта струк­тура содер­жит информа­цию о «сос­тоянии про­вай­дера внут­ри сес­сии» (вклю­чен/вык­лючен — поле IsEnable), о «при­над­лежнос­ти» к кон­крет­ной сес­сии (поле LoggerId), а так­же поля филь­тра­ции событий (MatchAnyKayword и MatchAllKayword).

Па­рамет­ры про­вай­дера, опи­сан­ные в струк­туре _TRACE_ENABLE_INFO, мож­но нас­тро­ить одновре­мен­но для всех сес­сий. Для это­го в струк­туре _ETW_GUID_ENTRY есть отдель­ное поле ProviderEnableInfo.

Как ты можешь заметить, у каж­дого про­вай­дера есть свой дес­крип­тор безопас­ности — это поле SecurityDescriptor в струк­туре _ETW_GUID_ENTRY.

Об­рати вни­мание, что пер­вый эле­мент струк­туры — GuidList. Это двус­вязный спи­сок, в виде которо­го хра­нят­ся все про­вай­деры. Что­бы зарегис­три­ровать в сис­теме новый про­вай­дер, ядру нуж­но прой­тись по всем эле­мен­там это­го спис­ка и в конец добавить ссыл­ку на новую струк­туру. А что­бы выпол­нить какую‑либо опе­рацию над зарегис­три­рован­ным про­вай­дером (добавить про­вай­дер в сес­сию, вклю­чить/вык­лючить, изме­нить дес­крип­тор безопас­ности) ядру при­дет­ся прой­ти по каж­дому эле­мен­ту, пока он не най­дет нуж­ного ему пос­тавщи­ка. Такой под­ход негатив­но ска­зыва­ется на про­изво­дитель­нос­ти.

Да­вай вер­немся к основной струк­туре, опи­сыва­ющей сос­тояние ETW (струк­тура _ETW_SILODRIVERSTATE), и обра­тим вни­мание на поле EtwpGuidHashTable, оно име­ет тип _ETW_HASH_BUCKET. Это поле пред­став­ляет собой мас­сив из 64 типов (64 эле­мен­тов) спис­ков про­вай­деров.

Де­ло в том, что с эво­люци­ей Windows сущес­твен­но уве­личи­лось количес­тво пос­тавщи­ков событий, и с точ­ки зре­ния про­изво­дитель­нос­ти было бы не очень разум­но хра­нить это мно­жес­тво зарегис­три­рован­ных в сис­теме про­вай­деров в виде одно­го спис­ка. Поэто­му раз­работ­чики решили раз­делить все про­вай­деры на груп­пы. Приз­наком при­над­лежнос­ти про­вай­дера к опре­делен­ной груп­пе слу­жит взя­тый от GUID хеш, который вычис­ляет­ся вот по такой фор­муле:

Guid->Data1 XOR (Guid->Data2 XOR Guid->Data4[0] XOR Guid->Data4[4])) & 0x3F

Зна­чение 0x3F огра­ничи­вает раз­мер хеша шестью битами (64 уни­каль­ных зна­чения). Отсю­да и берет­ся раз­мер мас­сива EtwpGuidHashTable рав­ный 64 эле­мен­там.

По­мимо того что про­вай­деры делят­ся на груп­пы в зависи­мос­ти от хеша, они еще быва­ют нес­коль­ких типов. Типы про­вай­деров опре­деле­ны перечис­лени­ем _ETW_GUID_TYPE. Так, ListHead[0] содер­жит спи­сок про­вай­деров типа EtwTraceGuidType, а ListHead[1] — спи­сок типа EtwNotificationGuidType. Этот факт усложня­ет пред­став­ление спис­ков про­вай­деров в ядре Windows.

Итак, в сис­теме сущес­тву­ет 64 груп­пы спис­ков про­вай­деров, опре­делен­ных мас­сивом EtwpGuidHashTable. Каж­дая груп­па име­ет три раз­личных спис­ка, в зависи­мос­ти от типа. Сна­чала это не так прос­то осоз­нать, но не вол­нуй­ся, со вре­менем все обя­затель­но уло­жит­ся в голове.

Пред­лагаю поуп­ражнять­ся и най­ти хеш для про­вай­дера {5770385F-C22A-43E0-BF4C-06F5698FFBD9}. Забегая впе­ред, ска­жу, что это про­вай­дер, зарегис­три­рован­ный про­цес­сом Sysmon64.exe — Microsoft-Windows-Sysmon.

(0x5770385F XOR 0xC22A XOR 0xBF XOR 0x69) & 0x3F = 0x23

0x23 — 35 в десятич­ной сис­теме счис­ления. Это озна­чает что наш про­вай­дер хра­нит­ся в 35-м наборе спис­ков (в 35-м эле­мен­те мас­сива EtwpGuidHashTable). Давай про­верим это:

  1. Получим 35-й эле­мент мас­сива EtwpGuidHashTable:dx -r0 @$GuidTable = ((nt!_ESERVERSILO_GLOBALS*)&nt!PspHostSiloGlobals)->EtwSiloState->EtwpGuidHashTable[35]
  2. Из него возь­мем нулевой эле­мент спис­ка ListHead и выведем содер­жимое это­го спис­ка:dx -g Debugger.Utility.Collections.FromListEntry(@$GuidTable.ListHead[0], "nt!_ETW_GUID_ENTRY", "GuidList").Select(entry => new {GUID = entry.Guid, SecurityDescriptor = entry.SecurityDescriptor})
  3. Убеж­даем­ся, что в 35-м наборе спис­ков при­сутс­тву­ет GUID Sysmon-про­вай­дера.

NT Kernel Logger Session

По­мимо того что сеан­сы трас­сиров­ки могут соз­давать­ся отдель­ными при­ложе­ниями, в сис­теме сущес­тву­ет спе­циаль­ный тип сес­сии — NT Kernel Logger, который пред­назна­чен для наб­людения за пре­доп­ределен­ными клас­сами событий ядра ОС (события под­систе­мы вво­да‑вывода, менед­жера управле­ния памятью, менед­жера кон­фигура­ции и сте­ка TCP/IP и дру­гих). Для нужд этой сес­сии в сис­теме сущес­тву­ет и спе­циаль­ный про­вай­дер SystemTraceProvider (а начиная с Windows 10 — нес­коль­ко про­вай­деров), который отве­чает за фор­мирова­ние этих самых событий.

Что­бы вклю­чить в сес­сию сис­темный про­вай­дер, в поле LogFileMode струк­туры EVENT_TRACE_PROPERTIES нуж­но помес­тить зна­чение EVENT_TRACE_SYSTEM_LOGGER_MODE (0x02000000). В соот­ветс­твии с ру­ководс­твом Microsoft, что­бы опре­делить перечень событий, за которы­ми мы хотим наб­людать, нам нуж­но ука­зать «спи­сок» фла­гов в поле EnableFlags струк­туры EVENT_TRACE_PROPERTIES.

SYSMON && ETW

В при­веден­ном выше опи­сании мы нем­ного осве­жили зна­ния, которые нам помогут при иссле­дова­нии про­цес­сов работы инс­тру­мен­та Sysmon. Пора прис­тупать к самому иссле­дова­нию.

Итак, что­бы получить хоть какие‑то доказа­тель­ства того, что Sysmon и ETW име­ют отно­шение друг к дру­гу, пос­мотрим на спи­сок хен­длов про­цес­са Sysmon64.exe.

О том, как работа­ют коман­ды search name <ProcessPattern> и show handles <PID> <Type>, я рас­ска­зывал в прош­лом матери­але.

Как видим, в таб­лице хен­длов при­сутс­тву­ют опи­сате­ли для двух объ­ектов ядра типа EtwConsumer. Этот объ­ект пред­став­ляет собой под­клю­чен­ный ETW-пот­ребитель, спо­соб­ный получать события от сеан­сов трас­сиров­ки.

Вы­вод выше озна­чает, что про­цесс Sysmon64.exe пот­ребля­ет события от двух сес­сий. Про­верим это. Пос­мотрим на спи­сок всех сеан­сов трас­сиров­ки, зарегис­три­рован­ных в сис­теме, и най­дем наибо­лее под­ходящие по смыс­лу для Sysmon.

Ко­ман­да search session <SessionPattern> вызыва­ет фун­кцию QueryAllTracesW:

ULONG WMIAPI QueryAllTracesW( [out] PEVENT_TRACE_PROPERTIES *PropertyArray, [in] ULONG PropertyArrayCount, [out] PULONG LoggerCount);

Пос­ледние два парамет­ра (PropertyArrayCount и LoggerCount) ука­зыва­ют на име­ющееся и тре­буемое количес­тво эле­мен­тов мас­сива PropertyArray.

На пер­вом парамет­ре (PropertyArray) давай оста­новим­ся нем­ного под­робнее. Это ука­затель на мас­сив ука­зате­лей на струк­туры типа EVENT_TRACE_PROPERTIES, каж­дая из которых опи­сыва­ет парамет­ры сес­сии. Вни­матель­ный читатель задас­тся воп­росом, почему же нель­зя было переда­вать в фун­кцию прос­то ука­затель на мас­сив струк­тур EVENT_TRACE_PROPERTIES. Это, ско­рее все­го, свя­зано с тем, что струк­тура, опи­сыва­ющая сес­сию, не име­ет пос­тоян­ного раз­мера.

Де­ло в том, что в самой струк­туре отсутс­тву­ют поля «имя лог‑фай­ла» и «имя сес­сии», раз­мер каж­дого из которых не дол­жен пре­вышать 1024 сим­вола. Эти поля записы­вают­ся в память за струк­турой, а в самой струк­туре ука­зыва­ются прос­то сме­щения (поля LogFileNameOffset и LoggerNameOffset) отно­ситель­но ее начала. Навер­ное, с целью эко­номии памяти раз­работ­чики решили сде­лать раз­мер этой струк­туры перемен­ной дли­ны.

Что­бы получить спи­сок сес­сий, нуж­но сде­лать как минимум два вызова фун­кции QueryAllTracesW. Пер­вый вер­нет количес­тво сес­сий. На осно­ве этой информа­ции нуж­но будет:

  1. Выделить память для мас­сива ука­зате­лей с количес­твом эле­мен­тов, рав­ным количес­тву сес­сий.
  2. Выделить буфер­ную память, в которую будет сох­ранена информа­ция обо всех сес­сиях.
  3. Раз­делить буфер­ную память на кус­ки, в каж­дый из которых будет помеще­на информа­ция об отдель­ной сес­сии, а адре­сами каж­дого из кус­ков ини­циали­зиро­вать мас­сив ука­зате­лей, объ­явленный на пер­вом шаге.
  4. Для каж­дого буфер­ного кус­ка (для каж­дой струк­туры EVENT_TRACE_PROPERTIES) уста­новить зна­чения полей BufferSize, LoggerNameOffset и LogFileNameOffset.

Сно­ва выз­вать фун­кцию QueryAllTracesW и получить спи­сок сес­сий (при усло­вии, что раз­мера выделен­ного буфера хва­тит для сох­ранения этой информа­ции).

Итак, про­делан­ные манипу­ляции поз­волили нам получить три сеан­са, по наз­ванию схо­жие с Sysmon. Как мы выяс­нили ранее, сес­сия EventLog-Microsoft-Windows-Sysmon-Operational соз­дана для того, что­бы служ­ба жур­нала событий Windows мог­ла пот­реблять события от Sysmon и писать их в соот­ветс­тву­ющий жур­наль­ный файл. Эту сес­сию давай оста­вим напос­ледок, а сей­час оста­новим­ся на сеан­сах SysmonDnsEtwSession и SYSMON TRACE.

Но для начала убе­дим­ся, что их пот­ребитель — это имен­но про­цесс Sysmon64.exe. Мне неиз­вестен спо­соб, как это мож­но сде­лать из режима поль­зовате­ля, поэто­му обра­тим­ся к нашему любимо­му отладчи­ку.

В WinDbg есть рас­ширение !wmitrace, которое поз­воля­ет удоб­но работать со струк­турами ETW. С помощью коман­ды !wmitrace.strdump получим спи­сок сеан­сов ETW.

Ко­ман­дой !wmitrace.logger <LoggerId> получим под­робную информа­цию о сес­сии SYSMON TRACE.

По­ле Consumer содер­жит сос­тоящий из одно­го эле­мен­та спи­сок адре­сов струк­тур _ETW_REALTIME_CONSUMER, каж­дая из которых содер­жит ука­затель на _EPROCESS.

Та­ким обра­зом мы убеж­даем­ся, что пот­ребите­лем сес­сии SYSMON TRACE явля­ется про­цесс Sysmon64.exe.

Для сеан­са SysmonDnsEtwSession пот­ребитель тоже Sysmon64.exe. Про­верить это ты можешь самос­тоятель­но, про­делав перечень шагов, ана­логич­ный опи­сан­ному выше.

МАНИПУЛИРУЕМ С ETW И ЛОМАЕМ SYSMON

Мы убе­дились, что Sysmon для сво­его фун­кци­они­рова­ния соз­дает нес­коль­ко сеан­сов трас­сиров­ки. Давай теперь пос­мотрим, какие имен­но манипу­ляции могут совер­шать ата­кующие при попыт­ке осле­пить Sysmon.

Выключаем провайдеры сессии SysmonDnsEtwSession

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

Да­вай пос­мотрим на спи­сок про­вай­деров, от которых сес­сия SysmonDnsEtwSession получа­ет события.

Ко­ман­да show session <SessionHandle> вызыва­ет фун­кцию ControlTraceW с парамет­ром EVENT_TRACE_CONTROL_QUERY.

ULONG WMIAPI ControlTraceW( [in] TRACEHANDLE TraceHandle, [in] LPCWSTR InstanceName, [in, out] PEVENT_TRACE_PROPERTIES Properties, [in] ULONG ControlCode);

Прой­дем­ся по парамет­рам.

  • TraceHandle при­нима­ет иден­тифика­тор (дес­крип­тор сес­сии).
  • Вто­рой параметр (InstanceName) — имя сес­сии. Один из пер­вых двух парамет­ров может быть равен NULL.
  • Сле­дующий параметр воз­вра­щает струк­туру опи­сания сес­сии EVENT_TRACE_PROPERTIES.
  • В парамет­ре ControlCode ука­зыва­ется код опе­рации. В нашем слу­чае он равен EVENT_TRACE_CONTROL_QUERY.

Вы­зов этой фун­кции поз­воля­ет получить информа­цию об име­ни сес­сии, ее GUID, а так­же парамет­ры LogFileMode и EnableFlags, но не пре­дос­тавля­ет информа­ции о про­вай­дерах.

Да­лее нам нуж­но получить информа­цию о про­вай­дерах, которые пре­дос­тавля­ют события в сес­сию. Я не знаю спо­соба, как зап­росто получить спи­сок про­вай­деров для кон­крет­ной сес­сии. Судя по тому, как это дела­ет оснас­тка perfmon.exe, логика тут сле­дующая: нуж­но получить пол­ный спи­сок про­вай­деров, зарегис­три­рован­ных в сис­теме, прой­тись по каж­дому и най­ти приз­наки его при­над­лежнос­ти к сес­сии ETW. В целом логика пов­торя­ет струк­туру пред­став­ления про­вай­деров в ядре Windows.

По­лучить спи­сок про­вай­деров мож­но с помощью вызова TdhEnumerateProviders:

TDHSTATUS TdhEnumerateProviders( [out] PPROVIDER_ENUMERATION_INFO pBuffer, [in, out] ULONG *pBufferSize);

Эта фун­кция воз­вра­щает струк­туру дан­ных типа PROVIDER_ENUMERATION_INFO, которая содер­жит информа­цию о количес­тве зарегис­три­рован­ных в сис­теме про­вай­деров (параметр NumberOfProviders), и мас­сив типа TRACE_PROVIDER_INFO, который опи­сыва­ет каж­дый про­вай­дер в отдель­нос­ти с ука­зани­ем име­ни (вычис­ляет­ся с помощью ProviderNameOffset) и GUID (поле ProviderGuid). Таким обра­зом, вызов фун­кции TdhEnumerateProviders вер­нет нам информа­цию об име­нах и GUID про­вай­деров, но не даст информа­ции о при­над­лежнос­ти про­вай­деров к кон­крет­ной сес­сии.

Что­бы получить недос­тающую информа­цию, мы для каж­дого про­вай­дера дол­жны выз­вать фун­кцию EnumerateTraceGuidsEx:

ULONG WMIAPI EnumerateTraceGuidsEx( [in] TRACE_QUERY_INFO_CLASS TraceQueryInfoClass, [in] PVOID InBuffer, [in] ULONG InBufferSize, [out] PVOID OutBuffer, [in] ULONG OutBufferSize, [out] PULONG ReturnLength);

Раз­берем парамет­ры.

  • TraceQueryInfoClass при­нима­ет тип зап­роса фун­кции. В нашем слу­чае он равен TraceGuidQueryInfo, это озна­чает, что нам нуж­но получить информа­цию о про­вай­дере.
  • GUID про­вай­дера переда­ется в виде буфера InBuffer.
  • Па­раметр InBufferSize опре­деля­ет раз­мер буфера.
  • Чет­вертым парамет­ром (OutBuffer) переда­ется ука­затель на воз­вра­щаемый буфер.
  • Пя­тый (OutBufferSize) и шес­той (ReturnLength) парамет­ры ука­зыва­ют раз­мер име­ющей­ся и тре­буемой памяти, в которую помеща­ется резуль­тат работы фун­кции.
  • Па­раметр OutBuffer пред­став­ляет собой струк­туру дан­ных, заголов­ком которой явля­ется TRACE_GUID_INFO.

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

Ви­дим, что в сес­сию вклю­чен один про­вай­дер — Microsoft-Windows-DNS-Client. Отклю­чим его от сес­сии SysmonDnsEtwSession. Это мож­но сде­лать с помощью фун­кции EnableTraceEx2 с парамет­ром EVENT_CONTROL_CODE_DISABLE_PROVIDER:

ULONG WMIAPI EnableTraceEx2( [in] TRACEHANDLE TraceHandle, [in] LPCGUID ProviderId, [in] ULONG ControlCode, [in] UCHAR Level, [in] ULONGLONG MatchAnyKeyword, [in] ULONGLONG MatchAllKeyword, [in] ULONG Timeout, [in, optional] PENABLE_TRACE_PARAMETERS EnableParameters);

  • Пер­вый параметр (TraceHandle) — дес­крип­тор сес­сии трас­сиров­ки. В нашем слу­чае этот параметр равен 0x23.
  • В сле­дующем парамет­ре (ProviderId) переда­ется GUID про­вай­дера. Для про­вай­дера Microsoft-Windows-DNS-Client он равен {1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}.
  • Па­раметр ControlCode при­нима­ет тип опе­рации (EVENT_CONTROL_CODE_DISABLE_PROVIDER).
  • Чет­вертый параметр (Level) — уро­вень логиро­вания. Уста­новим его в TRACE_LEVEL_INFORMATION.
  • Пя­тый и шес­той парамет­ры (MatchAnyKeyword и MatchAllKeyword) при­нима­ют парамет­ры филь­тра­ции событий. Уста­новим их рав­ными 0xFFFFFFFFFFFFFFFF и 0x00 соот­ветс­твен­но.
  • Пос­ледние парамет­ры (Timeout и EnableParameters) уста­новим рав­ными нулю.

Ко­ман­да disable <ProviderGuid> <SessionHandle> работа­ет на осно­ве фун­кции EnableTraceEx2.

От­кры­ваем оснас­тку «Прос­мотр событий», пыта­емся отре­зол­вить нас­коль­ко DNS-имен и убеж­даем­ся в отсутс­твии событий «EventID 22 (DNS query)» в жур­нале Microsoft-Windows-Sysmon\Operational.

Итак, нашему ата­кующе­му уда­лось скрыть события раз­решения имен от Sysmon, но остался еще один тип событий — «EventID 3 (Network connection detection)».

Изменяем флаги сессии SYSMON TRACE

Те­перь давай пос­мотрим, какие про­вай­деры отправ­ляют события в сеанс SYSMON TRACE.

Как видим, спи­сок про­вай­деров пуст, одна­ко тут сто­ит обра­тить вни­мание на зна­чение парамет­ра LogFileMode и вспом­нить про спе­циаль­ный тип сес­сий — NT Kernel Logger. Видим, что в спис­ке парамет­ров при­сутс­тву­ет EVENT_TRACE_SYSTEM_LOGGER_MODE (0x02000000). Это зна­чит, что про­вай­дером для нее явля­ется SystemTraceProvider, а перечень типов событий опре­деля­ется парамет­ром EnableFlags (0x10000).

Пред­ста­вим, что нашему ата­кующе­му приш­ло в голову отклю­чить все типы событий сис­темно­го про­вай­дера. Это мож­но сде­лать с помощью вызова фун­кции ControlTraceW с парамет­ром EVENT_TRACE_CONTROL_UPDATE. А в саму фун­кцию передать струк­туру EVENT_TRACE_PROPERTIES с парамет­ром EnableFlags, рав­ным 0x00. Коман­да set enableflags <SessionHandle> <Flags> выпол­няет эти опе­рации.

Пов­торно откры­ваем оснас­тку «Прос­мотр событий», пыта­емся уста­новить соеди­нение с каким‑нибудь сер­вером и убеж­даем­ся в отсутс­твии не толь­ко событий «EventID 22 (DNS query)», но и событий «EventID 3 (Network connection detection)» в жур­нале Microsoft-Windows-Sysmon\Operational.

Манипулируем дескрипторами безопасности сессии EventLog-Microsoft-Windows-Sysmon-Operational

В ито­ге всю информа­цию, получа­емую от модуля ядра SysmonDrv и от под­систе­мы ETW, служ­ба режима поль­зовате­ля Sysmon агре­гиру­ет внут­ри себя и пишет в жур­нал событий Microsoft-Windows-Sysmon\Operational.

В этом механиз­ме так­же задей­ство­ваны сес­сии ETW и про­вай­деры. Ранее мы с тобой видели, что в сис­теме при­сутс­тву­ют три сес­сии, соз­вучные с Sysmon, и пер­вая из них — EventLog-Microsoft-Windows-Sysmon-Operational, которую мы догова­рива­лись оста­вить на конец. Так вот, конец нас­тал!

Да­вай пос­мотрим на спи­сок про­вай­деров этой сес­сии.

Ви­дим, что у сес­сии есть один про­вай­дер — Microsoft-Windows-Sysmon.

Ра­нее, ког­да мы смот­рели струк­туры ядра, опи­сыва­ющие объ­екты сес­сии и про­вай­дера, видели, что у каж­дой из них есть поле SecurityDescriptor. Пред­лагаю поп­робовать помани­пули­ровать им.

Да­вай сна­чала поп­робу­ем изме­нить SecurityDescriptor для про­вай­дера Microsoft-Windows-Sysmon, а потом для сес­сии EventLog-Microsoft-Windows-Sysmon-Operational и пос­мотрим, что из это­го вый­дет.

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

Пос­мотрим на дес­крип­тор безопас­ности про­вай­дера. Это мож­но сде­лать, исполь­зуя вызов EventAccessQuery:

ULONG EVNTAPI EventAccessQuery( [in] LPGUID Guid, [in, out] PSECURITY_DESCRIPTOR Buffer, [in, out] PULONG BufferSize);

  • Пер­вым парамет­ром (Guid) переда­ется GUID сес­сии или про­вай­дера.
  • Вто­рым парамет­ром (Buffer) переда­ется адрес буфера, в который будет помещен дес­крип­тор безопас­ности сес­сии или про­вай­дера.
  • И наконец, пос­ледний параметр (BufferSize) получа­ет и воз­вра­щает раз­мер буфера.

Дес­крип­тор безопас­ности име­ет сле­дующий вид:

O:BAG:BAD:(A;;0x1800;;;WD)(A;;0x120fff;;;SY)(A;;0x120fff;;;LS)(A;;0x120fff;;;NS)(A;;0x120fff;;;BA)(A;;0xee5;;;LU)(A;;LC;;;MU)(A;;0x1800;;;AC)(A;;0x1800;;;S-1-15-3-1024-3153509613-960666767-3724611135-2725662640-12138253-543910227-1950414635-4190290187)

Пер­вая запись в спис­ке DACL (A;;0x1800;;;WD) озна­чает, что для учет­ной записи Everyone нуж­но пре­дос­тавить сле­дующий дос­туп:

TRACELOG_ACCESS_KERNEL_LOGGER | TRACELOG_REGISTER_GUIDS

Вто­рая запись ((A;;0x120fff;;;SY)) пре­дос­тавля­ет пол­ный дос­туп для учет­ной записи Local System.

Да­вай явно зап­ретим для Local System дос­туп к про­вай­деру — (D;;0x120fff;;;SY), а ACE для учет­ки Everyone вооб­ще убе­рем. Это мож­но сде­лать с помощью фун­кции EventAccessControl:

ULONG EVNTAPI EventAccessControl( [in] LPGUID Guid, [in] ULONG Operation, [in] PSID Sid, [in] ULONG Rights, [in] BOOLEAN AllowOrDeny);

  • Пер­вым парамет­ром (Guid) переда­ется иден­тифика­тор про­вай­дера или сеан­са, для которо­го нуж­но изме­нить дес­крип­тор безопас­ности.
  • Вто­рым (Operation) ука­зыва­ется тип опе­рации. Это может быть добав­ление записи в спис­ки DACL/SACL или пол­ная замена этих спис­ков.
  • Треть­им парамет­ром (Sid) переда­ется иден­тифика­тор учет­ной записи, для которой изме­няют­ся пра­ва дос­тупа.
  • Сле­дующим парамет­ром (Rights) переда­ется перечень прав дос­тупа в виде мас­ки.
  • И пос­ледним парамет­ром (AllowOrDeny) опре­деля­ется тип опе­рации: раз­решить или зап­ретить.

Ко­ман­да set sddldacl <Guid> <sddldacl> реали­зует вызов этой фун­кции.

Пе­резаг­ружа­ем машину и убеж­даем­ся, что в жур­нале Sysmon нет событий. При­чем пос­ледним событи­ем явля­ется EventID 255. Эта тех­ника, в отли­чие от пре­дыду­щих, будет пер­систен­тной.

По­луча­ем еще один детект для нашего SIEM:

Provider Name='Microsoft-Windows-Sysmon' and EventID='255' and Data Name.Description='Failed to open service configuration with error 94 - Last error: Носитель защищен от записи.'

Вер­нем все назад и поп­робу­ем про­делать ана­логич­ные манипу­ляции для сес­сии трас­сиров­ки. Спи­сок DACL име­ет сле­дующий вид:

D:(A;;0x1800;;;WD)(A;;0x120fff;;;SY)(A;;0x120fff;;;LS)(A;;0x120fff;;;NS)(A;;0x120fff;;;BA)(A;;0xee5;;;LU)(A;;LC;;;MU)(A;;0x1800;;;AC)(A;;0x1800;;;S-1-15-3-1024-3153509613-960666767-3724611135-2725662640-12138253-543910227-1950414635-4190290187)

По ана­логии с про­вай­дером ребутим хост, откры­ваем оснас­тку «Прос­мотр событий» и видим сле­дующую кар­тину.

И будет счастье нашему ата­кующе­му, ну а для нас это пол­ное разоча­рова­ние... На этот раз Sysmon даже ничего не ска­жет!

Од­нако не все так пло­хо: если у тебя в инфраструк­туре нас­тро­ен WEC, в жур­нале Microsoft-Windows-Eventlog-ForwardingPlugin/Operational ты можешь обна­ружить сле­дующее событие.

ВЫВОДЫ

Нам уда­лось вос­про­извести дей­ствия ата­кующе­го и осле­пить Sysmon, манипу­лируя с под­систе­мой ETW. Конеч­но же, пре­дел у фан­тазий хакеров отсутс­тву­ет нап­рочь: здесь еще огромное поле для твор­чес­тва, и мы обя­затель­но про­дол­жим его осва­ивать!