如何从lsof -i的结果中找出命令的完整路径

如何从lsof -i的结果中找出命令的完整路径

lsof是一个很棒的实用程序,刚刚开始使用它。

lsof -i | grep smtp=> 这给出了以下结果。

httpd.pl  212548          global    3u  IPv4 893092369      0t0  TCP server07.host...blah...

在上面的示例中,httpd.pl是发送垃圾邮件的 perl 脚本。

我怎样才能知道命令的完整路径。即在上面的结果中,我想知道完整路径httpd.pl

我尝试在主目录中搜索,但该文件httpd.pl不存在。而且,我尝试过lsof -p PID,这也没有给出它的路径。

有什么方法可以获取该文件的完整路径吗?

注意:这种问题在共享主机环境中很常见。因此,它对于共享主机或任何网络服务器管理员来说都非常有用。

答案1

首先,您不需要通过 grep:lsof -i:$PORT选择其任何 Internet 地址使用给定 $PORT 号(或服务名称)的文件列表,因此

lsof -i:smtp

在你的例子中就足够了。

如果您已经知道命令名称,lsof -c $COMMAND请选择执行名为 $COMMAND 的命令的进程的文件列表,例如:

lsof -c httpd.pl

第三个概念:如果您知道进程的 PID,则可以使用以下命令获取其完整命令路径

ps -p $PID -o command

其中$PID是它的 PID 号。

因此,如果您需要从 lsof 的结果中找出命令的完整路径,您可以使用:

ps -p $(lsof -i:$PORT |awk 'NR>1 {print $2}' |sort -n |uniq) -o comm

或者

ps -p $(lsof -c $COMMAND |awk 'NR>1 {print $2}' |sort -n |uniq) -o comm

注意 1:awksortuniq是从输出中跳过标题行并按 PID 编号聚合列表所必需的。

注意 2:如果您使用的目标端口 $PORT 被多个进程使用(例如 https),则需要单独解析每一行:

for PID in $(lsof -i:$PORT |awk 'NR>1 {print $2}' |sort -n |uniq); do
  ps -p $PID -o comm
done

答案2

一种方法是检查该进程打开的文件。FD列中显示的类型lsof:

FD         is the File Descriptor number of the file or:

               cwd  current working directory;
               ...
               txt  program text (code and data);

所以,尝试:

lsof -a -d txt -p 212548

对于脚本,这确实显示了所使用的解释器的路径(例如/bin/bash)。对于 shell 脚本,脚本文件似乎在我的系统上的 fd 255 上打开,但对于 Perl 脚本,输出中根本没有提及脚本文件lsof

答案3

httpd.pl就是有姓名的过程。这是从进程上次执行的文件的基本名称初始化的,但也可以通过其他方式进行修改。

对于perl,只需为 赋值即可$0

$ perl -e '$0 = "httpd.pl"; sleep 10' & ps -fp $!
[2] 11954
UID        PID  PPID  C STIME TTY          TIME CMD
stephane 11954 31685  0 09:57 pts/8    00:00:00 httpd.pl

所以,不知道这是否httpd.pl是一个名为这样的文件或其他名称的文件。仍然可以使用作为或从另一个文件或从标准perl输入传递的代码来运行...-e

如果 perl 代码是从名为 的文件httpd.pl(或任何其他相关文件)加载的,您可能无法分辨,因为perl通常会在读取其内容后关闭该文件,因此它不会显示在lsof -p PID.

如果脚本确实被传递给perl解释器,并且 perl 代码随后没有修改进程名称或参数,那么您可以通过使用 . 查看其命令行参数来获得线索ps -fp PID

然后您将看到作为参数传递的文件路径。它可能是相对路径,在这种情况下,您可以查看其中的cwd条目,lsof除非脚本更改当前工作目录,否则会有所帮助。

如果脚本是由 shell 启动的,您还可以在_环境变量(grep -z '^_=' /proc/PID/environ在 Linux 上)中找到路径(同样可能是相对路径)。

无论如何,脚本很可能在启动时首先删除自己。

如果你想对于该代码httpd.pl,最好是转储该进程内存的内容(如Linux 上的gcore、附带gdb或查看/proc/PID/{maps,mem})。并查找其中的代码。

例如,#!在 NUL 分隔的记录中查找:

perl -e '$p=shift;open MAPS, "/proc/$p/maps";
  open MEM, "/proc/$p/mem" or die "open mem: $!";
  for $m (grep !m{/|\[v}, <MAPS>){
    ($a,$b) = map hex, $m =~ /[\da-f]+/g;
    seek MEM, $a, 0 or die "seek: $!";
    read MEM, $c, $b - $a or die "read: $!";
    print $c
  }' PID | grep -z '#!'

YYMV 虽然原始源代码可能不再在那里。然后,您需要查找预编译的代码并对其进行解码。

这个 stackoverflow 问答然后会帮助你做到这一点。

答案4

其本身lsof -i仅列出互联网信息。您可以添加文件信息(或显示反而)使用该-d选项。例如:

lsof -d txt | grep -E '/httpd.pl$'

因为(除非进程更改其运行名称)命令名称将与加载的实际文件名匹配。

当然,该文件必须是可执行的 - 但它加载的共享库也可以。在真正病态的情况下,您可以让一个程序从加载共享库的脚本(例如用 Python 编写)运行 - 并在进程列表中重命名自身。

根据 CentOS 线程可疑进程 httpd.pl,有一个从 PHP 脚本启动的进程,该脚本调用自身httpd.pl

对于任何感兴趣的人。这是由 php shell 安装的后门。第一轮的清理工作并没有抓住它。

另一个线程,CentOS 服务器中运行的可疑进程提供更多详细信息:

httpd.pl 是一个运行 perl 的欺骗进程。

它通常是由 php shell 设置的后门,将加载到网站的某个位置

进一步阅读:

相关内容