每次登录服务器时的 LD_PRELOAD

Posted

技术标签:

【中文标题】每次登录服务器时的 LD_PRELOAD【英文标题】:LD_PRELOAD in every log in to server 【发布时间】:2018-06-01 15:29:44 【问题描述】:

我需要在 Linux 中记录所有终端命令。 我在 C 中找到了正确工作的库,但它仅在我运行 LD_PRELOAD=/usr/local/bin/bashpreload.so /bin/bash 时才有效:

# ldd /bin/bash
    linux-vdso.so.1 =>  (0x00007ffef59f8000)
    /usr/local/bin/bashpreload.so (0x00007fe691323000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007fe691102000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fe690efe000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe690b6a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe691524000)

如果我在此之后再次登录系统,我将看不到带有 ldd 的库:

[root@XXX ~]# LD_PRELOAD=/usr/local/bin/bashpreload.so /bin/bash
[root@XXX ~]# ldd /bin/bash
    linux-vdso.so.1 =>  (0x00007ffe481f6000)
    /usr/local/bin/bashpreload.so (0x00007f3f1b808000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f3f1b5e7000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f3f1b3e3000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f3f1b04f000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f3f1ba09000)
[root@XXX ~]# exit
[root@XXX ~]# logout
Connection to XXX closed.
[sahaquiel@sahaquiel-PC ~]$ ssh root@XXX
root@XXX's password: 
Last login: Tue Dec 19 11:28:22 2017 from YYY
[root@XXX ~]# ldd /bin/bash
    linux-vdso.so.1 =>  (0x00007ffca2f98000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f19a13ff000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f19a11fb000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f19a0e67000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f19a1620000)

还有一个麻烦:如果我使用这个库,我当前的 PID 正在改变:

Last login: Tue Dec 19 11:28:54 2017 from YYY
[root@XXX ~]# echo "Library is not uploaded"
Library is not uploaded
[root@XXX ~]# echo $$
4639
[root@XXX ~]# LD_PRELOAD=/usr/local/bin/bashpreload.so /bin/bash
[root@XXX ~]# echo $$
4654
[root@212-24-57-104 ~]# ps awwufx | grep -B5 [4]654
root      1706  0.0  0.0  66256  1192 ?        Ss   10:54   0:00 /usr/sbin/sshd
root      4517  0.0  0.0 104636  4644 ?        Ss   11:27   0:00  \_ sshd: root@pts/1 
root      4519  0.0  0.0 108320  1872 pts/1    Ss+  11:27   0:00  |   \_ -bash
root      4637  0.0  0.0 104636  4624 ?        Ss   11:30   0:00  \_ sshd: root@pts/0 
root      4639  0.0  0.0 108320  1872 pts/0    Ss   11:30   0:00  |   \_ -bash
root      4654  0.0  0.0 110376  1956 pts/0    S    11:31   0:00  |       \_ /bin/bash

所以,我需要两件事:

    为每个登录用户找到LD_PRELOAD的方法; 知道为什么在此之后我在子/bin/bash 进程中工作。

谢谢!

【问题讨论】:

Stack Overflow 是一个编程和开发问题的网站。这个问题似乎离题了,因为它与编程或开发无关。请参阅帮助中心的What topics can I ask about here。也许Super User 或Unix & Linux Stack Exchange 会是一个更好的提问地点。 【参考方案1】:

这是经典的XY problem。您需要记录用户操作、确定解决方案并就该解决方案提出问题。

即使解决方案不起作用。

因为使用LD_PRELOAD 库不是记录用户命令的可靠方式。

    用户只需取消设置 LD_PRELOAD 环境变量即可。不,marking it readonly doesn't work。因为它只是用户控制的进程内存中的一个变量。 您将 LD_PRELOAD 设置为 64 位共享对象。现在每个 32 位程序都将无法运行。 无论您的预加载库如何记录数据,它都是根据用户的权限/访问权限来记录的。因此,用户可以伪造记录的数据。

如果您需要记录用户的操作,请使用旨在安全地执行此操作的系统:auditing。

【讨论】:

审核不是我案例的最佳解决方案,我今天正在探索替代方案。感谢您的建议,32 位程序失败的原因对我来说至关重要。 “您将 LD_PRELOAD 设置为 64 位共享对象。现在每个 32 位程序都将无法运行”不是真的。如果 ELF 类不同,它将被简单地忽略;除了诊断消息之外,不会发生任何不愉快的事情,并且 32 位程序仍然可以正常运行。 @usr 如果 ELF 类不同,它将被简单地忽略 错误。试试file /usr/bin/bash。你会看到/usr/bin/bash: ELF 64-bit LSB...。然后export LD_PRELOAD=/lib/libc.so,一个32 位 共享对象。之后,输入/usr/bin/bash 以尝试运行bash 的另一个副本。你得到ld.so.1: bash: fatal: wrong ELF class: ELFCLASS32,因为LD_PRELOAD指定要加载的32位共享对象是错误的。 @AndrewHenle 如您所说,使用 32 位库会产生“错误:ld.so:无法预加载来自 LD_PRELOAD 的对象'/lib/i386-linux-gnu/libc.so.6'(错误的 ELF 类:ELFCLASS32):被忽略。”。就像我说的那样,它被忽略了(/lib/i386-linux-gnu/libc.so.6 是我系统上的 32 位 libc)。【参考方案2】:
    想办法为每个登录用户安静地执行 LD_PRELOAD

您需要为所有用户设置一个共同的位置,例如/etc/profile/etc/environment。 有关更多选项/详细信息,请参阅How to set environment variable for everyone under my linux system?。

    知道为什么在此之后我在子 /bin/bash 进程中工作。

这很简单——每当你创建一个进程时,它的 PID 就不同于它的父进程 :) 当你运行 /bin/bash 时,你显然会创建另一个 shell,这就是 $$ 不同的原因。这与LD_PRELOAD 无关。如果您在没有LD_PRELOAD 的情况下运行/bin/bash,您将观察到完全相同的行为。

【讨论】:

谢谢,我还是不太明白 LD_PRELOAD 是如何工作的,需要多读。 /etc/profile 的解决方案听起来不错,但你能解释一下,如何在 shell-script 中执行库添加?添加LD_PRELOAD /usr/local/bin/mylib.so /bin/bash 就足够了吗? UPD。它不起作用:(我不能使用export,因为我需要这个库只用于/bin/bash LD_PRELOAD=/usr/local/bin/bashpreload.so 是您在 /etc/profile 中设置的方式。但要非常小心 - 根据 LD_PRELOAD 库的作用,这可能会严重影响用户,并且可能是一个安全漏洞。有关 shell 特定选项,请参阅 unix.stackexchange.com/q/117467/192153。如果您只希望它用于 bash,您可以查看 bashrc 文件。【参考方案3】:

如果有人和我一样需要: 您可以在用户通过 SSH 登录之前在/etc/security/pam_env.conf 中添加环境变量,语法如下:

LD_PRELOAD     DEFAULT=        OVERRIDE="/usr/local/bin/bashpreload.so"

【讨论】:

以上是关于每次登录服务器时的 LD_PRELOAD的主要内容,如果未能解决你的问题,请参考以下文章

LD_PRELOAD和ld --wrap

facebook api:请求publish_stream是不是需要用户每次登录时的确认

LD_PRELOAD加载动态库

LD_PRELOAD加载动态库

一种简单的hook方法--LD_PRELOAD变量

敏感信息安全传输与传输