Launch Agent / 启动代理 (T1543.001)
一句话通俗理解
macOS 上让恶意程序在用户登录时自动启动的“开机自启“机制——本质是一个 plist 配置文件,告诉 launchd 在合适时机帮你把代码跑起来。
30秒速查卡
| 维度 | 你需要知道的 |
|---|---|
| 这是什么? | Launch Agent(T1543.001),创建或修改系统进程(T1543)的子技术,专指 macOS 上以用户身份运行的 LaunchAgent 持久化 |
| 为什么危险? | 用户登录即可自动拉起恶意进程,无需 root;plist 配置可触发 RunAtLoad(加载即运行)、KeepAlive(崩溃自动重启)、StartCalendarInterval(定时执行),兼具持久化与权限提升属性 |
| 谁需要关心? | macOS 终端管理员、企业 MDM 运维、SOC 分析师、红蓝队研究人员 |
| 你的第一步防御 | 监控 ~/Library/LaunchAgents/ 与 /Library/LaunchAgents/ 目录的 plist 写入,并审计 launchctl 命令执行 |
| 如果只做一件事 | 部署 KnockKnock 或 BlockBlock(Objective-See),对 LaunchAgent 新建事件实时告警 |
| 常见混淆点 | LaunchAgent(用户态,~/Library/LaunchAgents)≠ LaunchDaemon(系统态,/Library/LaunchDaemons,需 root);后者归 T1543.004 |
难度等级
⭐⭐ 中级 - 需要一定的技术基础和经验
前置知识检查
读这个文件需要什么?
- 操作系统权限模型基础(理解 user vs root)
- 创建或修改系统进程(T1543)的原理
- macOS 基础知识(launchd 守护进程、Property List 格式、
~/Library目录结构) - XML 基础语法(plist 文件格式)
技术描述
Launch Agent / 启动代理(T1543.001)是 创建或修改系统进程(T1543)的一个具体变体,属于 权限提升 与 持久化 阶段均会使用的攻击技术。MITRE ATT&CK 官方将其同时映射到 TA0004(权限提升)与 TA0003(持久化)两个战术。
macOS 通过 launchd 作为 1 号进程(PID 1)统一管理系统与服务。LaunchAgent 是 launchd 加载的一种特殊配置文件(Property List,扩展名 .plist),用于在特定条件下启动用户态进程。攻击者通过在受控位置写入恶意 plist,可让 launchd 在用户登录、系统启动或定时触发时自动拉起恶意可执行文件。
LaunchAgent 与 LaunchDaemon 的关键区别:
| 维度 | LaunchAgent (T1543.001) | LaunchDaemon (T1543.004) |
|---|---|---|
| 运行身份 | 当前登录用户 | root(系统级) |
| 加载时机 | 用户登录后 | 系统启动早期(用户登录前) |
| 用户级路径 | ~/Library/LaunchAgents/ | 无(仅系统级) |
| 系统级路径 | /Library/LaunchAgents/(影响所有用户) | /Library/LaunchDaemons/ |
| 系统原生路径 | /System/Library/LaunchAgents/(SIP 保护) | /System/Library/LaunchDaemons/(SIP 保护) |
| 写入权限要求 | 用户级只需普通用户权限;系统级需 root | 必须 root |
| GUI 访问 | 有(用户会话内) | 通常无(除非配置) |
具体怎么理解?
把 macOS 想象成一家公司,launchd 是总台调度员。LaunchAgent 是一张“委托单“放在总台的抽屉里,上面写着:“当 X 用户来上班时,自动帮我把这份工作跑起来。” 这张委托单放在用户的私人抽屉(~/Library/LaunchAgents/)只需要用户自己签字,不需要找总经理(root)。
plist 文件中的关键字段决定了“怎么跑“:
Label:唯一标识,反向域名格式(如com.evil.persist)ProgramArguments:要执行的可执行文件路径与参数数组RunAtLoad:true时加载即立即执行一次KeepAlive:true时进程退出会被自动重启;可配置为字典实现条件重启StartInterval:每隔 N 秒执行一次StartCalendarInterval:类 cron 的定时调度(指定时分秒日月周)WatchPaths/QueuedDirectories:监听指定路径变化触发执行
为什么有效?
- 机制原生可信:
launchd是 macOS 系统 1 号进程,安全工具默认不怀疑它派生子进程的行为 - 加载即执行:
RunAtLoad=true配合launchctl load可在写入瞬间触发执行,无需等待重启 - 持久稳定:
KeepAlive=true让恶意进程被 kill 后自动复活,蓝队难以彻底清除 - 权限门槛低:用户级 LaunchAgent 不需要 root,普通钓鱼落地后即可完成持久化
- 路径隐蔽:plist 是纯 XML 文本,可伪装成系统服务名(如
com.apple.update.plist),不仔细看难以发现 - 跨会话存活:每次用户登录都会触发,重启不影响持久化效果
真型场景
攻击者在 权限提升/持久化 阶段使用 Launch Agent 技术,以下是典型的攻击步骤:
graph TD
A["钓鱼投递 / 漏洞落地<br/>获得用户态执行权限"] --> B["写入恶意 plist<br/>到 ~/Library/LaunchAgents/"]
B --> C["launchctl load 加载<br/>或等待用户重新登录"]
C --> D["launchd 自动派生恶意进程<br/>以当前用户身份运行"]
D --> E["KeepAlive 保持常驻<br/>StartInterval 定时回调 C2"]
style A fill:#ff6b6b,stroke:#333,stroke-width:2px
style B fill:#ffa500,stroke:#333,stroke-width:2px
style C fill:#ffd700,stroke:#333,stroke-width:2px
style D fill:#ff6347,stroke:#333,stroke-width:2px
style E fill:#dc143c,stroke:#333,stroke-width:2px
步骤详解:
- 初始落地:攻击者通过钓鱼附件、漏洞利用或供应链投递获得目标 macOS 的用户态执行权限。此时进程仅在当前会话存活,重启即丢失。
- 写入 plist:在
~/Library/LaunchAgents/com.evil.persist.plist写入配置文件,ProgramArguments指向恶意可执行文件路径(通常藏在~/Library/Application Support/、/tmp/、~/.hidden/等隐蔽位置),并设置RunAtLoad=true、KeepAlive=true。 - 加载触发:调用
launchctl load ~/Library/LaunchAgents/com.evil.persist.plist主动加载,立即触发执行;或保持静默等待用户下次登录由 launchd 自动加载。 - 持续运行:launchd 派生子进程执行恶意代码,与 C2 服务器建立通信;进程被 kill 后由
KeepAlive自动拉起,登录会话切换或重启后仍能恢复。
攻击流程
1. 钓鱼落地获得普通用户权限
2. 构造 plist 配置文件(含恶意可执行路径)
3. 写入 ~/Library/LaunchAgents/com.evil.persist.plist
4. 调用 launchctl load 立即加载(或等待下次登录)
5. launchd 派生恶意进程并保持常驻
6. 通过 C2 通道持续接收指令
graph LR
A["构造 plist"] --> B["写入 LaunchAgents 目录"]
B --> C["launchctl load"]
C --> D["launchd 派生进程"]
D --> E["C2 通信"]
E -->|KeepAlive| D
style A fill:#ffa500,stroke:#333,stroke-width:2px
style B fill:#ff6b6b,stroke:#333,stroke-width:2px
style C fill:#ffd700,stroke:#333,stroke-width:2px
style D fill:#ff6347,stroke:#333,stroke-width:2px
style E fill:#dc143c,stroke:#333,stroke-width:2px
步骤详解:
-
构造 plist 文件
- 通俗描述:编写一个 XML 格式的配置文件,告诉 launchd 要运行什么、什么时候运行
- 技术细节:使用
Label(唯一标识)、ProgramArguments(执行命令数组)、RunAtLoad(加载即运行)、KeepAlive(保持常驻)等键 - 常用工具:直接
cat > file.plist写入;或用/usr/libexec/PlistBuddy命令式构造;也可用 Pythonplistlib模块生成
-
写入 LaunchAgents 目录
- 通俗描述:把 plist 文件放到 macOS 约定的“开机自启“目录
- 技术细节:用户级放
~/Library/LaunchAgents/(仅需普通用户权限);系统级放/Library/LaunchAgents/(需 root +sudo) - 常用工具:
mv、cp、curl远程下载、PlistBuddy
-
launchctl 加载
- 通俗描述:告诉 launchd “这张委托单生效了”
- 技术细节:旧语法
launchctl load -w ~/Library/LaunchAgents/com.evil.plist;macOS 10.10+ 新语法launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.evil.plist - 常用工具:
launchctl
-
launchd 派生进程并常驻
- 通俗描述:launchd 按照 plist 配置自动拉起恶意进程,被杀也会自动复活
- 技术细节:
RunAtLoad=true立即执行一次;KeepAlive=true进程退出后自动重启;StartInterval=N每 N 秒执行一次 - 常用工具:launchd 内置机制
实战 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>Label</key>
<string>com.apple.update.agent</string>
<key>ProgramArguments</key>
<array>
<string>/Users/victim/.hidden/updater</string>
<string>--silent</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StartInterval</key>
<integer>3600</integer>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
</dict>
</plist>
加载与卸载命令:
# 加载(旧语法,仍广泛兼容)
launchctl load -w ~/Library/LaunchAgents/com.apple.update.agent.plist
# 加载(新语法,macOS 10.10+)
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.apple.update.agent.plist
# 卸载
launchctl unload -w ~/Library/LaunchAgents/com.apple.update.agent.plist
launchctl bootout gui/$(id -u)/com.apple.update.agent
# 查看已加载的 LaunchAgent
launchctl list | grep -i update
真实案例
案例1:OceanLotus / APT32 macOS 后门
- 时间: 2017-2023 年(持续活跃)
- 目标: 东南亚国家政府机构、企业、异议人士的 macOS 设备
- 攻击组织: OceanLotus(APT32 / SeaLotus,越南背景)
- 手法: 通过伪装 Adobe Flash 更新包投递恶意
.app,安装后在~/Library/LaunchAgents/com.apple.google.plist创建持久化项,Label 伪装成 Google/Apple 系统服务,RunAtLoad=true+KeepAlive=true实现开机自启与自动重启。后门以当前用户身份运行,与 C2 通信执行命令、窃取文档。 - 影响: 长期静默潜伏(平均驻留 200+ 天),窃取大量内部文档与通信记录
- 参考链接:
案例2:DazzleSpy 水坑攻击
- 时间: 2021-2022 年
- 目标: 访问被劫持合法网站的香港/亚洲用户(macOS 用户)
- 攻击组织: DazzleSpy(疑似 APT41 关联组织)
- 手法: 水坑攻击注入 JavaScript 漏洞利用链,落地后写入
~/Library/LaunchAgents/com.apple.system.plist,调用launchctl load立即激活。Patrick Wardle 在《The Art of Mac Malware Vol 2》中详细分析了其 LaunchAgent 持久化机制:plist 中Program字段指向~/Library/Application Support/.local/agent,使用KeepAlive字典形式(SuccessfulExit=false)实现“非正常退出才重启“的精细化常驻。 - 影响: 完整后门功能——文件窃取、键盘记录、屏幕截图、命令执行
- 参考链接:
案例3:WindTail macOS 恶意软件
- 时间: 2018-2019 年
- 目标: 中东地区外交机构 macOS 用户
- 攻击组织: WindTail(疑似 APT 组织,未明确归因)
- 手法: 通过钓鱼邮件附件
Final_Presentation.app投递,启动后将自身复制到~/Library/.DS_Store.all(注意带点号的隐藏文件名伪装),并在~/Library/LaunchAgents/com.apple.FinderFix.plist创建 LaunchAgent。plist 中ProgramArguments指向隐藏可执行文件,RunAtLoad=true实现登录即触发。 - 影响: 窃取 Keychain 凭据、浏览器数据、文档,向 C2 持续外传
- 参考链接:
案例4:Silver Sparrow 神秘 macOS 恶意软件
- 时间: 2021 年 2 月发现
- 目标: 全球 macOS 用户(含 M1 芯片设备,首批原生 ARM64 macOS 恶意软件之一)
- 攻击组织: 未归因
- 手法: 使用
/usr/libexec/PlistBuddy命令行工具程序化构造 plist,写入~/Library/LaunchAgents/launch3.plist(命名刻意简单),RunAtLoad=true触发执行~/Library/.languageday隐藏二进制。Silver Sparrow 的特殊之处在于使用distribution.xml包裹的 Installer pkg,安装阶段即完成 LaunchAgent 部署,无需用户后续交互。 - 影响: 截至发现时未观察到实际 payload 执行(“无有效负载“特征),但已构建完整分发与持久化基础设施,被视为潜伏期威胁
- 参考链接:
案例5:XCSSET macOS 木马
- 时间: 2020-2021 年
- 目标: 通过恶意 Excel 宏文档感染 macOS 开发者
- 攻击组织: 未归因
- 手法: 利用 Excel for Mac 的宏功能执行 VBA 脚本,脚本枚举用户 Xcode 项目并植入恶意代码(开发者编译即传播)。持久化阶段在
~/Library/LaunchAgents/com.apple.xcsupd.plist创建 LaunchAgent,RunAtLoad=true自动拉起~/Library/Application Support/xcsupd/xcsupd。同时利用 Safari Cookie 注入、屏幕截图等组合技术。 - 影响: 感染开发者机器,污染下游编译产物(Xcode 供应链攻击变体),影响范围跨多个 Apple 平台
- 参考链接:
红队视角
⚠️ 免责声明:以下内容仅用于合法的安全测试、渗透测试和教育目的。未经授权对他人系统进行测试是违法行为。
实战技巧
- 深入理解原理:掌握 plist 各键的语义差异——
RunAtLoad是“加载即跑一次“,KeepAlive是“持续保持运行“,StartInterval是“定时跑“,组合使用可模拟多种持久化行为。KeepAlive还支持字典形式(SuccessfulExit、Crashed、OtherJobEnabled)实现精细控制。 - 环境适配:现代 macOS(10.10+)推荐使用
launchctl bootstrap gui/$(id -u) <plist>替代旧的launchctl load -w,避免触发部分 EDR 的旧命令特征规则。同时注意 macOS 13+ 对launchctl子命令的进一步收紧。 - 组合使用:LaunchAgent 可与 Login Items(T1547.013)、Launch Daemon(T1543.004)形成多层持久化——单点清除无法根除,蓝队需同时排查所有自启位置。结合 dylib 劫持(T1574.004)让“合法“系统进程加载恶意库可进一步降低特征。
- 隐蔽性考虑:Label 命名伪装成 Apple 系统服务(如
com.apple.update、com.apple.google、com.apple.FinderFix);可执行文件藏于~/Library/Application Support/、~/Library/Caches/、~/.hidden/等用户不易察觉的位置;plist 本身可放在子目录并设置StartCalendarInterval错峰运行,避免蓝队工作时间触发告警。
常用工具
| 工具名称 | 用途 | 平台 | 链接 |
|---|---|---|---|
launchctl | 系统原生,加载/卸载/查询 LaunchAgent | macOS 内置 | man launchctl |
PlistBuddy | 命令式构造/修改 plist(避免大段 XML) | macOS 内置(/usr/libexec/PlistBuddy) | man PlistBuddy |
Python plistlib | 程序化生成 plist,适合红队框架 | 跨平台 | Python Docs |
| Atomic Red Team T1543.001 | 标准化检测规则测试用例 | macOS | atomic-red-team |
| Empire / Mythic macOS agent | 红队 C2 框架,自带 LaunchAgent 持久化模块 | macOS | Empire |
注意事项
- 在授权的测试环境中使用这些技术,签署书面授权文件
- 注意操作安全(OPSEC):避免使用
RunAtLoad=true+ 立即launchctl load,该组合会在文件写入瞬间触发执行,是 EDR 的高优先级告警特征;可改用StartCalendarInterval延迟触发 - 使用匿名化技术和代理隐藏 C2 真实身份
- 测试结束后必须完整清理 plist 与可执行文件,避免残留被蓝队反向溯源
蓝队视角
检测要点
- 系统日志监控:通过 macOS Unified Log(
log show)+ Endpoint Security 框架采集launchd子进程派生事件;监控~/Library/LaunchAgents/、/Library/LaunchAgents/目录的write/rename/create文件系统事件。 - 异常行为检测:监控
launchctl load/launchctl bootstrap/launchctl enable命令执行;监控非交互式进程(如浏览器、邮件客户端、办公软件)派生launchctl子进程——这是落地即持久化的强信号。 - 工具特征识别:监控
PlistBuddy写入~/Library/LaunchAgents路径的事件(Silver Sparrow 模式);监控 plist 文件中RunAtLoad=true+KeepAlive=true组合;监控可执行文件路径位于/tmp/、/var/tmp/、~/Library/Application Support/.*/、~/.*/等隐蔽目录的 LaunchAgent。
监控建议
- 部署端点检测和响应(EDR)系统(推荐 CrowdStrike Falcon、SentinelOne、Microsoft Defender for Endpoint,均支持 macOS)
- 配置 SIEM 规则,关联分析来自多个来源的告警(文件系统写入 + 进程派生 + 网络外联)
- 定期进行安全评估和渗透测试(推荐使用 KnockKnock 每周扫描持久化点)
- 部署 Apple Endpoint Security 框架的自定义传感器(如 Google Santa、Elastic Endpoint Security)
避坑指南
红队新手常见错误:
-
plist XML 格式错误导致加载失败:plist 必须严格符合 Apple DTD 规范,缺一个
</dict>或大小写错误(如runatload应为RunAtLoad)都会导致launchctl load静默失败。对策:用plutil -lint file.plist校验后再加载。 -
Label与文件名不一致:Label字段必须与 plist 文件名(去.plist)完全一致,否则launchctl bootstrap会报Bootstrap failed: 125。对策:统一命名规范。 -
ProgramArguments用字符串而非数组:常见错误是直接写<string>/path/to/binary arg1 arg2</string>,正确写法是数组形式<array><string>/path/to/binary</string><string>arg1</string><string>arg2</string></array>。 -
可执行文件无执行权限或架构不匹配:Apple Silicon 设备需确保二进制为 Universal 2 或 ARM64;签名权限不足会被 Gatekeeper 拦截。对策:
chmod +x+codesign --sign - <binary>自签名。 -
忘记清理实验残留:测试环境遗留的 plist 在重启后仍会触发,污染后续实验。对策:每次实验结束执行
launchctl unload -w+ 删除 plist + 删除可执行文件三步清理。 -
误用
/System/Library/LaunchAgents/:该目录受 SIP(System Integrity Protection)保护,即使 root 也无法写入。对策:实验与攻击模拟均应使用~/Library/LaunchAgents/或/Library/LaunchAgents/。
检测建议
检测思路
检测 Launch Agent 的关键是识别 plist 文件的创建/修改 + launchctl 命令执行 + launchd 异常派生进程 三类事件的关联。以下是三个层面的检测方法:
网络层检测
方法:监控由 launchd 直接派生进程发起的出站连接(特别是非标准端口、低信誉 IP、近期注册域名),并关联回 plist 文件溯源。
# 使用 lsof 查看由 launchd 派生的进程的网络连接
sudo lsof -i -P -n | grep -E "launchd|launchctl"
# 使用 nettop 实时监控进程网络活动
nettop -p $(pgrep -f "com.evil" ) -J bytes_in,bytes_out
# 通过 Elastic Endpoint Security 等采集 launchd 子进程的网络外联事件
主机层检测
macOS Unified Log 事件:
process_hook事件:进程创建/退出(含父进程链)file_write事件:文件写入(含路径与进程)endpoint_security事件:Apple Endpoint Security 框架采集的高保真事件
auditd(OpenBSM Audit):
/var/audit/current中execve(2)系统调用记录open(2)写入~/Library/LaunchAgents/路径的事件
# 查看 launchctl 命令执行历史
log show --predicate 'process == "launchctl"' --last 24h
# 监控 LaunchAgents 目录的文件创建事件(实时)
log stream --predicate 'eventMessage CONTAINS "LaunchAgents"' --style compact
# 使用 fs_usage 实时监控 LaunchAgents 目录写入
sudo fs_usage -w -f filesys | grep -i "LaunchAgents"
# 列出当前用户已加载的所有 LaunchAgent
launchctl list | grep -v "com.apple"
# 查找所有第三方 LaunchAgent plist(排除 Apple 系统项)
find ~/Library/LaunchAgents /Library/LaunchAgents -name "*.plist" -exec plutil -p {} \; 2>/dev/null | grep -B1 "ProgramArguments"
用人话说:苹果自带的日志工具能看到 launchctl 被谁调用、写了哪个 plist、launchd 派生了什么进程;把这些事件关联起来就能识别“落地 → 写 plist → 加载 → 出网“的完整攻击链。重点盯三类信号:浏览器/Office 等非交互进程派生 launchctl、plist 中的可执行文件路径在临时或隐藏目录、Label 伪装成 com.apple.* 但位于用户目录。
title: macOS LaunchAgent 创建可疑持久化
status: experimental
description: 检测 ~/Library/LaunchAgents 或 /Library/LaunchAgents 目录中 plist 文件的创建/修改,关联 launchctl 加载行为
logsource:
category: file_event
product: macos
detection:
selection_path:
TargetFilename|contains:
- '/Library/LaunchAgents/'
selection_ext:
TargetFilename|endswith: '.plist'
filter_apple:
TargetFilename|contains: '/System/Library/LaunchAgents/'
condition: selection_path and selection_ext and not filter_apple
level: medium
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1543.001
应用层检测
Sigma 规则示例(增强版):
title: macOS LaunchAgent 持久化 — 可疑进程拉起 launchctl
id: 4d1c4c8c-7d8b-11ed-a1eb-0242ac120002
status: experimental
description: 非交互式进程(浏览器、Office、邮件客户端)派生 launchctl 子进程并加载 LaunchAgent plist,是落地即持久化的强信号
references:
- https://attack.mitre.org/techniques/T1543/001/
- https://taomm.org/vol2/pdfs/CH%205%20Persistence.pdf
author: SOC Team
date: 2026/07/27
logsource:
category: process_creation
product: macos
detection:
selection_parent:
ParentImage|endswith:
- '/Safari'
- '/Chrome'
- '/Firefox'
- '/Microsoft Word'
- '/Microsoft Excel'
- '/Mail'
- '/Outlook'
- '/Notes'
selection_child:
Image|endswith: '/launchctl'
CommandLine|contains:
- 'load'
- 'bootstrap'
- 'enable'
condition: selection_parent and selection_child
falsepositives:
- 极少见,浏览器/Office 通常不调用 launchctl
level: high
tags:
- attack.persistence
- attack.privilege_escalation
- attack.t1543.001
KnockKnock 持久化扫描示例:
# Objective-See KnockKnock 扫描所有持久化位置(含 LaunchAgent)
sudo /Applications/KnockKnock.app/Contents/MacOS/KnockKnock -scan -json > /tmp/knockknock_results.json
# 提取 LaunchAgent 项
cat /tmp/knockknock_results.json | jq '.[] | select(.category == "Launch Agents")'
缓解措施
优先级1:关键措施
限制 LaunchAgents 目录写入权限:通过 MDM 配置文件限制用户对 /Library/LaunchAgents/ 的写入权限;对 ~/Library/LaunchAgents/ 部署文件完整性监控(FIM)。
# 通过 MDM Profile 限制 /Library/LaunchAgents 写入(仅允许管理员)
sudo chmod 755 /Library/LaunchAgents
sudo chown root:admin /Library/LaunchAgents
# 部署 filebeat/fim 工具监控 ~/Library/LaunchAgents 变更
# 示例:使用 fswatch 持续监控
fswatch -0 ~/Library/LaunchAgents /Library/LaunchAgents | while read -d "" event; do
logger -t LAUNCHAGENT_WATCH "Change detected: $event"
done
部署 Apple Endpoint Security 框架的 EDR:现代 macOS EDR(Falcon、SentinelOne、Defender for Endpoint)基于 Endpoint Security API 实时采集进程派生、文件写入、launchctl 调用事件,是检测 LaunchAgent 滥用的最有效手段。
优先级2:重要措施
应用白名单(Santa / Gatekeeper):部署 Google Santa 或 Caesar Software Firewall 等白名单工具,仅允许签名可信的二进制执行——即使攻击者写入 plist,引用的恶意可执行文件也无法运行。
# Santa 配置示例:仅允许 Apple 签名与白名单二进制
sudo santactl rule --path /usr/bin/launchctl --allow
# 默认模式为 monitor,确认无误后切换至 lockdown
sudo defaults write com.google.santa batchSize -int 100
部署 KnockKnock + BlockBlock(Objective-See):KnockKnock 定期扫描所有持久化位置(LaunchAgent、LaunchDaemon、Login Items、Startup Items 等);BlockBlock 实时告警任何持久化点的创建/修改。
优先级3:建议措施
安全意识培训:教育员工识别钓鱼附件(特别是 .dmg、.pkg、.app 文件),不轻易安装来源不明的应用;启用 Gatekeeper “仅允许 App Store 与已识别开发者” 设置。
MDM 强制策略:通过 Jamf Pro / Kandji / Intune 等 MDM 推送以下策略:
- 禁用
~/Library/LaunchAgents/中非白名单 Label 的自动加载 - 强制 Gatekeeper 与 Notarization 检查
- 部署设备合规性检查,定期扫描持久化点
动手实验
⚠️ 所有实验必须在隔离的实验室环境中进行——建议使用 VMware Fusion / Parallels / UTM 隔离虚拟机,开启快照,实验后回滚。
实验1:理解基本原理(初级)
目标:理解 LaunchAgent 的 plist 格式与 launchctl 加载机制
步骤:
- 在隔离 macOS 虚拟机中创建
~/Library/LaunchAgents/com.test.hello.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>Label</key>
<string>com.test.hello</string>
<key>ProgramArguments</key>
<array>
<string>/bin/echo</string>
<string>LaunchAgent triggered at $(date)</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/hello.log</string>
</dict>
</plist>
- 验证 plist 语法:
plutil -lint ~/Library/LaunchAgents/com.test.hello.plist - 加载:
launchctl load ~/Library/LaunchAgents/com.test.hello.plist - 检查
/tmp/hello.log应有输出;用launchctl list | grep com.test.hello确认加载状态 - 卸载:
launchctl unload ~/Library/LaunchAgents/com.test.hello.plist,删除 plist
学习要点:掌握 plist 基本字段、RunAtLoad 触发机制、launchctl load/unload 命令
实验2:实际操作(中级)
目标:模拟恶意 LaunchAgent 持久化并分析检测特征
步骤:
- 编写一个简单 Python 反弹脚本
/tmp/test_agent.py(仅本机回环测试,不连外部)
#!/usr/bin/env python3
import time, os
while True:
with open('/tmp/agent_heartbeat.log', 'a') as f:
f.write(f"{time.strftime('%H:%M:%S')} alive pid={os.getpid()}\n")
time.sleep(10)
- 创建
~/Library/LaunchAgents/com.test.persist.plist,设置KeepAlive=true、StartInterval=10
<?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>Label</key>
<string>com.test.persist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>/tmp/test_agent.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
</dict>
</plist>
launchctl load加载,观察/tmp/agent_heartbeat.log持续写入- 尝试
kill -9 <pid>杀掉 Python 进程,观察 launchd 自动重启(KeepAlive 生效) - 用
log show --predicate 'process == "launchd"' --last 5m分析 launchd 日志 - 卸载并清理:
launchctl unload+ 删除 plist + 删除/tmp/test_agent.py+ 清空日志
学习要点:理解 KeepAlive 自动重启机制;学会通过 macOS Unified Log 分析 launchd 行为;体会“被 kill 后自动复活“的检测难点
实验3:防御验证(高级)
目标:验证检测规则的有效性
步骤:
- 部署 Sigma 规则(实验2中提到的两条)到 SIEM,或部署 BlockBlock 实时告警工具
- 执行实验2的攻击模拟
- 验证检测告警是否触发——重点检查:
- plist 文件写入事件是否被采集
launchctl load命令是否被记录- launchd 派生 Python 进程是否在进程树中可见
- 测试绕过:尝试用
PlistBuddy程序化构造 plist(而非直接写 XML),观察检测规则是否仍能触发 - 测试绕过:尝试用
launchctl bootstrap gui/$(id -u)新语法替代launchctl load,观察规则是否漏报
学习要点:理解攻防对抗的实际效果;学会从“绕过视角“反向优化检测规则;认识到单点检测(仅监控 launchctl load 命令)易被绕过,需多维度关联
术语解释
| 术语 | 通俗解释 |
|---|---|
| ATT&CK | MITRE 公司维护的攻击技术知识库 |
| Launch Agent | T1543.001,macOS 上以用户身份运行的 launchd 持久化项 |
| LaunchDaemon | T1543.004,macOS 上以 root 身份运行的系统级 launchd 持久化项 |
| launchd | macOS 的 1 号进程(PID 1),统一管理所有系统服务与持久化项 |
| plist | Property List,Apple 的 XML/二进制配置文件格式 |
| launchctl | 加载/卸载/查询 LaunchAgent 与 LaunchDaemon 的命令行工具 |
| PlistBuddy | Apple 内置的命令式 plist 编辑工具,常被攻击者用于程序化构造恶意 plist |
| SIP | System Integrity Protection,macOS 系统完整性保护,保护 /System/ 等目录 |
| Endpoint Security | Apple 提供的内核级安全事件采集框架,是现代 macOS EDR 的基础 |
| 创建或修改系统进程 | T1543,本子技术所属的父技术类别 |
| 权限提升 | 攻击链中的一个阶段,本技术同时也用于持久化(TA0003) |
| C2 | 命令与控制 |
| EDR | 端点检测与响应 |
被引用情况
以下父技术文档引用了本子技术:
参考资料
📚 官方文档(深入了解)
- MITRE ATT&CK - Launch Agent (T1543.001)
- MITRE ATT&CK - Create or Modify System Process (T1543)
- Apple Developer - Creating Launch Daemons and Agents
- Apple Developer - launchd.plist Manual
📰 安全报告(真实攻击)
- Patrick Wardle - The Art of Mac Malware Vol 2: Persistence
- Trend Micro - OceanLotus macOS Malware Updated
- ESET - DazzleSpy Analysis
- Patrick Wardle - WindTail Analysis (Objective-See)
- Red Canary - Silver Sparrow
- Trend Micro - XCSSET Mac Malware
🔧 工具与资源(动手试试)
- Atomic Red Team - T1543.001 - 标准化检测规则测试用例
- Objective-See KnockKnock - macOS 持久化点扫描
- Objective-See BlockBlock - 持久化实时告警
- Objective-See LuLu - macOS 防火墙
- Google Santa - 二进制白名单工具
- MITRE ATT&CK Navigator - ATT&CK 可视化工具