See my previous post for more information. Despite managing to type the following:
When (if) I’m done, I’ll write a new post about it.
The TL;DR is simply this: I borrowed some code from two projects and splyced them together, so that I can push threat intelligence from MISP to Microsoft Sentinel. My version simply allows you to push to multiple Azure tenants with guidance included.
For those of you who are unaware of what MISP is, it’s short for Malware Information Sharing Platform. It’s an open source threat intelligence platform used among other things to share indicators of compromise.
For more information, please visit their website.
An Indicator of compromise, or IOC for short, is a forensic artifact, observed on the network or host. An IOC indicates - with some level of confidence - a computer or network intrusion has occurred. IOCs are observable, which links them directly to measurable events. Some IOC examples include:
For more information on IOCs, please check out Indicator of compromise (IoC) overview from Microsoft Learn.
The two github projects I’ve used as a base for this update are the following:
They are both based on the original sample MISP to Microsoft Graph Security Script presented in the Integrating open source threat feeds with MISP and Sentinel techcommunity blog post from 2020.
graph LR
subgraph "Azure tenant x"
subgraph "Virtual Machine"
MF[MISP feed]
M[MISP server]
S[Script]
MF -->|Indicators| M
M -->|Pull indicators| S
end
MS[Microsoft Sentinel]
S -.->|Push| MS
subgraph "Azure AD"
APP[App registration]
end
G[Graph API]
S --> APP
APP --> G
G --> MS
end
If you wanted to push indicators from a single MISP-server to a single Microsoft Sentinel instance, you could run the script locally (and there’s even great guidance from the MISP project on how to accomplish this).
This however does not scale very well without modifications, and it feels a bit dated to push data from a virtual machine directly to Sentinel. It’s easier to integrate error handling, logging and alerts if we use Azure Functions to run the script instead.
The solution already exists - sort of. The project from zolderio already solves putting the misp2sentinel script into an Azure Function. That is already taken care of. It also covers the multi-sentinel part, but only for a single Azure tenant (as of writing this). It’s also not up to date with the latest developments going on in the cudeso/misp2sentinel repository, which has been pushed by the MISP-project as it’s updating the original script to account for the lastest MISP changes, and soon to allow for the use of the new Upload Indicators API
instead of the Graph Security API
.
Isn’t very different from the solution from zolderio presented - it’s a multi-sentinel version of the script, but updated with the cudeso code. I’ve also updated the guidance so that one might be able to push to multiple Azure tenants instead of just one.
graph LR
subgraph "Azure tenant x"
AZF[Azure Function]
subgraph "Virtual Machine"
MF[MISP feed]
M[MISP server]
MF -->|Indicators| M
end
M -->|Pull indicators| AZF
MS[Microsoft Sentinel]
AZF -.->|Push| MS
subgraph "Azure AD"
APP[App registration]
end
G[Graph API]
AZF --> APP
APP --> G
G --> MS
end
subgraph "Azure tenant n"
subgraph "Azure AD"
EAPP[Enterprise application]
end
APP --> |Admin consent| EAPP
EAPP --> GAPI[Graph API]
GAPI --> MS2[Microsoft Sentinel]
end
AZF -.-> |Push| MS2
Keep in mind, the logical diagrams might not correctly display what is going on, but the idea here is that we can create a multi-tenant app registration and use the enterprise application (once admin consent has been given) to push to multiple Azure tenants.
mispkey
and mispurl
to the environment settings of the script, allowing them to be set through the Azure Function configuration.
config.py
file using the os library.INSTALL.MD
with guidance for these changes.INSTALL.MD
with guidance for multi-tenant setup.README.MD
with the short-form guidance of the above changes.requirements.txt
to account for new dependencies and running in Azure Functions.Create a new Azure VM called MISP running Ubuntu LTS 20.04:
misp
. wget --no-cache -O /tmp/INSTALL.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.sh
We can now log in to the MISP server using default credentials.
Go to the Feeds
tab.
Enable the two default feeds.
We should be able to see events being pulled from the feeds now if we head over to the Administration
tab and select Jobs
.
URL
(this will be the Azure public IP address of the VM in the format of https://<ip address>/
)API key
(this was in the output when the install finished, but we can also add a new one by going to Administration
and selecting Add authentication key
.)Create a new App Registration in Azure AD called MISP2Sentinel
using all default settings.
Under API permissions, choose Add a permission and select Microsoft Graph.
Select Application Permissions.
Add ThreatIndicators.ReadWrite.OwnedBy
.
We then need to grant admin consent for the permissions by clicking on Grant admin consent for <tenant>
. Click yes when prompted.
Make sure the API permissions are granted correctly:
Application (client) ID
Directory (tenant) ID
Client secret
MISP2Sentinel-kv
using all default settings.mispkey
mispurl
tenants
tenants
secret is a JSON object containing the tenant ID, client id and secret of each tenant you want to push TI to:
{"<TENANT_ID>": {"id": "<APP_ID>", "secret": "<APP_SECRET>"}}
Make sure the ThreatIntelligence data connector is enabled.
MISP2Sentinel
After the creation of the Azure Function, add a system managed identity to the Azure Function. This will be used to authenticate with the Key Vault.
tenants
@Microsoft.KeyVault(SecretUri=https://<keyvaultname>.vault.azure.net/secrets/tenants/)
mispkey
@Microsoft.KeyVault(SecretUri=https://<keyvaultname>.vault.azure.net/secrets/mispkey/)
mispurl
https://<url>
or https://<ip address>
)timerTriggerSchedule
timerTriggerSchedule
takes a cron expression. For more information, see Timer trigger for Azure Functions.0 */2 * * *
AzureFunctionsJobHost__functionTimeout
00:10:00
if using the consumption plan, or 02:00:00
if using premium or dedicated plans. This setting is required to prevent the function from timing out when processing large amounts of data.This is how the application settings should look like (I like to start of with a low frequency on the timer trigger to make sure everything is working as expected):
config.py
. This will mainly consist of updating the filter and lifetime of the IOCs.
Azure Function
and select Deploy to Function App…The MISP2Sentinel
function should also show up under the Function App.
Add a redirect URI to the app registration we created earlier, like https://portal.azure.com
To make the app registration work in the other tenants you will need to grant admin consent to the enterprise app in each tenant. This can be done by navigating to the following URL:
https://login.microsoftonline.com/common/adminconsent?client_id=<APP_ID>&sso_reload=true
If done correctly, you should see the following page:
tenants
secret in the Key Vault to include the new tenant ID. The client ID and secret should remain the same.Click on Logs to see the output of the function live, or check the Invocations to see the execution history.
tenants
secretYou can also check the ThreatIntelligenceIndicator
table in the Log Analytics workspace to see the indicators that have been pushed to Sentinel.
This is a temporary update to the misp2sentinel project to allow it to run multi-tenant and in an Azure Function, deployed directly from the repository.
With the new Upload Indicators API being released and the work being done to port the current project to the new API, this update will be deprecated soon.
Once the project is up and running on the new API I will update this repository to reflect the changes and transfer this code to the new API to the best of my limited abilities.
If you spot any errors or bugs in this code, please let me know.
Happy hunting!