Microsoft Sentinel分析ルールの紐解き（First access credential added to Application or Service Principal where no credential was present）

Microsoft Sentinelにおいてもともと準備されている分析ルールについてクエリの中身や注意点等を紐解いていく。

:::note warn
このルールは利用環境によっては過検知が多発するためチューニングが必要である。
例えば
- 情報システム部門のメンテナンス作業対象のアプリケーションの検知除外を行う
- 情報システム部門のメンテナーは検知除外対象ユーザーとする

である
::: 

# 1. ルール概要
|項目|説明|
|--|--|
|重大度|高|
|ルール名|First access credential added to Application or Service Principal where no credential was present|
|ルールの種類|Scheduled|
|ルールの頻度|1時間ごとにクエリを実行|
|ルールの期間|過去1時間のデータ|
|バージョン|1.1.1|
|説明|これは、管理者またはアプリの所有者アカウントが、アプリケーションまたはサービスプリンシパルに新しいクレデンシャルを追加したときに警告を発しますが、そこには以前の検証用KeyCredentialは関連付けられていませんでした。脅威者が十分な権限を持つアカウントにアクセスし、このイベントの引き金となる代替認証材料を追加すると、脅威者はこのクレデンシャルを使用してアプリケーションまたはサービスプリンシパルとして認証することができるようになります。（by DeepL）|
|Ref（OAuth クレデンシャル付与）|https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow|
|Ref（AuditLogsについて）|https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities|

# 2. 活用するテーブル
|テーブル名|概要|参考URL|
|--|--|--|
|AuditLogs|Azure ADの監査ログ|https://learn.microsoft.com/ja-jp/azure/azure-monitor/reference/tables/auditlogs|

# 3. クエリ解説
```Kusto:First access credential added to Application or Service Principal where no credential was present / version1.1.1
// AzureADの監査ログを対象とする
AuditLogs
// 「サービス プリンシパルを追加する」と「アプリケーションの更新 - 証明書とシークレットの管理」をキャッチするため、操作名に大文字小文字問わず文字列を有するログを絞り込む
| where OperationName has_any ("Add service principal", "Certificates and secrets management") // captures "Add service principal", "Add service principal credentials", and "Update application - Certificates and secrets management" events
// 結果が大文字小文字問わず成功のログを絞り込む
| where Result =~ "success"
// 実行者のUPNもしくはアプリの表示名に@がつくログを絞り込む
| where tostring(InitiatedBy.user.userPrincipalName) has "@" or tostring(InitiatedBy.app.displayName) has "@"
// 対象の表示名を文字列型フィールドに格納する
| extend targetDisplayName = tostring(TargetResources[0].displayName)
// 対象のIDを文字列型フィールドに格納する
| extend targetId = tostring(TargetResources[0].id)
// 対象のタイプを文字列型フィールドに格納する
| extend targetType = tostring(TargetResources[0].type)
// 対象の変更情報をフィールドに格納する
| extend keyEvents = TargetResources[0].modifiedProperties
// 変更情報のすべてを展開する（変更情報が3種類あった場合、keyEventsフィールドの値が3種類違いその他のフィールドの値は同じログが生成される）
| mv-expand keyEvents
// 表示名が大文字小文字問わずKeyDescriptionのログにのみ絞り込む
| where keyEvents.displayName =~ "KeyDescription"
// 変更後の新しい値をフィールドに展開する
| extend new_value_set = parse_json(tostring(keyEvents.newValue))
// 変更前の値をフィールドに展開する
| extend old_value_set = parse_json(tostring(keyEvents.oldValue))
// 変更前の値が空白であるイベントを絞り込む
| where old_value_set == "[]"
// 新しい値のすべてを展開する
| mv-expand new_value_set
// new_value_setのデータをキーバリュー形式の値を指定した型で解析しフィールドに格納する
| parse new_value_set with * "KeyIdentifier=" keyIdentifier:string ",KeyType=" keyType:string ",KeyUsage=" keyUsage:string ",DisplayName=" keyDisplayName:string "]" *
// KeyUsageの値がVerifyもしくは空白のログにのみ絞り込む
| where keyUsage == "Verify"  or keyUsage == ""
// User-Agentのデータが存在する場合は展開し、ない場合は空白を格納する
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent",tostring(AdditionalDetails[0].value),"")
// クレデンシャルを追加したユーザーもしくはアプリ名をフィールドに展開する
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
// クレデンシャルを追加した際のIPアドレスをフィールドに展開する
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
// The below line is currently commented out but Microsoft Sentinel users can modify this query to show only Application or only Service Principal events in their environment
//| where targetType =~ "Application" // or targetType =~ "ServicePrincipal"
// 指定したフィールドを表示しないよう除外する
| project-away new_value_set, old_value_set
// 指定した順番にフィールドを並び替える
| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId
// エンティティに付与日時、対象のユーザーもしくはアプリ名、IPアドレスを設定する
| extend timestamp = TimeGenerated, AccountCustomEntity = InitiatingUserOrApp, IPCustomEntity = InitiatingIpAddress
```

# X. おまけ
|演算子|参考URL|
|--|--|
|parse|<https://learn.microsoft.com/ja-jp/azure/data-explorer/kusto/query/parseoperator>|
|project-away|<https://learn.microsoft.com/ja-jp/azure/data-explorer/kusto/query/projectawayoperator>|