Skip to content

Instantly share code, notes, and snippets.

@HackingLZ
Created March 18, 2024 19:18
Show Gist options
  • Save HackingLZ/e8fa55053181ec1e56e7f01e2891a94a to your computer and use it in GitHub Desktop.
Save HackingLZ/e8fa55053181ec1e56e7f01e2891a94a to your computer and use it in GitHub Desktop.
Basic Azure Enum
import argparse
import random
import re
import requests
import string
import socket
import xml.etree.ElementTree as ET
def generate_random_username(min_length=7, max_length=16):
length = random.randint(min_length, max_length)
letters = string.ascii_letters + string.digits
return ''.join(random.choice(letters) for _ in range(length))
def get_federation_tenants(search_text):
search_term = re.sub("[^A-Za-z0-9@\. -]", '', search_text)
headers = {
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': 'http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation',
'User-Agent': 'AutodiscoverClient',
'Accept-Encoding': 'identity',
}
url = 'https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc'
domain = search_term
xml = f'''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:exm="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:ext="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<a:Action soap:mustUnderstand="1">http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation</a:Action>
<a:To soap:mustUnderstand="1">https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc</a:To>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</soap:Header>
<soap:Body>
<GetFederationInformationRequestMessage xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<Request>
<Domain>{domain}</Domain>
</Request>
</GetFederationInformationRequestMessage>
</soap:Body>
</soap:Envelope>'''
try:
response = requests.post(url, data=xml, headers=headers)
response.raise_for_status()
result = response.text
except requests.exceptions.RequestException as e:
print(f"Error getting federation tenants: {e}")
return []
pattern = "<Domain>(.*?)</Domain>"
matches = re.findall(pattern, result)
return matches
def query_user_realm(tenant):
fakeuser = generate_random_username()
url = f"https://login.microsoftonline.com/getuserrealm.srf?login={fakeuser}@{tenant}&xml=1"
try:
response = requests.get(url, timeout=20)
if response.status_code == 400:
return 'Error', 'Domain does not exist'
response.raise_for_status()
root = ET.fromstring(response.text)
namespace_type = root.find('.//NameSpaceType').text if root.find('.//NameSpaceType') is not None else 'Unknown'
if namespace_type.lower() == 'federated':
sts_auth_url = root.find('.//STSAuthURL').text if root.find('.//STSAuthURL') is not None else 'No STSAuthURL found'
return namespace_type, sts_auth_url
elif namespace_type.lower() == 'managed':
return namespace_type, 'Managed'
else:
return namespace_type, 'Unknown namespace type'
except requests.exceptions.RequestException as e:
print(f"Error querying user realm: {e}")
return 'Error', 'Could not query user realm'
def get_tenant_guid(tenant_domain):
url = f"https://login.microsoftonline.com/{tenant_domain}/v2.0/.well-known/openid-configuration"
try:
response = requests.get(url, timeout=20)
if response.status_code == 400:
return 'Error querying tenant guid: Domain does not exist'
response.raise_for_status()
data = response.json()
token_endpoint = data.get('token_endpoint', '')
match = re.search(r'/([0-9a-fA-F-]+)(?:/oauth2/v2.0/token)?$', token_endpoint)
guid = match.group(1) if match else 'GUID not found'
return guid
except requests.exceptions.RequestException as e:
print(f"Error querying tenant guid: {e}")
return 'Error querying tenant guid'
def extract_tenant(domain):
pattern = r'(\w+)\.onmicrosoft\.com'
match = re.match(pattern, domain)
return match.group(1) if match else None
def get_http_code(url):
try:
response = requests.get(url, timeout=20)
return response.status_code
except requests.exceptions.RequestException as e:
print(f"Error getting status code: {e}")
return None
def check_service_availability(tenant, service):
domain = f"{tenant}.{service}"
try:
socket.gethostbyname(domain)
return domain, "Available"
except socket.gaierror:
return domain, "Not Available"
def check_modern_auth(domain):
url = f"https://{domain}"
status_code = get_http_code(url)
if status_code == 401:
return "Enabled"
elif status_code == 403:
return "Not Enabled"
else:
return "Status Unknown"
def domain_hit(domain):
print(f"\nChecking domain: {domain}")
namespace_type, sts_auth_url_or_message = query_user_realm(domain)
if sts_auth_url_or_message == 'Domain does not exist':
print("Domain does not exist.")
return
print(f"Namespace Type: {namespace_type}, STS Auth URL/Message: {sts_auth_url_or_message}")
tenant_guid = get_tenant_guid(domain)
if 'Domain does not exist' in tenant_guid:
print("Domain does not exist.")
return
print(f"Tenant GUID: {tenant_guid}")
tenants = get_federation_tenants(domain)
print("Federation tenants:", tenants)
results = {
'OriginalDomain': {
'NamespaceType': namespace_type,
'STSAuthURL/Message': sts_auth_url_or_message,
'TenantGUID': tenant_guid,
},
'Tenants': {}
}
for tenant_domain in tenants:
tenant = extract_tenant(tenant_domain)
if tenant:
print(f"\nExtracted tenant: {tenant}")
onedrive_status = check_service_availability(tenant, "my.sharepoint.com")
sharepoint_status = check_service_availability(tenant, "sharepoint.com")
atp_status = check_service_availability(tenant, "atp.azure.com")
modern_auth_status = check_modern_auth(sharepoint_status[0])
results['Tenants'][tenant] = {
'OneDrive': onedrive_status,
'SharePoint': sharepoint_status,
'ATP': atp_status,
'ModernAuth': modern_auth_status
}
print("\nResults:")
for key, value in results.items():
if key == 'OriginalDomain':
print("Original Domain Checks:")
for subkey, subvalue in value.items():
print(f" {subkey}: {subvalue}")
else:
print("Tenant Checks:")
for tenant, services in value.items():
print(f"\n Tenant: {tenant}")
for service, status in services.items():
print(f" {service}: {status}")
parser = argparse.ArgumentParser(description='Check domain information.')
parser.add_argument('domain', help='Domain to check, e.g., domain.com')
args = parser.parse_args()
if __name__ == "__main__":
domain_hit(args.domain)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment