將 Splunk 偵測規則移轉至 Microsoft Sentinel
Splunk 偵測規則是安全性資訊和事件管理 (SIEM) 元件,與 Sentinel Microsoft 中的分析規則相比較。 本文說明識別、比較和遷移至 Sentinel Microsoft的概念。 最佳方式是從 SIEM 移轉體驗開始,其會識別現成可用的 (OOTB) 分析規則,以自動轉譯為 。
如果您要移轉 Splunk Observability 部署,請深入了解如何從 Splunk 移轉至 Azure 監視器記錄。
稽核規則
Microsoft Sentinel 會使用機器學習分析來建立高精確度且可採取動作的事件。 某些現有的 Splunk 偵測在Microsoft Sentinel 中可能是多餘的,因此不要盲目移轉它們。 當您識別現有的偵測規則時,請檢閱這些考量事項。
- 請務必選取可證明規則移轉的使用案例,考慮商務優先順序和效率。
- 確認您了解 Microsoft Sentinel 規則類型。
- 確認您了解規則術語。
- 檢閱過去 6-12 個月沒有警示的過時規則,並判斷它們是否仍然相關。
- 消除您定期忽略的低階威脅或警示。
- 確認已連線的資料來源,並檢閱資料連線方法。 Microsoft Sentinel Analytics 要求在啟用規則之前,數據類型會出現在 Log Analytics 工作區中。 回顧覽資料收集交談,以確認您打算在使用案例上偵測的資料深度和廣度。 然後使用 SIEM 移轉體驗來確保數據源已適當對應。
移轉規則
識別要移轉的 Splunk 偵測之後,請檢閱移轉程式的下列考慮:
- 比較Microsoft Sentinel 的 OOTB 分析規則與目前使用案例的現有功能。 使用 SIEM 移轉體驗來查看哪些 Splunk 偵測會自動轉換成 OOTB 範本。
- 轉譯不符合 OOTB 分析規則的偵測。 自動轉譯 Splunk 偵測的最佳方式是搭配 SIEM 移轉體驗。
- 探索SOC Prime Threat Detection Marketplace 等社群資源,以探索更多使用案例的演算法。
- 如果無法使用或未自動翻譯內建規則,請手動轉譯偵測。 建立新的 KQL 查詢,並檢閱 規則對應。
如需詳細資訊,請參閱 移轉偵測規則的最佳做法。
規則移轉步驟
請確認已備妥測試系統來處理您要移轉的每個規則。
針對已移轉的規則準備驗證程序,包括完整的測試案例和指令碼。
請確定您的小組有實用的資源來測試已移轉的規則。
確認您已連線必要的數據源, 並檢閱您的數據連線方法。
確認您的偵測是否在 Microsoft Sentinel 中以 OOTB 範本的形式提供:
使用 SIEM 移轉體驗 ,將 OOTB 範本的翻譯和安裝自動化。
如需詳細資訊,請參閱使用 SIEM 移轉體驗 (部分機器翻譯)。
如果您有未反映在偵測中的使用案例,請使用 OOTB 規則範本為您自己的工作區建立規則。
在 Microsoft Sentinel 中,移至 [內容] 中 樞。
篩選分析規則範本的內容類型。
尋找並 安裝/更新 每個對應的內容中樞解決方案或獨立分析規則範本。
如需詳細資訊,請參閱立即偵測威脅。
如果您有Microsoft Sentinel 的 OOTB 規則未涵蓋的偵測,請先嘗試 SIEM 移轉體驗 進行自動轉譯。
如果 OOTB 規則和 SIEM 移轉都無法完全轉譯偵測,請手動建立規則。 在這種情況下,請使用下列步驟來建立規則:
識別您想要在規則中使用的資料來源。 藉由建立數據源與數據表之間的對應數據表,來識別您想要查詢的Microsoft Sentinel 數據表。
在您想要用於規則的資料中,識別任何屬性、欄位或實體。
識別您的規則準則和邏輯。 在這個階段,請考慮尋找規則範本作為如何建構 KQL 查詢的範例。
請考慮篩選、相互關聯規則、作用中清單、參考集、關注清單、偵測異常、彙總等等。 您可以使用舊版 SIEM 所提供的參考,以了解如何最正確對應查詢語法。
識別觸發條件和規則動作,然後建構並檢閱您的 KQL 查詢。 檢閱查詢時,請考慮 KQL 最佳化指引資源。
使用每個相關使用案例測試規則。 如果它未提供預期的結果,請檢閱並編輯 KQL 並再次進行測試。
當您滿意時,請考慮移轉的規則。 視需要為您的規則動作建立劇本。 如需詳細資訊,請參閱使用 Microsoft Sentinel 中的劇本將威脅回應自動化。
深入了解分析規則:
- 建立自訂分析規則以偵測威脅。 使用警示群組,藉由將在指定時間範圍內發生的警示分組,以減少警示疲勞。
- 將資料欄位對應至 Microsoft Sentinel 中的實體,讓 SOC 工程師能夠將實體定義為在調查期間追蹤之辨識項的一部分。 實體對應也可讓 SOC 分析師利用直覺式[調查圖表] (investigate-cases.md#use-the-investigation-graph-to-deep-dive),協助縮短時間和精力。
- 使用 UEBA 資料來調查事件,例如如何使用辨識項來呈現事件、警示,以及事件預覽窗格中與特定事件相關聯的任何書籤。
- Kusto 查詢語言 (KQL),您可以用來將唯讀要求傳送至您的 Log Analytics 資料庫,以處理資料並傳回結果。 KQL 也用於其他 Microsoft 服務,例如適用於端點的 Microsoft Defender 和 Application Insights。
比較規則術語
相較於以搜尋處理語言 (SPL) 為基礎的 Splunk 偵測,下表可協助您釐清Microsoft Sentinel 中以 Kusto 查詢語言 (KQL) 為基礎的規則概念。
Splunk | Microsoft Sentinel | |
---|---|---|
規則類型 | • 已排程 • 即時 |
• 排程的查詢 • 融合 • Microsoft 安全性 • Machine Learning (ML) 行為分析 |
準則 | 在 SPL 中定義 | 在 KQL 中定義 |
觸發條件 | • 結果數目 • 主機數目 • 來源數目 • 自訂 |
閾值:查詢結果數目 |
動作 | • 新增至觸發的警示 • 記錄事件 • 要查閱的輸出結果 • 及其他 |
• 建立警示或事件 • 與 Logic Apps 整合 |
對應和比較規則範例
使用這些範例,在各種案例中從 Splunk 到 Microsoft Sentinel 比較和對應規則。
常見的搜尋命令
SPL 命令 | 描述 | KQL 運算子 | KQL 範例 |
---|---|---|---|
chart/ timechart |
以表格式輸出傳回結果來繪製時間序列圖表。 | render 運算子 | … | render timechart |
dedup |
移除符合指定準則的後續結果。 | • distinct • summarize |
… | summarize by Computer, EventID |
eval |
計算運算式。 瞭解 一般 eval 命令。 |
extend | T | extend duration = endTime - startTime |
fields |
從搜尋結果中移除欄位。 | • project • project-away |
T | project cost=price*quantity, price |
head/tail |
傳回前 N 個或最後 N 個結果。 | top | T | top 5 by Name desc nulls last |
lookup |
從外部來源新增欄位值。 | • externaldata • lookup |
KQL 範例 |
rename |
重新命名欄位。 使用萬用字元來指定多個欄位。 | project-rename | T | project-rename new_column_name = column_name |
rex |
使用規則運算式指定群組名稱來擷取欄位。 | matches regex | … | where field matches regex "^addr.*" |
search |
將結果篩選為符合搜尋運算式的結果。 | search | search "X" |
sort |
依指定的欄位排序搜尋結果。 | sort | T | sort by strlen(country) asc, price desc |
stats |
提供統計資料,可選擇依欄位分組。 深入了解常見的 stats 命令。 | summarize | KQL 範例 |
mstats |
類似於 stats,用於計量而非事件。 | summarize | KQL 範例 |
table |
指定要保留在結果集的欄位,並以表格式格式保留資料。 | project | T | project columnA, columnB |
top/rare |
顯示欄位最常見或最不常見的值。 | top | T | top 5 by Name desc nulls last |
transaction |
將搜尋結果分組成交易。 SPL 範例 |
範例:row_window_session | KQL 範例 |
eventstats |
從事件中的欄位產生摘要統計資料,並將這些統計資料儲存在新欄位中。 SPL 範例 |
範例: • join • make_list • mv-expand |
KQL 範例 |
streamstats |
尋找欄位的累計總和。 SPL 範例: ... | streamstats sum(bytes) as bytes _ total \| timechart |
row_cumsum | ...\| serialize cs=row_cumsum(bytes) |
anomalydetection |
在指定的欄位中尋找異常。 SPL 範例 |
series_decompose_anomalies() | KQL 範例 |
where |
使用 eval 運算式篩選搜尋結果。 用來比較兩個不同的欄位。 |
where | T | where fruit=="apple" |
lookup
命令:KQL 範例
Users
| where UserID in ((externaldata (UserID:string) [
@"https://storageaccount.blob.core.windows.net/storagecontainer/users.txt"
h@"?...SAS..." // Secret token to access the blob
])) | ...
stats
命令:KQL 範例
Sales
| summarize NumTransactions=count(),
Total=sum(UnitPrice * NumUnits) by Fruit,
StartOfMonth=startofmonth(SellDateTime)
mstats
命令:KQL 範例
T | summarize count() by price_range=bin(price, 10.0)
transaction
命令:SPL 範例
sourcetype=MyLogTable type=Event
| transaction ActivityId startswith="Start" endswith="Stop"
| Rename timestamp as StartTime
| Table City, ActivityId, StartTime, Duration
transaction
命令:KQL 範例
let Events = MyLogTable | where type=="Event";
Events
| where Name == "Start"
| project Name, City, ActivityId, StartTime=timestamp
| join (Events
| where Name == "Stop"
| project StopTime=timestamp, ActivityId)
on ActivityId
| project City, ActivityId, StartTime,
Duration = StopTime – StartTime
用來 row_window_session()
計算串行化數據列集中數據行的會話開始值。
...| extend SessionStarted = row_window_session(
Timestamp, 1h, 5m, ID != prev(ID))
eventstats
命令:SPL 範例
… | bin span=1m _time
|stats count AS count_i by _time, category
| eventstats sum(count_i) as count_total by _time
eventstats
命令:KQL 範例
以下是 join
陳述式的範例:
let binSize = 1h;
let detail = SecurityEvent
| summarize detail_count = count() by EventID,
tbin = bin(TimeGenerated, binSize);
let summary = SecurityEvent
| summarize sum_count = count() by
tbin = bin(TimeGenerated, binSize);
detail
| join kind=leftouter (summary) on tbin
| project-away tbin1
以下是 make_list
陳述式的範例:
let binSize = 1m;
SecurityEvent
| where TimeGenerated >= ago(24h)
| summarize TotalEvents = count() by EventID,
groupBin =bin(TimeGenerated, binSize)
|summarize make_list(EventID), make_list(TotalEvents),
sum(TotalEvents) by groupBin
| mvexpand list_EventID, list_TotalEvents
anomalydetection
命令:SPL 範例
sourcetype=nasdaq earliest=-10y
| anomalydetection Close _ Price
anomalydetection
命令:KQL 範例
let LookBackPeriod= 7d;
let disableAccountLogon=SignIn
| where ResultType == "50057"
| where ResultDescription has "account is disabled";
disableAccountLogon
| make-series Trend=count() default=0 on TimeGenerated
in range(startofday(ago(LookBackPeriod)), now(), 1d)
| extend (RSquare,Slope,Variance,RVariance,Interception,
LineFit)=series_fit_line(Trend)
| extend (anomalies,score) =
series_decompose_anomalies(Trend)
一般 eval
命令
SPL 命令 | 描述 | SPL 範例 | KQL 命令 | KQL 範例 |
---|---|---|---|---|
abs(X) |
傳回 X 的絕對值。 | abs(number) |
abs() |
abs(X) |
case(X,"Y",…) |
接受 X 和 Y 引數的配對,其中 X 引數是布林運算式。 評估為 TRUE 時,引數會傳回對應的 Y 引數。 |
SPL 範例 | case |
KQL 範例 |
ceil(X) |
數字 X 的上限。 | ceil(1.9) |
ceiling() |
ceiling(1.9) |
cidrmatch("X",Y) |
識別屬於特定子網路的 IP 位址。 | cidrmatch ("123.132.32.0/25",ip) |
• ipv4_is_match() • ipv6_is_match() |
ipv4_is_match('192.168.1.1', '192.168.1.255') == false |
coalesce(X,…) |
傳回不是 null 的第一個值。 | coalesce(null(), "Returned val", null()) |
coalesce() |
coalesce(tolong("not a number"), tolong("42"), 33) == 42 |
cos(X) |
計算 X 的餘弦。 | n=cos(0) |
cos() | cos(X) |
exact(X) |
使用雙精確度浮點算術評估運算式 X。 | exact(3.14*num) |
todecimal() |
todecimal(3.14*2) |
exp(X) |
傳回 eX。 | exp(3) |
exp() | exp(3) |
if(X,Y,Z) |
如果 X 評估為 TRUE ,則結果為第二個引數 Y 。 如果 X 評估為 FALSE ,則結果會評估為第三個引數 Z 。 |
if(error==200, "OK", "Error") |
iif() |
KQL 範例 |
isbool(X) |
如果 TRUE 為布林值,則傳回 X 。 |
isbool(field) |
• iif() • gettype |
iif(gettype(X) =="bool","TRUE","FALSE") |
isint(X) |
如果 TRUE 是整數,則傳回 X 。 |
isint(field) |
• iif() • gettype |
KQL 範例 |
isnull(X) |
如果 TRUE 為 null,則傳回 X 。 |
isnull(field) |
isnull() |
isnull(field) |
isstr(X) |
如果 X 為字串,則會傳回 TRUE 。 |
isstr(field) |
• iif() • gettype |
KQL 範例 |
len(X) |
此函式傳回字串 X 的字元長度。 |
len(field) |
strlen() |
strlen(field) |
like(X,"y") |
只有在 X 類似 TRUE 中的 SQLite 模式時,才會傳回 Y 。 |
like(field, "addr%") |
• has • contains • startswith • matches regex |
KQL 範例 |
log(X,Y) |
使用第二個引數 Y 作為底數,傳回第一個引數 X 的對數。 Y 的預設值為 10 。 |
log(number,2) |
• log • log2 • log10 |
log(X) log2(X) log10(X) |
lower(X) |
傳回 X 的小寫值。 |
lower(username) |
tolower | tolower(username) |
ltrim(X,Y) |
傳回從左側修剪參數 Y 中的字元後的 X 。 Y 的預設輸出是空格和定位字元。 |
ltrim(" ZZZabcZZ ", " Z") |
trim_start() |
trim_start(“ ZZZabcZZ”,” ZZZ”) |
match(X,Y) |
如果 X 符合 RegEx 模式 Y,則傳回。 | match(field, "^\d{1,3}.\d$") |
matches regex |
… | where field matches regex @"^\d{1,3}.\d$") |
max(X,…) |
傳回資料行中的最大值。 | max(delay, mydelay) |
• max() • arg_max() |
… | summarize max(field) |
md5(X) |
傳回字串值 X 的 MD5 雜湊。 |
md5(field) |
hash_md5 |
hash_md5("X") |
min(X,…) |
傳回資料行中的最小值。 | min(delay, mydelay) |
• min_of() • min() • arg_min |
KQL 範例 |
mvcount(X) |
傳回 X 值的數目 (總數)。 |
mvcount(multifield) |
dcount |
…| summarize dcount(X) by Y |
mvfilter(X) |
根據布林 X 運算式篩選多重值欄位。 |
mvfilter(match(email, "net$")) |
mv-apply |
KQL 範例 |
mvindex(X,Y,Z) |
傳回多重值 X 引數從開始位置 (從零開始) Y 到 Z (選擇性) 的子集。 |
mvindex( multifield, 2) |
array_slice |
array_slice(arr, 1, 2) |
mvjoin(X,Y) |
已知多重值欄位 X 和字串分隔符號 Y ,使用 Y 聯結 X 的個別值。 |
mvjoin(address, ";") |
strcat_array |
KQL 範例 |
now() |
傳回以 Unix 時間表示的目前時間。 | now() |
now() |
now() now(-2d) |
null() |
不接受引數並傳回 NULL 。 |
null() |
null | null |
nullif(X,Y) |
包含兩個引數 X 和 Y ,如果引數不同,則傳回 X 。 否則傳回 NULL 。 |
nullif(fieldA, fieldB) |
iif |
iif(fieldA==fieldB, null, fieldA) |
random() |
傳回 0 到 2147483647 之間的虛擬隨機數。 |
random() |
rand() |
rand() |
relative_ time(X,Y) |
已知 Epoch 時間 X 和相對時間規範 Y ,傳回將 Y 套用至 X 後的 Epoch 時間值。 |
relative_time(now(),"-1d@d") |
unix 時間 | KQL 範例 |
replace(X,Y,Z) |
傳回以字串 Z 取代 X 字串中出現的每個規則運算式字串 Y 而形成的字串。 |
傳回月份和日期數字交換後的日期。 例如,以 4/30/2015 為例,輸出為 30/4/2009 :replace(date, "^(\d{1,2})/ (\d{1,2})/", "\2/\1/") |
replace() |
KQL 範例 |
round(X,Y) |
傳回以 Y 指定的小數位數四捨五入的 X 。 預設是四捨五入為整數。 |
round(3.5) |
round |
round(3.5) |
rtrim(X,Y) |
傳回從右側修剪字元 Y 後的 X 。 如果未指定 Y ,則會修剪空格和定位字元。 |
rtrim(" ZZZZabcZZ ", " Z") |
trim_end() |
trim_end(@"[ Z]+",A) |
searchmatch(X) |
如果事件符合搜尋字串 X ,則傳回 TRUE 。 |
searchmatch("foo AND bar") |
iif() | iif(field has "X","Yes","No") |
split(X,"Y") |
以多重值欄位的形式傳回 X ,並以分隔符號 Y 分割。 |
split(address, ";") |
split() |
split(address, ";") |
sqrt(X) |
傳回 X 的平方根。 |
sqrt(9) |
sqrt() |
sqrt(9) |
strftime(X,Y) |
傳回使用 Y 指定的格式轉譯的 Epoch 時間值 X 。 |
strftime(_time, "%H:%M") |
format_datetime() |
format_datetime(time,'HH:mm') |
strptime(X,Y) |
已知字串 X 代表的時間,傳回從格式 Y 剖析的值。 |
strptime(timeStr, "%H:%M") |
format_datetime() | KQL 範例 |
substr(X,Y,Z) |
傳回從開始位置 (從零開始) Y 起 Z 個 (選擇性) 字元的子字串欄位 X 。 |
substr("string", 1, 3) |
substring() |
substring("string", 0, 3) |
time() |
傳回精確至微秒的時鐘時間。 | time() |
format_datetime() |
KQL 範例 |
tonumber(X,Y) |
將輸入字串 X 轉換成數字,其中 Y (選擇性,預設值為 10 ) 定義要轉換成的數字底數。 |
tonumber("0A4",16) |
toint() |
toint("123") |
tostring(X,Y) |
說明 | SPL 範例 | tostring() |
tostring(123) |
typeof(X) |
傳回欄位型別的字串表示法。 | typeof(12) |
gettype() |
gettype(12) |
urldecode(X) |
傳回已解碼的 URL X 。 |
SPL 範例 | url_decode |
KQL 範例 |
case(X,"Y",…)
SPL 範例
case(error == 404, "Not found",
error == 500,"Internal Server Error",
error == 200, "OK")
case(X,"Y",…)
KQL 範例
T
| extend Message = case(error == 404, "Not found",
error == 500,"Internal Server Error", "OK")
if(X,Y,Z)
KQL 範例
iif(floor(Timestamp, 1d)==floor(now(), 1d),
"today", "anotherday")
isint(X)
KQL 範例
iif(gettype(X) =="long","TRUE","FALSE")
isstr(X)
KQL 範例
iif(gettype(X) =="string","TRUE","FALSE")
like(X,"y")
例
… | where field has "addr"
… | where field contains "addr"
… | where field startswith "addr"
… | where field matches regex "^addr.*"
min(X,…)
KQL 範例
min_of (expr_1, expr_2 ...)
…|summarize min(expr)
…| summarize arg_min(Price,*) by Product
mvfilter(X)
KQL 範例
T | mv-apply Metric to typeof(real) on
(
top 2 by Metric desc
)
mvjoin(X,Y)
KQL 範例
strcat_array(dynamic([1, 2, 3]), "->")
relative time(X,Y)
KQL 範例
let toUnixTime = (dt:datetime)
{
(dt - datetime(1970-01-01))/1s
};
replace(X,Y,Z)
KQL 範例
replace( @'^(\d{1,2})/(\d{1,2})/', @'\2/\1/',date)
strptime(X,Y)
KQL 範例
format_datetime(datetime('2017-08-16 11:25:10'),
'HH:mm')
time()
KQL 範例
format_datetime(datetime(2015-12-14 02:03:04),
'h:m:s')
tostring(X,Y)
以字串形式傳回 X
的欄位值。
- 如果
X
的值是數字,則X
重新格式化為字串值。 - 如果
X
是布林值, 則X
重新格式化為TRUE
或FALSE
。 - 如果
X
是數字,則第二個引數Y
是選擇性,可以是hex
(將X
轉換成十六進位)、commas
(以逗號和兩個小數位數來格式化X
),或duration
(將X
從以秒為單位的時間格式轉換成看得懂的時間格式:HH:MM:SS
)。
tostring(X,Y)
SPL 範例
此範例傳回:
foo=615 and foo2=00:10:15:
… | eval foo=615 | eval foo2 = tostring(
foo, "duration")
urldecode(X)
SPL 範例
urldecode("http%3A%2F%2Fwww.splunk.com%2Fdownload%3Fr%3Dheader")
常見的 stats
命令 KQL 範例
SPL 命令 | 描述 | KQL 命令 | KQL 範例 |
---|---|---|---|
avg(X) |
傳回欄位 X 的平均值。 |
avg() | avg(X) |
count(X) |
傳回欄位 X 的出現次數。 若要指出要比對的特定欄位值,請將 X 格式化為 eval(field="value") 。 |
count() | summarize count() |
dc(X) |
傳回欄位 X 的相異值計數。 |
dcount() | …\| summarize countries=dcount(country) by continent |
earliest(X) |
傳回 X 的最早時序值。 |
arg_min() | … \| summarize arg_min(TimeGenerated, *) by X |
latest(X) |
傳回 X 的最晚時序值。 |
arg_max() | … \| summarize arg_max(TimeGenerated, *) by X |
max(X) |
傳回欄位 X 的最大值。 如果 X 的值不是數值,則透過字母順序找到最大值。 |
max() | …\| summarize max(X) |
median(X) |
傳回欄位 X 的最中間值。 |
percentile() | …\| summarize percentile(X, 50) |
min(X) |
傳回欄位 X 的最小值。 如果 X 的值不是數值,則透過字母順序找到最小值。 |
min() | …\| summarize min(X) |
mode(X) |
傳回欄位 X 中最常出現的值。 |
top-hitters() | …\| top-hitters 1 of Y by X |
perc(Y) |
傳回 Y 欄位的第 X 個百分位值。 例如,perc5(total) 傳回欄位 total 的第五個百分位值。 |
percentile() | …\| summarize percentile(Y, 5) |
range(X) |
傳回欄位 X 的最大值和最小值之間的差異。 |
range() | range(1, 3) |
stdev(X) |
傳回欄位 X 的樣本標準差。 |
stdev | stdev() |
stdevp(X) |
取得欄位 X 的母體標準差。 |
stdevp() | stdevp() |
sum(X) |
傳回欄位 X 的值總和。 |
sum() | sum(X) |
sumsq(X) |
傳回欄位 X 的平方值總和。 |
||
values(X) |
以多重值項目傳回欄位 X 的所有相異值清單。 值依字母順序排列。 |
make_set() | …\| summarize r = make_set(X) |
var(X) |
傳回欄位 X 的樣本變異數。 |
variance | variance(X) |
下一步
在本文中,您已了解如何將移轉規則從 Splunk 對應至 Microsoft Sentinel。