Skip to content

Commit

Permalink
Merge pull request #1207 from jahamilto/azure
Browse files Browse the repository at this point in the history
Azure Token Revoker Responder
  • Loading branch information
nusantara-self authored Oct 18, 2024
2 parents 8401628 + 4cb6312 commit 724f997
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 45 deletions.
12 changes: 6 additions & 6 deletions responders/AzureTokenRevoker/AzureTokenRevoker.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"name": "AzureTokenRevoker",
"version": "1.0",
"author": "Daniel Weiner @dmweiner",
"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 Azure authentication session tokens for a list of User Principal Names",
"dataTypeList": ["thehive:case"],
"command": "AzureTokenRevoker.py",
"dataTypeList": ["thehive:case_artifact"],
"command": "AzureTokenRevoker/AzureTokenRevoker.py",
"baseConfig": "AzureTokenRevoker",
"configurationItems": [
{"name": "redirect_uri",
"description": "Azure AD Application URI (Example: https://login.microsoftonline.com/TENANTIDHERE/oauth2/token)",
{"name": "tenant_id",
"description": "Azure Directory/Tenant ID",
"type": "string",
"multi": false,
"required": true
Expand Down
83 changes: 44 additions & 39 deletions responders/AzureTokenRevoker/AzureTokenRevoker.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# encoding: utf-8
# Author: Daniel Weiner @dmweiner
# Author: Daniel Weiner @dmweiner, revised by @jahamilto
import requests
import traceback
import datetime
Expand All @@ -10,55 +10,60 @@
class AzureTokenRevoker(Responder):
def __init__(self):
Responder.__init__(self)
self.client_id = self.get_params('config.client_id', None, 'Azure AD Application ID/Client ID Missing')
self.client_secret = self.get_params('config.client_secret', None, 'Azure AD Registered Application Client Secret Missing')
self.redirect_uri = self.get_params('config.redirect_uri', None, 'Set a redirect URI in Azure AD Registered Application. (ex. https://logon.microsoftonline.<tenant id>/oauth2/token)')
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):
try:
self.user = self.get_params('data.data', None, 'No UPN supplied to revoke credentials for')
if not self.user:
self.error("No user supplied")
base_resource = "https://graph.microsoft.com"
Responder.run(self)

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'
}
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

token_r = requests.post(self.redirect_uri, data=token_data)
token = token_r.json().get('access_token')
#Authenticate to the graph api

if token_r.status_code != 200:
self.error('Failure to obtain azure access token: {}'.format(token_r.content))
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')

# Set headers for future requests
headers = {
'Authorization': 'Bearer {}'.format(token)
}
if token_r.status_code != 200:
self.error('Failure to obtain azure access token: {}'.format(token_r.content))

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

r = requests.post(base_url + 'users/{}/revokeSignInSessions'.format(self.user), headers=headers)
# 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))
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()

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)
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__':
Expand Down
37 changes: 37 additions & 0 deletions responders/AzureTokenRevoker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Azure 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.

### Config

To enable the responder, you need three values:
1. Azure 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.

## Setup

### Prereqs
User account with the Cloud Application Administrator role.
User account with the Global Administrator Role (most of the steps can be done with only the Cloud App Administrator role, but the final authorization for its API permissions requires GA).

### Steps

#### Creation
1. Navigate to the [Azure Portal](https://portal.azure.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.

#### Secret
4. Navigate to Certificates and Secrets.
5. Create a new client secret. Enter a relevant description and set a security-conscious expiration date.
6. Copy the Value. **This will only be fully visible for a short time, so you should immediately copy it and store it in a safe place**.

#### API Permissions
7. Navigate to API permissions.
8. Add the Directory.ReadWrite.All and User.ReadWrite.All permissions (Microsoft Graph API, application permissions).
9. Using a GA account, select the "Grant admin consent for *TENANTNAME*" button.

10. Place the relevant values into the config within Cortex.

0 comments on commit 724f997

Please sign in to comment.