有些东西一直在破坏我的系统,但我无法确定是哪个程序。这种情况每小时发生几次。我在日志中找到了 PID,但该程序的寿命很短,所以当我能找到它时ps -fp pid
,它已经消失了。
我可以设置日志记录以查看之后的所有 PID 吗?哪个程序说 pid 12345 带有时间戳?我尝试过find /proc/ -maxdepth 2 -name cmdline -mmin -3 -not -type d|while read l;do echo -n $l;cat $l;done
多次运行该程序及其变体,但都没有成功。我正在运行 Ubuntu 16.04。
答案1
我曾经管理过一个公共 shell 主机,用户在其中运行各种偶尔会出错的进程。我们有如下所示的 root cron 作业:
* * * * * (date; ps auxwwww) >> /var/log/ps.log
* * * * * (date; lsof -n) >> /var/log/lsof.log
我们还为这两个日志文件安装了轮换,以免它们溢出。
当我们发现系统出现问题时,我们会检查 ps 日志以捕获恶意进程的名称及其参数,并检查 lsof 日志以查找该进程的可执行映像以及它打开的任何有趣的文件。
但是,如果您要查找的恶意进程运行时间只有几秒钟或更短,那么上述脚本不太可能捕获该进程,因为这些脚本每分钟只运行一次。您可以编写自己的监控脚本,以更快的速度运行上述命令,例如每秒运行一次。
如果这还不足以捕获它,您将需要某种东西来从系统中的每个进程中清除数据。Ubuntu 16.04 机器应该能够运行相对较新的性能工具,例如 bpf:
http://www.brendangregg.com/blog/2016-06-14/ubuntu-xenial-bcc-bpf.html
如果不行,您可以尝试对恶意进程的父进程使用 strace,假设您知道它是什么。如果是 cron 运行的某个程序或用户通过 ssh 登录,那么精心编写的 strace 命令(仅捕获进程事件并忽略其他所有内容)可能会起作用 - 但要非常小心,因为它可能会造成破坏,尤其是当您一次跟踪太多东西时。
最后,您无需指定系统上发生了什么“恶作剧” - 有多种方法可以根据系统事件(文件更新、网络接口上出现数据包、CPU 过高)触发命令,这些命令可能会根据您的症状为您发挥作用。
答案2
您可以尝试创建一个 cron 任务,提取新进程并将其记录到文件中。
例如,每分钟执行一次 ps 命令,只选择上次 cron 执行之后的进程并将其记录到文件中。您有机会捕获它。
答案3
首先,我运行这个程序来了解 10 秒内消耗了多少 PID。您可以根据需要调整睡眠时间。
$ bash -c 'echo $$'; sleep 10; bash -c 'echo $$'
示例输出。这告诉我 10 秒内消耗了近 200 个 PID,大约每秒 20 个 PID。
11355
11528
这是我用来查找消耗 PID 的内容的方法。我使用“L”选项来包含线程。同样,您可以调整睡眠时间。
$ ps -eLf | awk '{print $1,$2,$3,$8}' > x1; sleep 0.5; ps -eLf | awk '{print $1,$2,$3,$8}' > x2; diff x[12]
当我除了运行的命令之外没有捕获任何内容时,输出如下所示。
1149,1150c1149,1150
< mudd 18109 1684 ps
< mudd 18110 1684 awk
---
> mudd 18187 1684 ps
> mudd 18188 1684 awk
这是我快速而粗略的方法。这是一个 Python 脚本,它在无限循环中执行相同的操作。psutil
必须将模块添加到 Python2 中pip install psutil
才能使用此功能。我time.sleep
在循环末尾添加了一个以减慢速度,但这是可选的。
#! /usr/bin/env python
import datetime
import time
import psutil
prev_pid2details = {}
pid2details = {}
first_pass = True
while True:
for p in psutil.process_iter():
try:
start_time = str(datetime.datetime.fromtimestamp(p.create_time()))[:22]
key = (p.pid, start_time)
if not first_pass and key not in prev_pid2details:
print key, p.ppid(), p.name(), p.cmdline()
pid2details[key] = (p.ppid(), p.name(), p.cmdline())
except psutil.NoSuchProcess:
continue
print '---'
prev_pid2details = pid2details
pid2details = {}
first_pass = False
time.sleep(0.3)
ps
上述方法并非万无一失。下面是一个通过比较命令或的输出来使用无法跟踪的 PID 的示例psutil
。
$ while true; do bash -c 'exit'; done