Швидкий Парсинг Логів Через Splunk
Вступ
У попередньому пості йшла мова про Splunk як інструмент що дає зручну панель для аналізу зібраних під час DFIR логів. Однак, часто виникають ситуації коли зібрані логи потрібно додатково розпарсити - тобто перетворити оригінальні “сирі” події в набір конкретних полів по яких зручно вести пошук, як от:
# Оригінальна подія
1750779000 [api] "bob" logged in from 10.2.5.5 via access key!
# Розпаршена подія
time=2025-06-24,15:30:00; system=api; auth=key; user=bob; ip=10.2.5.5
Сьогодні розповім як можна швидко розпарсити будь-які текстові логи, коли це може бути корисно, та коли цього робити не варто. А допоможуть у цьому команди eval, spath, та rex:
Інженерний Підхід
Рекомендованим рішенням для парсингу логів є Splunk Add-ons - модулі що вказують спланку як правильно читати той чи інший тип логів. Зазвичай, першою реакцією SIEM інженерів на “Треба завести логи X” є пошук відповідного аддону, як от для веб-логів IIS. Якщо потрібного модуля немає, тоді інженери беруться за CONF файли, що вже є поза межами знань більшості аналітиків.
Однак, не завжди в команді є Splunk експерт і не завжди є час на конфігурацію аддону. Також, логи зібрані під час DFIR часто не варті великих зусиль - достатньо розпарсити декілька ключових полів і провести них швидкий пошук. Саме тому парсинг без аддонів “на ходу” може часто стати в пригоді.
Команда Rex
Якщо логи зібрали специфічним методом або якщо адмін налаштував власний формат логування, тоді аддони можуть не спрацювати. Як от на скріншоті нижче: кастомні Apache логи, що мають префікс REQ та поля в нетиповому порядку, та які потрібно проаналізувати.
Перед тим як скористатись командою rex та розпарсити події з прикладу, потрібно зрозуміти формат логів та написати під них регулярний вираз (regex). З цим можуть допомогти LLM типу ChatGPT, а також сайт Regex101. Нижче простенький regex що парсить айпі клієнта, HTTP метод, URL, та HTTP статус код:
REQ (?P<src_ip>\S+) \[.+\] "(?P<method>\S+) (?P<url>\S+) HTTP.*" (?P<status>\d+)
Наступним кроком буде власне використати команду rex - яка в параметр field
приймає поле яке треба розпарсити та далі очікує регулярний вираз. У результаті ви маєте отримати нові розпаршені поля, по яких можна вести пошук. Не забудьте екранувати подвійні лапки та віндові слеші!
Команда Spath
Не завжди проблемою є одразу вся нерозпаршена подія, можливий і випадок коли потрібно допарсити конкретне поле. Найпростіший приклад - коли аддон вже розпарсив поля URL або Full Name, але вам потрібна додаткова розбивка на компоненти:
# Нехай є поле identity зі значенням "Mykyta Kozak - M":
| rex field=identity "(?P<name>\S+) (?P<surname>\S+) - (?P<sex>[MF])
Проте, якщо всередині CSV захований JSON (як от при експорті логів M365), або XML посеред EVTX (як от в події 4698) - регулярні вирази це не найкращий варіант. У прикладі CSV з скріншоту нижче розпаршене тільки поле AuditData, яке ніби як містить JSON:
Для парсингу JSON можна використати команду spath, яка в один рядок дістане усі поля з строки в параметрі input
. Завдяки цій команді вийшло швидко розбити AuditData на набір корисних полів, як от ClientIP чи UserId. Також, зверніть увагу на команду eval - надзвичайно потужну функцію яка може перетворити ледь не будь-які логи у потрібний вам формат, достатньо лиш загуглити проблему.
Додаткові Команди
Наостанок, декілька корисних команд які також можуть допомогти розпарсити складні логи, зібрати додатковий контекст, або покращити вигляд логів для демо:
Concat: Утворює нове поле з інших полів (через .
)
# Об'єднюємо ім'я та прізвище в одне поле
| eval fullname = name." ".surname
Mvindex: Дістає вказаний елемент з масиву JSON (з 0)
# Дістаємо перший елемент з масиву Array
| eval first = mvindex('Array{}', 0)
Regex: Фільтрує логи по регулярних виразах, не плутайте з rex!
# Шукаємо підозрілі PowerShell команди
| regex content = "(?i)\b(iex|iwr|frombase64string)\b"
Iplocation: Повертає геолокацію IP адреси по вбудованих базам
# Маючи поле ip_addr, отримуємо поля Country та City
| iplocation ip_addr
| table ip_addr Country City
Coalesce: Зводить назву поля до одного формату
# В певних логах юзер це User, десь userId, а десь subject
| eval user = coalesce(User, userId, subject)
| search user != "noisy_user"
У Підсумку
Rex чудово працює з текстовими даними, а spath з JSON та XML. Ці команди зручно використовувати під час DFIR, особливо коли вам на аналіз дають логи самописної тули, під яку немає сенсу писати аддон. Однак, парсинг “на ходу” досить ресурсоємний та працює тільки в межах вашої вкладки, тому краще все ж скористатись інженерним підходом якщо з логами активно працює декілька людей, або якщо подій дуже і дуже багато.