多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

iMessage恶意附件捕获实录:从“干净”样本到后门与辅助模块

iMessage恶意附件捕获实录:从“干净”样本到后门与辅助模块 做安全分析这么多年有一个感受越来越深真正难的不是漏洞利用本身而是当恶意样本被伪装成一颗“无害的糖”送到你面前时你有没有能力把它从海量的正常流量里捞出来。三角测量系列我们已经复盘到第7篇了前几篇一直在讲漏洞利用链和WebKit漏洞的细节这次换个角度重点聊一聊这个过程中最有“临场感”的部分——一个iMessage消息附件后门连同它的辅助模块样本到底是怎么被我们捕捉到的。这篇内容适合三类人一是正在做移动端恶意样本分析的同行二是负责威胁狩猎、想搭建移动端样本捕获链路的安全工程师三是对APT攻击链感兴趣、但一直搞不清“样本从哪来”的研究者。我不会把重点放在某个具体CVE的利用代码上而是把完整捕获思路、工具选择、分析手法和踩坑过程拆开讲。你会发现所谓“捕捉”从来不是靠某一个神奇工具而是一整套“线索—捕获—关联—溯源”的闭环。1. 第一条线索一个哈希陌生、行为却异常“干净”的附件1.1 从威胁情报队列入手的可疑样本我们捕获这批样本的起点其实不是设备告警而是一条威胁情报。某个平台上突然出现了一条新的IOC记录文件名叫Invoice_2024_06.pkpass哈希值完全陌生VT上的检测结果只有零星两三个引擎报风险大部分引擎都判定为“未发现恶意”。这里就有一个典型误区很多人看到低检测率就觉得没问题但做过恶意样本分析的人都知道越是针对特定目标的样本在VT上曝光率越低。真正让我警觉的是这个文件的类型——pkpass是Apple Wallet的票据格式而当时我们监控的几台测试iPhone上确实收到了类似的iMessage消息推送。也就是说这个文件和实际攻击时间线存在微妙的重合。1.2 为什么iMessage附件是攻击者的首选投递通道简单说三个原因信任链、零点击潜力、落盘隐蔽。信任链iMessage消息自带Apple生态的“可信”光环用户收到好友发来的附件点开概率远高于邮件附件。零点击潜力在三角测量这类攻击链中发送方可以在消息中加入特制附件部分漏洞利用甚至不需要用户点击只要收到消息就会触发解析逻辑。落盘隐蔽附件会被自动存储在~/Library/SMS/Attachments目录中用户几乎不会主动去翻而且文件名经过系统重排取证时第一步很难定位。所以当我们把视线从“检测哈希”转向“攻击链出发机理”之后思路就变了与其守株待兔等杀毒引擎报毒不如主动部署一套面向iMessage消息链路的捕获机制。1.3 把“干净”文件重新解读为“伪装干净”最初拿到那个pkpass文件时我们做了基础的file命令检查结果很“正常”Zip archive内含pass.json和一些图片资源。但当我们用二进制查看器打开后发现pass.json的末尾有一段很长的Base64字符串而且这块数据明显不是Wallet标准字段。这就是我要强调的一个理念恶意样本分析中“干净”不是一个结论而是一个问号。你发现了一个不合常理的干净文件恰恰说明它可能在刻意模仿正常格式。后面的事实也证明这段Base64字符串里藏着一个自解压的Mach-O载荷——它会在PassKit框架解析票据时被释放到临时目录。提示遇到pkpass、ics、vcf这些iMessage常见附件类型不要只看扩展名和文件头。用binwalk扫一遍再检查pass.json里是否存在超出标准字段的键值对。标准库里没有的字段往往就是开门的钥匙。2. 样本捕捉链路测试机、MDM日志与流量镜像的配合2.1 捕获架构不是抓网络流量而是抓设备行为移动端样本捕获和在PC端用蜜罐不一样。iOS的推送和附件下载都走Apple推送服务流量是加密的而且证书固定想在网络层做中间人解密很容易触发设备安全机制。我们试过在网关层直接镜像流量最终发现问题不在“拿不到流量”而在“流量无法和具体设备行为对应起来”——你看到一条TLS记录但不知道它对应哪个进程、哪个文件操作。后来我们把捕获架构反过来设计放弃在流量层做全量解密转而在一台专门准备的测试iPhone上做行为监控。通过MDM描述文件把设备的sysdiagnose日志、崩溃日志、进程列表以及com.apple.madridiMessage服务的消息处理日志实时回传到我们自己的日志服务器。这样从消息到达设备的那一刻起每个系统动作都会有记录。这套架构很像是“在门口装摄像头而不是在锁孔里装窃听器”。我们确实丢失了一部分细粒度网络报文但换来了更干净、更完整的系统行为链。2.2 触发路径还原从推送通知到附件落盘在测试机上一条恶意iMessage消息的处理流程大致是消息先进入SpringBoard的推送处理进程然后转交给IMTransferAgent处理附件下载附件会先落盘到临时目录再根据文件类型决定由哪个解析器打开。我们在监控里最关注的也是这条链路上的三个节点消息到达后IMTransferAgent是否创建了新的临时文件附件在Attachments目录里的最终扩展名是否被重写有没有非系统进程在附件落盘后的几百毫秒内启动了新进程或访问了PassKit相关服务。实际捕获到的那个样本在IMTransferAgent落盘后差不多400毫秒一个名为/private/var/tmp/.itmd的进程就被拉起来了。这个时间窗口非常关键——如果只监控进程创建而不监控文件访问很容易漏掉这种瞬时启动的载荷。2.3 动态监控沙箱与隔离网络的配置细节动态分析iOS恶意样本很多人习惯找现成沙箱但市面上的公开沙箱对iMessage攻击链的支持都比较有限原因很简单它们不会模拟Apple推送链路。我们最后采用的是“真实设备网络隔离”的方案。网络隔离的配置细节值得展开说一下。我们在测试iPhone上安装了一个自签的MDM描述文件把Wi-Fi的HTTP代理指向一台本地代理服务器同时用pf规则限制了设备对外的TCP连接只允许访问我们伪造的C2域名通过绑定hosts实现。这样一来恶意样本即使尝试外联通信也会落在我们的代理层里我们可以记录请求头、TLS指纹、DNS解析并且通过代理返回伪造的C2响应观察样本的下一步动作。注意这一步的前提是先把设备的自动时区、自动锁屏、iCloud同步全部关掉避免设备在分析中途“自己找活干”影响日志纯净度。我们吃过一次亏设备自动同步了iCloud备份结果日志里多出一大堆与样本无关的进程活动排查时浪费了半天。3. 辅助模块样本先于后门一步现身的“配角”3.1 辅助模块在攻击链里的位置载荷投递前的开锁工具很多分析报告会把注意力全放在后门主样本上但其实在三角测量这类攻击链里辅助模块往往更早出现也更容易被忽略。辅助模块在攻击链里扮演的角色通常是“开锁工具”——它负责处理漏洞利用阶段的内存布局、绕过沙箱、加载主后门的核心逻辑。我们捕获到的辅助模块是一个动态库文件名是libExtension.dylib大小只有200多KB。它被释放到/private/var/tmp目录后会先从自身数据段里解密出一份包含多个内存地址偏移的配置文件然后根据当前设备型号和系统版本选择对应的偏移量来修改运行时数据结构。这里有一个很值得玩味的细节辅助模块本身不含网络通信代码它所有的数据传递都通过共享内存和主后门进程对接。也就是说即使你把这个辅助模块单独拿出来分析网络层也看不到任何异常——这又是“干净”伪装策略的一个变体。3.2 样本关联的实用手法模糊哈希与样本方差阈值辅助模块样本往往不是一个版本而是一个“家族”。攻击者会根据不同iOS版本编译出多个变体但这些变体的代码骨架基本相同只有偏移量配置不同。这时候怎么从一堆样本里快速找出“近亲”就很重要了。我们用的是两层判断。第一层用ssdeep做模糊哈希比对找出相似度在60%以上的样本簇第二层对每个样本簇提取指令序列特征例如特定函数序言的字节频率计算它们在向量空间里的距离这个概念有点像统计里的样本方差——样本方差小说明这些样本的指令分布高度集中基本可以断定来自同一个编译流程样本方差大的簇则要怀疑是否存在多个攻击者共用同一套代码框架。实际效果很理想。我们当天抓到的5个辅助模块变体全部被聚到同一个簇里最小的ssdeep相似度也有72%。这为我们后续在更大范围的历史流量里回溯同族样本提供了依据。3.3 解密与脱壳静态特征让位给行为特征辅助模块做了一层轻量级加壳传统方式是用dyld注入或frida在运行时dump内存。不过在样本捕获初期我们通常不会急着上Frida——因为Frida本身会改变进程运行环境部分恶意代码会检测frida-server进程名或者DYLD_INSERT_LIBRARIES环境变量。所以我们的流程是先静态分析字符串和符号把壳的入口函数标记出来然后通过log stream监控设备日志看辅助模块在加载时访问了哪些路径、读取了哪些系统服务最后才决定是否上动态调试。有一次我们试图用调试器附加辅助模块进程结果进程直接退出设备上弹出一个异常崩溃日志。崩溃的原因不是我们暴露了而是模块设置了“被调试即自杀”的保护逻辑。后来我们改用lldb的process launch方式启动进程配合DYLD_PRELOAD注入一个空操作库绕过了一部分反调试检查。实操心得移动端样本分析不要一上来就追求“脱壳拿完整二进制”。很多时候行为特征比静态特征更早给出结论——它访问了哪个路径、加载了哪个系统框架、修改了哪个文件权限这些信息足够我们判断样本用途脱壳只是锦上添花。4. 后门本体的关键动作分析4.1 Mach-O结构检查与签名伪装辅助模块确认之后我们就有了明确的目标在内存中寻找真正的主后门。通过监控辅助模块启动后创建的子进程我们在它的task_for_pid调用后面找到了一个从共享内存映射出来的Mach-O镜像。这个后门本体有几个结构特征非常典型。首先是LC_CODE_SIGNATURE段是存在的但签名者信息被替换成了一个非Apple的普通开发者ID。这在攻击链里很常见——签名不是为了通过系统校验而是为了在文件落地时躲过一部分基于签名者信誉的扫描引擎。其次是__TEXT段的段权限是r-x符合常规可执行文件特征但它的入口地址被修改过指向的不是第一个函数而是位于__DATA段的一个跳转表。这意味着静态反汇编的前几十条指令都是“诱饵”真正的逻辑在运行时才被覆盖进内存。4.2 内存中的第二阶段载荷我们在后门进程的堆内存里发现了一个用AES-CBC加密的第二阶段载荷解密密钥由设备本身的硬件标识衍生而来。换句话说这个载荷是“绑定设备”的换一台设备就无法解密。这种设计给大家伙提了个醒分析这类样本不能只在文件系统层面找证据。必须把内存镜像完整地保存下来否则核心载荷会随着进程退出而消失。我们的做法是在确认样本启动后立即用memory_status工具抓取进程的完整内存区域再做离线分析。期间要特别小心不要触发任何可能让进程主动退出的信号——样本里存在针对SIGTERM和SIGINT的自毁逻辑。4.3 命令回传与模块化更新机制后门与C2之间的通信并不复杂但很隐蔽。它没有使用固定端口而是通过HTTPS模拟正常的apple.com流量请求路径也伪装成了/v1/config这种看似合法的接口。真正让它在流量层隐身的原因是它使用了CGFont相关的系统API来做数据编码——也就是说网络请求里夹带的不是明文的指令而是一段被编码成“字体轮廓数据”的二进制流。我们当时在代理层看到这条流量时第一反应是设备在更新字体直到后门主动向C2请求了一个辅助模块更新包我们才意识到这其实就是命令通道。这个发现也解释了为什么早期流量特征规则很难命中这类样本它没有明显的恶意UA也没有可疑的URL路径只是把一个系统API用在了非预期的场景里。从后门的更新机制来看它支持三种指令更新主模块、下发新辅助模块、自毁清除。这种模块化设计使得攻击者可以在不重投递消息的情况下持续调整植入体的能力——你捕获到的某个样本可能只是整个攻击链里的“一小块零件”。5. 从单样本到家族回溯式排查的完整链路5.1 YARA规则与历史样本回扫拿到一个样本之后最想做的事情就是往前追溯它在更早的时间点有没有出现过我们基于已有样本提取了三条YARA特征后门内存载荷中固定的AES密钥派生函数字节序列辅助模块里那段用于计算内核偏移的常量数组头部伪造C2请求中特有的“字体轮廓数据”编码函数入口特征。用这三条规则在内部样本库和历史流量抓包记录里回扫我们找到了一个三个月前的样本——因为当时它的检测率也是零所以一直被归在“未知文件”类别里吃灰。这一次回扫直接把这个未知文件提升为“确认恶意”整个时间线往前推了三个月。5.2 时间线重构先有辅助模块还是先有后门同一个攻击波次里辅助模块和后门的投放顺序并不总是固定的。我们通过分析设备日志发现在最早的一个案例里辅助模块比后门早到了约6天。这说明攻击者可能先把辅助模块作为“预植入探针”部署到目标设备上观察设备环境是否适合后续利用再选择合适的时机下发主后门。时间线重构的价值在于它能帮助我们理解攻击者的决策逻辑而不是只盯着最终的恶意载荷。如果你在某台设备上只找到了后门没有找到辅助模块那么合理的推断是这台设备可能是后补的目标或者是攻击者通过其他路径例如本地提权工具直接部署的而不是通过iMessage附件投递的。5.3 失陷判断清单与取证要点在实际排查中我们往往会遇到“样本还没抓到但设备行为有点怪”的场景。这时候以下取证要点可以帮大家快速判断是否存在同类攻击检查~/Library/SMS/Attachments目录下是否存在异常扩展名的文件尤其是pkpass、ics、vcf改名为jpg或png的情况查询IMTransferAgent日志看是否有短时间内大量下载附件的记录查看崩溃报告中是否频繁出现PassKit框架或WebKit框架的崩溃崩溃栈中是否有非系统库的帧用log show过滤com.apple.madrid进程检查是否存在异常的消息发送者ID。这套清单不保证能发现所有变种但至少能在没有完整样本的情况下为后续调查提供一个相对明确的起点。6. 实际操作中的坑与经验6.1 最容易被忽略的扩展属性我第一次接触这类样本时犯过一个低级错误只看了文件的内容却没有查看文件系统的扩展属性。后来才知道攻击者会把一部分信息隐藏在com.apple.metadata:kMDItemWhereFroms这个扩展属性里用来记录消息发送者的原始地址和消息到达时间。对于取证来说这个扩展属性价值极高你不仅能确认投递路径还能把多个攻击波次关联起来。所以强烈建议在分析任何iMessage附件时第一步先用xattr -l查看文件的全部扩展属性再做内容分析。6.2 警惕“测试机上的偶然成功”我们在多台不同型号的测试设备上运行同一个样本结果并不是每次都触发成功。有一台旧设备运行时没有弹出任何异常进程后来排查发现是系统版本过低样本在判断系统版本时主动选择了“不执行”。这种“偶然成功”很容易误导分析方向让人误以为当前环境下的某个动作是攻击触发点。解决方法是保持测试设备的环境可控且统一固定iOS版本、固定MDM描述文件配置、记录每次运行的前置状态。凡是结果不一致的情况优先检查环境差异而不是怀疑分析工具出了问题。6.3 日志与样本的“时间戳证据链”最后分享一个我们内部一直在用的土办法。捕捉样本时我们会同时记录设备日志、代理日志和样本访问行为的三个时间轴设备日志时间轴用系统时间代理日志时间轴用UTC样本访问行为时间轴用文件时间戳。三条时间轴对齐之后用“秒”做粒度画一条横向对比图就能清晰看出哪个进程先启动、哪个网络请求先发出、哪个文件先落盘。这个方法我们用了很多年几乎所有攻击链的触发顺序问题最后都能靠它给出靠谱的答案。写在最后。三角测量的样本捕获工作说到底拼的不是“运气”而是耐心先怀疑每一个过于干净的附件再用一套可靠的环境去验证自己的判断最后靠关联分析把孤立的样本拼回完整的攻击链。如果你也在做类似的移动端恶意样本分析希望这篇复盘能给你一些可以落地的新思路。下一次当你发现某个样本异常干净时别急着放它走——先问一句这份干净是不是对方刻意做给你看的
返回列表