기술문서 14. 08. 13. 작성 GNU C library dynamic linker $ORIGIN expansion Vulnerability Author : E-Mail : 윤지환 131ackcon@gmail.com Abstract 2010 년 Tavis Ormandy 에 의해 발견된 취약점으로써 정확한 명칭은 GNU C library dynamic linker $ORIGIN expansion Vulnerability 이고 CVE-2010-2847 로 등록이 되어있다. 이 취약점은 Command Injection 을 사용하여 Local 환경에서의 root 권한을 획득할 수 있는 취약점을 가지고 있다. Page 1
<차 례> Abstract 1 1. 취약점 개요 4 1.1 Information 4 1.2 Target System 4 2. Background 5 2.1 Command Injection 5 2.2 File descriptor 6 2.3 Link 7 3. CVE-2010-3847 분석 8 4. Exploit 11 5. Patch 12 6. Reference 13 6.1 참고 문헌 13 6.2 참고 사이트 13 Page 2
1. 취 약 점 개 요 1.1 Information > 이름 : GNU C library dynamic linker $ORIGIN expansion Vulnerability > CVE : 2010-3847 > 발표일 : 2010 년 10 월 18 일 > 취약점 영향 : Local linux 환경에서의 일반 user 가 root 로의 권한상승 1.2 Target System - RedHat Enterprise Server 5.x - CentOS 5.x - Fedora Core 13 - Ubuntu 10 Page 3
2. Background 취약점 분석하기에 앞서서 취약점에 필요한 간략한 단어들을 설명하겠습니다. 2.1 Command Injection 시스템 명령어를 호출하는 어플리케이션을 조작하여 의도하지 않은 시스템 명령어를 실행시키는 공격 기법입니다. 예를 들어 <그림 1>과 같은 상황으로 진행될 수 있고 시나리오는 다음과 같은 순으로 진행됩니다. < 그림 1 > < 시나리오 > 1) ls 명령어를 실행시키는 프로그램을 생성 2) 자신의 디렉토리에 ls 라는 프로그램을 생성( 여기서는 /bin/sh 를 링크걸었습니다. ) 3) 환경변수의 PATH 에 자신의 디렉토리 경로를 추가시켜 줍니다. 4) 1 번에서 생성한 바이너리를 실행함으로써 자신의 디렉토리에 있는 ls 가 시작되고, 이 ls 는 /bin/sh 의 링크파일이기 때문에 shell 을 획득할 수 있습니다. Page 4
2.2 File descriptor - 파일을 사용할 때 각 파일에 대한 정보를 유지하는 기억장치의 한 영역 - 할당받은 메모리의 영역을 정수로 표기 - 0 : 표준 입력, 1 : 표준 출력, 2 : 표준 에러, 나머지는 할당되는 순서대로 매겨진다. < 그림 2 > 모든 file 또는 data 들은 입출력 장치와 통신을 하기 위해서는 반드시 메모리를 중심으로 움직여야 합니다 그러기 위해서는 메모리 영역에 이들만을 위한 영역을 할당해주어야 하며, 이때 할당된 영역을 정수로 표시하게 됩니다. 이를 File Descriptor 라 하고, 입출력을 하기 위해 메모리에 특정 영역을 할당해 주는 기법을 Memory mapped IO 라고 합니다. 2.3 Link 리눅스의 링크에는 symbolic link 와 hard link 가 있습니다. 먼저 하드링크란 파일명은 다르지만 동일한 Inode( 파일속성, 파일 위치 등 파일 정보를 가짐 )를 가르키는 것을 말합니다. 하드링크로 이루어진 파일들은 원본 파일과 inode 는 같고 이름만 다른 동일한 파일을 뜻합니다. 또 심볼릭 링크는 하드링크와 달리 원본파일의 경로를 받아 오는 링크입니다. 사용자가 링크걸린 파일을 실행하면 커널에서는 원본파일의 경로를 찾아서 원래 파일에 접근을 합니다. 그렇기 때문에 원본파일이 손상되면 링크된 파일은 실행되지 않습니다. > command : ln [src path] [dstpath] Page 5
2.4 SetUID & Sticky bit 1) SetUID user 의 권한으로 특정 프로그램을 실행할 때 프로그램의 소유자권한을 잠시 위임 받는 개념입니다. ping 명령어를 예로 들면, raw socket 을 전송할 때는 root 의 권한이 있어야지만 전송이 가능합니다. 하지만 일반 유저도 ping 을 입력하여 결과를 볼 수 있다는 것은 set uid 가 설정되어서 raw socket 전송을 할 때 root 의 권한을 잠시 위임받았기 때문입니다. ( chmod 시 4xxx 를 부여 ) < 그림 3 > 2) Sticky bit 파일을 생성한 소유자만이 대상 파일을 삭제할 수 있습니다. A 라는 파일에 권한이 777 로 설정되어 있어서 다른 사용자가 해당 파일을 삭제하려고 시도할 때 A 파일에 Sticky bit 가 걸려 있다면 삭제는 불가능합니다. ( chmod 시 1xxx 을 부여하면 sticky bit 가 설정 됨. ) < 그림 4 > Page 6
3. CVE-2010-3847 분 석 이 취약점이 발표되기 이전의 리눅스에서는 Library 를 로딩 할 때 $ORIGIN 사용을 못하도록 설정해두었습니다. 하지만 2010 년에 GLIBC 를 업데이트 하면서 $ORIGIN 을 다시 사용할 수 있게 되었습니다. Tavis 는 $ORIGIN 과 LD_AUDIT 환경변수를 사용하여 로컬 권한 상승 취약점을 발견했습니다. 3.1 $ORIGIN $ORIGIN 은 실행파일의 경로를 저장하고 있고, 이 값은 ELF 바이너리 안의 DT_PATH 또는 DT_RUNPATH 에 저장되어있습니다. (DT_PATH 란, 동적 로더가 라이브러리를 찾을 때 검색할 경로) 3.2 LD_AUDIT( rld-audit ) LD_AUDIT 이란, Linker auditing API 와 같이 사용되고 LD_PRELOAD 처럼 프로그램이 실행되기 전에 라이브러리를 불러오는 환경변수입니다. 그리고 SUID bit 가 설정된 프로그램은 이 환경변수를 무시하고 자신만의 라이브러리 경로를 검색하여 사용합니다. 하지만 SUID 가 설정된 프로그램을 Hard Link 로 설정해서 Sticky bit Directory 에 생성하면 LD_AUDIT 을 사용자가 지정할 수 있습니다. - ld : 리눅스 환경에서의 동적 Linker 입니다. 프로그램이 라이브러리를 로드할 때 필요로 하며 사용될 때마다 해당 경로를 참조하여 불러옵니다. 보통 /lib 과 /usr/lib 에 있고 사용자가 환경변수로 설정할 경우 LD_LIBRARY_PATH 변수에 저장되어 있습니다. - rtld-audit : GNU 동적 링커는 동적링크 이벤트가 발생할 때 프로그램에 알리는 auditing API 를 지원합니다. Page 7
3.3 GBLIC ELF loader : elf/dl-load.c GLIBC 2.1 버전이전의 버전에서는 $ORIGIN 을 사용 못하도록 되어있었는데 GLIBC 2.1 버전으로 업데이트가 되면서 $ORIGIN 을 다시 사용할 수 있게 되었습니다. $ORIGIN 을 사용하기 위해서는 아래의 3 가지 함수를 통과해야하는데 차례로 설명하겠습니다. _dl_init_paths() -> _dl_dst_substitute() -> _is_dst() (Trigger) < _dl_init_path() > 위의 이미지는 DST( Dynamic String Token)를 확장하는 부분입니다. 이 함수 내부에서 메모리를 할당해주기 위해 _dl_dst_subtitue()함수를 호출하고 있습니다. Page 8
< _dl_dst_substitute() > 빨간색으로 강조한 부분만 보면 되겠습니다. 라이브러리를 추가하기 위해서는 name 첫 바이트 위치에 $ 가 오고, 그 후 is_dst()함수를 이용해 $뒤의 문자열인 ORIGIN 을 파싱합니다. < is_dst() > 문자열의 끝만을 분석하여 끝이 NULL 이거나, colon( : )일 경우에 파싱됩니다. 인자로 넘어온 문자열은 Library 경로들이 나열된 구조체이며 만약 이 인자 중에서 가장 앞부분에 공격자가 원하는 라이브러리를 로드한다면 해당 라이브러리가 실행 될 것입니다. Page 9
String : /tmp/ex : /usr/lib/lib.so : /lib/ld.so 예를 들어 위의 String 을 is_dst()의 인자로 받으면 가장 처음 있는 라이브러리인 /tmp/ex 가 파싱이 되고 바이너리를 실행할 때 로드되는 라이브러리는 /tmp/ex 가 됩니다. 4. Exploit 지금까지 분석한 정보들을 토대로 실제 System 에서 권한상승을 해보겠습니다. 저는 다음과 같은 환경에서 실습을 했습니다. Exploit 의 과정은 다음과 같습니다. 1) $ORIGIN 을 사용하여 exploit 을 진행 할 것이기 때문에 user 의 권한이 있는 Directory( /tmp, /usr.. )에 새로운 Directory 를 하나 생성합니다. 2) LD_AUDIT 은 SUID 가 설정된 바이너리에서 사용을 못하기 때문에 SUID 로 설정된 바이너리( ping, passwd.. )를 새로 생성한 Directory 에 Hard Link 된 파일을 생성합니다. 3) Hard Link 된 파일에 File Descriptor 를 부여합니다. 4) 뒷부분에서 라이브러리의 이름을 $ORIGIN 과 동일하게 만들기 위해 생성한 Directory( /tmp/ex/ )를 삭제합니다. 이때 삭제를 하더라도 proc 에는 /tmp/ex/target 이 유지되어 있고 target 의 $ORIGIN 은 여전히 /tmp/ex 값을 가지고 Page 10
있습니다. 5) exploit 에 사용될 라이브러리를 생성하는데 library 의 파일명을 4)에서 언급한 /tmp/ex 값으로 생성합니다. 6) 최종 공격부분인 LD_AUDIT= \$ORIGIN exec /proc/self/fd/3 을 설명하겠습니다. 우선 $ORIGIN 의 값은 /tmp/ex/target 의 경로인 /tmp/ex 가 들어가 있습니다. 이 값( /tmp/ex )을 LD_AUDIT 에 넣는데 LD_AUDIT 은 이 경로( /tmp/ex )를 Library 로 인식하게 됩니다. 즉, fd/3 을 실행할 때 LD_AUDIT 는 공격코드가 삽입된 라이브러리( /tmp/ex )를 로드하게 되어 root 권한의 shell 을 획득하게 됩니다. 5. Patch 위의 취약점을 보안하기 위해서는 root directory( / )와 Sticky bit Directory( /tmp, /usr..)를 따로 Mount 시켜야 합니다. 이 이후로 patch 된 것은 Open 된 파일은 삭제를 하지 못하고 SUID 프로그램을 Hard Link 걸지 못한다. Page 11
6. Reference 6.1 참고 문헌 Ÿ http://math.ut.ee/~mroos/turve/2010/referaadid/referaat-ivanov.pdf 6.2 참고 사이트 Ÿ Ÿ Ÿ http://marc.info/?l=full-disclosure&m=128739684614072&w=2 http://www.exploit-db.com/exploits/15274/ https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/dl-load.c;h=a7162eb77de7a53823 5a43 Page 12