☰
一次YApi漏洞引发的挖矿木马处置实录:从告警到溯源加固
2026/10/21 18:00:30 网站建设 项目流程

1. 事发当天:一次普通告警背后的异常

干运维这几年,处理过的告警没有一千也有八百。服务器CPU飙高、磁盘写满、进程挂掉,这些“常规节目”见多了,人难免会麻木。但那次YApi相关的告警,让我真正意识到:有时候最普通的异常,可能藏着整个服务器被控制的事实。

那天的情况很典型。上午十点左右,监控平台开始刷屏,某台服务器的CPU使用率持续100%,load average直接飙到8以上,而平时这台机器跑的只是内部接口文档服务和几个定时任务,负载常年稳定在0.5以下。按常规思路,第一反应是业务方发版了,或者哪个定时任务脚本写了个死循环。但查了一圈发布记录,当天没有任何变更,定时任务也都是老任务。

这时候我隐隐觉得不对劲。登录服务器,top一眼扫过去,发现进程列表里有一个kswapd0,占用CPU接近200%。说实话,对Linux熟悉的朋友都知道,kswapd0是内核线程,负责内存页交换,确实存在且有CPU占用是正常的。但问题是,真正的内核kswapd0通常不会这么吃CPU,而且进程列表里有两个kswapd0,其中一个明显是冒牌货。

用ps -ef确认了一下,那个假kswapd0的启动路径在/usr/tmp下,文件名为一串随机字符。好家伙,这是被种挖矿木马了。

那个瞬间心里咯噔一下。服务器被入侵,这事平时只在演练和事故报告里看到过,真落到自己头上,第一反应其实是“不能慌,证据先保留”。我没有直接杀掉进程,而是先把当时的top输出、进程信息、网络连接都留了快照。这一步后来证明非常关键,因为很多挖矿木马都有守护机制,你要是直接kill,它马上会通过计划任务或另一个守护进程重新拉起来,而且还会把原文件删掉,给你追查线索的时间窗口就那几分钟。

简单总结一下我做对的几点:保持冷静、先取证再处置、不要把现场搞乱。这次事件的后续处理,全都是建立在这个前提之上的。

2. 逐步定位:从进程异常反查入侵路径

2.1 进程伪装与网络外连,两条线索同时指向挖矿

我先用ls -l /proc/<PID>/exe查看那个假kswapd0进程的可执行文件路径,结果指向/usr/tmp/.x/test这类隐藏目录。再配合/proc/<PID>/cmdline,可以看到它执行的完整命令行参数,居然还带了一个类似-a 矿池地址 -p 钱包地址的参数。这种格式我见过,是门罗币等加密货币的挖矿客户端常见启动方式。

接着用netstat -antp看外联,服务器上有好几个到未知IP的ESTABLISHED连接,目标端口是4444、3333这类不常见端口。正常业务根本不会连这些端口,基本可以断定是矿池地址的连接。

到这里,事件性质已经从“性能故障”转变成“安全事件”。我立刻执行了一个保底动作:把服务器的公网访问策略临时收紧,先用iptables封掉那几个外联IP。这一步的意义在于,就算挖矿进程还在跑,它往矿池传数据的通道被断了,至少不会继续作为肉鸡帮别人赚钱。同时,隔离观察可以防止攻击者继续通过这台机器发起对外攻击。

2.2 翻日志,找到那条“不和谐”的请求记录

确认是挖矿木马之后,第二个问题来了:服务器是怎么被攻破的?

我花了不少时间排查系统日志,但很快意识到——系统日志里干净得像什么都没发生过,SSH登录记录、sudo记录都没有异常。这有两种可能:要么攻击者非常小心,清理了日志痕迹;要么攻击入口压根不在系统层,而在应用层。顺着后者去查,问题就清晰了。

这台机器上跑着YApi,是团队内部做接口文档管理和Mock服务的平台。我打开YApi所在目录的日志文件,以及前置Nginx的访问日志,看到在事发前一两天的记录里,有大量针对/api/user/reg、/api/project/get这类接口的请求,而且来源IP五花八门,显然不是自己人。其中有几个请求返回了200状态码,响应体大小还不一样,说明攻击者成功执行了某种未授权操作。

到这里基本上清楚了:YApi的旧版本存在接口层面的远程命令执行漏洞,攻击者无需登录或只需拿到普通权限,就能通过构造特定请求,在服务器上执行命令。命令的内容就是下载远程恶意脚本并执行,也就是我们后来在定时任务里发现的那条链接。

2.3 攻击链全貌:扫描、漏洞利用、植入、持久化

事后花了两天时间,把整个攻击过程完整复盘了一遍,大致是这样的:

  1. 攻击者通过全网扫描,发现这台服务器的特定端口对外开放,并且运行的是YApi。
  2. 利用YApi远程命令执行漏洞发起攻击,向服务器写入一段简单命令。
  3. 命令通过wget或curl下载一个脚本到/tmp目录下,通过chmod +x赋予执行权限后启动。
  4. 这个脚本再下载真正的挖矿程序,放到/usr/tmp/.x这类不容易被注意到的目录,伪装成系统进程名。
  5. 同时设置计划任务,每几分钟执行一次,保证就算挖矿进程被杀掉,也会被重新拉起来。
  6. 最后在/root/.ssh/authorized_keys里写入攻击者的公钥,留下远程后门。

整个链条走完可能只需要几分钟,而且整个过程完全自动化。最扎心的是,这些攻击每天每时每刻都在互联网上发生,不是针对我们这一家,纯粹是撞上了。

2.4 为什么YApi会成为突破口

YApi本身是一个很好用的接口管理平台,团队一直用它维护接口文档。问题不在工具本身,而在于当时部署方式存在几个硬伤:

  • 服务直接监听在0.0.0.0:3000,公网可访问,没有任何访问控制;
  • 管理员密码非常简单,形同虚设;
  • 使用的YApi版本比较旧,存在已知的远程命令执行漏洞,一直没升级;
  • 服务器上除了YApi,还跑着其他业务服务,权限没有做隔离。

这几点单独拿出来,任何一点可能都谈不上致命,但合在一起,就等于给攻击者开了门。YApi这台机器被攻破之后,攻击者拥有了普通用户甚至root权限,随后通过定时任务和SSH公钥完成了驻留。如果我们当时把服务放在内网、做反向代理加认证、保持组件更新、把非必要端口全部关掉,这次事件完全可以避免。

3. 清除木马与修复后门:一场拉锯战

3.1 清理顺序很关键,先封通道再动手

很多运维同行处置这类事件,上来就是kill -9,杀完进程心里踏实了,结果没过几分钟又死灰复燃。正确顺序应该是:先断外联、再清计划任务、再杀进程、再删文件,最后检查后门。

我的做法是这样的:

# 1. 先封掉木马连接的可疑IP iptables -A OUTPUT -d 203.0.113.10 -j DROP iptables -A OUTPUT -d 203.0.113.11 -j DROP # 2. 查看并记录当前计划任务 crontab -l cat /var/spool/cron/root

为什么要先封IP?因为挖矿木马有“失联自毁”机制,有些木马检测不到矿池连接,会自动删除自身痕迹以逃避检测。如果我们直接杀掉进程,反而给了它销毁证据的机会。先把通道封了,木马还在,但已经变成“断线的肉鸡”,这时候再去分析和清理,主动权就在我们手里。

封完IP之后,我保留了所有原始证据,包括恶意进程的二进制文件、脚本、计划任务内容,全部复制一份放到单独的备份目录。事后如果要做溯源分析,这些文件都是第一手材料。

3.2 计划任务:木马最重要的“复活开关”

挖矿木马最怕的不是你杀进程,而是你找到它的“复活开关”。绝大多数木马都会通过计划任务定时执行,让被清理后的进程重新出现。

这次也不例外。清理时发现/var/spool/cron/root下多了一条任务,每隔1分钟执行一次:

*/1 * * * * /usr/tmp/.x/update >/dev/null 2>&1

另外在/tmp目录下还有一个用于拉取的脚本,内容大致是从某个可疑地址下载压缩包,解压后执行。我把这两处全部删除,并且用crontab -r清掉了当前用户的计划任务。

删完计划任务,接下来才轮到杀进程:

# 找到挖矿相关进程并强制终止 ps -ef | grep -E 'kswapd0|update|xmr' | grep -v grep kill -9 <PID>

第一次kill之后,我等了两分钟,再用ps看,进程没有重新出现,心里才踏实了一些。为了保险,又连续观察了三个小时,确认没有复活。

3.3 隐藏文件、SSH公钥和系统库劫持,一个都不能漏

挖矿木马通常不止一个文件。清理完计划任务和主进程之后,我开始地毯式搜索所有可疑文件。重点检查了几个目录:

# 查看常见临时目录 ls -la /tmp /var/tmp /usr/tmp # 查看系统目录下近期新增的可疑文件 find /usr -mtime -3 -type f -name '.*' 2>/dev/null

果不其然,在/usr/tmp/.x目录下躺着主挖矿程序,在/tmp下还有几个辅助脚本。把这些文件全部删除之后,我顺手用chattr +i锁了关键的目录,防止再次被写入。

然后检查SSH后门:

cat /root/.ssh/authorized_keys

不看不知道,一看吓一跳,authorized_keys里多了一条公钥,前缀注释还有一串看不懂的字符串。这明显是攻击者留的后门。我立刻备份原文件后,把这条公钥删除,只保留我们自己人的公钥。

还有一个容易被忽视的地方是/etc/ld.so.preload。这是一个“库劫持”手段,攻击者可以通过在预加载配置文件里指定恶意动态库,让所有执行程序都被注入恶意代码。检查后发现这个文件是空的,虚惊一场。

另外排查了/etc/rc.local、/etc/init.d/、systemd服务目录,看看有没有自启动脚本。这次暂时没发现,但这类位置是木马的藏身之地,不可不查。

3.4 双人复核与持续监控,清洗效果才算数

单人的排查总会漏掉东西。清理完第一轮之后,我请另一位同事从独立视角再做了一遍复核,重点对照了“新增用户”、“SUID文件”、“历史命令”和“对外连接”几个维度。双人复核不是为了走形式,而是防止一个人思维惯性导致漏判。

同时,我在服务器上部署了一个简单的监控脚本,每5分钟记录一次可疑进程和网络连接,持续观察48小时。这也是一个好习惯,清理完成不等于事件结束,观察期内的数据才能真正证明是否清理干净。

这轮下来,CPU恢复到了正常水平,load average回到1以下,网络连接也只剩正常的SSH和业务连接。至此,木马算是清干净了。

4. 溯源与加固:这次事件带给我最大的几点教训

4.1 关于YApi版本与官方修复方案

前面提到,YApi存在可利用的远程命令执行漏洞。建议所有正在使用YApi的团队,都去官方仓库看一下自己使用的版本是否在受影响范围内,并根据官方指导进行升级或打补丁。如果实在无法升级,至少要做到服务不要直接暴露在公网,并且加上身份验证和访问控制。

YApi这种开源项目管理工具,很多团队部署时都是“装完即用”,很少关注后续安全更新。尤其像这类内部工具,经常被大家默认“反正只有内部人知道,没人会攻击”。实际上,扫描全网找漏洞的自动化工具,根本不会区分你的系统是“内部”还是“外部”。任何暴露到公网的服务,都应视为高危。

4.2 删除无用账号,关闭不必要的服务

处理完木马之后,我把整台服务器上的用户账户梳理了一遍,删掉了几个长期不用的普通账号,并检查了/etc/passwd、/etc/shadow里是否有可疑新增项。这项操作看似基础,却是阻止二次入侵的重要环节,因为攻击者很有可能通过新建账号来维持访问。

同时,我对监听端口做了一次全面梳理:

netstat -tlnp

确认开放的端口只剩下业务必需的SSH(并修改为仅内网访问)、YApi的Nginx入口和监控agent端口。其余端口全部通过防火墙关闭。这里的原则是:默认拒绝,按需放行。

4.3 从补丁到应急,形成习惯闭环

这次事件之后,团队定了个规矩:所有对外服务,一律走前置Nginx做反向代理并加强制认证;YApi管理员账号改成了强密码,且只允许特定IP访问管理后台;任何第三方工具升级,优先级提到和业务版本发布同等高度。同时,监控告警加入了对新进程名称、新计划任务、新SSH公钥等变化的检测。

应急预案也重新梳理了。我们知道,当服务器出现异常时,第一步不是盲杀进程,而是先隔离、取证、再处置。这次事件后,我写了一份内部安全事件处理手册,把“现场保护→证据快照→通道隔离→木马清除→后门排查→观察复验”这几个阶段写清楚,给团队其他人一个明确的参考。

说白了,安全不是某个人的事情,而是体系问题。你能堵住一次扫描撞库,不一定能堵住下一种未知漏洞。建立一套持续维护、持续监测的机制,比处理单一事件更值得投入。

5. 最后分享一个实用习惯

事件完全平息之后,我养成了一个新习惯:每隔一段时间,手动去服务器上看一眼那几条命令的输出,不依赖监控平台,就用最原始的方式确认一下机器状态。

ps aux --sort=-%cpu | head -15 netstat -antp | grep ESTABLISHED

这两条命令加起来不到两秒,但能让你对服务器的“日常状态”形成直觉。有了这种直觉,当问题真的来临的时候,你才能一眼看出哪里不对劲,而不是等告警阈值把你从座位上弹起来。

这台机器后来运行了很长时间,没有再出现任何异常。但每次登录它,我都会想起那个上午——一个普通得不能再普通的告警,背后是一整套针对互联网上所有暴露服务的自动化攻击。警惕之心,什么时候都不能放下。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询