【发布时间】:2019-07-05 23:15:49
【问题描述】:
TL;DR:我可以在执行二进制文件和 RUID != UID 时跳过加载放置在 ld.so.preload 中的共享库或其中的特定代码吗?
嗨。
我正在编写一个共享对象,一个库,我通过 ld.so.preload 加载它以挂钩一些函数。我想知道是否可以根据某些条件跳过加载此类库或其中的某些部分。
上下文:我正在处理TOCTTOU(Time To Check To Time To Use)漏洞,我正在编写一个userland 库,它将通过linux's loader ld.so.preload feature 加载。主要思想是挂钩所有对文件进行操作的函数,进行一些检查,然后调用原始函数,使其对用户和其他程序透明。
现在,问题是:因为我不想让系统过载,并且我希望我的库的影响和开销尽可能小,所以我想执行它,即挂钩函数,仅当 RUID != EUID 时。这是基于文件的 TOCTTOU 前提之一,当攻击者的权限低于易受攻击的应用程序时,就会发生这种情况。
目前我想到的唯一方法是在每个函数声明周围加上:
if(RUID == EUID){
call original function;
} else {
do my checkings;
call original function;
}
编辑:上面的代码可以替换为等效的更短的代码:
if(RUID != EUID){
do my checkings;
}
call original function;
但这实际上非常糟糕,因为我要挂钩近 50 个函数以及使用 __attribute 构造函数和析构函数,这意味着在每个函数中都使用 if-else 块填充我的代码。
请记住,ld.so.preload 在任何其他库之前加载列出的库。
我想知道是否有任何方法可以根据RUID != EUID 条件不加载库,或者加载库但跳过挂钩代码。
【问题讨论】:
-
我真的不认为你可以自动地做到这一点,而不必编写一些像你展示的那样的代码。但是,您可以构建一个非常小的包装程序来检查 RUID == EUID:如果它们相等,则执行
exec(target...),否则首先预加载您的库,然后执行exec(target...)。 -
由于我的库是系统范围的,我无法为其创建任何包装器。 @MarcoBonelli 也就是说,我使用 -shared -ldl 标志对其进行编译,并将其绝对路径写入 /etc/ld.so.preload 文件中。
-
那么我认为您无能为力,除了自己重新编译加载器并在查看 ld.so.preload 之前添加所需的检查
-
我猜你是对的,我无能为力。我认为重新编译加载程序本身有点激烈。我不能假设放置在 ld.so.preload 中的每个库都需要 RUID != EUID 检查。
-
嗯,当然可以检查lib的路径和名称。
标签: c shared-libraries ld