Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename & rework existing Azure AD analyzer & responder for Entra ID name change #1285

Merged
merged 6 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
{
"name": "GetAzureSignIns",
"name": "GetEntraIDSignIns",
"version": "1.0",
"author": "@jahamilto",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "AGPL-V3",
"description": "Pull all Azure sign ins for a user within the specified amount of time.",
"description": "Pull all Microsoft Entra ID sign ins for a user within the specified amount of time.",
"dataTypeList": ["mail"],
"command": "GetAzureSignIns/GetAzureSignIns.py",
"baseConfig": "GetAzureSignIns",
"command": "GetEntraIDSignIns/GetEntraIDSignIns.py",
"baseConfig": "GetEntraIDSignIns",
"configurationItems": [
{"name": "tenant_id",
"description": "Azure Directory/Tenant ID",
"description": "Microsoft Entra ID Tenant ID",
"type": "string",
"multi": false,
"required": true
},
{"name": "client_id",
"description": "Client ID/Application ID of Azure AD Registered App",
"description": "Client ID/Application ID of Microsoft Entra ID Registered App",
"type": "string",
"multi": false,
"required": true
},
{"name": "client_secret",
"description": "Secret for Azure AD Registered Application",
"description": "Secret for Microsoft Entra ID Registered Application",
"type": "string",
"multi": false,
"required": true
Expand Down Expand Up @@ -53,7 +53,9 @@
"multi": false,
"required": false
}

]

],
"registration_required": true,
"subscription_required": true,
"free_subscription": false,
"service_homepage": "https://www.microsoft.com/security/business/identity-access/microsoft-entra-id"
}
30 changes: 16 additions & 14 deletions analyzers/GetAzureSignIns/GetAzureSignIns.py → ...rs/GetEntraIDSignIns/GetEntraIDSignIns.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
from cortexutils.analyzer import Analyzer

# Initialize Azure Class
class GetAzureSignIns(Analyzer):
class GetEntraIDSignIns(Analyzer):
def __init__(self):
Analyzer.__init__(self)
self.client_id = self.get_param('config.client_id', None, 'Azure AD Application ID/Client ID Missing')
self.client_secret = self.get_param('config.client_secret', None, 'Azure AD Registered Application Client Secret Missing')
self.tenant_id = self.get_param('config.tenant_id', None, 'Azure AD Tenant ID Mising')
self.client_id = self.get_param('config.client_id', None, 'Microsoft Entra ID Application ID/Client ID Missing')
self.client_secret = self.get_param('config.client_secret', None, 'Microsoft Entra ID Registered Application Client Secret Missing')
self.tenant_id = self.get_param('config.tenant_id', None, 'Microsoft Entra ID Tenant ID Mising')
self.time_range = self.get_param('config.lookup_range', 7)
self.lookup_limit = self.get_param('config.lookup_limit', 12)
self.state = self.get_param('config.state', None)
Expand Down Expand Up @@ -142,19 +142,21 @@ def run(self):
def summary(self, raw):
taxonomies = []

if len(raw['signIns']) == 0:
taxonomies.append(self.build_taxonomy('info', 'AzureSignins', 'SignIns', 'None'))
if len(raw.get('signIns', [])) == 0:
taxonomies.append(self.build_taxonomy('info', 'EntraIDSignins', 'SignIns', 'None'))
else:
taxonomies.append(self.build_taxonomy('safe', 'AzureSignins', 'Count', len(raw['signIns'])))
taxonomies.append(self.build_taxonomy('safe', 'EntraIDSignins', 'Count', len(raw['signIns'])))

# If the summary stats are present, then add them. If not, don't.
stats = raw["sum_stats"]
if stats["riskySignIns"] != 0: taxonomies.append(self.build_taxonomy('suspicious', 'AzureSignins', 'Risky', stats[0]))
if stats["externalStateSignIns"] != 0: taxonomies.append(self.build_taxonomy('suspicious', 'AzureSignins', 'OutOfState', stats[1]))
if stats["foreignSignIns"] != 0: taxonomies.append(self.build_taxonomy('malicious', 'AzureSignins', 'ForeignSignIns', stats[2]))

stats = raw.get("sum_stats", {})
if stats.get("riskySignIns", 0) != 0:
taxonomies.append(self.build_taxonomy('suspicious', 'EntraIDSignins', 'Risky', stats["riskySignIns"]))
if stats.get("externalStateSignIns", 0) != 0:
taxonomies.append(self.build_taxonomy('suspicious', 'EntraIDSignins', 'OutOfState', stats["externalStateSignIns"]))
if stats.get("foreignSignIns", 0) != 0:
taxonomies.append(self.build_taxonomy('malicious', 'EntraIDSignins', 'ForeignSignIns', stats["foreignSignIns"]))

return {'taxonomies': taxonomies}


if __name__ == '__main__':
GetAzureSignIns().run()
GetEntraIDSignIns().run()
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## Azure Sign In Retreiver
## Microsoft Entra ID Sign In Retriever

This responder allows you to revoke the session tokens for an Azure AD user. Requires the UPN of the account in question, which should be entered as a "mail" oberservable in TheHive.
This responder allows you to revoke the session tokens for an Microsoft Entra ID user. Requires the UPN of the account in question, which should be entered as a "mail" oberservable in TheHive.

### Config

To enable the responder, you *need* three values:
1. Azure Tenant ID
1. Microsoft Entra ID Tenant ID
2. Application ID
3. Application Secret

The first two values can be found at any time in the application's Overview page in the Azure portal. The secret must be generated and then stored in a safe place, as it is only fully visible when you first make it.
The first two values can be found at any time in the application's Overview page in the Microsoft Entra ID portal. The secret must be generated and then stored in a safe place, as it is only fully visible when you first make it.

You can also specify the limits for how far back the analyzer requests sign ins. You can specify time and count for how many sign ins get returned.

Expand All @@ -24,7 +24,7 @@ User account with the Global Administrator Role (most of the steps can be done w
### Steps

#### Creation
1. Navigate to the [Azure Portal](https://portal.azure.com) and sign in with the relevant administrator account.
1. Navigate to the [Microsoft Entra ID Portal](https://entra.microsoft.com/) and sign in with the relevant administrator account.
2. Navigate to App Registrations, and create a new registration.
3. Provide a display name (this can be anything, and can be changed later). Click Register.

Expand All @@ -46,4 +46,4 @@ It is possible to add a color coding system to the long report as viewed from Th

### Example

Let's say you are in an organization where almost all of your users will be signing in from a single state. You could color code the table so that out-of-state sign ins are highlighted yellow, and out-of-country sign ins are highlighted in red. To enable customization like this, you must modify this analyzer's long.html to check for values within the full JSON report using the ng-style tag in the *table body > table row* element. An example exists as a comment in the long.html file at line 34.
Let's say you are in an organization where almost all of your users will be signing in from a single state. You could color code the table so that out-of-state sign ins are highlighted yellow, and out-of-country sign ins are highlighted in red. To enable customization like this, you must modify this analyzer's long.html to check for values within the full JSON report using the ng-style tag in the *table body > table row* element. An example exists as a comment in the long.html file at line 34.
32 changes: 0 additions & 32 deletions responders/AzureTokenRevoker/AzureTokenRevoker.json

This file was deleted.

35 changes: 35 additions & 0 deletions responders/EntraIDTokenRevoker/EntraIDTokenRevoker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "EntraIDTokenRevoker",
"version": "1.1",
"author": "Daniel Weiner @dmweiner, revised by @jahamilto",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "AGPL-V3",
"description": "Revoke all Microsoft Entra ID authentication session tokens for a User Principal Name.",
"dataTypeList": ["thehive:case_artifact"],
"command": "EntraIDTokenRevoker/EntraIDTokenRevoker.py",
"baseConfig": "EntraIDTokenRevoker",
"configurationItems": [
{"name": "tenant_id",
"description": "Microsoft Entra ID Tenant ID",
"type": "string",
"multi": false,
"required": true
},
{"name": "client_id",
"description": "Client ID/Application ID of Microsoft Entra ID Registered App",
"type": "string",
"multi": false,
"required": true
},
{"name": "client_secret",
"description": "Secret for Microsoft Entra ID Registered Application",
"type": "string",
"multi": false,
"required": true
}
],
"registration_required": true,
"subscription_required": true,
"free_subscription": false,
"service_homepage": "https://www.microsoft.com/security/business/identity-access/microsoft-entra-id"
}
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
#!/usr/bin/env python3
# encoding: utf-8
# Author: Daniel Weiner @dmweiner, revised by @jahamilto
import requests
import traceback
import datetime
from cortexutils.responder import Responder
# Initialize Azure Class
class AzureTokenRevoker(Responder):
def __init__(self):
Responder.__init__(self)
self.client_id = self.get_param('config.client_id', None, 'Azure AD Application ID/Client ID Missing')
self.client_secret = self.get_param('config.client_secret', None, 'Azure AD Registered Application Client Secret Missing')
self.tenant_id = self.get_param('config.tenant_id', None, 'Azure AD Tenant ID Mising')
self.time = ''
def run(self):
Responder.run(self)
if self.get_param('data.dataType') == 'mail':
try:
self.user = self.get_param('data.data', None, 'No UPN supplied to revoke credentials for')
if not self.user:
self.error("No user supplied")
token_data = {
"grant_type": "client_credentials",
'client_id': self.client_id,
'client_secret': self.client_secret,
'resource': 'https://graph.microsoft.com',
'scope': 'https://graph.microsoft.com'
}
#Authenticate to the graph api
redirect_uri = "https://login.microsoftonline.com/{}/oauth2/token".format(self.tenant_id)
token_r = requests.post(redirect_uri, data=token_data)
token = token_r.json().get('access_token')
if token_r.status_code != 200:
self.error('Failure to obtain azure access token: {}'.format(token_r.content))
# Set headers for future requests
headers = {
'Authorization': 'Bearer {}'.format(token)
}
base_url = 'https://graph.microsoft.com/v1.0/'
r = requests.post(base_url + 'users/{}/revokeSignInSessions'.format(self.user), headers=headers)
if r.status_code != 200:
self.error('Failure to revoke access tokens of user {}: {}'.format(self.user, r.content))
else:
#record time of successful auth token revokation
self.time = datetime.datetime.utcnow()
except Exception as ex:
self.error(traceback.format_exc())
# Build report to return to Cortex
full_report = {"message": "User {} authentication tokens successfully revoked at {}".format(self.user, self.time)}
self.report(full_report)
else:
self.error('Incorrect dataType. "mail" expected.')
if __name__ == '__main__':
AzureTokenRevoker().run()
#!/usr/bin/env python3
# encoding: utf-8
# Author: Daniel Weiner @dmweiner, revised by @jahamilto
import requests
import traceback
import datetime
from cortexutils.responder import Responder

# Initialize Azure Class
class EntraIDTokenRevoker(Responder):
def __init__(self):
Responder.__init__(self)
self.client_id = self.get_param('config.client_id', None, 'Microsoft Entra ID Application ID/Client ID Missing')
self.client_secret = self.get_param('config.client_secret', None, 'Microsoft Entra ID Registered Application Client Secret Missing')
self.tenant_id = self.get_param('config.tenant_id', None, 'Microsoft Entra ID Tenant ID Mising')
self.time = ''
def run(self):
Responder.run(self)

if self.get_param('data.dataType') == 'mail':
try:
self.user = self.get_param('data.data', None, 'No UPN supplied to revoke credentials for')
if not self.user:
self.error("No user supplied")

token_data = {
"grant_type": "client_credentials",
'client_id': self.client_id,
'client_secret': self.client_secret,
'resource': 'https://graph.microsoft.com',
'scope': 'https://graph.microsoft.com'
}


#Authenticate to the graph api

redirect_uri = "https://login.microsoftonline.com/{}/oauth2/token".format(self.tenant_id)
token_r = requests.post(redirect_uri, data=token_data)
token = token_r.json().get('access_token')

if token_r.status_code != 200:
self.error('Failure to obtain azure access token: {}'.format(token_r.content))

# Set headers for future requests
headers = {
'Authorization': 'Bearer {}'.format(token)
}

base_url = 'https://graph.microsoft.com/v1.0/'

r = requests.post(base_url + 'users/{}/revokeSignInSessions'.format(self.user), headers=headers)

if r.status_code != 200:
self.error('Failure to revoke access tokens of user {}: {}'.format(self.user, r.content))

else:
#record time of successful auth token revokation
self.time = datetime.datetime.utcnow()

except Exception as ex:
self.error(traceback.format_exc())
# Build report to return to Cortex
full_report = {"message": "User {} authentication tokens successfully revoked at {}".format(self.user, self.time)}
self.report(full_report)
else:
self.error('Incorrect dataType. "mail" expected.')


if __name__ == '__main__':
EntraIDTokenRevoker().run()
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## Azure Sign In Token Revoker Responder
## Microsoft Entra ID Sign In Token Revoker Responder

This responder allows you to revoke the session tokens for an Azure AD user. Requires the UPN of the account in question, which should be entered as a "mail" oberservable in TheHive.
This responder allows you to revoke the session tokens for an Microsoft Entra ID user. Requires the UPN of the account in question, which should be entered as a "mail" observable in TheHive.

### Config

To enable the responder, you need three values:
1. Azure Tenant ID
1. Microsoft Entra ID Tenant ID
2. Application ID
3. Application Secret

The first two values can be found at any time in the application's Overview page in the Azure portal. The secret must be generated and then stored in a safe place, as it is only fully visible when you first make it.
The first two values can be found at any time in the application's Overview page in the Microsoft Entra ID portal. The secret must be generated and then stored in a safe place, as it is only fully visible when you first make it.

## Setup

Expand All @@ -20,7 +20,7 @@ User account with the Global Administrator Role (most of the steps can be done w
### Steps

#### Creation
1. Navigate to the [Azure Portal](https://portal.azure.com) and sign in with the relevant administrator account.
1. Navigate to the [Microsoft Entra ID Portal](https://entra.microsoft.com/) and sign in with the relevant administrator account.
2. Navigate to App Registrations, and create a new registration.
3. Provide a display name (this can be anything, and can be changed later). Click Register.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="panel panel-success" ng-if="success && content.signIns.length == 0">
<div class="panel-heading">
Azure Sign Ins
Microsoft Entra ID Sign Ins
</div>

<div class="panel-body">
Expand All @@ -10,7 +10,7 @@

<div class="panel panel-primary" ng-if="success && content.signIns.length > 0">
<div class="panel-heading">
Azure Sign Ins
Microsoft Entra ID Sign Ins
</div>

<div class="panel-body">
Expand Down