Linux IR - 应急响应排查
Linux IR - 应急响应排查
最近遇到了一个 Linux 应急响应 (Linux Incident Response) 的突发事件, 记录一下遇到的问题, 踩到的坑, 系统的响应流程以及常用命令。
应急响应流程 (PDCERP)
应急响应流程总的来说就是分为两部分, 未雨绸缪和亡羊补牢。
- 准备 (Preparation)
提前建立响应能力, 指定相关计划, 组建并培训 IR 团队, 准备相应的工具包等等。最典型的活动就是管理日志, 网络流量捕获。
- 检测 (Detection & Analysis)
发现并确认安全事件, 监控告警, 并进行初步分析。
- 遏制 (Containment)
隔离受感染系统,阻止攻击扩散。切断网络, 拔网线 (物理), 主机隔离, 杀掉进程等。
- 根除 (Eradication)
彻底清除攻击载体, 之后二次扫描比对等, 确保完全删除恶意文件。对 Linux 来说, 需要注意授权密钥对, crontab 等。
- 恢复 (Recovery)
问题解决后逐渐解决业务正常运行。
- 事后总结 (Post-Incident Activity)
写报告总结, 比如如果存在 0day 的话就很有必要写清楚。
常用命令 + 执行顺序
为了免得下次碰到这个情况手忙脚乱, 先把合适的命令整理下来
系统信息搜集
系统信息不论如何都必须进行, 较为老旧的 Linux 内核几几乎必然存在提权漏洞:
1 | # 查看操作系统 + 内核信息 |

进程分析
恶意木马执行后一定会伴随一个恶意进程, 恶意进程的典型特征: 对 CPU 占用异常; 进程的运行时间, 持续时间与普通进程差异非常明显; 进程路径命令参数异常; 可能替换系统指令。
1 | # 显示进程表, 视图效果类似任务管理器 |

1 | # 查找指定进程 |

1 | # 查看相关联文件 |

1 | # 查看进程关联文件 |
进程隐藏
理解进程隐藏之前, 要先了解 Linux 系统指令的本质: Linux 的系统其实就是一个个编译好的二进制文件, 当用户执行指令时, 系统会从 $PATH 中从前往后读取, 取出其中的第一个源文件执行。如果攻击者修改并上传编译好的命令文件覆盖原有指令, 就可以达到偷梁换柱的效果。
例如用
which这个指令就可以看某个命令具体的二进制代码在哪, 搜索规则同样是从$PATH里面读取:
当攻击者完成提权后, 可以通过多重手段来进行进程隐藏。
例如:
本地编译上传覆盖或软连接劫持;
可以查看命令的修改、更改时间来判断该命令是否被更改,还可以对比可疑命令和正常命令的 MD5 值是否相同。
HooK 系统调用:
/proc是一个虚拟文件系统, 是 VFS 的实现形式,/proc中包含了内核信息, 硬件信息, 进程信息等,ps等工具就是通过分析/proc文件系统中进程相关目录的信息获取进程信息汇总。ps的工作原理, 调用openat系统函数获取/proc目录的文件句柄,然后调用系统函数getdents递归获取/proc目录下所有文件信息(包括子目录),然后开始open函数打开/proc/进程pid/stat,/proc/PID/status,/proc/PID/cmdline文件开始获取进程信息,然后打印给你看。Hook 类型的进程隐藏为拦截或者迷惑
ps等工具从/proc获取分析结果的过程, 而非其本身。最简单的方法就是利用环境变量LD_PRELOAD或者配置ld.so.preload文件以使恶意的动态库先于系统标准库加载。
1 | # 下载的恶意的动态库文件 |
伪造进程名称
这个很好理解:
1 | $ exec -a bash python ./attack.py |
挂载隐藏
就是将另一个磁盘挂载到原有目录, 这样一来就会形成覆盖。
1 | $ ps -ef | grep attack |
这一点可以通过 fstab 查看到挂载信息, 或者用这两个指令:
1 | cat /proc/$$/mountinfo |
列如:
1 | # 查看是否有利用mount —bind 将其他目录或文件挂载至/proc下的进程目录的行为 |
网络分析
1 | # 查看端口开放情况 |
端口参考:
| 端口 | 服务 | 渗透测试 |
|---|---|---|
| tcp 20,21 | FTP(文件传输协议) | 允许匿名的上传下载, 爆破, 嗅探, win提权, 远程执行(proftpd 1.3.5), 各类后门(proftpd, vsftp 2.3.4) |
| tcp 22 | SSH(安全外壳协议) | 可根据已搜集到的信息尝试爆破, v1版本可中间人, ssh隧道及内网代理转发, 文件传输等等 |
| tcp 23 | Telnet(远程终端协议) | 爆破, 嗅探, 一般常用于路由, 交换登陆, 可尝试弱口令 |
| tcp 25 | SMTP(简单邮件传输协议) | 邮件伪造, vrfy/expn查询邮件用户信息, 可使用smtp-user-enum工具来自动跑 |
| tcp/udp 53 | DNS(域名系统) | 允许区域传送, dns劫持, 缓存投毒, 欺骗以及各种基于dns隧道的远控 |
| tcp/udp 69 | TFTP(简单文件传送协议) | 尝试下载目标及其的各类重要配置文件 |
| tcp 80-89, 443, 8440-8450, 8080-8089 | 各种常用的Web服务端口 | 可尝试经典的topn, vpn, owa, webmail, 目标oa, 各类Java控制台, 各类服务器Web管理面板, 各类Web中间件漏洞利用, 各类Web框架漏洞利用等等…… |
| tcp 110 | POP3(邮局协议版本3) | 可尝试爆破, 嗅探 |
| tcp 111,2049 | NFS(网络文件系统) | 权限配置不当 |
| tcp 137,139,445 | SMB(NETBIOS协议) | 可尝试爆破以及smb自身的各种远程执行类漏洞利用, 如ms08-067, ms17-010, 嗅探等…… |
| tcp 143 | IMAP(邮件访问协议) | 可尝试爆破 |
| udp 161 | SNMP(简单网络管理协议) | 爆破默认团队字符串, 搜集目标内网信息 |
| tcp 389 | LDAP(轻量目录访问协议) | ldap注入, 允许匿名访问, 弱口令 |
| tcp 512,513,514 | Linux rexec(远程登录) | 可爆破, rlogin登陆 |
| tcp 873 | Rsync(数据镜像备份工具) | 匿名访问, 文件上传 |
| tcp 1194 | OpenVPN(虚拟专用通道) | 想办法钓VPN账号, 进内网 |
| tcp 1352 | Lotus(Lotus软件) | 弱口令, 信息泄漏, 爆破 |
| tcp 1433 | SQL Server(数据库管理系统) | 注入, 提权, sa弱口令, 爆破 |
| tcp 1521 | Oracle(甲骨文数据库) | tns爆破, 注入, 弹shell… |
| tcp 1500 | ISPmanager(主机控制面板) | 弱口令 |
| tcp 1723 | PPTP(点对点隧道协议) | 爆破, 想办法钓VPN账号, 进内网 |
| tcp 2082,2083 | cPanel(虚拟机控制系统) | 弱口令 |
| tcp 2181 | ZooKeeper(分布式协调系统) | 未授权访问 |
| tcp 2601,2604 | Zebra(zebra路由) | 默认密码zerbra |
| tcp 3128 | Squid(代理缓存服务器) | 弱口令 |
| tcp 3312,3311 | kangle(web服务器) | 弱口令 |
| tcp 3306 | MySQL(数据库) | 注入, 提权, 爆破 |
| tcp 3389 | Windows rdp(桌面协议) | shift后门[需03以下系统], 爆破, ms12-020 |
| tcp 3690 | SVN(版本控制系统) | svn泄露, 未授权访问 |
| tcp 4848 | GlassFish(应用服务器) | 弱口令 |
| tcp 5000 | Sybase/DB2(数据库) | 爆破, 注入 |
| tcp 5432 | PostgreSQL(数据库) | 爆破, 注入, 弱口令 |
| tcp 5900,5901,5902 | VNC(远程控制) | 弱口令爆破 |
| tcp 5984 | CouchDB(数据库) | 未授权导致任意指令执行 |
| tcp 6379 | Redis(数据库) | 可尝试未授权访问, 弱口令爆破 |
| tcp 7001,7002 | WebLogic(WEB应用系统) | Java反序列化, 弱口令 |
| tcp 7778 | Kloxo(虚拟主机管理系统) | 主机面板登录 |
| tcp 8000 | Ajenti(Linux服务器管理面板) | 弱口令 |
| tcp 8443 | Plesk(虚拟主机管理面板) | 弱口令 |
| tcp 8069 | Zabbix(系统网络监视) | 远程执行, SQL注入 |
| tcp 8080-8089 | Jenkins, JBoss(应用服务器) | 反序列化, 控制台弱口令 |
| tcp 9080-9081,9090 | WebSphere(应用服务器) | Java反序列化/弱口令 |
| tcp 9200,9300 | ElasticSearch(搜索服务器) | 远程执行 |
| tcp 11211 | Memcached(缓存系统) | 未授权访问 |
| tcp 27017,27018 | MongoDB(数据库) | 爆破, 未授权访问 |
| tcp 50070,50030 | Hadoop(分布式文件系统) | 默认端口未授权访问 |
启动项分析
这一项比较多并且复杂, 首先要了解 service 和 systemctl:
服务项排查
CentOS6 中服务 Service 启动脚本都放在
/etc/rc.d/init.d/下,/etc/init.d/是/etc/rc.d/init.d/的软链接; CentOS7 中Service命令会被重定向到Systemctl的脚本。
CentOS7 的服务
systemctl脚本存放在/usr/lib/systemd/下,并且有着 user 和 system 的区分,就像在 windows 中有着系统启动以及用户登录之分。像需要开机不登陆就能运行的程序,即/usr/lib/systemd/system目录下。
1 | [root@localhost ~]# ll /usr/lib/systemd/system | grep sshd |
Linux 7种运行级别:runlevel查看当前运行级别;init[0~6]切换运行级别
运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
运行级别1:单用户工作状态,root权限,用于系统维护,禁止远程登陆
运行级别2:多用户状态(没有NFS)
运行级别3:完全的多用户状态(有NFS),登陆后进入控制台命令行模式
运行级别4:系统未使用,保留
运行级别5:X11控制台,登陆后进入图形GUI模式
运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动;
可以试试自己创建一个 .service 文件并设置开机启动, .service 文件分为三部分: [Unit]、[Service] 和 [Install]:
1 | [root@localhost ~]# vim attack.service |
启动脚本排查
rc.local
CentOS7 中启动脚本命令放在了 /etc/rc.d 目录下的 rc.local 文件中,该脚本在正常情况下是没有可执行权限的 [644],在这种情况下若向文件中添加启动命令也不会执行。那么若黑客对失陷的 CentOS 服务器配置了脚本开机启动,则该文件的权限为 [755]。
1 | [root@localhost rc.d]# chmod +x rc.local |
chkconfig
通过 chkconfig 的方式添加 .sh 启动脚本,chkconfig主要包括 5 个原始功能:为系统管理增加新的服务、为系统管理移除服务、列出单签服务的启动信息、改变服务的启动信息和检查特殊服务的启动状态。当单独运行 chkconfig 命令而不加任何参数时,他将显示服务的使用信息。
--add: 开启指定的服务程序;--del: 关闭指定的服务程序;--list: 列出chkconfig所知道的所有服务;--level<number>: 设置服务程序的等级代号,它是一串0~7的数字,如-level35代表指定运行等级 3 和 5;--help: 显示帮助信息;--version: 显示版本信息;
1 | [root@localhost ~]# vim /etc/rc.d/init.d/linux_ln.sh |
计划任务排查
这也是个非常常见的攻击面, crond 会定期执行计划任务:
1 | [root@localhost tmp]# systemctl stop crond.service |
查看所有用户的任务表:
1 | cat /etc/passwd | cut -f 1 -d : |xargs -I {} crontab -l -u {} |
文件修改
首先要了解文件修改属性:
- 当读取文件时,access time改变,而modify,change time不会改变。
- 当修改文件时,access, modify,change time都会跟着改变。
- 当修改属性时,change time改变,而access,modify time不变。
- more、less、cat.、nl、tail、 tac等命令会更改atime。
- Is、stat命令不会修改文件的atime。
- 修改时间,修改时间是文件内容最后一次被修改时间。比如: vi后保存文件。
- 状态改动时间,是该文件的i节点最后一次被修改的时间,所谓的i节点说白了就是文件信息。
- 通过
chmod.chown修改文件属性,会更新ctime。touch则会更改atime,ctime,mtime。
当在检查 linux 服务器的时候需要用 stat 或者 ls 进行确认服务器本身的命令没有被替换掉 (ps 命令和 netstat 命令),看 modify 改变时间是否和事发时间是否存在关联性,一般来讲 /bin 下面的命令文件 mtime 通常不会是最新的。
例如:
1 | [root@localhost ~]# stat linux.elf |
如果仍然不确定, 那么可以进一步的用 md5 来检查:
1 | # 例如算出 ps 命令的哈希 |
根据文件修改时间检查:
当我们的 linux 操作系统被恶意入侵的时候,攻击者往往会在一些重要的目录下修改部分文件或者创建文件,就例如开机启动项、启动脚本等。那么如果需要快速的查找特定时间内被修改的文件,则可以通过以下几种方法来进行。
1 | #第一种方法: |
SUID, SGID 专栏
如果一个可执行文件 (必须是二进制文件) 设置了 SUID/SGID, 那么运行该文件的时候将以 文件所有者/文件所有者所在组 的权限执行, 而不是执行者自身权限。
原理和例子在 Linux 提权总结 中已有。
举个例子, 如果 find 命令的二进制源文件设置了 SUID 且所有者为 root, 那么其他用户 (user) 就可以使用这个命令来轻而易举的提权, 设想这条命令:
1 | find / -exec whoami |
返回结果将是 “root” 而非 “user”, 因为在 find 内部执行 whoami 时使用的身份是 root。换句话说, 这个情景几乎就等于可任意执行 root 代码, 非常容易提权。
find 命令检查绕过
find 命令检索的是文件的 mtime 或者 ctime,那么我们只要将时间修改为一个很久之前或者文件原来的时间点,那么就可以轻松的绕过 find 命令的检索。
1 | [root@localhost ~]# stat attack.sh |
可疑用户排查
当前登录用户
检查当前登录用户, 这个命令的查看痕迹在: /var/run/utmp
1 | [root@localhost bin]# w |
异常用户排查
利用 /etc/passwd 可以查看当前系统中存在的所有用户,排查是否有异常新建用户、用户弱口令、是否拥有 shell。需要注意 /etc/passwd 默认权限为 644,其最小权限为444。
1 | [root@localhost ~]# cat /etc/passwd |grep root |
- 红队攻击命令:创建超级用户
1 | useradd attack;echo 'attack:123456'|chpasswd |
- 蓝队防守命令: 删除或禁用用户
1 | usermod -L user |
- 现代 Linux 密码文件:
/etc/shadow, 默认权限为 600, 最小权限为400;
1 | [root@localhost ~]# cat /etc/shadow |grep root |
- sudo 配置文件:
/etc/sudoers规定了系统中的用户是否可以执行 sudo 命令,以及通过 sudo 可以执行哪些命令。
一个用户即使 uid 和 gid 均不为 0, 也可能通过这个文件来实现管理员身份的操作;
正常情况下
/etc/sudoers开放的权限只有 440,仅可读。若发现sudoers文件具有可写权限,则需要警惕。
1 | [root@localhost ~]# chmod 744 /etc/sudoers |
/etc/group文件是用户组配置文件,即用户组的所有信息都存放在此文件中。排查是否有用户被添加到了root组中。
1 | [root@localhost ~]# cat /etc/group |grep root |
历史登录信息
1 | [root@localhost ~]# last |
日志审查
用户日志
每个用户家目录下都有:
1 | [root@localhost ~]# cat .bash_history |
登录日志
登录信息检查
1 | [root@localhost ~]# cat /var/log/secure* |
系统服务日志
1 | cat /var/log/cron |
apache 日志
apache日志的存放目录:cat /var/log/apache2/access.log
- 当前WEB服务器中联接次数最多的ip地址:
netstat -ntu |awk '{print $5}' |sort | uniq -c| sort -nr - 查看日志中访问次数最多的前10个IP:
cat access_log |cut -d ' ' -f 1 |sort |uniq -c | sort -nr | awk '{print $0 }' | head -n 10 |less - 查看日志中出现100次以上的IP:
cat access_log |cut -d ' ' -f 1 |sort |uniq -c | awk '{if ($1 > 100) print $0}'|sort -nr |less - 查看最近访问量最高的文件:
cat access_log |tail -10000|awk '{print $7}'|sort|uniq -c|sort -nr|less - 查看日志中访问超过100次的页面:
cat access_log | cut -d ' ' -f 7 | sort |uniq -c | awk '{if ($1 > 100) print $0}' | less - 统计某url,一天的访问次数:
cat access_log|grep '12/Aug/2009'|grep '/images/index/e1.gif'|wc|awk '{print $1}' - 前五天的访问次数最多的网页:
cat access_log|awk '{print $7}'|uniq -c |sort -n -r|head -20 - 从日志里查看该ip在干嘛:
cat access_log | grep 218.66.36.119| awk '{print $1"\t"$7}' | sort | uniq -c | sort -nr | less - 列出传输时间超过 30 秒的文件:
cat access_log|awk '($NF > 30){print $7}' |sort -n|uniq -c|sort -nr|head -20 - 列出最最耗时的页面(超过60秒的)
cat access_log |awk '($NF > 60 && $7~/\.php/){print $7}' |sort -n|uniq -c|sort -nr|head -100
扫描
枚举工具
除了 Linux 提权总结 已经提到的自动枚举工具, 还有 lynis 可用:
项目地址:github
1 | cd lynis; |
其他日志
参考这个链接: 日志分析
脚本
用这个 脚本 来快速扫盘。
总结
跟着这个万能流程来可以减少错误和风险, 所有步骤都不要跳过:





























































