XFRM隐藏隧道

摘要 Linux 内核的 XFRM 框架负责 IPsec 变换,其中 ESP 的 BEET(Bound End-to-End Tunnel)模式在解密 IPsec 包后,会重构内部 IP 头。然而,在某些内核路径中,用于构造新 IP 头的 skb 区域未被完全初始化为零,导致内核堆中残留的指针或数据碎片被嵌入数据包并返回给远端用户。攻击者可从互联网发送特制的空载荷 ESP 包,在解密后的响应中泄露堆上的内核基址、堆地址甚至密钥材料,从而彻底击溃 KASLR 并为后续内核利用铺路。 BEET 模式 IPsec ESP 隧道 IPsec ESP 支持两种经典模式:传输模式仅加密传输层以上内容,保留原始 IP 头;隧道模式则加密整个原始 IP 数据包,并添加新的外部 IP 头。BEET 模式是两者的混合:它使用外部 IP 头进行路由,但内部 IP 头在解密后被重新计算,并以最小开销嵌入外部 IP 头之后。这种模式常用于移动 IPv6 和端到端加密场景。 其核心特性对比可以参考以下表: 维度 传输模式 隧道模式 BEET 模式 IP 标头数量 1 个(原始…

Swift 中的不可见角色

摘要 Swift 5.10 引入了严格并发检查,通过 @Sendable 闭包和 Actor 隔离在编译期防止数据竞争。然而,这些安全保证几乎完全依赖于编译器的静态分析,运行时缺乏强制机制。攻击者可利用 UnsafeMutablePointer 将非 Sendable 类型强制转换为 @Sendable 闭包,并将其跨 Actor 传递;在另一个 Actor 上通过 withUnsafeCurrentTask 执行任意代码,破坏原 Actor 的状态,实现数据竞争和类型混淆。更隐蔽的是,利用 TaskLocal 传递裸指针,或通过 GCD 直接调度绕过 @MainActor 隔离,可在服务器端 Swift 应用(如 Vapor)中实现持久化的隐蔽后门。 Sendable与 Actor 隔离 Sendable协议的类型安全承诺 Sendable 是 Swift 并发模型的核心协议之一,用于标记可以安全地跨并发域传递的类型。值类型(如 Int、String)、无内部共享状态的 final class 以及显式标记为 @Sendable 的闭包均符合 Sendable。编译器会检查所有跨 Actor 或 Task 传递的值的类型,如果非 Sendable 类型被错误传递,则发出严格并发检查的编译错误或警告。 在底层,@Sendable 闭包会被编译器转换为捕获不可变副本或同步原语保护的上下文,但这一转换完全发生在 SIL(Swift Intermediate Language)层,最终生成的 LLVM IR 中并没有额外的运行时检查。也就是说,一旦绕过编译器的静态检查,运行时将不加区别地执行任何闭包。 Actor 隔离的执行语义 Actor 是一种引用类型,通过串行执行队列保护其内部状态。所有对 Actor 可变状态的访问都必须通过 await 异步调用或在 Actor 内部的同步代码中进行。编译器负责保证这一约束:在 Actor 外部,无法直接访问其存储属性或调用未标记 nonisolated 的方法。 运行时实现上,Actor 携带一个内部的 DistributedActor 标识和串行执行器。当任务需要在 Actor 上执行时,会被调度到该执行器上排队。但 Actor 的执行器本身是可替换的,且 GCD 等旧并发 API 可以绕过这一调度机制,直接将任务提交到任意队列执行。这构成了 Actor…

Matter 智能家居的分布式信任崩溃

摘要 Matter 协议通过 Thread 网络实现低功耗智能家居设备的互联,其中 TREL(Thread Radio Encapsulation Link)作为桥接技术,将 Thread 的 IEEE 802.15.4 帧封装为 UDP 包在 Wi-Fi 骨干网上传输。然而,TREL 未强制端到端加密,仅依赖 PAN ID 进行网络隔离,这为跨媒介的信任边界崩溃埋下了伏笔。攻击者可在 Wi-Fi 段部署伪 TREL 端点,拦截并注入“Update Key”广播消息,使全网络设备切换到攻击者已知的密钥,从而静默接管智能门锁、安防传感器等关键设备。 Thread 与 TREL Matter 的分层架构与 Thread 的角色 Matter 是由 CSA(连接标准联盟)推出的统一智能家居应用层协议,工作在 IP 之上。 它依赖底层的网络传输协议,包括 Wi-Fi、Ethernet 以及 Thread。Thread 是一种基于 IEEE 802.15.4 的 IPv6 网状网络协议,专为低功耗、低带宽的 IoT 设备设计,支持自愈网状拓扑与休眠节点。在 Matter 架构中,Thread 通常负责连接门磁、运动传感器、智能门锁等电池供电设备,而 Wi-Fi 承载高带宽设备(如摄像头、语音助手)。…

SPI NOR 内存幽灵

摘要 SPI NOR Flash 作为嵌入式设备、物联网终端及安全芯片的关键非易失性存储介质,存储着固件、引导代码、密钥与证书等敏感信息。然而,其物理擦除机制与文件系统的逻辑删除之间存在根本性的鸿沟:逻辑删除仅清除索引,而实际数据仍残留在存储单元中,直到被显式擦除或覆写。更严峻的是,即使执行了整片擦除,攻击者仍可通过物理读出未分配块、提取磨损均衡映射表或利用电压毛刺使擦除命令提前终止,恢复出厂密钥与证书,甚至还原已删除的固件映像。 SPI NOR NOR Flash 的存储结构 SPI NOR Flash 内部存储阵列由扇区(Sector,通常 4KB)、块(Block,32KB/64KB)或整个芯片组成。NOR 支持随机读取,但写入前必须将目标区域擦除为全 0xFF。擦除操作以扇区或块为单位,通过特定的命令序列(如 Write Enable + Sector Erase)触发,由内部状态机执行,耗时数百毫秒至秒级。 擦除操作本质上是将浮栅上的电子移出,使存储单元回到初始状态。但擦除并非瞬时完成:在状态机执行期间,如果电源不稳定或收到非法命令,擦除可能被中断,导致部分区域未被完全擦除,原有数据仍有残留。 安全擦除的误区 许多安全应用信赖整片擦除(Bulk Erase)命令可以彻底清除所有数据。但实际上,Bulk Erase 的执行时间较长(典型值为数十秒),期间芯片可通过外部引脚(如 RESET# 或 CS#)被中断。 Command (C7h/60h) | v +—-+ CS# _____| |___________________________________________________/_______ <–>(1) <–>(3) t_CSS t_CSH +–+ +–+ +–+ +–+ +–+ SCK __| |__| |__| |__| |_. . .__|…

D-Bus 语义投毒

摘要 D-Bus 是 Linux 桌面环境的神经中枢,Flatpak 和 Snap 等沙箱方案依赖 D-Bus 代理过滤不受信任的调用。然而,xdg-dbus-proxy 的过滤规则存在一个语义漏洞:它根据消息头中的发送者唯一名称来放行回复,却没有验证该名称是否由可信的进程生成。攻击者可以从沙箱内部伪造一条回复消息,冒充系统守护进程(如 org.freedesktop.systemd1),绕过接口白名单,直接调用 systemd 的管理方法创建恶意服务单元,从而逃逸沙箱并以宿主机权限执行任意代码。 D-Bus 安全模型与过滤代理 D-Bus 消息结构与身份标识 D-Bus 通信基于消息总线,最常用的会话总线和系统总线分别处理用户会话和系统级服务。 每条消息包含固定的头部字段:消息类型(方法调用、方法返回、错误、信号)、路径、接口、成员以及若干可选字段,其中 SENDER 字段表示消息的发送者唯一名称(如 :1.42)。总线守护进程 dbus-daemon 在连接建立时为每个连接分配唯一的名称,并在后续消息中自动添加 SENDER 字段——如果消息本身没有提供,daemon 会设置它;但如果消息已经包含了 SENDER,daemon 的行为在不同版本中存在差异:旧版本 daemon 可能直接信任消息中已有的 SENDER 值,而非强制覆盖。 这构成了第一道裂缝:若攻击者能够直接与对端套接字通信并伪造 SENDER,总线守护进程不会拒绝,接收端将信任伪造的发送者身份。 Flatpak 沙箱 Flatpak 等沙箱技术通过 Bubblewrap 限制应用的文件系统和网络访问,并通过 D-Bus 代理 (xdg-dbus-proxy) 控制应用与 D-Bus 总线的交互。代理运行在沙箱外部,根据预定义或动态协商的过滤器规则,对来自沙箱内部的消息进行审查。规则通常基于: 接口和方法名:例如只允许 org.freedesktop.portal.* 接口的调用。 发送者:允许来自特定 D-Bus 名称的回复。 访问方向:允许接收某些信号,禁止发送某些调用。 当沙箱内的应用发送一条方法调用消息时,代理检查目标接口和方法是否在白名单中。对于信号的订阅,代理也进行过滤。但关键的安全漏洞在于:代理在处理回复(类型为 method_return 或 error)时,会检查该回复是否对应于之前从沙箱发出的某个调用。为了将此回复路由给正确的调用者,代理会查看回复消息中的 reply_serial 字段(匹配之前调用的序列号)。然而,代理假设只有合法的服务进程才会生成带有正确 reply_serial 和 SENDER 的回复——它并未验证该回复消息是否真的来自目标服务,也未强制要求回复消息中的 SENDER 必须与之前调用的 DESTINATION 匹配。 过滤机制的语义漏洞 攻击场景:沙箱内的恶意应用希望调用系统总线上的 org.freedesktop.systemd1.Manager.StartTransientUnit 方法来创建一个恶意服务单元,该方法在沙箱的过滤器白名单中显然不存在。但攻击者可以采用以下步骤绕过: 沙箱应用向系统总线发送一条伪造的方法调用,声称目的地是 org.freedesktop.systemd1,但实际上这条调用并不真正发送到 systemd,而是由攻击者自己在沙箱内部的另一个线程接收并处理。 攻击者构造一条伪造的回复消息,类型为 method_return,reply_serial 匹配之前那条调用的序列号,SENDER 字段设置为 :1.XXX(实际 systemd 拥有的唯一名称),但这条回复实际上是由沙箱内部的恶意线程生成并通过沙箱与代理之间的套接字发送给代理的。 代理收到这条“回复”后,根据 reply_serial 找到之前尚未完成的调用记录,认为这确实是 systemd 对该调用的回复,于是将其放行——因为代理默认放行已许可调用的回复。 攻击者在构造这条“回复”消息的同时,在消息体中嵌入了另一个新的方法调用:在 method_return 的回复体内部,可以放置一条任意的方法调用(这是…

AI 模型「溶枪」

摘要 开放神经网络交换格式(ONNX)通过 Protobuf 结构描述计算图,其灵活的自定义操作机制允许绑定任意外部动态库。这一设计便利了硬件厂商的算子优化,却也使得模型文件成为可注入恶意代码的“特洛伊木马”。攻击者可将后门逻辑伪装成合法的预处理或量化算子,在模型中嵌入定制的动态库加载指令。当模型被 ONNX Runtime 等服务加载时,隐藏的代码便会悄无声息地启动反向 Shell、窃取推理数据或篡改预测结果。由于计算图结构极其复杂,大多数静态扫描工具难以识别这类寄生在算子语义中的“溶枪式”后门。 ONNX 的自定义算子和外部数据信任链路 自定义算子的能力边界 ONNX 的自定义算子通过 op_type 和 domain 标识,由推理引擎注册的内核实现。ONNX Runtime 提供 RegisterCustomOp 接口,允许开发者动态添加算子,内核可以调用任意系统 API。这一能力原本是为硬件加速器(如 TPU)预留的,却也为攻击者打开了执行任意代码的通道。攻击者只需将恶意内核封装为动态库(libCustomOp.so),并在模型加载时通过配置文件或环境变量指定该库的路径,即可在推理进程上下文中执行任意操作。 更隐蔽的方式是,攻击者直接修改模型文件中的 external_data 字段,将恶意动态库打包为张量的“权重数据”。在 ONNX 规范中,大张量可通过 external_data 引用外部文件,但也可以将整个库嵌入模型内部。当模型首次推理时,自定义内核的初始化函数会解包该文件到临时目录并调用 dlopen,从而完成自我加载——整个过程无需用户额外配置任何库文件。 模型加载流程中的可注入点 ONNX Runtime 的模型加载流程主要包括:解析模型文件 → 构建计算图 → 注册内置和自定义算子 → 分配内存 → 执行图。 攻击者可劫持以下环节: 图构建阶段:通过修改 GraphProto 中的 node 条目,插入一个高优先级的自定义算子,声称用于“权重解密”或“校验和验证”。该算子会在模型加载后立即执行,先于正常推理。 算子注册阶段:若推理服务允许通过环境变量 ORT_CUSTOM_OP_LIBRARY 指定自定义库,攻击者可通过模型附带的启动脚本设置该变量,实现环境投毒。 外部数据解析阶段:利用 external_data 的 offset 和 length 字段,将一个看似正常的张量指向模型文件末尾的恶意 Shellcode,再由自定义算子读取并执行。 多阶段溶枪攻击链 环境准备与侦察 攻击者植入的第一个自定义算子名为 EnvProbe,域为 ai.utils。它在 ONNX 图中被标记为 Constant 节点的“消费者”,宣称负责“设备能力探测”。实际上,该算子执行以下操作: 检查当前进程权限和操作系统版本; 读取环境变量,确认是否在目标推理服务器上运行; 若判定为生产环境,则释放第二阶段载荷;否则保持静默。 这种选择性激活的策略有效规避了在开发或测试环境中被提前发现的风险。 动态库落地与持久化 EnvProbe 通过 external_data 获取一个压缩的共享库 libsyslog.so(伪装成日志库)。算子将其解压到 ~/.cache/ort_custom/libsyslog.so,并调用 dlopen 加载。该库的构造函数会: 修改 ~/.bashrc,追加一条自动拉取远程脚本的命令; 在 /etc/cron.d/ort_health 中写入一个每 10 分钟执行的定时任务,用于维持反向 Shell; 注册一个新的自定义算子 DataSink,用于后续数据窃取。 数据窃取与回传…