使用Anomalize进行异常检测与威胁狩猎

本文详细介绍了如何使用R语言的anomalize包进行时间序列异常检测,结合STL和Twitter方法分析安全事件日志,适用于蓝队进行安全监控和威胁狩猎的实际应用场景。

工具匠 #133 - 使用Anomalize进行异常检测与威胁狩猎

在十月和十一月的工具匠文章中,我在“R语言调查员深度功能(DFIR)”的前提下重新定义了DFIR,发现这只是“冰山一角”。因此,我想通过额外的发现和机会重新探讨这一概念。实际上,这是在原始且至关重要的DFIR(数字取证/事件响应)通用实践中的DFIR(R语言调查员深度功能)案例。

正如之前讨论的,我们这些从事DFIR实践以及蓝队工作的人,都被数据和规模所淹没。成功确实需要算法方法。如果你还没有投入其中,我有一个关于使用anomalize进行整洁异常检测的即时应用案例研究。

首先,让我完全归功于后续的工作。我讨论和提供的一切都直接源自Business Science(@bizScienc),特别是Matt Dancho(@mdancho84)。他创建了anomalize,“一个基于时间的整洁异常检测算法(构建在tibbletime之上),并且可以从一个时间序列扩展到多个时间序列”,当时一个客户要求Business Science构建一个满足他们需求的开源异常检测算法。我认为他回应得非常漂亮,当他的博客文章通过R-Bloggers进入我的视野时,它在我浏览器中作为一个打开的标签页存在了一个多月,直到生成这篇工具匠文章。请将Matt的文章视为此过程的第一步必读内容。在转换上下文之前,我将特别引用Matt的话:“我们的客户有一个具有挑战性的问题:在大规模的每日或每周数据的时间序列中检测异常。异常表示异常事件,可能是营销领域中增加的网络流量,或IT领域中故障服务器。无论如何,标记这些异常事件以确保业务平稳运行非常重要。其中一个挑战是客户处理的不是单个时间序列,而是数千个需要分析这些极端事件的时间序列。”

关键要点:在大规模的每日或每周数据的时间序列中检测异常。异常表示异常事件。

现在与我一起转换上下文到安全特定事件和事故,因为它们涉及安全监控、事件响应和威胁狩猎。在我2017年11月的文章中,回想一下我讨论了使用Holt-Winters方法的时间序列回归,并专注于季节性和趋势。不幸的是,我无法分享我们如何应用TSR的代码,但指出了替代方法,包括使用Loess的季节和趋势分解(STL):

  • 处理任何类型的季节性~可以随时间变化
  • 趋势周期的平滑度也可以由用户控制
  • 对异常值具有鲁棒性

现在,Matt创建了一种立即应用STL方法以及Twitter方法(参考页面)的手段,作为他的time_decompose()函数的一部分,这是anomalize包特有的三个函数之一。除了将时间序列分解为季节性、趋势和剩余组件的time_decompose()之外,anomalize还包括:

  • anomalize():将异常检测方法应用于剩余组件。
  • time_recompose():计算将“正常”数据与异常分离的限制。

anomalize()中使用的方法,包括IQR和GESD,在Matt的参考页面中有描述。Matt最终着手构建Twitter的AnomalyDetection包的可扩展适配,以解决客户在处理不是单个而是数千个需要分析极端事件的时间序列的挑战。你会注意到Matt使用CRAN上15个tidyverse包的每日下载计数的数据集来描述anomalize,这是相关的,因为他利用了tidyverse包。我最初尝试调整Matt的演示,以模拟从CRAN下载安全特定R包(是的,有这些东西)的情况,包括RAppArmor、net.security、securitytxt和cymuservices,后两个由我们亲爱的数据驱动安全:分析、可视化和仪表板的Bob Rudis(@hrbrmstr)提供。唉,这只是一个复制和替换,并没有在应得的、多样的、真正安全特定的上下文中展示anomalize的使用。也就是说,我能够立即生成结果,如图1所示。

我想针对真实的安全数据场景运行anomalize,所以我回到了原始DFIR文章中的数据集,其中我使用了给定服务器集上每个用户每天4624事件ID的计数。正如最初使用的那样,我只代表了一个设备和用户的结果,但 herein是anomalize的美妙之处。我们可以在多个时间序列(多个系统/用户)上实现快速结果。这个前提只是许多可以将时间序列分析和季节性应用于安全数据的场景之一。

我最初尝试将log.csv中的日志数据直接写入anomalize.R脚本,使用logs = read_csv(“log.csv”)到tibble中(准备好你的tibbles笑话),这没有被准确解析,特别是时间属性。为了纠正这一点,我从Matt的Github获取了tidyverse_cran_downloads.R,并修改如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
library(dplyr)
library(tibbletime)
setwd("C:/coding/R/anomalize/")
logs <- read_csv("log.csv")
security_access_logs <- logs %>%
  group_by(server) %>%
  as_tbl_time(date)
security_access_logs

这得益于tibbletime包大大帮助,它是“一个允许创建时间感知tibbles的扩展。一些直接优势包括:能够在tibbles上执行基于时间的子集化,快速按时间段总结和聚合结果。猜猜看,Matt也写了tibbletime。:-)

然后我按照Matt在Business Science上发布的序列,但将我的日志定义为Security_Access_Logs_Function.R中的一个函数。接下来,我将给你代码片段,如从Matt的示例修订而来,然后是它们各自处理我的事件ID 4624每日计数日志的结果。

首先,让我们总结四个月内三个服务器上的每日登录计数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
library(tidyverse)
library(anomalize)
security_access_logs %>%
  ggplot(aes(date, count)) +
  geom_point(color = "#2c3e50", alpha = 0.25) +
  facet_wrap(~ server, scale = "free_y", ncol = 3) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1)) +
  labs(title = "Server Logon Counts",
 subtitle = "Data from Security Event Logs, Event ID 4624")

结果在图2中显而易见。

接下来,让我们使用Matt的三个主要函数time_decompose()、anomalize()和time_recompose(),以及可视化函数plot_anomalies(),确定哪些每日下载登录是异常的,跨越相同的三个服务器四个月。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
security_access_logs %>%
 # 数据操作 / 异常检测
  time_decompose(count, method = "stl") %>%
  anomalize(remainder, method = "iqr") %>%
  time_recompose() %>%
 # 异常可视化
  plot_anomalies(time_recomposed = TRUE, ncol = 3, alpha_dots = 0.25) +
  labs(title = "Security Event Log Anomalies", subtitle = "STL + IQR Methods") 

结果在图3中揭示。

遵循Matt使用Twitter的AnomalyDetection包的方法,结合time_decompose(method = “twitter”)与anomalize(method = “gesd”),同时调整trend = “4 months"来调整中位数跨度,我们将只关注SERVER-549521。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
# 仅获取SERVER549521访问
SERVER549521 <- security_access_logs %>%
  filter(server == "SERVER-549521") %>% 
  ungroup()
# Anomalize!!
SERVER549521 %>%
 # Twitter + GESD
  time_decompose(count, method = "twitter", trend = "4 months") %>%
  anomalize(remainder, method = "gesd") %>%
  time_recompose() %>%
 # 异常可视化
  plot_anomalies(time_recomposed = TRUE) +
  labs(title = "SERVER-549521 Anomalies", subtitle = "Twitter + GESD Methods")

在图4中,你会注意到SERVER-549521在六月有异常的登录计数。

我们可以比较Twitter(time_decompose)和GESD(anomalize)方法与STL(time_decompose)和IQR(anomalize)方法,它们使用不同的分解和异常检测方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
SERVER549521 %>%
 # STL + IQR异常检测
  time_decompose(count, method = "stl", trend = "4 months") %>%
  anomalize(remainder, method = "iqr") %>%
  time_recompose() %>%
 # 异常可视化
  plot_anomalies(time_recomposed = TRUE) +
  labs(title = "SERVER-549521 Anomalies", subtitle = "STL + IQR Methods")

再次,我们注意到六月的异常,如图5所示。

显然,结果非常相似,正如人们所希望的那样。最后,让我们使用Matt的plot_anomaly_decomposition()来可视化算法如何检测SERVER-549521剩余中的异常的内部工作。

1
2
3
4
5
6
7
8
9
# 从Anomalize项目创建,Matt Dancho
# https://github.com/business-science/anomalize
security_access_logs %>%
  filter(server == "SERVER549521") %>%
  ungroup() %>%
  time_decompose(count) %>%
  anomalize(remainder) %>%
  plot_anomaly_decomposition() +
  labs(title = "Decomposition of Anomalized SERVER-549521 Downloads")

结果是一个四部分的可视化,包括观察到的、季节、趋势和剩余,如图6所示。

我真的很期待在更大规模、更广泛的事件日志数据集上使用这些方法。我坚定地断言,蓝队在对抗自动化对手策略和纯粹规模的问题上已经远远落后,所以…很多…数据。只有通过像Matt的anomalize这样的策略,以及其他类似的方法,防御者才能希望成功。一定要观看Matt关于anomalize的YouTube视频,Business Science正在构建一系列视频,所以密切关注那里和他们的Github,以获取更多我们可以应用蓝队/防御者上下文的伟大工作。

所有代码片段都在我的GitHubGist这里,示例日志文件、单个R脚本和Jupyter Notebook都可以在我的Github上的toolsmith_r下获得。我希望你发现anomalize像我一样令人兴奋和有用,Matt做了伟大的工作,期待看到Business Science的下一步。

干杯…直到下次。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计