发现新的恶意软件 - 使用 Splunk 检测新域名





0/5 (0投票)
在本系列“使用 Splunk 进行狩猎:基础知识”的这一部分中,我们将探讨如何检测“新”域名的可疑且潜在的恶意网络流量。
这篇博文是“使用 Splunk 进行狩猎:基础知识”系列文章的第十三部分。我们可能会比平时稍微滥用“基础知识”这个词,但我相信这个主题对组织来说至关重要。我对 Andrew 写的这篇内容感到非常自豪,希望你们和我一样喜欢它。– Ryan Kovar
问题
在本系列“使用 Splunk 进行狩猎:基础知识”的这一部分中,我们将探讨如何检测“新”域名的可疑且潜在的恶意网络流量。首先,让我们深入探讨一下我们所说的“新”域名是什么意思,以及为什么你应该养成检测这种活动的习惯。
用户(和应用程序)是习惯的生物。如果你的组织很典型,那么今天你的网络请求的域名与昨天的请求有很大的重叠。如果我查看我的浏览记录,我每天都会访问大约相同的 20 个网站。毕竟,我不能错过今天的 xkcd 或 Dilbert!我的笔记本电脑、手机和其他系统发出的网络请求的应用程序通常每天都会访问相同的域名。
但是,我今天网络请求的互联网域名中,只有一小部分以前是我的系统没有访问过的呢?这就是我所说的“新”域名。当然,今天会有一部分合法的流量会访问一些以前在网络上没见过的域名,但这可能只占域名总集的一小部分。剩余的这些新的、从未见过的域名则代表着潜在的威胁。
为什么你应该将访问新域名的网络活动视为可疑且潜在的恶意?恶意软件和恶意行为者会定期使用他们拥有或控制的域名进行各种恶意活动。例如,攻击者控制的域名可以作为 命令和控制通信 的中心,而另一个域名则用于 数据泄露。这些域名可以利用 动态域名、使用 域名生成算法 (DGA) 创建的子域名、更 看起来合法、人类可读的域名 以及其他技术。这些都是在各种现代攻击中常见的标准技术。通过搜寻这些新域名,我们可以增加发现威胁的机会,然后快速进行调查和缓解。
所需数据
在此背景下,让我们讨论需要什么数据。简而言之,就是 Splunk 中包含指向外部域名的网络请求字段的任何数据。这可能包括能够整齐地解析出域名字段的数据。或者,我们也可以从 URL 中提取域名。
也许查找这些数据的最佳位置是你的 Web 代理日志。如果你的 Splunk 中有这些数据,你已经拥有了你网络请求的 URL 的巨大存储库。使用免费的 Splunkbase 应用程序 URL Toolbox 从 URL 中 提取域名。
另一个包含域名请求的网络流量的良好来源是 DNS 数据。你可以从你的面向外部的 DNS 服务器获取此数据,或使用诸如 Splunk Stream 这样的线路数据收集工具,以 JSON 格式 从线路中提取此数据。
方法
非常感谢 SPL 大师 David Veuve,让我们深入探讨一些搜寻这些新域名的 SPL 想法。请确保你已安装免费的 Splunk 应用程序 URL Toolbox,以便这些搜索正常工作。首先,通过从过去 15 分钟内的代理日志中获取域名列表(包含我们看到的最新和最旧时间),来验证你是否有数据。
为了方便查看,这是我们的搜索。我们逐行解释它的工作原理。
tag=web url=* | eval list="mozilla" | `ut_parse_extended(url,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain
第一行检索我们的代理数据(检查 URL 字段中是否有值)。你可能需要在你的环境中修改它,限制为特定的索引和/或 sourcetype,而不是(或除了)使用 web 标签。你还可以通过过滤掉嘈杂的域名(如内容分发网络、IP 地址和/或 IP 地址范围)来优化你的搜索。
eval 命令创建一个新字段,我们将把它传递给下一行的 URL Toolbox 宏。它告诉宏 URL 的预期格式。宏本身接受 2 个参数——包含 URL 的字段名称(本例中为“url”)以及 URL 的格式(本例中为“mozilla”)。请注意,与 Splunk 中的所有宏一样,它们使用 `反引号` 而不是 '单引号'。stats 命令仅创建一个表,其中包含我们在数据集中看到的每个域名的最新时间(latest)和最早时间(earliest),并按宏执行时提取的 ut_domain 值进行分组。
如果一切顺利,你的数据此时应该与我的有些相似。要找到今天的“新域名”,请将今天的域名请求与前 6 天的基线进行比较。这很容易做到,只需将时间范围设置为 7 天并扩展我们之前的搜索。
tag=web url=* | eval list="mozilla" | `ut_parse_extended(url,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | eval isOutlier=if(earliest >= relative_time(now(), "-1d@d"), 1, 0) | convert ctime(earliest) ctime(latest)
前 4 行与我们原始搜索相同。第 5 行是实现神奇的地方。eval 命令创建一个名为“isOutlier”的新字段。此命令使用 if()
函数来确定我们在此数据集中看到的域名的最早(首次)出现时间是否在过去一天内(使用 eval 中可用的 now()
和 relative_time()
函数)。最后一行使用带有 ctime()
函数的 convert 命令,使时间字段人类可读。
此时,我们可以按 isOutlier 字段排序(单击列标题)来查找我们的新域名。或者,我们可以添加 | where isOutlier=1 来仅返回新域名。如果我们想要一个警报,我们可以在添加 where 命令后保存搜索,并在找到新域名时收到通知。
虽然此搜索可以完成任务,但从长远来看可能不是最优的。首先,正如你(如果尝试运行它)可能注意到的那样,它可能很慢。其次,我们每次运行它都需要检索 7 天的数据,即使那样,我们的视图也是有限的,因为我们只将今天与前 7 天进行比较。上周可能包含联邦假日?或者如果每个人都决定参加 .conf18?这可能不是一个足够大的基线来避免误报。
操作化和调优
幸运的是,借助 Splunk 的强大功能,我们可以通过几种方式解决这些问题。基本上,我们将使用 Splunk 的查找功能来创建一个先前已见域名的缓存,然后在一组更小的数据上运行针对新域名的搜索,将其与缓存进行比较,同时更新缓存。
我们将首先使用 Splunk 创建一个前 30 天的初始基线缓存,并将其写入 Splunk 中的 CSV 查找文件。此搜索可能需要一段时间才能运行,但一旦运行一次,你就不必再执行此操作了。我们的基线填充搜索如下所示。
tag=web url=* | eval list="mozilla" | `ut_parse_extended(url,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | outputlookup previously_seen_domains.csv
这看起来与我们的第一个搜索非常相似,但现在我们将写入一个 CSV 文件,供我们将在下一个搜索中使用。
有了基线后,我们可以创建一个搜索,将过去 15 分钟内请求的域名与基线进行比较。该搜索将使用新数据更新 CSV 文件(更新先前已见域名的 earliest 和 latest 时间,并为新域名添加行),同时标记任何异常值。它将如下所示。
tag=web url=* earliest=-15m | eval list="mozilla" | `ut_parse_extended(url,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | inputlookup append=t previously_seen_domains.csv | stats min(earliest) as earliest max(latest) as latest by ut_domain | outputlookup previously_seen_domains.csv | eval isOutlier=if(earliest >= relative_time(now(), "-1d@d"), 1, 0) | convert ctime(earliest) ctime(latest) | where isOutlier=1
前 4 行与之前的工作方式相同,只是这次我们将搜索范围限制在过去 15 分钟内。其思路是,我们将此搜索作为相关性或警报搜索运行,如果 Splunk 返回任何命中,我们可以使用自适应响应或警报框架来采取行动,例如在 Splunk Enterprise Security 中更新风险评分或启动工作流。
第 5 行的 inputlookup 命令使用 append 标志来检索我们在基线步骤中创建的 CSV 文件,并将其添加到过去 15 分钟内的数据集中。然后,我们使用第 6 行的 stats 命令来查看数据集中每个域名的“earliest earliest”和“latest latest”时间。这使我们能够查看过去 15 分钟内的数据和基线域名列表的组合数据。在执行 stats 命令并按 ut_domain 分组时,如果域名以前在 CSV 中,则 latest 字段可能会被更新,而以前不在 CSV 中的新域名将以其 earliest 和 latest 时间被添加。
搜索的其余部分只是将更新后的表写入同一个 CSV 查找文件,像以前一样标记异常值(新域名),并清理时间格式。由于我们正在进行警报,where 命令仅过滤出异常值,以便你可以对它们采取行动。
让我们进行 TSTAT 搜索
优化此搜索的另一种方法是将 CIM 兼容的加速数据模型应用于搜索。我们之前搜索的所有相同原理都适用,但我们将利用 tstats 的速度(不熟悉 tstats?请查看 Splunk Answers 上的此回复)。
假设你拥有 CIM 兼容的数据和已填充的数据模型,你可以通过手动运行 7 天的搜索来测试该搜索。
| tstats count from datamodel=Web by Web.url _time | rename "Web.url" as "uri" | eval list="mozilla" | `ut_parse_extended(uri,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | eval isOutlier=if(earliest >= relative_time(now(),"-1d@d"), 1, 0) | convert ctime(earliest) ctime(latest)
使用 tstats 与我们其他搜索的区别在于搜索的前两行。该搜索使用 tstats 命令,该命令对于加速数据来说非常快。然后,我们在将其传递给宏之前,将默认的“Web.url”字段重命名为“uri”。其余部分完全相同,但运行速度快得多。
要像上面那样将其操作化并使用查找,我们只需要做一些更改。初始查找填充搜索将如下所示。
| tstats count from datamodel=Web by Web.url _time | rename "Web.url" as "uri" | eval list="mozilla" | `ut_parse_extended(uri,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | outputlookup previously_seen_domains.csv
同样,操作化搜索将每 15 分钟左右运行一次,使用查找文件来扩展我们的时间范围并提高性能,如下所示。
| tstats count from datamodel=Web by Web.url _time | rename "Web.url" as "uri" | eval list="mozilla" | `ut_parse_extended(uri,list)` | stats earliest(_time) as earliest latest(_time) as latest by ut_domain | inputlookup append=t previously_seen_domains.csv | stats min(earliest) as earliest max(latest) as latest by ut_domain | outputlookup previously_seen_domains.csv | eval isOutlier=if(earliest >= relative_time(now(), "-1d@d"), 1, 0) | convert ctime(earliest) ctime(latest) | where isOutlier=1
希望这能为你提供多种搜寻新域名的方法,并可能为更多“首次出现”的威胁搜寻提供其他想法。为了进一步探索这些概念,我强烈建议查看 Splunkbase 上优秀的 Splunk Security Essentials 应用程序。