-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.py
153 lines (133 loc) · 6.92 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from dotenv import load_dotenv
load_dotenv()
import aiohttp
import asyncio
import json
import os
import re
import shutil
from pathlib import Path
from azure.identity.aio import DefaultAzureCredential
from msgraph_beta import GraphServiceClient
from kiota_abstractions.base_request_configuration import RequestConfiguration
from kiota_http.middleware.options import ResponseHandlerOption
from kiota_abstractions.native_response_handler import NativeResponseHandler
from msgraph_beta.generated.device_management.configuration_settings.configuration_settings_request_builder import ConfigurationSettingsRequestBuilder
from msgraph_beta.generated.security.microsoft_graph_security_run_hunting_query.microsoft_graph_security_run_hunting_query_request_builder import MicrosoftGraphSecurityRunHuntingQueryRequestBuilder
from msgraph_beta.generated.security.microsoft_graph_security_run_hunting_query.run_hunting_query_post_request_body import RunHuntingQueryPostRequestBody
client = GraphServiceClient(DefaultAzureCredential(), ['https://graph.microsoft.com/.default'])
request_config = RequestConfiguration(
options=[ResponseHandlerOption(NativeResponseHandler())],
)
# id_10699 -> id
def cleanDCv1Ids(setting):
id = '_'.join(setting.get('id').split('_')[:-1])
setting['id'] = id
for child in setting.get('childSettings', []):
cleanDCv1Ids(child)
for option in setting.get('options', []):
for child in option.get('children', []):
cleanDCv1Ids(child)
for column in setting.get('columns', []):
if metadata := column.get('metadata'):
cleanDCv1Ids(metadata)
async def main():
# Setting status errors
async with aiohttp.ClientSession() as session, session.get('https://intune.microsoft.com/signin/idpRedirect.js') as resp:
versions = await resp.text()
versions = re.search(r'\"extensionsPageVersion\":({[^}]+})', versions).group(1)
versions = json.loads(versions)
root = 'https://afd-v2.hosting.portal.azure.net'
root_devicesettings = f'{root}/intunedevicesettings/Content/{versions.get('Microsoft_Intune_DeviceSettings')[0]}/Scripts/DeviceConfiguration'
# map setting error codes to descriptions
async with session.get(f'{root_devicesettings}/Blades/DevicePoliciesStatus/SettingStatus.js') as resp:
data = await resp.text()
data = re.search(r'SettingStatusErrorMap = ({[^}]+})', data).group(1)
data = json.loads(data, strict=False) # some strings have control characters
with open('SettingStatusErrors.json', 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
# DCv1 policies
output = 'DCv1'
shutil.rmtree(output)
for source in ['Configuration', 'Compliance']:
os.makedirs(Path(output, source))
async with session.get(f'{root_devicesettings}/Metadata/{source}Metadata.js') as resp:
data = await resp.text()
data = re.search(r'(?s)metadata = ({.+});', await resp.text()).group(1)
data = json.loads(data)
for family in data.values():
for setting in family:
# id_10699 -> id
id = '_'.join(setting.get('id').split('_')[:-1])
cleanDCv1Ids(setting)
path = Path(output, source, id).with_suffix('.json')
with open(path, 'w', encoding='utf-8') as f:
json.dump(setting, f, ensure_ascii=False, indent=4)
data = await client.service_principals.with_url('https://graph.microsoft.com/beta/servicePrincipals/appId=0000000a-0000-0000-c000-000000000000/endpoints').get(request_configuration=request_config)
value_array = data.json().get('value')
sorted_value_array = sorted(value_array, key=lambda x: x['capability'])
with open('Endpoints.json', 'w', encoding='utf-8') as f:
json.dump(sorted_value_array, f, ensure_ascii=False, indent=4)
# Service principals (Enterprise Apps)
if os.path.exists('ServicePrincipals'):
shutil.rmtree('ServicePrincipals')
os.makedirs('ServicePrincipals')
next = 'https://graph.microsoft.com/beta/servicePrincipals'
while next is not None:
data = await client.service_principals.with_url(next).get(request_configuration=request_config)
data = data.json()
for sp in data.get('value'):
app_id = sp.get('appId')
with open(f'ServicePrincipals/{app_id}.json', 'w', encoding='utf-8') as f:
json.dump(sp, f, ensure_ascii=False, indent=4)
next = data.get('@odata.nextLink')
for table in [
'AlertEvidence',
'AlertInfo',
'BehaviorEntities',
'BehaviorInfo',
'AADSignInEventsBeta',
'AADSpnSignInEventsBeta',
'CloudAppEvents',
'IdentityInfo',
'IdentityLogonEvents',
'EmailAttachmentInfo',
'EmailEvents',
'EmailPostDeliveryEvents',
'EmailUrlInfo',
'UrlClickEvents',
'ExposureGraphEdges',
'ExposureGraphNodes',
]:
data = await client.security.microsoft_graph_security_run_hunting_query.post(request_configuration=request_config, body=RunHuntingQueryPostRequestBody(
# match columns of 1P schema endpoint
query=f'{table} | getschema | project Description="", Type=split(DataType, ".")[1], Entity="", Name=ColumnName'
))
if data.json().get('results') is not None:
with open(f'Defender/{table}.json', 'w', encoding='utf-8') as f:
json.dump(data.json().get('results'), f, ensure_ascii=False, indent=4)
# DCv2 policies eg Settings Catalog
output = 'DCv2'
shutil.rmtree(output)
source = 'Settings'
os.makedirs(Path(output, source))
# kiota 1.9.1 started dropping deviceManagement from endpoint
data = await client.device_management.with_url('https://graph.microsoft.com/beta/deviceManagement/configurationSettings').get(request_configuration=request_config)
for item in data.json().get('value'):
item.pop('version')
item.pop('riskLevel', None)
path = Path(output, source, item.get('id')).with_suffix('.json')
with open(path, 'w', encoding='utf-8') as f:
json.dump(item, f, ensure_ascii=False, indent=4)
# backwards compat
shutil.rmtree('settings')
shutil.copytree(Path(output, source), 'settings')
source = 'Templates'
os.makedirs(Path(output, source))
# kiota 1.9.1 started dropping deviceManagement from endpoint
data = await client.device_management.with_url('https://graph.microsoft.com/beta/deviceManagement/configurationPolicyTemplates').get(request_configuration=request_config)
for item in data.json().get('value'):
path = Path(output, source, item.get('id')).with_suffix('.json')
with open(path, 'w', encoding='utf-8') as f:
json.dump(item, f, ensure_ascii=False, indent=4)
asyncio.run(main())