Skip to content

出口带宽突然打满

01 前置理论与核心机制

1. 异常外发流量的底层特征

  • 单向 UDP 洪泛 (UDP Flood):若常规业务无高带宽需求,但服务器出口带宽突然满载,通常是因为服务器被攻击者控制成为僵尸网络节点(Botnet),正在向外发起 DDoS 攻击。其典型特征是:仅有极高的出站流量,入站流量几乎为 0。由于 UDP 是无连接协议,恶意程序可直接向外高频发送伪造报文,无需建立 TCP 握手。
  • 进程伪装机制:恶意木马进程通常会将自身进程名伪装成 systemd、kworker 等系统内核线程或常见服务名称,并将可执行文件隐藏在 /tmp、/var/tmp 或 /dev/shm 等临时目录或内存文件系统中。

2. 状态查询的注意事项 (netstat -l)

  • 切勿添加 -l 参数:常规排查端口监听时习惯使用 netstat -tulnp。但 -l (listen) 参数仅用于过滤处于监听状态的入站端口。恶意程序主动向外发包时,使用的是操作系统随机分配的动态源端口,并不处于监听状态。若加上 -l 参数,将无法在结果中看到该异常进程。

02 故障排查与恢复闭环 SOP

当收到监控告警提示出口带宽占满,且排除正常业务突发流量后,按以下步骤执行定位与止损:

步骤一:使用 iftop 锁定异常外发端口

优先确认消耗带宽的具体连接及流量方向特征:

# 监控指定网卡 (假设为 ens33),-n 不解析域名,-N 不解析端口服务名,-P 显示端口号
iftop -i ens33 -nNP
  • 观测点:若观察到本地某个动态高端口(如 46904)正向大量外部 IP 高频发包,且出站速率极高、入站速率接近 0,即可确认服务器正向外发起 UDP Flood 攻击。记录该本地源端口号。

步骤二:通过 netstat 反查异常进程 PID

退出 iftop,利用记录的异常源端口号,反查占用该端口的进程号:

# -a 显示所有连接,-n 不解析名称,-p 显示进程 PID,-u 仅显示 UDP (注意不能加 -l)
netstat -anpu | grep 46904
  • 观测点:提取输出右侧对应的进程号 (PID),例如 18126。

步骤三:利用 /proc 定位真实可执行文件路径

获取 PID 后,定位恶意程序在磁盘上的物理文件路径。Linux 下每个运行中的进程在 /proc 目录下均有对应的元数据记录:

# 查看该 PID 对应的可执行文件符号链接
ls -al /proc/18126/exe

  • 观测点:观察符号链接指向的真实物理路径。恶意程序通常会指向 /tmp/kworkerd 或 /var/tmp/.crypto/miner 等非常规目录。即便进程名称与系统组件一致,只要其物理文件位于 /tmp 或 /dev/shm 下,即可判定为恶意程序。

步骤四:终止异常进程与流量复测

确认恶意进程与文件路径后,发送 SIGKILL 信号强制终止该进程,并清理物理文件:

kill -9 18126
rm -f /tmp/kworkerd
操作完成后再次运行 iftop -i ens33 -nNP,确认异常外发 UDP 流量消失,出口带宽回落至正常水位。

步骤五:排查常见持久化后门

终止进程仅能临时恢复带宽。为防止恶意程序被再次拉起,必须排查攻击者常用的三类持久化配置位置:

# 1. 检查当前用户及系统级的定时任务
crontab -l
ls -al /etc/cron* /var/spool/cron/

# 2. 检查免密登录的 SSH 授权公钥,确认是否被追加未知密钥
cat /root/.ssh/authorized_keys

# 3. 检查开机自启脚本与系统服务
cat /etc/rc.local

  • 处置动作:若发现未知的远程下载执行脚本(如 curl x.x.x.x/run.sh | bash)或非授权的 SSH 公钥,需立即清理。

03 真实生产故障现象与案例库

案例 1:伪装成系统组件的驻留木马

  • 故障现象:云平台持续发送“异常外发流量”与“出口带宽满载”告警。
  • 排查结果:执行 netstat -anpu 发现大量未知的 UDP 随机高端口连接,进程名显示为 systemd-network。通过 ls -al /proc//exe 查出其真实物理路径位于 /dev/shm/.hidden/systemd-network。
  • 根因与处置:攻击者利用内存文件系统 /dev/shm 运行恶意程序以规避常规磁盘目录排查。强制终止进程并删除该隐藏目录后,出口流量恢复正常。

案例 2:Redis 未授权访问导致的持续感染

  • 故障现象:某新上线的测试服务器出口带宽被打满。
  • 排查结果:终止 /tmp 下的恶意进程并删除文件后,数分钟内异常进程再次出现。检查 crontab -l 发现存在每分钟执行的远程拉起脚本。
  • 根因与处置:溯源入侵路径,发现主机上的 Redis 服务绑定在公网 0.0.0.0 且未配置密码认证。攻击者利用 Redis 未授权访问漏洞直接写入定时任务与 SSH 公钥获取了 Root 权限。处置方案为修改 Redis 绑定地址并配置强密码,清理定时任务与异常公钥。

案例 3:可执行文件已删除但仍在内存中驻留

  • 故障现象:通过 ls -al /proc//exe 查看时,路径末尾显示 (deleted) 标记。
  • 排查结果:恶意程序在启动加载至内存后,自动删除了磁盘上的自身实体文件,仅在内存中驻留运行,以增加排查难度。
  • 根因与处置:对于带有 (deleted) 标记的异常进程,直接执行 kill -9 即可释放其占用的内存与网络资源。若需保留样本进行安全取证,必须在终止进程前执行 cp /proc//exe /tmp/malware.sample,直接从内核映射中提取二进制样本。

04 生产排障速查表(带宽满载与进程溯源)

顺序排查层级执行命令 / 观测点异常定性处置动作01流量定界iftop -i <网卡> -nNP单向高频向外发包,入站流量极低定性为对外 UDP Flood 攻击,记录本地源端口02进程锁定netstat -anpu | grep <端口>注意不能加 -l 参数提取占用该动态端口的进程 PID03路径溯源ls -al /proc/<PID>/exe指向 /tmp、/var/tmp 或 /dev/shm锁定恶意程序物理文件位置并取证04紧急止损kill -9 <PID> 及 rm -f <文件>出口带宽指标立即回落阻断异常外发流量,恢复基础网络通信05后门清理检查 crontab 与 authorized_keys存在未知的下载脚本或陌生公钥移除恶意定时任务、启动项与非授权公钥06根源治理漏洞封堵与系统重装主机已发生 Root 权限沦陷修复应用层/中间件漏洞,备份业务数据后重装系统

05 面试应答参考话术

面试官问:“监控报警提示服务器出口带宽被打满了。如果平时业务并没有这么大的流量,你怎么排查?”

可以这样回答:如果常规业务没有高带宽需求,出口带宽突然打满,通常是因为服务器被入侵并作为受控节点向外发起 DDoS(如 UDP Flood)攻击。我的排查链路是:定位异常端口 -> 反查进程 PID -> 追踪物理路径 -> 终止进程并清理持久化后门。第一步:观测实时流量特征

首先使用 iftop -i eth0 -nNP 查看网卡的实时流量明细。此类故障通常会看到服务器正通过本地的某个随机高端口,向大量外部 IP 高频发包,且仅有出站流量、无入站回包。这种无握手、单向发包的特征,基本可以判定为对外发起的 UDP Flood 攻击。此时记录下该本地源端口号。第二步:反查进程 PID(关键细节)

获取端口号后,使用 netstat -anpu | grep <端口> 反查对应的进程。这里需要注意:不能加上习惯性的 -l 参数。因为恶意程序是主动向外发包,并不处于监听(Listen)状态,加上 -l 会导致过滤结果为空。通过该命令可直接获取异常进程的 PID。第三步:通过 /proc 追踪真实文件路径

恶意进程常将名称伪装成系统组件。拿到 PID 后,执行 ls -al /proc/<PID>/exe 查看内核记录的可执行文件真实路径。如果发现路径指向 /tmp、/var/tmp 或 /dev/shm 等临时目录,即可确认为恶意程序。第四步:终止进程与清理持久化后门

直接执行 kill -9 终止该进程并删除对应文件,出口带宽通常会立即回落。随后必须排查常见的持久化位置以防进程被再次拉起:包括使用 crontab -l 检查定时任务、查看 /root/.ssh/authorized_keys 是否被植入未知公钥、以及检查 /etc/rc.local 和 systemd 启动项,将异常配置全部清理。总结与安全基线:

上述步骤属于应急止损手段。在生产环境中,一旦确认服务器曾被攻击者获取过 Root 权限,该操作系统的完整性已无法完全信任。恢复业务后,标准的做法是查明入侵入口(如 Redis 未授权访问或 Web 漏洞),修复漏洞并迁移业务后,直接重装该节点操作系统。

06 面试高频追问与应答预案

追问 1:为什么执行 netstat -anpu 时,能看到端口连接,但后面的 PID 和进程名显示为空或横杠(-)?

  • 回答要点:
  • 执行权限不足:在 Linux 系统中,普通用户执行 netstat 或 ss 时,受限于内核权限隔离,无法读取属于其他用户(尤其是 root 用户)的进程元数据,因此 PID 列会显示为 -。
  • 处置方案:排查系统级网络异常时,必须使用 sudo 提权或直接切换至 root 账号执行命令。

追问 2:如果执行 kill -9 终止进程后,不到 1 秒钟它立刻换了一个新 PID 重新启动,且检查定时任务完全正常,这是什么原因?如何处理?

  • 回答要点:
  • 存在守护进程监控:恶意程序采用了父子进程或双进程互相监控机制。除发包工作进程外,后台还运行着一个隐藏的守护进程(Daemon),一旦检测到工作进程退出,会立即在毫秒级时间内重新 fork 拉起新进程。
  • 处置方案:仅终止工作子进程无效。需执行 ps -ef --forest 或 pstree -p 查看进程树,向上溯源找到其父进程(PPID)。处置时可先使用 kill -STOP 发送暂停信号将父子进程同时挂起(使其无法继续执行拉起逻辑),然后再统一执行 kill -9 彻底清理。

07 异常外发流量与后门巡检脚本(check_botnet_traffic.sh)

该脚本用于快速检测本机是否存在异常的高并发 UDP 外发行为,并自动核查定时任务与 SSH 授权公钥配置。

#!/usr/bin/env bash
# ==============================================================================
# 脚本名称: check_botnet_traffic.sh
# 功能描述: 服务器异常 UDP 外发连接诊断与常见持久化后门巡检 (纯只读)
# 使用方式: 在目标 Linux 服务器上以 root 权限执行
# ==============================================================================

set -o pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PLAIN='\033[0m'

echo -e "${BLUE}================================================================${PLAIN}"
echo -e "${BLUE}           服务器出口带宽异常与木马特征自动诊断脚本             ${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"

# 1. 检查是否存在异常的高频 UDP 外发连接
echo -e "\n${YELLOW}[1/3] 扫描本机并发 UDP 外发连接...${PLAIN}"
# 提取非本地回环的 UDP 连接进程信息并按并发数排序 (已修复管道符)
SUSPICIOUS_UDP=$(ss -unp | grep -v "127.0.0.1" | awk '{print $NF}' | grep "pid=" | sort | uniq -c | sort -nr | head -n 3)

if [ -n "$SUSPICIOUS_UDP" ]; then
    echo -e "  -> ${RED}[WARN] 检测到存在并发 UDP 外发连接的进程:${PLAIN}"
    echo "$SUSPICIOUS_UDP" | while read -r count process_info; do
        # 提取 PID 与进程名
        PID=$(echo "$process_info" | grep -o 'pid=[0-9]*' | head -n 1 | cut -d'=' -f2)
        PNAME=$(echo "$process_info" | grep -o '("[^"]*"' | head -n 1 | tr -d '"(')

        if [ -n "$PID" ] && [ -d "/proc/$PID" ]; then
            EXE_PATH=$(readlink "/proc/$PID/exe" 2>/dev/null)
            # 已修复字符串中的管道符
            echo -e "     连接数: ${RED}${count}${PLAIN} | 进程名: ${PNAME} | PID:${PID}"
            echo -e "     -> 物理路径: ${YELLOW}${EXE_PATH}${PLAIN}"

            # 已修复逻辑或双竖线
            if [[ "$EXE_PATH" == /tmp/* ]] || [[ "$EXE_PATH" == /var/tmp/* ]] || [[ "$EXE_PATH" == /dev/shm/* ]]; then
                echo -e "     -> ${RED}[高危告警] 该可执行文件位于临时目录,极可能为恶意程序,请核实并执行 kill -9 $PID${PLAIN}"
            fi
        fi
    done
else
    echo -e "  -> ${GREEN}[OK] 当前未检测到明显的异常 UDP 外发连接。${PLAIN}"
fi

# 2. 检查定时任务风险
echo -e "\n${YELLOW}[2/3] 检查 root 用户 Crontab 定时任务...${PLAIN}"
if crontab -l &>/dev/null; then
    CRONS=$(crontab -l | grep -v "^#")
    if echo "$CRONS" | grep -q -E "curl|wget|bash|sh|base64|nc"; then
        echo -e "  -> ${RED}[WARN] root 定时任务中包含网络下载或脚本执行指令 (curl/wget/bash等),请人工核实:${PLAIN}"
        echo -e "${YELLOW}${CRONS}${PLAIN}"
    else
        echo -e "  -> ${GREEN}[OK] root 定时任务未发现明显的远程下载执行特征。${PLAIN}"
    fi
else
    echo -e "  -> ${GREEN}[OK] root 用户当前无定时任务配置。${PLAIN}"
fi

# 3. 检查 SSH 授权公钥
echo -e "\n${YELLOW}[3/3] 检查 root 用户 SSH 授权密钥 (authorized_keys)...${PLAIN}"
AUTH_KEYS_FILE="/root/.ssh/authorized_keys"
if [ -f "$AUTH_KEYS_FILE" ]; then
    KEY_COUNT=$(grep -v "^#" "$AUTH_KEYS_FILE" | grep -c -E "ssh-rsa|ssh-ed25519|ecdsa")
    echo -e "  -> 当前存在 ${KEY_COUNT} 条授权公钥记录。"
    if [ "$KEY_COUNT" -gt 0 ]; then
        echo -e "  -> ${YELLOW}[提示] 请核对以下尾部公钥是否属于受信任的管理员:${PLAIN}"
        tail -n 3 "$AUTH_KEYS_FILE" | awk '{print "     " $1 " ... " $3}'
    fi
else
    echo -e "  -> ${GREEN}[OK] 未发现 /root/.ssh/authorized_keys 文件。${PLAIN}"
fi

echo -e "\n${BLUE}================================================================${PLAIN}"
echo -e "${BLUE}诊断结束。若确认主机已被植入木马且丢失 root 权限,应急止损后建议重装系统。${PLAIN}"
echo -e "${BLUE}================================================================${PLAIN}"