Оглавление
- Введение
- Существенные изменения планировщика задач в Windows 8
- Новые (не)удобные фичи и их последствия
- Структура Actions
- Плагин «4RAYS TaskCache» для Registry Explorer
- Выводы
Введение
Команда Solar 4RAYS изучила множество материалов, посвященных DFIR в операционных системах Windows, и мы заметили,
что сообщество информационной безопасности игнорирует важное изменение в работе планировщика задач, которому уже
исполнилось 12 лет. Об обнаруженных нами проблемах писали в том или ином виде, но данная информация не освещается
широко и разбросана по разным статьям без общего вывода о критичности. А проблемы связаны с тем, что при анализе
систем начиная с Windows 8 вы можете не видеть часть задач, которые выполняет планировщик.
Представьте, что вы являетесь начинающим специалистом-форензиком и вам требуется изучить «Windows Persistence». Что
вы будете читать? Чем пользоваться? Курсы или книги могут отличаться, однако с высокой вероятностью вы все равно
столкнетесь с проблемой, когда ваше обучение дойдет до «Scheduled Task/Job T1053.005».
Для начала давайте ответим на вопрос:
Вам предоставили на анализ систему Windows 10, где атакующие точно закрепились с использованием планировщика
задач, и система даже включена! Увы, все журналы были очищены. Где вы будете искать командлайн вредоносной
задачи?
Ответ:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache
Так как иные артефакты могут содержать недействительные данные о задачах, а некоторые задачи могут быть скрыты
из
вывода популярных утилит и WinAPI, но продолжать работать
Если на данный вопрос вы ответили иначе, то добро пожаловать! Мы собрали в одном месте всё, что вы могли не знать о
планировщике задач в Windows.
Существенные изменения планировщика задач в Windows 8
В Windows 8 были внесены существенные изменения в расположение хранилища задач: хоть xml-файлы и продолжают
создаваться по пути «C:\Windows\System32\Tasks», на самом деле планировщик задач загружает данные из реестра, а
именно – из ключа TaskCache, который появился еще во времена Windows 7:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache
В ключе TaskCache имеется несколько разделов, и в актуальных версиях Windows образует следующую структуру:
В младших версиях Windows некоторые значения отсутствуют, однако сама структура не изменяется.
Далее остановимся на разделах и значениях, интересных с точки зрения DFIR:
Раздел\Значение |
Описание |
---|---|
TaskCache\Tree |
Используется системой для отображения задач при запросе их списка или дерева. Содержит разделы, |
TaskCache\Tree\TaskPath\Task\Index |
Тип триггера задачи. Имеет значение от 1 до 4: 1 – Boot 2 – Logon 3 – Plain
4 – Maintenance |
TaskCache\Tree\TaskPath\Task\Id |
UUID задачи |
TaskCache\Tree\SD TaskCache\Tree\TaskPath\SD TaskCache\Tree\TaskPath\Task\SD |
Security Descriptor, описывающий права доступа на просмотр данной задачи или дерева. Не связан с *появился лишь в Windows 10 |
TaskCache\Tasks |
Используется системой для хранения данных о задачах, включая командлайн. Содержит разделы, имена |
TaskCache\Tasks\{Id}\Actions |
Действия, которые должны выполниться после выполнения условий триггера |
TaskCache\Tasks\{Id}\Author |
Может содержать УЗ, с помощью которой была создана задача, но чаще всего содержит ссылку на dll |
TaskCache\Tasks\{Id}\DynamicInfo |
Содержит временные метки создания, последнего запуска и последнего завершения выполнения задачи |
TaskCache\Tasks\{Id}\Hash |
CRC32 или SHA256 хэш xml-файла задачи (C:\Windows\System32\Tasks\) |
TaskCache\Tasks\{Id}\Path |
Содержит относительный путь до объекта в дереве или xml-файла в директории Tasks |
TaskCache\Tasks\{Id}\SecurityDescriptor |
Права, определяющие кому и что разрешено делать с задачей |
TaskCache\Tasks\{Id}\Triggers |
Триггеры, запускающие задачу |
TaskCache\Boot TaskCache\Logon TaskCache\Maintenance TaskCache\Plain |
Содержит разделы, имена которых соответствуют UUID задач. Наличие раздела означает наличие ссылки Boot – содержит ссылки на задачи, которые требуется выполнить при загрузке системы Logon – при входе в систему Maintenance – при автоматическом обслуживании системы Plain – иные задачи |
В Windows 10 перенос задач в реестр был завершен окончательно, и xml-файлы остались лишь легаси-фичей, с помощью
которой можно быстро экспортировать и импортировать задачи через интерфейс планировщика.
Чтобы убедиться в этом, достаточно создать новую задачу в Windows 10 и удалить ее файл из директории
«C:\Windows\System32\Tasks» – планировщик продолжит корректно отображать и запускать «удаленную» задачу даже после
перезагрузки, а файл восстановится лишь в случае модификации задачи непосредственно через WinAPI.
В Windows 7 аналогичные действия приведут к полному удалению задачи из системы.
При этом в Windows 8 существование xml-файла задачи является обязательным для ее запуска и отображения в интерфейсе
планировщика, но содержимое данного файла никак не влияет на параметры задачи – файл может быть модифицирован или
даже очищен, а задача продолжит выполняться корректно, так как данные берутся из реестра. Однако при перезагрузке
службы планировщика задач файл будет восстановлен до исходного состояния.
Описанные далее выявленные проблемы в работе планировщика задач применимы ко всем версиям Windows с 8 по 11, включая
их серверные версии.
Новые (не)удобные фичи и их последствия
Новая логика работы планировщика принесла с собой несколько новых функций, которые обернулись неприятными
последствиями.
Легаси
Как уже было написано выше, xml-файл задачи по стандартному пути продолжает появляться при создании или модификации
задачи через интерфейс планировщика или утилиту командной строки schtasks. Однако он никак не влияет на работу
задачи, поэтому начиная с Windows 8 пользователь может модифицировать (а в Windows 10-11 даже удалить) xml-файл, не
изменив параметры задачи и не нарушив работу системы.
Содержимое xml-файлов в «C:\Windows\System32\Tasks\» начиная с Windows 8 не является достоверным источником
информации о задачах, которые работают в системе, так как целостность файла существующей задачи может быть нарушена
без влияния на систему
❗ Если ваша BlueTeam в выключенной системе смотрит лишь xml-файлы, вредоносные задачи с поддельным или удаленным
xml-файлом могут быть пропущены.
Начиная с Windows 8 удаление задач требуется выполнять лишь через интерфейс планировщика или утилиту schtasks. В
крайнем случае требуется удалить соответствующие задаче 3 раздела реестра.
❗ Если ваши системные администраторы продолжают удалять лишь xml-файлы задач в надежде удалить задачу из
планировщика, как это было в Windows 7 и частично подходит для Windows 8, то начиная с Windows 10 задача остается
активной.
Скрытие задач из вывода WinAPI и основанных на нем утилит
Техники, о которых писали давно, но не получившие широкого распространения. Они связаны с значениями Index и SD
раздела реестра в TaskCache\Tree.
- В значении SD указываются права на просмотр задачи, и при установке невалидного значения задача пропадает из
вывода утилит, использующих WinAPI, кроме прямого просмотра содержимого реестра; - В значении Index указывается тип триггера задачи (в диапазоне от 1 до 4), но если установить значение 0, то
задача также скроется от WinAPI.
Баг это или фича – неизвестно, но одними из первых об этом написали
сами же Microsoft в 2022 году в своем блоге, посвященном безопасности. Однако в указанной статье нет упоминания про
значение Index, о котором далее напишут коллеги из R-Vision в своей статье на
Habr. Реализацию техники с изменением Index со стороны атакующих мы также упомянули в статье «Reign of King: тактики и инструментарий группировки Obstinate
Mogwai».
При исследовании данной техники выяснилось, что она работает лишь начиная с Windows 10. В Windows 8 еще не было
реализовано значение SD, а изменение Index не влечет за собой сокрытия задачи.
Но что такое «невалидный SD»? В обнаруженных нами материалах многие пишут про случай, когда «SD = null», то есть
значение удалено, однако это лишь часть большей проблемы с данным значением.
Для выполнения техники с сокрытием задачи, атакующий может:
1) Удалить значение SD;
2) Очистить или изменить на произвольные байты содержимое SD;
3) Удалить из структуры SD информацию о владельце или группе.
При этом данные действия могут быть выполнены не только с разделом самой задачи, но и с разделом, который является
частью пути до задачи:
Таким образом, любые задачи, которые будут размещаться по пути «\Microsoft\Windows\Evil\», будут скрыты из вывода
списка задач WinAPI, но продолжат работать.
Вывод списка задач с помощью стандартных утилит (или основанных на WinAPI) начиная с Windows 10 также не является
достоверным источником данных о задачах, так как они могут быть скрыты из этого вывода.
❗ Если ваша BlueTeam в запущенной системе Windows 10 (и старше) смотрит задачи через утилиты, которые работают лишь
с WinAPI и не берут данные из реестра, то вредоносная задача будет пропущена.
Интересный факт: если задача скрыта с помощью изменения значения Index, то хоть она и скрыта из вывода списка задач,
прямой доступ к ней можно получить через консоль, если известен путь до неё. Из-за этого мы можем не только получить
информацию о самой задаче, но и удалить её:
schtasks /query /tn "\Microsoft\Windows\Evil\Task"
schtasks /delete /tn "\Microsoft\Windows\Evil\Task"
Однако если задача скрыта с помощью установки невалидного значения SD, аналогичные действия приведут к «Внутренней
ошибке».
Также можно отметить, что в Windows 10 и 11 атакующие могут удалить значение Index – без него задачи продолжат
выполняться, но тогда «Внутренняя ошибка» будет возникать каждый раз при открытии планировщика задач, и из системы
уже скроются абсолютно все задачи.
Обход логирования планировщика и изменение метадаты
Импорт, изменение или удаление значения в реестре системы, не является триггером для генерации событий планировщика
задач.
Для выполнения данной техники атакующим требуется создать файл с значениями для импорта.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Plain\{00000000-0000-0000-0000-000000000001}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\Evil]
"SD"=hex:01,00,04,80,88,00,00,00,98,00,00,00,00,00,00,00,14,00,00,00,02,00,74,\
00,04,00,00,00,00,10,18,00,9f,01,1f,00,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,00,10,14,00,9f,01,1f,00,01,01,00,00,00,00,00,05,12,00,00,00,00,\
10,18,00,ff,01,1f,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,00,00,\
24,00,89,00,12,00,01,05,00,00,00,00,00,05,15,00,00,00,da,29,6a,f7,90,54,53,\
10,ba,4e,d6,6f,e8,03,00,00,30,b5,26,31,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,01,05,00,00,00,00,00,05,15,00,00,00,da,29,6a,f7,90,54,53,10,ba,\
4e,d6,6f,01,02,00,00
"Id"="{00000000-0000-0000-0000-000000000001}"
"Index"=dword:00000003
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{00000000-0000-0000-0000-000000000001}]
"Path"="\\Evil"
"Triggers"=hex:17,00,00,00,00,00,00,00,00,df,17,79,58,00,00,00,00,00,00,00,00,\
00,00,00,00,df,17,79,58,00,00,00,ff,ff,ff,ff,ff,ff,ff,ff,38,21,41,42,48,48,\
48,48,cc,ca,a4,6b,48,48,48,48,0e,00,00,00,48,48,48,48,41,00,75,00,74,00,68,\
00,6f,00,72,00,00,00,48,48,00,00,00,00,48,48,48,48,00,48,48,48,48,48,48,48,\
00,48,48,48,48,48,48,48,01,00,00,00,48,48,48,48,1c,00,00,00,48,48,48,48,01,\
05,00,00,00,00,00,05,15,00,00,00,da,29,6a,f7,90,54,53,10,ba,4e,d6,6f,e8,03,\
00,00,48,48,48,48,1a,00,00,00,48,48,48,48,53,00,41,00,4e,00,44,00,42,00,4f,\
00,58,00,5c,00,55,00,73,00,65,00,72,00,00,00,48,48,48,48,48,48,2c,00,00,00,\
48,48,48,48,00,00,00,00,ff,ff,ff,ff,80,f4,03,00,ff,ff,ff,ff,07,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,48,48,\
48,48,77,77,00,00,00,00,00,00,00,df,17,79,58,00,00,00,00,00,00,00,00,00,00,\
00,00,df,17,79,58,00,00,00,ff,ff,ff,ff,ff,ff,ff,ff,00,00,00,00,ff,ff,ff,ff,\
00,00,00,00,00,00,00,00,00,00,00,00,00,02,00,00,01,ff,ff,ff,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,48,48,48,48,08,00,00,00,00,00,00,00,01,48,\
48,48,48,48,48,48
"Actions"=hex:03,00,0c,00,00,00,41,00,75,00,74,00,68,00,6f,00,72,00,66,66,00,\
00,00,00,06,00,00,00,63,00,6d,00,64,00,44,00,00,00,2f,00,63,00,20,00,73,00,\
74,00,61,00,72,00,74,00,20,00,68,00,74,00,74,00,70,00,3a,00,2f,00,2f,00,6c,\
00,6f,00,63,00,61,00,6c,00,68,00,6f,00,73,00,74,00,2f,00,6d,00,65,00,74,00,\
61,00,64,00,61,00,74,00,61,00,00,00,00,00,00,00
"DynamicInfo"=hex:03,00,00,00,00,57,F1,FB,5D,44,D1,01,00,48,F1,AF,C5,B1,9D,01,\
00,00,00,00,00,00,00,00,00,48,F1,AF,C5,B1,9D,01
Далее, обладая правами системы, требуется выполнить импорт значений в реестр. При перезагрузке службы планировщика
задача начнет работать без генерации событий о ее создании. Таким же образом задача может быть модифицирована и
удалена. Подробнее с примерами про это писали
R-Vision в той же статье на Habr.
❗ Если ваша BlueTeam смотрит лишь события создания, модификации или удаления задач в соответствующих журналах, то
вредоносная задача может быть пропущена.
Однако при проверке данной техники выяснилось, что помимо обхода логирования, атакующие также могут вписать
произвольные данные в значения, которые являются метадатой, что логично.
Так при проверке в Windows 10 выяснилось, что содержимое следующих значений может не содержать действительной
информации, а сами значения вовсе могут быть удалены:
- TaskCache\Tasks\{Id}\Author
- TaskCache\Tasks\{Id}\Date
- TaskCache\Tasks\{Id}\DynamicInfo
- TaskCache\Tasks\{Id}\Hash
- TaskCache\Tasks\{Id}\Schema
- TaskCache\Tasks\{Id}\URI
Временные метки в значениях Date и DynamicInfo могут быть подменены атакующими. Более ценной временной меткой
является модификация разделов, соответствующих задаче:
- TaskCache\Tasks\{Id}\ – модифицируется при работе задачи из-за изменения DynamicInfo;
- TaskCache\Tree\Name\ – модифицируется лишь при создании/изменении самой задачи и, в случае подмены метки
создания в метадате, может быть наиболее близко к действительной дате создания.
Значение Hash также может содержать недействительное значение – фильтрация по нему недопустима.
❗ Если ваша BlueTeam фильтрует задачи по хэшу xml-файла или значению TaskCache\Tasks\{Id}\Hash, то вредоносная
задача может быть пропущена.
Сообщество разработчиков утилит для DFIR
Вероятно, многие действительно пропустили переезд задач в реестр или не отметили важность данного обновления.
Безусловно, самая популярная утилита для удобного просмотра реестра Registry Explorer в 2024 году (спустя 12 лет
после релиза Windows все еще не обрабатывает их должным образом. А точнее, игнорирует значение Actions, которое
содержит командлайн задачи:
Данное значение можно посмотреть вручную, но там отображается лишь бинарная структура, требующая дополнительной
обработки.
Однако Registry Explorer – единственное ПО, которое хоть каким-то образом обрабатывает значения TaskCache: колонки
Created On, Last Start и Last Stop – это результат обработки значения DynamicInfo, которое также является бинарной
структурой. Впрочем, требуется помнить, что данные значения могут быть подменены атакующими.
Ситуация с популярным нынче Velociraptor двоякая. В документации были обнаружены весьма обнадеживающие страницы:
1) Задачи уже считаются сущностью из реестра, а логика сбора артефактов не связана с xml-файлами. Но здесь нас
встречает абзац TODO, где обещано добавить данный артефакт в основной репозиторий. На момент исследования в сентябре
2024 в релизной версии всё ещё отсутствует данное обновление.
Однако при ручном добавлении данного модуля выяснилось, что значение Actions не обрабатывается и сохраняется в
base64, которое абсолютно непригодно для просмотра человеком и требует дополнительной ручной обработки или
автоматизации. Еще один недостаток – отсутствие обработки значения DynamicInfo.
2) Отдельно подготовлен модуль для поиска скрытых задач, но он опирается лишь на значение SD в разделах задач, без
учета случаев с Index и модификации SD в разделе, который является частью пути. В релизной версии данного модуля
также не обнаружено. Дополнительно отмечается, что данный модуль лишь проверяет значение SD на null, когда задача
может быть скрыта модификацией значения, а не с помощью его удаления.
Прочие популярные инструменты, такие как AutoPsy, OsForensics и X-Ways, отображают реестр так же, как и стандартный
редактор реестра Windows: значение Actions не обрабатывается и представлено в виде hex-string. Утилиты Sysinternals
Autoruns и Nirsoft TaskSchedulerView не обнаруживают скрытые задачи в Windows 10-11, так как используют WinAPI,
однако отображают задачи без xml-файла.
Популярные утилиты для DFIR всё еще не обрабатывают ключ TaskCache:
1) Type Viewer в Registry Explorer позволяет немного упростить просмотр разделов, но это потребует поочередного
ручного просмотра значений, где их может быть более сотни;
2) Velociraptor при добавлении неопубликованных модулей позволяет собирать значения Actions, но сохранение
значения в base64 требует дополнительной обработки. При использовании данной утилиты из коробки, задачи из
TaskCache никак не обрабатываются.
Структура Actions
Если ни в одной из популярных утилит не реализована обработка значения Actions, неужели это невозможно? Структура
значения не является задокументированной Microsoft, но данным вопросом уже занимались исследователи
Windows еще в 2022 году. Мы не будем дублировать весь материал, представленный в исследовании с ресурса cyber.wtf, а
рассмотрим и дополним лишь основные моменты.
Структура состоит из заголовка и от одного до множества тел Actions. Если задача выполняет 3 действия при
срабатывании триггера, то структура будет иметь 3 последовательно записанных тела.
Тело Actions разделяется на несколько типов, которое определяется Magic-строкой в начале тела:
1) 0x6666 – прямой запуск исполняемого файла с необходимыми аргументами;
2) 0x7777 – запуск COM-объектов;
3) 0x8888 – отправка Email (устаревшее);
4) 0x9999 – вывод Message Box (устаревшее).
Отмечается, что планировщик задач не позволяет создавать устаревшие типы Actions.
Рассмотрим пример. В значении Actions хранятся данные:
03000C00000041007500740068006F00720066660000000010000000630061006C0063002E006500780065000000000000000000000077770000000029B731AEFDD51E40AF42784074835AFE3E0000002D0052006500670069007300740065007200550073006500720044006500760069006300650020002D004E00650077004100630063006F0075006E007400
Структура этих данных выглядит следующим образом:
|
Типы данных |
Описание |
---|---|---|
|
int16 версия int32 длина строки Unicode string |
Заголовок структуры. Содержит версию, а также Context задачи |
|
Magic: Action-Type int32 длина строки Unicode string int32 длина строки Unicode string int32 длина строки Unicode string int32 длина строки Unicode string Флаги |
Тело структуры, которое начинается с типа Action. Для типа 6666, далее следует 4 пары int32 и Unicode строки, которые хранят в себе значения: 1) id 2) command 3) arguments 4) directory
Данный тип завешается на 2 байта флагов, которые пока нам не встречались (флаги имеются лишь с |
|
Magic: Action-Type int32 длина строки Unicode string byte COM-object int32 длина строки Unicode string |
Для типа Action 7777, далее также следует пара int и Unicode строки для хранения значения id, после |
В результате обработки можно получить следующие данные:
Version: Context: |
3 Author |
ID: Command: Arguments: Working Directory: |
null calc.exe null null |
ID: COM-object: Data: |
null {29B731AE-FDD5-1E40-AF42-784074835AFE} -RegisterUserDevice -NewAccount |
А чтобы автоматически обработать значение из примера, можно использовать следующий код на C#:
byte[] keyValue = StringToByteArray("03000C00000041007500740068006F00720066660000000010000000630" +
"061006C0063002E006500780065000000000000000000000077770000000029B731AEFDD51E40AF42784074835A" +
"FE3E0000002D0052006500670069007300740065007200550073006500720044006500760069006300650020002" +
"D004E00650077004100630063006F0075006E007400");
using Stream stream = new MemoryStream(keyValue);
using BinaryReader reader = new BinaryReader(stream);
//Header
short version = reader.ReadInt16();string context = (version >= 2) ?
Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32())) : string.Empty;
//ActionType 0x6666
short type_first = reader.ReadInt16();
string id_first = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
string path = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
string arguments = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
string workingDirectory = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
short flags = (version >= 3) ?
reader.ReadInt16() : (short)0;
//ActionType 0x7777
short type_second = reader.ReadInt16();
string id_second = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
Guid clsid = new Guid(reader.ReadBytes(16));
string data = Encoding.Unicode.GetString(reader.ReadBytes(reader.ReadInt32()));
Плагин «4RAYS TaskCache» для Registry Explorer
Мы готовы поделиться собственным плагином для Registry Explorer, который позволяет просматривать значение Actions и
помогает искать скрытые задачи:
- Key Name – GUID задачи;
- Path – путь до задачи в дереве;
- Actions – перечисление командлайнов, которые выполняет задача;
- Actions Type – перечисление типов, которые используется в задаче;
- Tree Key Last Write – временная метка модификации раздела задачи в дереве;
- Created On, Last Start, Last Stop – обработка значения DynamicInfo;
- Index – соответствующее значение из дерева;
- Tree SD – уникальные значения SD разделов, образующие путь до задачи в дереве, с подсвечиванием случаев, когда
задача может быть скрыта из планировщика.
Если значение Index будет соответствовать 0 или возникнет один из описанных случаев с значением SD, то в колонке
Alert будет отображаться значение True, по которому также можно отфильтровать таблицу.
Загрузить скомпилированный плагин, а также ознакомиться с исходным кодом можно в нашем GitHub.
Для его установки требуется поместить dll-файл в директорию «..\RegistryExplorer\Plugins», после запуска
RegistryExplorer, при открытии «View» > «Plugins» должен появиться новый плагин.
При открытии ключа TaskCache, доступного в стандартных закладках, откроется таблица:
Поддержку данного плагина пока гарантировать не можем, однако о багах вы можете сообщить нам в GitHub в разделе
Issues.
Выводы
С обновления планировщика задач прошло уже 12 лет. Вероятно, BlueTeam пора отреагировать на данное изменение:
- Усовершенствовать инструменты для просмотра и сбора задач как для работы с работающими системами, так и при
работе с артефактами; - Внести правки в обучающие материалы по DFIR;
- Говорить об этой проблеме шире: некоторые системные администраторы всё ещё по привычке удаляют xml-файл задачи,
сохраняя в системе Persistence.
Еще раз повторим, почему стоит все это сделать уже сейчас:
- При работе с Windows 8, 10, 11 (и, вероятно, в будущих релизах) достоверные данные о работающих в системе
задачах хранятся лишь в реестре в ветке TaskCache:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache
- Xml-файлы по прежним путям – это лишь легаси файлы, которые могут быть модифицированы или удалены без влияния на
значения в реестре; - Во включенной системе задачи могут быть скрыты из вывода стандартных утилит или иных утилит, основанных на
WinAPI, если в значения Index или SD будут внесены изменения атакующим; - Создание, модификация и удаление задач с помощь импорта значений в реестр не генерирует событий соответствующих
действий с задачами; - На момент написания статьи ни одна из популярных утилит для DFIR не отображает скрытые задачи, а также не
обрабатывает все значения ключа TaskCache; - На текущий момент лучшим инструментом для просмотра и поиска подобных задач, по нашему мнению, является Registry
Explorer, в котором уже давно реализован просмотр списка задач по данным из реестра (но, к сожалению, без
командлайнов), а теперь для данного инструмента мы подготовили соответствующий плагин для дополнительной обработки
значений; - Удаление задач требуется выполнять лишь с помощью планировщика (интерфейс или командлайн). В крайнем случае –
удалять задачу напрямую из реестра. - Для удаления скрытых задач:
- Если Index = 0: удалить с помощью командлайна;
- Если значение SD не является валидным требуется удалить разделы реестра:
- ..\TaskCache\Tasks\{Id}
- ..\TaskCache\Tree\Path\TaskName
- ..\TaskCache\ (Boot / Logon / Maintenance / Plain) \{Id}
Напоследок приведем памятку про скрытые задачи:
А также итоговый таймлайн изменений в планировщике задач:
Версия Windows |
Изменения |
---|---|
Windows 7 Windows Server 2008 R2 Standard |
Первое появление TaskCache. Разделы задач содержат лишь 4 значения:
В дереве задач имеются значения:
Удаление xml-файла или ключей TaskCache равносильно удалению задачи
После ручного изменения xml-файла возникает ошибка «образ задачи был поврежден», а задача перестанет |
Windows 8 Windows Server 2012 |
В разделах задач стало больше значений:
TaskCache становится основным хранилищем задач, но без соответствующего задаче файла по пути |
Windows 10 Windows Server 2016 Windows Server 2019 Windows Server 2022 |
В разделах дерева появилось новое значение:
Для выполнения задач больше не требуется наличие какого-либо файла в «C:\Windows\System32\Tasks», Появление фич (багов) со скрытием задач, при изменении SD или Index в дереве |
Windows 11 |
Без изменений. Скрытие задач всё еще возможно. |
На этом у нас все. Пользуйтесь плагином на здоровье и, как говорится, happy hunting!
Полезные источники:
https://cyber.wtf/2022/06/01/windows-registry-analysis-todays-episode-tasks/
https://habr.com/ru/companies/rvision/articles/723050/
Уровень сложностиСредний
Время на прочтение14 мин
Количество просмотров16K
Привет, Хабр!
Многие передовые компании в области информационной безопасности в конце 2022 подвели итоги года по самым популярным техникам MITRE ATT&CK, используемым атакующими. Один из таких отчетов по обнаруженным угрозам был предоставлен RedCanary, а другой Лабораторией Касперского, согласно которым одной из наиболее популярных техник закрепления в системе является Scheduled Task(T1053.005) или, говоря русским языком, запланированная задача. На сегодняшний день существует много известных способов проведения данной техники: стандартная оснастка Task Scheduler от Microsoft, утилита schtasks, а также Poweshell командлеты, которые в свою очередь опираются на RPC-функции и др.
В данной статье хочу рассказать вам о нестандартном способе проведения техники Scheduled Task с помощью удаленного реестра (Remote Registry). После чего я представлю возможный вариант детектирования данного способа и попытаюсь раскрыть все сложности, с которыми придется столкнуться в процессе.
Предлагаю начать и сперва ознакомиться с тем, что собой представляет Scheduled Task.
Что такое Scheduled Task
Task Scheduler или Планировщик задач — служба в Windows, которая позволяет автоматизировано выполнять запланированные задачи на устройстве по заранее заданному триггеру (время, наступление определенного события и т.п.). Это одна из самых «древних» служб в Windows: впервые данный компонент появился в Windows 95, а в текущем виде он представлен в Windows Vista. Таким образом, за десятки лет активного использования Scheduled Task появилось достаточное количество способов и инструментов для работы с запланированными задачами.
Данная техника привлекает злоумышленников тем, что запланированные задачи являются легитимными в операционной системе Windows. Это позволяет замаскировать вредоносные действия, а сам функционал планировщика задач не будет отключен администраторами, так как на нем строится работа всей системы. Так, например, запланированные задачи повышают надежность системы, обеспечивая ее бесперебойную работу за счет выполнения обслуживающих задач, таких как, очистка диска, дефрагментация, проверка на ошибки. Также Scheduled Task позволяет повысить производительность системы путем выполнения задач по типу резервного копирования или обновлений в наиболее оптимальное время, которое соответствует определенному триггеру. Еще один плюс — снижение человеческого фактора и рабочей нагрузки на администраторов системы.
Теперь давайте разберемся, где и как запланированные задачи хранятся в памяти системы.
Представление запланированных задач в памяти
При планировании задачи стандартными утилитами (schtasks, оснастка Task Scheduler, командлеты Powershell) создание определенных ключей реестра и xml файла на диске можно отследить с помощью Process Monitor или Sysmon (примеры Sysmon событий будут дальше в статье).
Рассмотрим подробнее какие ключи реестра при этом задействованы:
-
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks
— содержит список подразделов, представляющих запланированную задачу. Каждая задача имеет уникальный идентификатор GUID, который выступает в качестве имени ключа в реестре; -
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree
— представляет собой структуру планировщика заданий Windows. Здесь хранятся метаданные для регистрации задачи в системе; -
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{GUID}
— содержит все настройки задачи; -
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\{Plain\Logon\Boot}\{GUID}
— ветка реестра, которая выбирается в зависимости от того, по какому триггеру будет запускаться задача:-
Plain — по заранее заданному расписанию;
-
Logon — при входе пользователя;
-
Boot — при загрузке системы.
-
На рисунке 2 и 3 представлен пример хранения параметров задачи в ключах реестра перечисленных выше.
Также при создании задачи формируется файл в формате xml с параметрами запланированной задачи по пути C:\Windows\System32\Tasks
.
Само содержимое xml-файла с параметрами задачи вы можете увидеть под спойлером.
XML с параметрами задачи
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2023-02-27T13:08:20</Date>
<Author>USER</Author>
<URI>\spawn</URI>
</RegistrationInfo>
<Triggers>
<TimeTrigger>
<StartBoundary>2023-02-27T20:10:00</StartBoundary>
<Enabled>true</Enabled>
</TimeTrigger>
</Triggers>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<Duration>PT10M</Duration>
<WaitTimeout>PT1H</WaitTimeout>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>C:\windows\system32\cmd.exe</Command>
</Exec>
</Actions>
<Principals>
<Principal id="Author">
<UserId>USER</UserId>
<LogonType>InteractiveToken</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
</Task>
Перейдем к самому интересному и посмотрим как же можно создать запланированную задачу, не используя при этом специально предназначенные для этого утилиты.
Создание задачи с помощью реестра
Для удаленного подключения к реестру можно использовать графический интерфейс regedit.exe
или из командной строки утилиту reg.exe
.
# Удаленное редактирование реестра с помощью reg.exe
REG ADD \\<REMOTE_COMPUTER>\HKLM\...
Для того чтобы изменять требуемые ветки реестра, нам необходима учетная запись SYSTEM, по крайней мере по умолчанию только она обладает нужными правами. Но удаленно подключиться под SYSTEM не получится.
Тогда возникает вопрос как удаленно из-под SYSTEM редактировать реестр, если подключиться под ней нельзя? Тут можно предложить несколько вариантов. Первый — ,заполучив SYSTEM, добавить права на редактирование другой учетной записи и уже все действия осуществлять от ее имени. Второй вариант — использовать psexec
из пакета от Sysinternals или от Impacket, также можно использовать smbexec
и подобные ей. Еще один из способов повысить привилегии до SYSTEM это использование различных «картошек» (например, RoguePotato, JuicyPotatoNG, RasmanPotato и др.). Либо прибегнуть к атаке Silver Ticket для создания TGS билета с SYSTEM в PAC, но для этого нужен NTLM-хеш учетной записи устройства.
Предположим, что тем или иным способом мы получили возможность удаленно редактировать реестр. Тогда, чтобы не испытывать сложности при создании требуемых веток в реестре и заполнении ключей, мы можем создать задачу локально, а далее перенести ее на удаленную машину.
Пример экспортированной задачи приведен ниже под спойлером.
Пример экспортированной задачи
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\remoteregistry1053]
"SD"=hex:01,00,04,80,88,00,00,00,98,00,00,00,00,00,00,00,14,00,00,00,02,00,74,\
00,04,00,00,00,00,10,18,00,9f,01,1f,00,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,00,10,14,00,9f,01,1f,00,01,01,00,00,00,00,00,05,12,00,00,00,00,\
10,18,00,ff,01,1f,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,00,00,\
24,00,89,00,12,00,01,05,00,00,00,00,00,05,15,00,00,00,fb,65,0e,da,0c,ec,58,\
4f,d2,95,df,b7,3a,38,00,00,35,00,7d,00,01,02,00,00,00,00,00,05,20,00,00,00,\
20,02,00,00,01,05,00,00,00,00,00,05,15,00,00,00,fb,65,0e,da,0c,ec,58,4f,d2,\
95,df,b7,01,02,00,00
"Id"="{B24EFFF8-2161-46E8-917D-1FF04C433EBE}"
"Index"=dword:00000003
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{B24EFFF8-2161-46E8-917D-1FF04C433EBE}]
"Path"="\\remoteregistry1053"
"Hash"=hex:9b,ea,c8,ba,7a,d1,d4,6c,6f,66,2c,07,83,ff,e9,35,2c,7c,ef,0b,cf,48,\
22,de,4d,65,02,c3,3f,dc,e0,6f
"Schema"=dword:00010002
"Date"="2022-11-04T21:33:12.6610933"
"Author"="DOMAIN\USER"
"URI"="\\remoteregistry1053"
"Triggers"=hex:17,00,00,00,00,00,00,00,01,07,0b,00,00,00,04,00,80,13,62,a9,95,\
f0,d8,01,01,e7,d4,7b,7a,01,00,00,80,d3,cb,d3,5e,f1,d8,01,38,21,41,42,48,48,\
48,48,88,f6,c6,53,48,48,48,48,0e,00,00,00,48,48,48,48,41,00,75,00,74,00,68,\
00,6f,00,72,00,00,00,48,48,00,00,00,00,48,48,48,48,00,48,48,48,48,48,48,48,\
00,48,48,48,48,48,48,48,01,00,00,00,48,48,48,48,1c,00,00,00,48,48,48,48,01,\
05,00,00,00,00,00,05,15,00,00,00,fb,65,0e,da,0c,ec,58,4f,d2,95,df,b7,3a,38,\
00,00,48,48,48,48,1e,00,00,00,48,48,48,48,53,00,45,00,41,00,5c,00,64,00,6b,\
00,6f,00,7a,00,68,00,75,00,73,00,68,00,6f,00,6b,00,00,00,48,48,2c,00,00,00,\
48,48,48,48,00,00,00,00,ff,ff,ff,ff,80,f4,03,00,ff,ff,ff,ff,07,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,48,48,\
48,48,dd,dd,00,00,00,00,00,00,01,07,0b,00,00,00,04,00,80,13,62,a9,95,f0,d8,\
01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,2c,01,00,00,80,51,01,00,ff,ff,ff,ff,00,00,00,00,00,\
00,00,00,00,00,00,00,00,01,4a,7c,01,00,00,00,00,00,00,00,d1,61,00,00,00,00,\
00,00,48,48,48,48
"Actions"=hex:03,00,0c,00,00,00,41,00,75,00,74,00,68,00,6f,00,72,00,66,66,00,\
00,00,00,0e,00,00,00,63,00,6d,00,64,00,2e,00,65,00,78,00,65,00,00,00,00,00,\
00,00,00,00,00,00
"DynamicInfo"=hex:03,00,00,00,59,22,57,e5,7b,f0,d8,01,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Plain\{B24EFFF8-2161-46E8-917D-1FF04C433EBE}]
Посмотрим на алгоритм действий при экспортировании:
-
Создать задачи с требуемыми параметрами на локальной машине;
-
Произвести экспорт следующих веток реестра:
-
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{NAMETASK}
-
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{Id TASK}
-
`Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Plain{Id TASK}
-
-
Произвести импорт этих веток реестра на удаленную машину;
-
Далее появится созданная задача в списке задач, но при запуске будет ошибка.
Для исправления данной ошибки существует два способа:
-
Перезапустить службы
Schedule
. Таким образом задача подгрузится в память соответствующего процессаsvchost
. Для перезапуска службы требуются права SYSTEM, либо можно попросту перезагрузить ПК; -
Произвести Update задачи из графического интерфейса, schtasks или других подобных инструментов. Согласно документации Microsoft обновлять задачу могут пользователи, создавшие ее, а также члены группы администраторов и учетная запись SYSTEM.
Чтобы не создавать «лишний шум» в журнале событий, связанный с появлением новых ключей в реестре, атакующий вместо создания новой задачи может редактировать отдельные, уже существующие ключи в реестре. Он также имеет возможность осуществлять это как вручную, так и через импорт-экспорт определенных ключей, как было показано выше. В то же время такие задачи требуется активировать с новыми параметрами.
При импорте веток реестра на удаленную машину регистрируются события изменения реестра от имени процесса C:\Windows\system32\svchost.exe -k localService -p -s RemoteRegistry
. Данные события можно проследить в журнале Sysmon EventId 12 (RegistryEvent Object create or delete) и 13(RegistryEvent Value Set).
Сразу после импорта ключей реестра задача появится в графическом интерфейсе планировщика задач, но каких-либо событий по созданию задачи в журналах нет, в том числе и события 4698(A scheduled task was created). На следующем этапе данную задачу нужно активировать.
Если в качестве активации выбран Update задачи, то регистрируется событие в Sysmon с EventId 11(FileCreate). То есть происходит создание xml файла в C:\Windows\System32\Tasks
с описанием задачи от имени svchost.exe
, связанного со службой Schedule. Пример данного события представлен выше на Рисунке 4.
Также в журнале Security регистрируется событие с EventId 4702(A scheduled task was updated), свидетельствующее об обновлении задачи. Как и в событии 4698 данное событие содержит xml с описанием задачи.
При перезапуске службы Schedule
не происходит создание xml файла с описанием задачи и нет каких-либо событий, свидетельствующих о подгрузке задачи в память процесса svchost.exe
связанный со службой (т.е. отсутствуют события 4698 и 4702).
Чтобы удаленно редактировать реестр потребуется включить службу Remote Registry.
Настройка службы удаленного реестра:
Запустить Remote Registry можно с помощью учетной записи, обладающей правами локального администратора или SYSTEM.
Для этого потребуется выполнить несколько шагов:
Перейти в оснастку "Services.msc"
Открыть свойства "Remote Registry service"
Во вкладке General выбрать тип запуска Automatic
Применить изменения
Если атакующий захочет как можно дальше спрятать свои действия и тем самым еще больше усложнить жизнь специалистам по мониторингу и расследованиям инцидентов, то он сможет это сделать за счет «трюка», позволяющего скрыть запланированную задачу.
В чем же заключается этот трюк мы разберем дальше.
Скрытие задачи в планировщике задач
На этот раз скрытие происходит из оснастки Task Scheduler и других утилит (schtasks, Powershell Get-ScheduledTask) по работе с запланированными задачами. Трюк заключается в том, чтобы удалить определенные ключи в реестре, связанные с задачей.
Давайте посмотрим, что это за ключи и попробуем объединить два метода: создание задачи с помощью реестра (как описано в предыдущем разделе) и скрытие за счет отсутствие определенных ключей. Таким образом, задача будет создана уже без требуемых ключей. В таком случае для активации задачи не представляется возможным использовать Update, а единственным возможным из мне известных вариантов является перезапуск службы Schedule
(если вы знаете альтернативные методы, то пишите о них в комментариях к статье). Если же производить манипуляцию с ключами, перечисленными ниже у уже активированной задачи, то дополнительно перезапускать службы или что-то обновлять не требуется. Тогда задача мгновенно пропадает из рассматриваемых утилит после изменений в реестре.
Первый ключ в реестре, который позволяет скрыть задачу, называется Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{NAMETASK}\SD
. SD отвечает за дескриптор безопасности. Если создать задачу без этого ключа, то она не будет отображаться в планировщике задач.
Второй ключ, который можно попробовать не указывать при создании задачи, является Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{NAMETASK}\Index
. Однако в текущей ситуации в оснастке Task Scheduler перестают отображаться вообще какие-либо задачи, а при открытии планировщика появляется ошибка «An internal server error occurred», при этом сами задачи работают по-прежнему.
Также можно попробовать не удалять полностью ключ Index
, а изменить его. Таким образом, значение данного поля зависит от того по какому триггеру будет выполняться задача и, соответственно, она связана с веткой HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\{Plain\Logon\Boot}\{GUID}
(при Boot Index
=0x1, при Logon Index
=0x2, при Plain Index
=0x3). Если Index
установить равным 0x0, то задача будет скрыта в планировщике, но при этом ее работа не нарушится. Установка Index
равным 0x4 и более, не повлияет на скрытие задачи.
Вишенкой на торте является то, что если совершить Update задачу (schtasks /change /TN TASKNAME /TR PROGRAM
), производя манипуляции с ключом Index
, то она удалится без какого-либо события в журнале Security, в том числе и не будет события 4699 (A scheduled task was deleted).
Изучив особенности проведения техники Scheduled Task с помощью Remote Registry, перейдем к возможным способам ее детектирования.
Детектирование
Выше было рассказано как можно создать запланированную задачу максимально скрытым способом, а теперь мы поговорим, как защитникам детектировать данные случаи. Думаю очевидно, что стандартным способом за счет событий, связанных с задачами (4698, 4699, 4702), детектировать не получиться, так как они попросту будут отсутствовать в журнале.
Первое на что хотелось бы обратить внимание, так это на то, что везде происходило редактирование реестра. При стандартных способах создания запланированных задач по требуемым веткам вносятся изменения от имени C:\\Windows\\system32\\svchost.exe -k netsvcs -p -s Schedule
(т.е. службой Schedule
). В нашем же случае все изменения происходили от имени C:\Windows\system32\svchost.exe -k localService -p -s RemoteRegistry
. В случае использования psexec и подобных, родительским процессом будет используемая утилита по редактированию реестра, например, ею может выступать reg.exe
. То, что редактирование определенных веток реестра происходит с помощью процесса отличающегося от службы Schedule
, может как раз и служить одним из маркеров. При этом определить какая именно служба производит изменения в реестре возможно с помощью события Sysmon 1 (Process Creation). Сопоставлять 1, 12 и 13 события можно по полю ProcessGuid (если родительским процессом выступает утилита) или ParentProcessGuid (если родительским процессом выступает служба). Ниже, на основе этого анализа, мною будет представлено-псевдо правило для детекта.
Таким образом, псевдо-правило для детекта выглядит так:
SELECT *
FROM (EventCode=1)
WHERE (ParentProcessGuid OR ProcessGuid) IN
(
SELECT ProcessGuid
FROM (EventCode=12 OR EventCode=13)
WHERE TargetObject="HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tree\\*"
)
AND ParentCommandLine!="C:\\Windows\\system32\\svchost.exe -k netsvcs -p -s Schedule"
Также следует отметить, что при активации задачи с помощью Update
формируется событие 4702. Данное событие содержит описание задачи, поэтому с помощью ML (Machine Learning) может быть проверено на аномалии. В качестве другой аномалии может выступать тот факт, что были созданы новые ветки реестра, но за этим не последовало события 4698, говорящего о создании задачи.
В совокупности с вышесказанным, но не по отдельности, мы имеем возможность отслеживать перезапуск службы Scheduler с помощью ETW TaskScheduler\Operational
события 402 (Service shutting down) и 400 (Service started) или через Process Creation (4688). Почему не стоит полагаться на данные события, как на самостоятельные? Только потому, что данные события происходят при каждом включении ПК, что будет приводить к ложно-положительным сработкам. В свою очередь связать перезапуск службы с перезапуском устройства можно с помощью события 1074 (System has been shutdown by a process/user) в журнале System.
TaskScheduler\Operational
, говорящее об остановке службы Schedule
TaskScheduler\Operational
, говорящее старте службы Schedule
Schedule
Также не следует забывать о ситуации, когда задача была создана стандартным способом, а после были удалены ключи в реестре для ее сокрытия. Для этого следует следить за удалением/изменением отдельных ключей реестра (SD и Index).
При удаленном способе редактирования веток реестра применяется протокол WINREG. Внутри пакетов трафик зашифрован. Поэтому использовать информацию внутри трафика для детекта нельзя. Но можно зайти с другой стороны и задаться вопросом, а как часто и для каких целей может использоваться протокол WINREG в корпоративной среде? Ответ на этот вопрос зависит от конкретной организации и выстроенных в ней IT-процессов. Так, если в компании администраторы не применяют инструменты для удаленного редактирования реестра или ПО, в основе которого лежит WINREG, то появление событий в трафике с использованием данного протокола, должны выглядеть подозрительно, что будет служить аномалией.
Заключение
В этой статье мы рассмотрели интересный метод создания запланированной задачи в Windows системе, а также возможный способ сокрытия задачи в планировщике задач. В результате чего стало понятно, что стандартные способы детектирования техники по созданию запланированных задач на основе событий из Security журнала 4698, 4699, 4702 не подходят в конкретном случае. Также мною были предложены маркеры, на основе которых можно построить детект. Основная идея заключается в мониторинге изменения определенных веток реестра от имени процесса отличного от Schedule
. Для наиболее точного распознавания таких случаев были представлены другие дополнительные маркеры детектирования, но рассматривать их стоит в совокупности, а не каждый по отдельности.
Надеюсь данная статья оказалась для вас полезной! Если у вас появились вопросы, пишите в комментариях!
Автор: Кожушок Диана( @wildresearcher), аналитик-исследователь киберугроз в компании R-Vision
Многие из приложений-оптимизаторов, а также те приложения, которые следят за актуальностью версий установленного на ПК программного обеспечения, создают во встроенном планировщике заданий соответствующие задачи, выполняющиеся даже когда запланировавшие их приложения неактивны. Если такая самодеятельность вам не по нраву или созданная задача не была удалена после деинсталляции приложения, вы можете удалить ее из планировщика самостоятельно как минимум тремя способами.
Через сам планировщик заданий
Начнем с самого очевидного и простого способа.
Открываем штатный планировщик выполненной в окошке Run (Win + R) заданий командой taskschd.msc и в левой колонке нажмите мышкой по родительскому каталогу «Библиотека планировщика заданий». Именно в ней сохраняют свои задания сторонние приложений.
Отыщите в средней колонке задание, имя которого указывает на создавшую его программу, нажмите по нему правой кнопкой мыши и выберите «Удалить».
Также можно нажать «Удалить» в правой колонке управления элементами.
В командной строке
Удалить запланированную задачу можно с помощью командной строки.
Это менее удобный способ, к тому же вам нужно знать точное название задачи.
Удаление выполняется в запущенной от имени классической командной строке с использованием консольной утилиты schtasks.exe, распложенной в папке System32.
Команда удаления выглядит следующим образом:
schtasks /Delete /TN «путь/имя-задачи» /F
Задача будет тут же удалена.
Путь указывать не нужно, если запись задачи располагается в корневом каталоге «Библиотека планировщика заданий».
Удаление задач с помощью командной строки чаще всего находит применение в скриптах.
В PowerShell
Аналогичным целям может служить и консоль PowerShell, в которой предусмотрен ряд командлетов, предназначенных как раз для взаимодействия с запланированными в taskschd.msc задачами.
Команда удаление задания выглядит так:
Unregister-ScheduledTask -TaskName «имя-задачи» -Confirm:$false
Если задание располагается не в корне, в команду добавляется строка -TaskPath «путь-к-папке», путь указывается относительный, обратные слеши справа и слева удалять не нужно, смотрите скриншот ниже.
В редакторе реестра
Наконец, избавиться от запланированной задачи можно, удалив соответствующий ей ключ реестра.
Откройте редактор реестра командой regedit и разверните ветку:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree
Подраздел Tree содержит дочерние подразделы с именами расположенных в корне планировщика заданий.
Кликните по выбранной папке ПКМ и выберите «Удалить».
В результате задача будет удалена также из планировщика.
File: <SYSTEMROOT>\System32\config\SOFTWARE
Registry keys:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tasks\<TASK_GUID>
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tree\<TASK_NAME>
Overview
Scheduled tasks are used to automatically perform a task on the system whenever
the criteria associated to the scheduled task occurs. The scheduled tasks can
either be run at a defined time, on repeat at set intervals, or when a specific
event occurs, such as the system boot.
The following registry keys are created upon the creation of a new scheduled
task:
Schedule\Taskcache\Tasks\<TASK_GUID>
.Schedule\Taskcache\Tree\<TASK_NAME>
.
A scheduled task can be created through direct manipulation of the
registry only, as implemented in
GhostTask for instance. Creating a
scheduled task this way will not generate task creation ETW events.
However, the task will not be functional until the Schedule
service is
restarted or task configuration modified, to a reload by the Schedule
service. Modifying the task would generate associated ETW events (channel
Microsoft-Windows-TaskScheduler/Operational
, event 140 or Security
, non
default event 4702).
Additionally, a scheduled task can continue to run even if its associated
elements in the registry and/or on disk (XML
files) are deleted. The
scheduled task will be fully hidden but will persist until the system is
rebooted or the svchost.exe
process associated with that task is terminated.
The ETW
events generated by the task execution will however still be
generated.
Information of interest
Each scheduled task configuration is defined in a dedicated subkey under
Schedule\Taskcache\Tasks
, identified by the task GUID (i.e.
Schedule\Taskcache\Tasks\<TASK_GUID>
).
For each tasks, the following notable information is available under the task
GUID root key Schedule\Taskcache\Tasks\<TASK_GUID>
:
-
The task path.
-
Some lifecycle timestamps of the task: created on, last start, and last
stop in theDynamicInfo
value (in binary format). -
The task trigger(s) (
Triggers
value) and action(s) (Actions
value) in
binary, non human readable format. A single scheduled task can be
associated with one or multiple trigger(s) and one or multiple action(s).
A single task can thus execute multiple distinct executables. -
The task security descriptor (in
SDDL
notation), in the
SecurityDescriptor
value.
The mapping between a task name and its GUID can be done using the subkeys of
the Schedule\Taskcache\Tree
keys. Indeed, each task is referenced by its name
as a subkey of the Schedule\Taskcache\Tree
key (i.e.
Schedule\Taskcache\Tree\<TASK_NAME>
), with the GUID of the task
stored in the Id
value.
Additionally, the Schedule\Taskcache\Tree\<TASK_NAME>
hold the
Security Descriptor
of the scheduled task (in the SD
value). Removing this
value will hide the scheduled task, from utilities such as schtasks
or the
Task Scheduler
, while leaving it functional. This was implemented in the
Tarrask malware, as discovered by Micosoft.
References
-
Microsoft — Tarrask malware uses scheduled tasks for defense evasion
-
WithSecure — Riccardo Ancarani — Scheduled Task Tampering
-
cyber.wtf — Luca Ebach — Windows Registry Analysis — Today’s Episode: Tasks
View on GitHub
Hi,
This post is developed by the trial and error principle 😉 . Here you can find some background.
On Windows a User with just “normal” user rights cannot see and execute Tasks created from User with Administrator permissions. There are dozed of sites that describes that the permissions of an task can be changed by setting the filesystems rights in C:\Windows\System32\Tasks. But this won’t work since some early Versions of Windows 10 (IMHO 1607).
Ok, let’s start. Let use assume you have a Task MyTask in Folder MyAdminTasks.
Then you have to adjust 2 Security Descriptors.
The 1st is necessary to see, modify or delete the task. It is located in the Registry Path
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\MyAdminTasks\MyTask\SD
The 2nd is the SecurityDescriptor Value in the Tasks Key. The Task ID can be determined under the Tree Key
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\MyAdminTasks\MyTask\Id
And the task itself is located in den TaskCache\Tasks key.
HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\
The SecurityDescriptor value controls who can execute a Task. If the SecurityDescriptor value not exists only Administrators and the User who created the Task can execute it.
For example the builtin Task SilentCleanup
[Reflection.Assembly]::LoadWithPartialName("System.Security.Principal") $sExampleTask="Microsoft\Windows\DiskCleanUp\SilentCleanup" $sTaskPath=$sExampleTask $oACL=[System.Security.AccessControl.RawSecurityDescriptor]::new((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$sTaskPath").SD,0) foreach($oACLEntry in $oACL.DiscretionaryAcl) { $oSID = New-Object System.Security.Principal.SecurityIdentifier($oACLEntry.SecurityIdentifier) write-host "User" (($oSID.Translate([System.Security.Principal.NTAccount])).Value) $oACLEntry.AccessMask } User Administrators AccessMask: 2032127 User SYSTEM AccessMask: 2032127 User Authenticated User AccessMask: 1179817 User Local Service AccessMask: 1179817 User Administrators AccessMask: 2032031 User SYSTEM AccessMask: 2032031 User Authenticated User AccessMask: 1179785 User Lokaler Dienst AccessMask: 1179785 User Network Service AccessMask: 1179785 User Administrators AccessMask: 2032127 $sTaskUID=(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$sTaskPath").Id $sTaskACL=(Get-ItemProperty ("HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\$sTaskUID")).SecurityDescriptor # $oDACL=ConvertFrom-SddlString $sTaskACL $oDACL=[System.Security.AccessControl.RawSecurityDescriptor]::new($sTaskACL) foreach($oACLEntry in $oDACL.DiscretionaryAcl) { $oSID = New-Object System.Security.Principal.SecurityIdentifier($oACLEntry.SecurityIdentifier) write-host "User" (($oSID.Translate([System.Security.Principal.NTAccount])).Value) "AccessMask:" $oACLEntry.AccessMask } User Administrators AccessMask: 2032127 User SYSTEM AccessMask: 2032127 User Authenticated User AccessMask: 1179817
Typically 3 Access Masks are found on a tasks which could controlled from Authenticated users: 2032127 -> 0x1f01ff (System , Administrators), 1179817-> 0x1200a9 (SYSTEM, Authenticated User, Local Service, Network Service) and 1179785 is the readonly access mask.
This simple function converts the access mask to a bitmask.
function Int32BitMask([int32]$Value) { for($i=31;$i -ge 0;$i--){write-host -NoNewLine ([string]::Format(" {0:d2}",$i))} write-host "" for($i=31;$i -ge 0;$i--){if($Value -band ([math]::Pow(2,$i))){write-host -NoNewLine ([string]::Format(" {0:d1}",1))}else{write-host -NoNewLine ([string]::Format(" {0:d1}",0))}} write-host "" }
This is the bitmask for read only user.
PS D:\> $AccessMask=1179785 PS D:\> Int32BitMask $AccessMask 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1
This is the bitmask for standard (Authenticated) user. Bit 0-7 are the object type specific access mask and Bit 5 controls if a user could run a task
PS D:\> $AccessMask=1179817 PS D:\> Int32BitMask $AccessMask 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 1
According to MSDN the Standard Access Mask Bit 17 and 20, READ_CONTROL| SYNCHRONIZE
While System and Administrators have all rights SYNCHRONIZE|WRITE_OWNER|WRITE_DAC|READ_CONTROL|DELETE
PS D:\> $AccessMask=2032127 PS D:\> Int32BitMask $AccessMask 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
So the easiest way to permitted non administrative Users, means Authenticated Users, to execute tasks created by an Adminstrators is to copy both security descriptor registry values from an well defined Task to your Task.
Note you have to do this with the SYSTEM Account. Adminstrators does not have the permissions to change the registry under HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule.
Here are the steps to open a powershell as User SYSTEM. Get psexec from Microsoft Sysinternals. Open a command shell elevated as Administrator. Then start powershell as SYSTEM
C:\> psexec -s -h powershell.exe PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com Windows PowerShell Copyright (C) Microsoft Corporation. PS C:\> whoami system
The code 🙂 The Taskpathes TemplateTask and MyTask are relative to HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree registry key
PS D:\> $TemplateTask="Microsoft\Windows\DiskCleanUp\SilentCleanup" PS D:\> $MyTask="MyAdminTasks\MyTask" PS D:\> $sTaskUID=(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$TemplateTask").Id PS D:\> $sTaskDefACL=(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$TemplateTask").SD PS D:\> $sTaskACL=(Get-ItemProperty ("HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\$sTaskUID")).SecurityDescriptor PS D:\> $sMyTaskUID=(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$MyTask").Id PS D:\> New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$MyTask" -Name "SD" -Value $sTaskDefACL -Type Binary -Force PS D:\> New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\$sMyTaskUID" -Name "SecurityDescriptor" -Value $sTaskACL -Type String -Force PS D:\>
The hard way is to manipulate the Security Descriptor by adding ace (System.Security.AccessControl.CommonAce) entries.
Determine the SID of the Account/Group you want to add, Accessmask 1179817 means Read & run permissions on the task MyAdminTasks\MyTask. In this example the User MyUser
PS D:\> # Local user for example PS D:\> $sTaskPath="MyAdminTasks\MyTask" PS D:\> $UserToAdd="MyUser" PS D:\> $SID=(get-localuser $UserToAdd).SID.Value PS D:\> # $SID="S-1-5-21-103132666-1872472456-3852854213-672354" PS D:\> $AccessMask=1179817 PS D:\> $oNewACE=new-object System.Security.AccessControl.CommonAce([System.Security.AccessControl.AceFlags]::None,` [System.Security.AccessControl.AceQualifier]::AccessAllowed,` $AccessMask,` (new-object System.Security.Principal.SecurityIdentifier($SID)),` $false,` ([byte[]]@())) PS D:\> $oMyTaskACL=[System.Security.AccessControl.RawSecurityDescriptor]::new((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$sTaskPath").SD,0) PS D:\> $sMyTaskUID=(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$sTaskPath").Id PS D:\> $oMyTaskACL.DiscretionaryAcl.InsertACE($oMyTaskACL.DiscretionaryAcl.Count,$oNewACE) PS D:\> $aACLBytes=([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($oMyTaskACL.GetSddlForm(15)).BinarySD PS D:\> New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\$sTaskPath" -Name "SD" -Value $aACLBytes -Type Binary -Force PS D:\> New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\$sMyTaskUID" -Name "SecurityDescriptor" -Value $oMyTaskACL.GetSddlForm(15) -Type String -Force
Ok thats is, comments are welcome :-).
Update 21.02.2020 Added a Script to edit the ACE entries. Does currently not take care about duplicate ACE Entries!
Michael