天天看點

linux無檔案執行— fexecve 揭秘

前言

良好的習慣是人生産生複利的有力助手。

繼續2020年的flag,至少每周更一篇文章。

無檔案執行

之前的文章中,我們講到了無檔案執行的方法以及混淆程序參數的方法,今天我們繼續講解一種linux上無檔案執行的技巧,是背景朋友給我的提醒,萬分感謝,又學到了新的東西。

linux無檔案執行,首先要提到兩個函數:memfd_create 和 fexecve。

memfd_create 和 fexecve

  1. memfd_create:第一個允許我們在記憶體中建立一個檔案,但是它在記憶體中的存儲并不會被映射到檔案系統中,至少,如果映射了,我是沒找到,是以不能簡單的通過ls指令進行檢視,現在看來這的确是相當隐蔽的。事實上,如果一個檔案存在,那麼我們還是可以去發現它的,誰會去調用這個檔案呢?使用如下的指令:
lsof | grep memfd
           
  1. 第二個函數,fexecve同樣的功能很強大,它能使我們執行一個程式(同execve),但是傳遞給這個函數的是檔案描述符,而不是檔案的絕對路徑,和memfd_create搭配使用非常完美!

但是這裡有一個需要注意的地方就是,因為這兩個函數相對的比較新,memfd_create 是在kernel3.17才被引進來,fexecve是glibc的一個函數,是在版本2.3.2之後才有的, 沒有fexecve的時候, 可以使用其它方式去取代它,而memfd_create隻能用在相對較新的linux核心系統上。

fexecve的實作

今天不談memfd_create,這是linux的新特性,沒有什麼好玩的,本人對fexecve 的實作很有興趣,因為fexecve是glibc中的函數,而不是linux的系統調用。先看一下fexecve的用法,下面的fexecve_test.c 代碼是實作ls -l /dev/shm 功能。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

static char *args[] = {
    "hic et nunc",
    "-l",
    "/dev/shm",
    NULL
};

extern char **environ;

int main(void) 
{
    struct stat st;
    void *p;
    int fd, shm_fd, rc;

    shm_fd = shm_open("wurstverschwendung", O_RDWR | O_CREAT, 0777);
    if (shm_fd == -1) {
	perror("shm_open");
	exit(1);
    }

    rc = stat("/bin/ls", &st);
    if (rc == -1) {
	perror("stat");
	exit(1);
    }

    rc = ftruncate(shm_fd, st.st_size);
    if (rc == -1) {
	perror("ftruncate");
	exit(1);
    }

    p = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
	     shm_fd, 0);
    if (p == MAP_FAILED) {
	perror("mmap");
	exit(1);
    }

    fd = open("/bin/ls", O_RDONLY, 0);
    if (fd == -1) {
	perror("openls");
	exit(1);
    }

    rc = read(fd, p, st.st_size);
    if (rc == -1) {
	perror("read");
	exit(1);
    }
    if (rc != st.st_size) {
	fputs("Strange situation!\n", stderr);
	exit(1);
    }

    munmap(p, st.st_size);
    close(shm_fd);
    
    shm_fd = shm_open("wurstverschwendung", O_RDONLY, 0);
    fexecve(shm_fd, args, environ);
    perror("fexecve");
    return 0;
}
           

代碼中主要是分為了三步:

  1. 首先通過shm_open函數在 /dev/shm中建立了wurstverschwendung檔案
  2. 将ls 指令檔案寫入到wurstverschwendung檔案
  3. 通過fexecve執行wurstverschwendung檔案,因為/dev/shm在記憶體中,是以fexecve實際上是在記憶體中執行檔案。

對fexecve_test.c 進行編譯并執行,可以看到/dev/shm下面确實生成了wurstverschwendung檔案。

linux無檔案執行— fexecve 揭秘

調試角度

fexecve是如何執行記憶體中的檔案的呢?一般可以從調試和源碼的角度來探究其中的原理。首先使用strace調試一下:

strace -f -tt -T ./fexecve_test
           

從列印的日志中,找到open系統調用,從建立檔案開始關聯:

linux無檔案執行— fexecve 揭秘

大家可以看到shm_open 其實是在/dev/shm建立檔案,而execve的執行檔案為/proc/self/fd/3,為程序中打開的檔案符号連結,這個指向的就是shm_open建立的檔案,但是從監控execve的角度來說, execve無法擷取執行檔案的路徑,進而實作了混淆。

源碼角度

從上文中,我們大緻知道了原理。具體細節還是要看源碼:glibc中的代碼庫中(https://github.com/jeremie-koenig/glibc/blob/master-beware-rebase/sysdeps/unix/sysv/linux/fexecve.c)。

#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>


/* Execute the file FD refers to, overlaying the running program image.
   ARGV and ENVP are passed to the new program, as for `execve'.  */
int
fexecve (fd, argv, envp)
     int fd;
     char *const argv[];
     char *const envp[];
{
  if (fd < 0 || argv == NULL || envp == NULL)
    {
      __set_errno (EINVAL);
      return -1;
    }

  /* We use the /proc filesystem to get the information.  If it is not
     mounted we fail.  */
  char buf[sizeof "/proc/self/fd/" + sizeof (int) * 3];
  __snprintf (buf, sizeof (buf), "/proc/self/fd/%d", fd);

  /* We do not need the return value.  */
  __execve (buf, argv, envp);

  int save = errno;

  /* We come here only if the 'execve' call fails.  Determine whether
     /proc is mounted.  If not we return ENOSYS.  */
  struct stat st;
  if (stat ("/proc/self/fd", &st) != 0 && errno == ENOENT)
    save = ENOSYS;

  __set_errno (save);

  return -1;
}

           

關鍵部位代碼:

char buf[sizeof "/proc/self/fd/" + sizeof (int) * 3];
  __snprintf (buf, sizeof (buf), "/proc/self/fd/%d", fd);

  /* We do not need the return value.  */
  __execve (buf, argv, envp);
           

fexecve本質上還是調用execve,隻不過檔案路徑是在/proc中。fexecve_test中實作的功能,可以用bash來簡單描述,作用是等同的:

linux無檔案執行— fexecve 揭秘

最後

關注公衆号:七夜安全部落格

linux無檔案執行— fexecve 揭秘

回複【1】:領取 Python資料分析 教程大禮包

回複【2】:領取 Python Flask 全套教程

回複【3】:領取 某學院 機器學習 教程

回複【4】:領取 爬蟲 教程

回複【5】:領取 編譯原理 教程

回複【6】:領取 滲透測試 教程

回複【7】:領取 人工智能數學基礎 教程

本文章屬于原創作品,歡迎大家轉載分享,禁止修改文章的内容。尊重原創,轉載請注明來自:七夜的故事 http://www.cnblogs.com/qiyeboy/

本文章屬于原創作品,歡迎大家轉載分享,禁止修改文章的内容。尊重原創,轉載請注明來自:七夜的故事 http://www.cnblogs.com/qiyeboy/

繼續閱讀