Credential added after admin consented to Application
Id | 707494a5-8e44-486b-90f8-155d1797a8eb |
Rulename | Credential added after admin consented to Application |
Description | This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user. If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential. Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow. For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities |
Severity | Medium |
Tactics | CredentialAccess Persistence PrivilegeEscalation |
Techniques | T1555 T1098 |
Required data connectors | AzureActiveDirectory |
Kind | Scheduled |
Query frequency | 1d |
Query period | 2d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Entra ID/Analytic Rules/CredentialAddedAfterAdminConsent.yaml |
Version | 1.1.1 |
Arm template | 707494a5-8e44-486b-90f8-155d1797a8eb.json |
let auditLookbackStart = 2d;
let auditLookbackEnd = 1d;
AuditLogs
| where TimeGenerated >= ago(auditLookbackStart)
| where OperationName =~ "Consent to application"
| where Result =~ "success"
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "ServicePrincipal"
| extend targetResourceName = tostring(TargetResource.displayName),
targetResourceID = tostring(TargetResource.id),
targetResourceType = tostring(TargetResource.type),
targetModifiedProp = TargetResource.modifiedProperties
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "ConsentContext.IsAdminConsent"
| extend isAdminConsent = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "ConsentAction.Permissions"
| extend Consent_TargetPermissions = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "TargetId.ServicePrincipalNames"
| extend Consent_TargetServicePrincipalNames = tostring(extract_all(@"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})",trim(@'"',tostring(Property.newValue)))[0])
)
| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Consent_InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend Consent_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend Consent_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend Consent_InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend Consent_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| join kind=inner (
AuditLogs
| where TimeGenerated >= ago(auditLookbackEnd)
| where OperationName =~ "Add service principal credentials"
| where Result =~ "success"
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "ServicePrincipal"
| extend targetResourceName = tostring(TargetResource.displayName),
targetResourceID = tostring(TargetResource.id),
targetModifiedProp = TargetResource.modifiedProperties
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "KeyDescription"
| extend Credential_TargetKeyDescription = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "Included Updated Properties"
| extend UpdatedProperties = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "TargetId.ServicePrincipalNames"
| extend Credential_TargetServicePrincipalNames = tostring(extract_all(@"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})",trim(@'"',tostring(Property.newValue)))[0])
)
| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Credential_InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend Credential_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend Credential_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend Credential_InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend Credential_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
) on targetResourceName, targetResourceID
| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1
| where TimeConsent < TimeCred
| project TimeConsent, TimeCred, targetResourceName, targetResourceType, isAdminConsent,
Consent_InitiatingUserOrApp, Consent_TargetServicePrincipalNames, Consent_TargetPermissions,
Consent_InitiatingAppName, Consent_InitiatingAppServicePrincipalId, Consent_InitiatingUserPrincipalName, Consent_InitiatingAadUserId, Consent_InitiatingIpAddress,
Credential_InitiatingUserOrApp, Credential_TargetServicePrincipalNames, Credential_TargetKeyDescription,
Credential_InitiatingAppName, Credential_InitiatingAppServicePrincipalId, Credential_InitiatingUserPrincipalName, Credential_InitiatingAadUserId, Credential_InitiatingIpAddress
| extend Consent_AccountName = tostring(split(Consent_InitiatingUserPrincipalName, "@")[0]), Consent_UPNSuffix = tostring(split(Consent_InitiatingUserPrincipalName, "@")[1])
| extend Credential_AccountName = tostring(split(Credential_InitiatingUserPrincipalName, "@")[0]), Credential_UPNSuffix = tostring(split(Credential_InitiatingUserPrincipalName, "@")[1])
id: 707494a5-8e44-486b-90f8-155d1797a8eb
tactics:
- CredentialAccess
- Persistence
- PrivilegeEscalation
queryPeriod: 2d
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Entra ID/Analytic Rules/CredentialAddedAfterAdminConsent.yaml
triggerThreshold: 0
name: Credential added after admin consented to Application
query: |
let auditLookbackStart = 2d;
let auditLookbackEnd = 1d;
AuditLogs
| where TimeGenerated >= ago(auditLookbackStart)
| where OperationName =~ "Consent to application"
| where Result =~ "success"
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "ServicePrincipal"
| extend targetResourceName = tostring(TargetResource.displayName),
targetResourceID = tostring(TargetResource.id),
targetResourceType = tostring(TargetResource.type),
targetModifiedProp = TargetResource.modifiedProperties
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "ConsentContext.IsAdminConsent"
| extend isAdminConsent = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "ConsentAction.Permissions"
| extend Consent_TargetPermissions = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "TargetId.ServicePrincipalNames"
| extend Consent_TargetServicePrincipalNames = tostring(extract_all(@"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})",trim(@'"',tostring(Property.newValue)))[0])
)
| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Consent_InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend Consent_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend Consent_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend Consent_InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend Consent_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| join kind=inner (
AuditLogs
| where TimeGenerated >= ago(auditLookbackEnd)
| where OperationName =~ "Add service principal credentials"
| where Result =~ "success"
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "ServicePrincipal"
| extend targetResourceName = tostring(TargetResource.displayName),
targetResourceID = tostring(TargetResource.id),
targetModifiedProp = TargetResource.modifiedProperties
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "KeyDescription"
| extend Credential_TargetKeyDescription = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "Included Updated Properties"
| extend UpdatedProperties = trim(@'"',tostring(Property.newValue))
)
| mv-apply Property = targetModifiedProp on
(
where Property.displayName =~ "TargetId.ServicePrincipalNames"
| extend Credential_TargetServicePrincipalNames = tostring(extract_all(@"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})",trim(@'"',tostring(Property.newValue)))[0])
)
| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Credential_InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend Credential_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend Credential_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend Credential_InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend Credential_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
) on targetResourceName, targetResourceID
| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1
| where TimeConsent < TimeCred
| project TimeConsent, TimeCred, targetResourceName, targetResourceType, isAdminConsent,
Consent_InitiatingUserOrApp, Consent_TargetServicePrincipalNames, Consent_TargetPermissions,
Consent_InitiatingAppName, Consent_InitiatingAppServicePrincipalId, Consent_InitiatingUserPrincipalName, Consent_InitiatingAadUserId, Consent_InitiatingIpAddress,
Credential_InitiatingUserOrApp, Credential_TargetServicePrincipalNames, Credential_TargetKeyDescription,
Credential_InitiatingAppName, Credential_InitiatingAppServicePrincipalId, Credential_InitiatingUserPrincipalName, Credential_InitiatingAadUserId, Credential_InitiatingIpAddress
| extend Consent_AccountName = tostring(split(Consent_InitiatingUserPrincipalName, "@")[0]), Consent_UPNSuffix = tostring(split(Consent_InitiatingUserPrincipalName, "@")[1])
| extend Credential_AccountName = tostring(split(Credential_InitiatingUserPrincipalName, "@")[0]), Credential_UPNSuffix = tostring(split(Credential_InitiatingUserPrincipalName, "@")[1])
severity: Medium
triggerOperator: gt
kind: Scheduled
relevantTechniques:
- T1555
- T1098
tags:
- Solorigate
- NOBELIUM
queryFrequency: 1d
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
description: |
'This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user.
If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.
Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.
For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities'
status: Available
version: 1.1.1
entityMappings:
- fieldMappings:
- columnName: Consent_InitiatingAppName
identifier: Name
- columnName: Consent_InitiatingAppServicePrincipalId
identifier: AadUserId
entityType: Account
- fieldMappings:
- columnName: Credential_InitiatingAppName
identifier: Name
- columnName: Credential_InitiatingAppServicePrincipalId
identifier: AadUserId
entityType: Account
- fieldMappings:
- columnName: Consent_InitiatingUserPrincipalName
identifier: FullName
- columnName: Consent_AccountName
identifier: Name
- columnName: Consent_UPNSuffix
identifier: UPNSuffix
entityType: Account
- fieldMappings:
- columnName: Consent_InitiatingAadUserId
identifier: AadUserId
entityType: Account
- fieldMappings:
- columnName: Credential_InitiatingUserPrincipalName
identifier: FullName
- columnName: Credential_AccountName
identifier: Name
- columnName: Credential_UPNSuffix
identifier: UPNSuffix
entityType: Account
- fieldMappings:
- columnName: Credential_InitiatingAadUserId
identifier: AadUserId
entityType: Account
- fieldMappings:
- columnName: Consent_InitiatingIpAddress
identifier: Address
entityType: IP
- fieldMappings:
- columnName: Credential_InitiatingIpAddress
identifier: Address
entityType: IP
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/707494a5-8e44-486b-90f8-155d1797a8eb')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/707494a5-8e44-486b-90f8-155d1797a8eb')]",
"properties": {
"alertRuleTemplateName": "707494a5-8e44-486b-90f8-155d1797a8eb",
"customDetails": null,
"description": "'This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user.\n If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\n Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.\n For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities'\n",
"displayName": "Credential added after admin consented to Application",
"enabled": true,
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Consent_InitiatingAppName",
"identifier": "Name"
},
{
"columnName": "Consent_InitiatingAppServicePrincipalId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Credential_InitiatingAppName",
"identifier": "Name"
},
{
"columnName": "Credential_InitiatingAppServicePrincipalId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Consent_InitiatingUserPrincipalName",
"identifier": "FullName"
},
{
"columnName": "Consent_AccountName",
"identifier": "Name"
},
{
"columnName": "Consent_UPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Consent_InitiatingAadUserId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Credential_InitiatingUserPrincipalName",
"identifier": "FullName"
},
{
"columnName": "Credential_AccountName",
"identifier": "Name"
},
{
"columnName": "Credential_UPNSuffix",
"identifier": "UPNSuffix"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Credential_InitiatingAadUserId",
"identifier": "AadUserId"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "Consent_InitiatingIpAddress",
"identifier": "Address"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "Credential_InitiatingIpAddress",
"identifier": "Address"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Entra ID/Analytic Rules/CredentialAddedAfterAdminConsent.yaml",
"query": "let auditLookbackStart = 2d;\nlet auditLookbackEnd = 1d;\nAuditLogs\n| where TimeGenerated >= ago(auditLookbackStart)\n| where OperationName =~ \"Consent to application\" \n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetResourceType = tostring(TargetResource.type),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentContext.IsAdminConsent\"\n | extend isAdminConsent = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentAction.Permissions\"\n | extend Consent_TargetPermissions = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Consent_TargetServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Consent_InitiatingAppName = tostring(InitiatedBy.app.displayName)\n| extend Consent_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend Consent_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| extend Consent_InitiatingAadUserId = tostring(InitiatedBy.user.id)\n| extend Consent_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| join kind=inner ( \nAuditLogs\n| where TimeGenerated >= ago(auditLookbackEnd)\n| where OperationName =~ \"Add service principal credentials\"\n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend Credential_TargetKeyDescription = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"Included Updated Properties\"\n | extend UpdatedProperties = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Credential_TargetServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Credential_InitiatingAppName = tostring(InitiatedBy.app.displayName)\n| extend Credential_InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend Credential_InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| extend Credential_InitiatingAadUserId = tostring(InitiatedBy.user.id)\n| extend Credential_InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n) on targetResourceName, targetResourceID\n| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1\n| where TimeConsent < TimeCred \n| project TimeConsent, TimeCred, targetResourceName, targetResourceType, isAdminConsent, \nConsent_InitiatingUserOrApp, Consent_TargetServicePrincipalNames, Consent_TargetPermissions,\nConsent_InitiatingAppName, Consent_InitiatingAppServicePrincipalId, Consent_InitiatingUserPrincipalName, Consent_InitiatingAadUserId, Consent_InitiatingIpAddress,\nCredential_InitiatingUserOrApp, Credential_TargetServicePrincipalNames, Credential_TargetKeyDescription,\nCredential_InitiatingAppName, Credential_InitiatingAppServicePrincipalId, Credential_InitiatingUserPrincipalName, Credential_InitiatingAadUserId, Credential_InitiatingIpAddress\n| extend Consent_AccountName = tostring(split(Consent_InitiatingUserPrincipalName, \"@\")[0]), Consent_UPNSuffix = tostring(split(Consent_InitiatingUserPrincipalName, \"@\")[1])\n| extend Credential_AccountName = tostring(split(Credential_InitiatingUserPrincipalName, \"@\")[0]), Credential_UPNSuffix = tostring(split(Credential_InitiatingUserPrincipalName, \"@\")[1])\n",
"queryFrequency": "P1D",
"queryPeriod": "P2D",
"severity": "Medium",
"status": "Available",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"CredentialAccess",
"Persistence",
"PrivilegeEscalation"
],
"tags": [
"Solorigate",
"NOBELIUM"
],
"techniques": [
"T1098",
"T1555"
],
"templateVersion": "1.1.1",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}