Security


2016/07/18 - [Security] - Shared Library Injection (1)




이전 글에 이어서 Shared Library Injection에 대해 알아보도록 하겠습니다.


이번 포스트에서는 일명 "공유 라이브러리 후킹"이라고 불리는 LD_PRELOAD을 이용한 방법에 대해 알아볼까 합니다.

사실 LD_PRELOAD를 이용하는 것은 리눅스에서 허용하는 정상적인 방법이기 때문에 공격이라고 보기는 어렵습니다.



프로그램이 실행되면서 실행에 필요한 shared library 들이 차례로 프로세스의 주소 공간으로 로딩되기 시작하는데, 만약 해당 실행 코드에 대한 라이브러리가 이미 로딩되어 있을 경우 로딩된 코드를 참조하고 없을 경우에만 로딩합니다.

따라서 동일한 코드가 여러 라이브러리에 분산되어 있더라도 가장 먼저 로딩된 코드만 사용하게 됩니다.


shared library가 로딩되는 순서는 일반적으로 다음과 같습니다.


DYNAMIC_SECTION의 NEED가 설정된 라이브러리

LD_LIBRARY_PATH

/etc/ld.so.conf

/lib, /usr/lib와 같은 표준 라이브러리 경로



DYNAMIC_SECTION

DYNAMIC_SECTION은 EFL 파일 시스템에 설정되어 있고 우선 순위가 가장 높습니다.

일반적으로 libc들이 여기에 속해 있습니다. 



LD_LIBRARY_PATH

LD_LIBRARY_PATH는 환경변수이고 라이브러리가 존재하는 경로를 추가할 수 있습니다.



/etc/ld.so.conf

/etc/ld.so.conf 파일을 열어보면 아래와 같이 /etc/ld.so.conf.d 디렉토리 하위의 모든 *.conf를 포함하도록 되어 있습니다.



해당 디렉토리에는 위와 같은 파일들이 있고, 해당 파일들은 또 아래와 같이 shared library가 존재하는 디렉토리의 경로를 포함하고 있습니다.



ld.so 또는 ld-linux.so 같은 런타임 링커는 캐시된 데이터를 참조해서 라이브러리의 경로를 파악하며 이 파일은 /etc/ld.so.cache 입니다.

해당 파일은 아래와 같이 file type은 data로 되어 있고 strings 로 열어보면 /etc/ld.so.conf.d/*.conf 파일들의 경로 내 shared library들이 포함되어 있습니다.




LD_PRELOAD


만약 LD_PRELOAD 환경 변수를 지정할 경우 프로세스는 다른 어떤 라이브러리보다도 먼저 이 환경변수에 설정된 라이브러리를 로딩하게 됩니다.


앞에서 이야기했듯이 라이브러리가 먼저 로딩되어 있다면 다음 라이브러리는 무시되고 로딩되지 않습니다. 즉 LD_PRELOAD 환경 변수를 이용하면 동일한 이름의 함수들이 로딩되기 전에 해당 함수를 오버라이딩 하는 것이 가능하게 되는 것입니다.



만약 LD_PRELOAD를 이용하여 libc의 함수들을 오버라이딩 할 수 있다면 여러가지 재밌는 일을 할 수가 있는데요, w 명령 결과에서 특정 사용자를 감추는 것을 한번 해보도록 하겠습니다.


아래는 정상적인 상황에서의 w 명령어 결과이며 현재 로그인 한 사용자인 ubuntu가 보여지는 것을 확인할 수 있습니다.




w 명령 실행 시 어떠한 일이 일어나는지 ltrace를 이용해 한번 알아보면,



...이렇습니다.


ltrace는 library call tracer로써 프로그램 실행 시 동적 호출되는 라이브러리와 시그널을 추적하는 프로그램입니다. 비슷한 프로그램으로 strace는 시스템 콜과 시그널을 추적합니다. 

root를 획득한 해커가 패스워드 크랙이 잘 안될 때 strace를 telnet이나 ssh에 걸어서 패스워드를 빼내기도 합니다. ^^;


어쨌든 ltrace 프로그램을 이용하면 w 프로그램 실행 후 터미널에 현재 로그인 한 사용자가 출력되기 전에 호출되는 라이브러리 함수들을 볼 수 있습니다. 

위의 화면에서 잘 보시면 중간쯤에 보면 strncpy 함수가 보이는데요, 이 함수에 ubutu라는 사용자 이름이 어딘가에 복사된 후 출력이 되는 것을 알 수 있습니다. 이 함수를 오버라이딩 해서 ubuntu 사용자의 목록을 지워보도록 하겠습니다.


우리가 오버라이딩 해야 할 strncpy 함수의 원형은 아래와 같습니다.

char *strncpy(char *dest, const char *src, size_t n);



이제 이 함수를 오버라이딩 해 보도록 하겠습니다.


original strncpy 함수에 대한 함수 포인터를 org_strncpy 라는 이름으로 선언합니다.

insert code 라는 주석 아래에 ubuntu 사용자에 대한 처리를 하는 코드가 들어간 후 original strncpy 함수를 호출하면 됩니다.


ubuntu 사용자에 대한 처리를 하는 코드를 넣은 완성된 라이브러리 코드는 아래와 같습니다.




아래와 같이 컴파일을 해서 라이브러리를 생성합니다.



자, 이제 생성된 라이브러리와 LD_PRELOAD 환경 변수를 이용해 w 프로그램을 실행시켜 보도록 하겠습니다.

짜잔~



원하는 결과를 확인할 수 있습니다~~



libc 내 함수만 후킹이 가능한 것일까?



자, 여기서 한가지 의문이 드는 것은 "LD_PRELOAD를 이용할 경우 libc 함수만 후킹이 가능한 걸까" 입니다.

결론부터 말씀드리면 함수명만 알 수 있다면 어떤 함수라도 가능합니다.

물론 함수명을 알아내는 것은 또 다른 일이기는 합니다. ^^;



지금까지 LD_PRELOAD를 이용한 shared library injection에 대해 알아보았습니다.

전체 소스는 아래에 올려두었습니다.

my_strncpy.cpp




이번 포스트는 여기서 마치도록 하겠습니다.


읽어 주셔서 감사합니다.








'Security' 카테고리의 다른 글

how to exploit window kernel (1)  (0) 2017.07.21
Shared Library Injection (3)  (0) 2016.08.02
Shared Library Injection (1)  (0) 2016.07.18