Linux ELF 恶意软件分析 是做什么的?
使用场景
- Linux 服务器或容器被入侵,发现可疑的 ELF 二进制文件
- 分析 Linux 僵尸网络(Mirai、Gafgyt、XorDDoS)、挖矿病毒或勒索软件
- 调查针对云基础设施、Docker 容器或 Kubernetes Pod 的恶意软件
- 逆向工程 Linux Rootkit 和内核模块
- 分析为 Linux x86_64、ARM 或 MIPS 架构编译的跨平台恶意软件
禁止用于 Windows PE 二进制分析;Windows 恶意软件请使用 PEStudio、Ghidra 或 IDA。
先决条件
- 支持 Linux ELF 格式的 Ghidra 或 IDA,用于反汇编和反编译
- Linux 分析虚拟机(推荐 Ubuntu 22.04)并安装开发工具
- strace、ltrace 和 GDB,用于动态分析和调试
- GNU binutils 中的 readelf、objdump 和 nm,用于静态检查
- Radare2,用于快速二进制分类和脚本化分析
- Docker,用于基于容器的隔离恶意代码执行
工作流程
步骤 1:识别 ELF 二进制属性
检查 ELF 头部和基本属性:
# 文件类型识别
file suspect_binary
# 详细 ELF 头部分析
readelf -h suspect_binary
# 节区头部
readelf -S suspect_binary
# 程序头部(段)
readelf -l suspect_binary
# 符号表(若未被剥离)
readelf -s suspect_binary
nm suspect_binary 2>/dev/null
# 动态链接信息
readelf -d suspect_binary
ldd suspect_binary 2>/dev/null # 仅在匹配的架构上执行!
# 计算哈希值
md5sum suspect_binary
sha256sum suspect_binary
# 检查是否存在加壳/UPX
upx -t suspect_binary
# 基于 Python 的 ELF 分析
from elftools.elf.elffile import ELFFile
import hashlib
with open("suspect_binary", "rb") as f:
data = f.read()
sha256 = hashlib.sha256(data).hexdigest()
with open("suspect_binary", "rb") as f:
elf = ELFFile(f)
print(f"SHA-256: {sha256}")
print(f"类别: {elf.elfclass}-位")
print(f"字节序: {'小端序' if elf.little_endian else '大端序'}")
print(f"机器架构: {elf.header.e_machine}")
print(f"类型: {elf.header.e_type}")
print(f"入口点: 0x{elf.header.e_entry:X}")
# 检查是否被剥离
symtab = elf.get_section_by_name('.symtab')
print(f"已剥离: {'是' if symtab is None else '否'}")
# 节区熵分析
import math
from collections import Counter
for section in elf.iter_sections():
data = section.data()
if len(data) > 0:
entropy = -sum((c/len(data)) * math.log2(c/len(data))
for c in Counter(data).values() if c > 0)
if entropy > 7.0:
print(f" [!] 高熵节区: {section.name} (熵值: {entropy:.2f})")
步骤 2:提取字符串和指标
搜索嵌入式 IOC 和功能性线索:
# ASCII 字符串
strings suspect_binary > strings_output.txt
# 搜索网络指标
grep -iE "(http|https|ftp)://" strings_output.txt
grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_output.txt
grep -iE "[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn)" strings_output.txt
# 搜索 shell 命令
grep -iE "(bash|sh|wget|curl|chmod|/tmp/|/dev/)" strings_output.txt
# 搜索加密货币挖矿指标
grep -iE "(stratum|xmr|monero|pool\.|mining)" strings_output.txt
# 搜索 SSH/凭据窃取
grep -iE "(ssh|authorized_keys|id_rsa|shadow|passwd)" strings_output.txt
# 搜索持久化机制
grep -iE "(crontab|systemd|init\.d|rc\.local|ld\.so\.preload)" strings_output.txt
# 使用 FLOSS 提取混淆字符串(如果可用)
floss suspect_binary
步骤 3:分析系统调用和库使用情况
识别恶意软件使用的系统调用和库:
# 列出导入的函数(动态链接)
readelf -r suspect_binary | grep -E "socket|connect|exec|fork|open|write|bind|listen"
# 执行期间跟踪系统调用(仅在隔离 VM 中)
strace -f -e trace=network,process,file -o strace_output.txt ./suspect_binary
# 跟踪库调用
ltrace -f -o ltrace_output.txt ./suspect_binary
# 需要关注的关键系统调用:
# 网络: socket, connect, bind, listen, accept, sendto, recvfrom
# 进程: fork, execve, clone, kill, ptrace
# 文件: open, read, write, unlink, rename, chmod
# 持久化: inotify_add_watch(文件监控)
步骤 4:使用 GDB 进行动态分析
调试恶意软件以观察运行时行为:
# 启动 GDB 并加载二进制文件
gdb ./suspect_binary
# 在关键函数上设置断点
(gdb) break main
(gdb) break socket
(gdb) break connect
(gdb) break execve
(gdb) break fork
# 运行并分析
(gdb) run
(gdb) info registers # 查看寄存器状态
(gdb) x/20s $rdi # 检查字符串参数
(gdb) bt # 回溯调用栈
(gdb) continue
# 对于已剥离的二进制文件,在入口点设置断点
(gdb) break *0x400580 # 从 readelf 获取的入口点
(gdb) run
# 执行期间监控网络连接
# 在另一个终端中:
ss -tlnp # 列出监听中的套接字
ss -tnp # 列出已建立的连接
步骤 5:使用 Ghidra 进行逆向工程
对 ELF 二进制文件执行深度代码分析:
针对 Linux ELF 的 Ghidra 分析:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 导入:文件 -> 导入 -> 选择 ELF 二进制文件
- Ghidra 自动检测 ELF 格式和架构
- 接受默认分析选项
2. 关键分析目标:
- main() 函数(如果被剥离则使用入口点)
- 套接字创建和连接函数
- 命令调度逻辑(基于接收数据的 switch/case)
- 加密/编码例程
- 持久化安装代码
- 自我传播/扫描函数
3. 对于 Mirai 类僵尸网络,关注:
- 暴力破解凭据列表(telnet/SSH)
- 攻击模块选择(UDP 洪水、SYN 洪水、ACK 洪水)
- 扫描器模块(对脆弱设备进行端口扫描)
- 杀手模块(杀死竞争僵尸网络)
4. 对于挖矿病毒,关注:
- 矿池连接(stratum 协议)
- 钱包地址字符串
- CPU/GPU 利用函数
- 进程隐藏技术
步骤 6:分析 Linux 特有的持久化机制
检查持久化机制:
# 检查 LD_PRELOAD rootkit
strings suspect_binary | grep "ld.so.preload"
# 恶意软件写入 /etc/ld.so.preload 可以钩住所有动态库调用
# 检查 crontab 持久化
strings suspect_binary | grep -i "cron"
# 检查 systemd 服务创建
strings suspect_binary | grep -iE "systemd|\.service|systemctl"
# 检查 init 脚本创建
strings suspect_binary | grep -iE "init\.d|rc\.local|update-rc"
# 检查 SSH 密钥注入
strings suspect_binary | grep -i "authorized_keys"
# 检查内核模块(rootkit)加载
strings suspect_binary | grep -iE "insmod|modprobe|init_module"
# 检查进程隐藏
strings suspect_binary | grep -iE "proc|readdir|getdents"
关键概念
| 术语 | 定义 |
|---|---|
| ELF(可执行与可链接格式) | Linux 可执行文件、共享库和核心转储的标准二进制格式,包含头部、节区和段 |
| 已剥离的二进制文件 | 已移除调试符号的 ELF 二进制文件,由于函数名称丢失,逆向工程难度增加 |
| LD_PRELOAD | Linux 环境变量,指定在所有其他库之前加载的共享库;被 Rootkit 滥用以拦截系统库调用 |
| strace | Linux 系统调用跟踪器,记录进程发出的所有系统调用和信号,揭示文件、网络和进程操作 |
| GOT/PLT | 全局偏移表和过程链接表;用于动态链接的 ELF 结构,可能被劫持用于函数钩子 |
| 静态链接 | 编译时将库代码包含在二进制文件中的方式;常见于 IoT 恶意软件,以便在没有匹配共享库的系统上运行 |
| Mirai | 通过 telnet 暴力破解针对 IoT 设备的高产 Linux 僵尸网络;源代码泄露,导致出现大量变种 |
工具与系统
- Ghidra:NSA 逆向工程工具,完全支持 x86、x86_64、ARM、MIPS 等 Linux 架构的 ELF 格式
- Radare2:开源逆向工程框架,提供命令行界面,用于快速二进制分析和脚本化操作
- strace:Linux 系统调用跟踪工具,用于观察二进制文件行为,包括文件、网络和进程操作
- GDB:GNU 调试器,用于设置断点、检查内存和单步执行 Linux 二进制文件
- pyelftools:Python 库,用于以编程方式解析 ELF 文件,构建自动化分析流水线
常见场景
场景:分析在受损 Linux 服务器上发现的挖矿病毒
背景:某云服务器 CPU 使用率持续 100%。调查发现 /tmp 目录下有一个未知二进制文件,名称可疑。需要分析该文件以确认是否为挖矿病毒,并识别攻击者所用的钱包和矿池。
方法:
- 将二进制文件复制到分析 VM,计算 SHA-256 哈希值
- 运行
file和readelf识别架构和链接类型 - 提取字符串,搜索矿池地址(stratum+tcp://)和钱包地址
- 在沙箱中使用 strace 运行,观察网络连接(矿池连接)
- 导入 Ghidra 以识别挖矿算法和配置提取方式
- 检查持久化机制(crontab、systemd 服务、SSH 密钥)
- 记录所有 IOC,包括矿池地址、钱包、C2 更新地址和持久化痕迹
注意事项:
- 在沙箱外运行
ldd(ldd 可能执行二进制文件中的代码) - 在尝试 x86_64 执行前未检查 ARM/MIPS 架构
- 遗漏配套脚本(.sh 文件),这些脚本可能处理持久化和清理工作
- 忽略初始入侵向量(挖矿程序如何部署:SSH 暴力破解、Web 漏洞利用、容器逃逸)
输出格式
LINUX ELF 恶意软件分析报告
====================================
文件: /tmp/.X11-unix/.rsync
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
类型: ELF 64 位 LSB 可执行文件,x86-64
链接方式: 静态链接(所有库已嵌入)
已剥离: 是
大小: 2,847,232 字节
加壳器: UPX 3.96(已解包用于分析)
分类
家族: XMRig 挖矿病毒(修改版)
变种: 自定义构建,包含 C2 更新机制
功能
[*] 通过 RandomX 算法进行 XMR(门罗币)挖矿
[*] 连接 Stratum 矿池以提交工作
[*] 向 C2 签到以获取配置更新
[*] 进程名伪装(argv[0] = "[kworker/0:0]")
[*] 杀死竞争进程(清除其他挖矿程序)
[*] SSH 密钥注入以便重新访问
网络指标
矿池: stratum+tcp://pool.minexmr[.]com:4444
C2 服务器: hxxp://update.malicious[.]com/config
钱包: 49jZ5Q3b...Monero_Wallet_Address...
持久化
[1] Crontab 条目: */5 * * * * /tmp/.X11-unix/.rsync
[2] SSH 密钥已添加到 /root/.ssh/authorized_keys
[3] Systemd 服务: /etc/systemd/system/rsync-daemon.service
[4] 修改了 /etc/ld.so.preload 以实现进程隐藏
进程隐藏
LD_PRELOAD: /usr/lib/.libsystem.so
钩子: readdir() 用于从 ls 中隐藏 /tmp/.X11-unix/.rsync
钩子: fopen() 用于阻止读取 /proc/*/maps