setuid 二进制文件的 LD_PRELOAD

setuid 二进制文件的 LD_PRELOAD

我正在尝试覆盖程序的 malloc/free 函数,这需要 setuid/setgid 权限。为此,我使用 LD_PRELOAD 变量。根据ld文档,我需要将我的库放入标准搜索目录之一(我选择/usr/lib)并为其授予 setuid/setgid 权限。我已经这么做了。但是,我仍然无法链接到我的 .so 文件,出现错误:

object 'liballoc.so' from LD_PRELOAD cannot be preloaded: ignored

可能的原因是什么?在没有 setuid/setgid 权限的程序上测试了这个 .so 文件,一切正常。操作系统:红帽7.0

答案1

根据 ld 文档,我需要将我的库放入标准搜索目录之一(我选择/usr/lib

这就是错误。你应该把它放进去/usr/lib64(假设你的机器是 x86_64)。

我刚刚在 Centos 7 VM 上尝试了联机帮助页中的配方(应该与 RHEL 7 相同)并且它有效:

作为根用户:

cynt# cc -shared -fPIC -xc - <<<'char *setlocale(int c, const char *l){ errx(1, "not today"); }' -o /usr/lib64/liblo.so
cynt# chmod 4755 /usr/lib64/liblo.so

作为使用 setuid 程序的普通用户:

cynt$ LD_PRELOAD=liblo.so su -
su: not today

使用该功能是否是一个好主意是完全不同的事情(恕我直言,事实并非如此)。

答案2

man ld.so

安全执行模式
出于安全原因,如果动态链接器确定二进制文件应在安全执行模式下运行,则某些环境变量的影响将被无效或修改
[...]
如果满足以下条件,则二进制文件将以安全执行模式执行:

  • 进程真实有效用户ID不同

[...]
LD_预加载
在安全执行模式下,包含斜杠的预加载路径名将被忽略。此外,共享对象仅从标准搜索目录预加载,并且仅当它们启用了 set-user-ID 模式位时(这不是典型的)。

如果执行 SUID 二进制文件,则会出现这种情况:真实 UID 和有效 UID 不同。但是,如果此二进制文件执行不同的(非 SUID)二进制文件,则父级的 EUID 将成为子级的 RUID 和 EUID:

sudo sleep 1000 &

ps -o pid,ruid,euid,args --pid $! --ppid $!
  PID  RUID  EUID COMMAND
 7286  1000     0 sudo sleep 1000
 7287     0     0 sleep 1000

因此,如果您想避免 LD_PRELOAD 限制,您可以通过 sudo 调用您的二进制文件,或者创建一个包装器 SUID 二进制文件来调用实际的二进制文件。

答案3

这样做的原因是为了防止恶意代码提升。 AC 程序确实不是在main()中开始运行。相反,首先调用 C 运行时库,它设置其环境(包括 STDIO 流)、任何不是编译时常量的全局变量,然后调用 main()。

恶意行为者可以使用 LD_PRELOAD= 使用自定义库覆盖 libc.o 库,并修改启动函数(例如) - 恢复 LD_PRELOAD,然后调用 /bin/sh。如果 SUID 进程没有忽略 LD_PRELOAD=,则该用户可以运行 /bin/passwd,并且他们现在拥有 root shell。他们现在可以从那里安装 rootkit 等。

相关内容