监控哪些程序调用了可执行文件

Gil*_*il' 5 linux monitoring executable files

我想知道什么程序调用了特定的可执行文件,包括该可执行文件何时通过 shebang 行用作解释器。

这与了解哪个程序访问特定文件并不完全相同。例如,auditctl -w /usr/bin/myprogram告诉我程序正在由……本身执行,因为审计事件是在成功execve调用后生成的。

一种选择是用包装程序替换可执行文件,就像这样......

#!/bin/sh
logger "$0: executed by uid=$(id -u) ruid=$(id -ur) cmd=$(ps -o args= -p $PPID)"
exec "$0.real" "$@"
Run Code Online (Sandbox Code Playgroud)

但这需要移动实际文件,这是破坏性的(文件不能是只读的,它与包管理器所做的修改相冲突,等等)。如果将程序用作脚本的解释器,则它不起作用,因为 shebang 不嵌套。(在那种情况下,auditctl -w /usr/bin/interpreter确实给出了一个有用的结果,但我想要一个适用于这两种情况的解决方案。)如果/bin/sh是 bash,它也不适用于 setuid 程序,因为 bash 会删除特权。

我如何监视特定可执行文件的执行,包括将可执行文件用作 shebang 解释器,特别是记录有关调用进程的有用信息(不仅是 PPID,而且至少是进程名称或父可执行文件路径,理想情况下还有调用用户和参数)?最好不要用包装器替换文件。特定于 Linux 的解决方案很好。

PSk*_*cik 5

这将是hacky,但如果它是一个动态链接的可执行文件,您可以设置一个全局预加载,/etc/ld.so.preload如果它检测到您在正确的可执行文件中,它只会触发一个日志钩子。

就像是:

#define _XOPEN_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define TARGET "/some_executable"

__attribute__((constructor)) 
static void 
logger(int argc, char** argv){ 
    /*catch own argv right here and parent's later from /proc */

    static char buf[sizeof(TARGET)];

    readlink("/proc/self/exe", buf, sizeof(buf)-1);

    if ( 0==strcmp(TARGET, buf)){
        /* ... */
        syslog(/*...*/);
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的明显缺点是它会稍微延迟系统上每个动态链接的可执行文件的执行,但我的测量表明延迟非常小(<1ms,其中 fork+exec 的成本约为 2ms)。

至于删除权限问题,您可以有一个小的 setuid-root 二进制文件,它会无条件地读取和回显其祖父母 proc 文件(status最有可能的文件),可能当且仅当其父级是您要记录其父级的可执行文件时. 然后,您可以在日志挂钩中生成该 setuid 可执行文件,以获取有关可执行文件父级(setuid 助手的祖父级)的信息。


meu*_*euh 5

您可以使用fanotify API 来侦听对给定文件系统中的文件进行的所有打开。该信息以事件结构流的形式提供,其中包括提供正在打开的文件名的文件描述符和请求者的进程 ID。

您的程序可以选择允许或拒绝打开,这意味着它可以/proc在允许它继续之前查找 pid以找到执行打开的命令和用户,而不会出现竞争条件。

手册页fanotify(7)提供了一个完整的 C 程序来获取事件和对打开的请求进行调解,所以你只需要插入一些额外的行来从/proc. 请注意,您将获得整个挂载点中所有文件的事件,因此请在专门挂载的小型文件系统上测试您的代码。

fatrace命令显示了如何在一个简单的测试中获取这些信息。例如,复制/bin/bash/tmp/bash,然后~/test2

#!/tmp/bash
pwd
Run Code Online (Sandbox Code Playgroud)

并仅fatrace/tmp文件系统上运行(假设它是一个单独的 tmpfs 挂载),通过使用选项-c来侦听当前目录文件系统,并-f O侦听打开:

cd /tmp
sudo fatrace -c -f O
Run Code Online (Sandbox Code Playgroud)

现在当你跑

sh -c 'echo $$; ~/test2'
expect -c 'spawn /home/meuh/test2'
~/test2
Run Code Online (Sandbox Code Playgroud)

你应该看到记录

sh(7360): RO /tmp/bash
expect(7414): RO /tmp/bash
bash(7590): RO /tmp/bash
Run Code Online (Sandbox Code Playgroud)