초보자를 위한 리눅스 루트킷(RootKits). 침입방지에서 제거까지
소개(Introduction)
어느날 집에서 리눅스 유저 그룹으로부터 온 메일 리스트를 읽고 있는 중에, 도움을 요청하는 것을 발견했다. 그건 귀찮은 문제에 직면한 초보 리눅스 유저로부터 배달되어 온 것이었다. 리눅스 시스템에서 몇몇 루틴을 체크하던 중, 그는 유저 아이디 '0(즉 루트(root)-관리자)'로 등록된 한 명의 유저를 발견했다. 처음 든 생각은 그것이 루트킷(rootkit)일 수 있다는 것이었다. 그는 어떻게 그것이 정말 루트킷인지 검증할 수 있는지 알고 싶었고 시스템으로 부터 어떻게 제거하는지도 알고 싶었다. 그는 더 나아가 이런 종류의 공격이 다시 일어나지 않도록 보장하는 예방책을 알려줄 것을 요청했다. 이런 상황 때문에 나는 루트킷에 대한 이해와 루트킷이 끼치는 영향을 이해하기 위한 목적으로 이 보고서를 만들게 되었다. 또한 이 보고서에서는 루트킷을 모니터링하는 방법과 그것을 제거하는 절차에 대해서도 논의하고자 한다.
루트킷이란 무엇인가?
"http://www.whatis.com"에 따르면 "루트킷은 해커가 침입을 위장하기 위해 사용하여 한대의 컴퓨터 또는 일련의 컴퓨터 네트워크에 대한 관리자 접근권한을 획득하는 도구(프로그램)의 집합이다(역자주-앞에 게시한 루트킷(Rootkit) 참조). 루트킷은 일반적으로 리눅스, BSD, SunOS등 유닉스 운영체제 계열을 대상으로 만들어진다. 이 보고서는 리눅스 운영체제를 위해 만들어진 루트킷에 주안점을 둘 것이다. 기본적으로는 같은 기능을 수행하는 루트킷에는 많은 다른 버전들이 있다. 잘 알려진 리눅스 루트킷에는 LRK, tOrn, Adore등이 있고, 윈도우 루트킷에는 NTROOT, NTKap, Nullsys등이 있다. 이 루트킷의 파일 복사본과 관련된 세부 정보는 Packet Storm 사이트에서찾을 수 있다.
http://packetstormsecurity.nl/UNIX/penetration/rootkits/
루트킷은 공격자의 존재를 숨기기 위해 만들어질 뿐만 아니라, 미래의 관리자 레벨(루트)접근을 획득하기 위해 사용되기도 하며, DDoS(distributed denial of service)공격을 시작하거나, 또는 재정적인 정보 및 기밀정보를 습득하는데 사용되기도 한다. 루트킷은 공격자를 숨기기 위한 목적으로 만들었기 때문에, 루트킷이 어떤 기능을 갖고 있는지 이해할 필요가 있다. 루트킷이 설치될 때, ls,ps,netstat 같이 일상적으로 사용되는 많은 명령어들을 덮어쓴다. 이런 명령어들을 덮어씀으로써, 루트킷의 잠입을 관리자로부터 숨길 수 있다.
다음의 시나리오를 살펴보라 -
침임자는 패치되지 않은 애플리케이션에 대해 최근에 공표된 취약성을 통하여 이제 막 시스템에 접근하였다. 그러면, 침입자는 루트킷 설치프로그램을 기동한다. 이 루트킷은 'ls' 명령어를 막 덮어썼다. 이렇게 함으로써 어느 때든지 트로이목마화된(trojaned) 'ls' 명령어가 실행됨으로써 루트킷에 의해 설치된 모든 파일은 화면에 나타나지 않게 된다. 이 루트킷은 'ps'의 트로이목마화된 버전을 인스톨하기도 한하여 결국에는, 스니퍼(sniffer), 백도어(backdoor), 로그 파싱(parsing)프로세스 등도 화면에 보이지 않게 된다. 'ls' 와 'ps'명령어 만이 루트킷에 의해서 덮어쓰여질 수 있는 명령어는 아니다. 다음은 루트킷에 의해 덮어쓰여지는 일반적인 명령어들의 목록이다.
netstat: 현재 시스템에 연결되어 있는 네트워크 커넥션들, 라우팅 테이블(routing tables), 인터페이스 통계(interface statistics)에 관한 정보를 표시해 주기 위해 사용되는 유용한 툴. Netstat은 침입자에 의해서 시스템에 대한 내부로의 및 외부로의 연결을 숨기기 위해서 루트킷에 의해 수정된다.
du: 파일의 저장공간 사용율을 화면에 표시하기 위해 사용되는 명령어이다. 'ls' 명령어와 매우 유사한 이 'du'는 계층적 디렉토리 구조를 보여준다. 또한 각각의 파일 또는 이렉토리가 얼마나 많은 디스크 공간을 사용하는지 보여준다. du는 루트킷에의해 설치된 파일과 디렉토리를 숨기기 위해 주로 트로이목마화 된다.
find: 디렉토리 계층그조 하에서 파일들을 찾기위해 사용된다. find 명령어를 변형시킴으로써 침입자는 루트킷에 의해 설치된 이미 알려진 파일을 관리자가 찾기 어렵게 만든다. 'ls','du' 와 같이 find는 루트킷 관련 파일의 존재를 숨기기 위해 트로이목마화 된다.
ifconfig: 네트워크 인터페이스 관련사항을 설정하고 화면에 표시하기 위해 사용. 스니퍼(sniffer)가 설치되서 실행되면, 네트워크 인터페이스는 promiscuous 모드에 위치하게 된다. 인터페이스를 'Promiscuous mode'로 설정하는 것은 네트워크 인터페이스로 하여금 네트워크 상에 있는 패킷을 가로채서 읽을 수 있도록 하는 것이다. ifconfig는 인터페이스가 'promiscusous mode'상태에 있다는 것을 감춤으로써 스니퍼(sniffer)또는 패스워드 수집기(password grabber)의 존재를 숨기는 기능을 하도록 변형된다.
inetd (xinetd): 인터넷 서비스를 제공하는 프로그램을 시작시키기 위해 설계된 '슈퍼서버'
(x)inetd는 그때 그때 적절한 서버를 생성시켜 서비스 연결 요청을 받아들인다. 많은 루트킷은 어떤 한 특정한 포트에 접근되었을 때, 루트킷 서비스를 실행시키도록 환경설정 파일에 자신들의 애플리케이션을 첨부한다.
killall: 프로세스를 중단시키는 명령어. Killall은 대부분 루트킷에서 트로이목마화 됨으로써 관리자가 루트킷이 설치한 특정한 프로세스를 중단할 수 없게 된다.
login: 시스템에 접속인증시 사용되는 데몬. 로그인 데몬(daemon)은 모든 사용자 이름 및 패스워드를 기록하기 위해 수정된다. 이 기록된 리스트는 추후 사용을 위해 디렉토리에 저장될 수 있고, 또는 다른 시스템에 전송될 수도 있으며, 채팅서버나 뉴스그룹 같은 대체 시스템에 표시될 수도 있다.
lsof: 열려있는 파일들을 목록화하기 위해 사용되는 명령어. 'lsof'는 루트킷에 의해 열린 파일이나 프로세스를 숨기기 위해 덮여쓰기 된다.
모든 루트킷이 명령어를 덮어쓰기 하는 것은 아니다. Adore Knark같은 루트킷은 임시로 로딩가능한 커널 모듈(loadable kernel modules:LKM)로서 만들어진다. LKM루트킷은 시스템 호출(system call)을 이용하여 실질적으로 명령어를 수정할 필요없이 명령어의 행위를 변경한다.
일반인들은 시스템 호출을 "사용자 레벨 애플리케이션이 운영체제에 애플리케이션을 위한 어떤 기능을 수행하도록 요구하는 방법"라고 정의한다. 시스템 호출 테이블에는 각 시스템 호출 목록이 들어있다.
루트킷은 자신의 존재를 숨기도록 만들어졌기 때문에, 어떤 명령어가 어떤 루트킷에 영향을 받았더라도 그 이전과 동일하게 기능해야만 한다.
** 오늘의 용어설명 **
Sniffer & Promiscuous Mode(전자상거래 혁명-최인영, 동일출판사)
스니퍼는 네트워크의 한 호스트에서 실행되어 그 주위를 지나다니는 패킷들을 엿보는 프로그램으로서 계정과 패스워드를 알아내기 위해서 침입자들에 의해 자주 사용되는데 아무리 네트워크 보안에 신경을 쓴 호스트라도 주변의 호스트가 공격당해서 스니핑을 위해 사용된다면 무력해질 수 밖에 없다. 즉, 나의 컴퓨터와 연결된 호스트 중 하나에 해커가 침입하여 스니퍼를 설치하게 되면 나의 호스트로 접근하는 루트 패스워드를 가로채어 알아낼 수 있게 되며 같은 방법으로 인접해 있는 호스트들은 모두 스니핑을 당하게 된다. 스니퍼는 이더넷의 설계상 약점에 의해 발생하는 기술로 원리를 알아보면 다음과 같다.
가장 일반적인 LAN의 구성 방법은 이더넷을 사용하는 것으로 주변에서 가장 쉽게 접하는 경우이다. 이더넷을 통한 통신방법은 매우 간단하다. A라는 호스트가 B라는 호스트로 패킷을 보내고 싶다면 호스트 A는 B와의 배타적인 연결을 통하는 것이 아니라 그 패킷을 이더넷에 뿌린다. 그리고 그 패킷은 일반적으로 수신 주소의 호스트만이 받도록 기대된다. 그러나 그것은 기대 사항일 뿐 언제라도 깨어질 위험 부담을 안고 있는 프로토콜이다. 네트워크 디바이스는 자신에게 오지 않고 다른
호스트를 향해 지나가는 패킷까지 받는 상태에 들어갈 수 있는데, 그 때를 'Promiscuous Mode'라고 부른다.
스니퍼는 바로 그 상태에서 동작한다. 이렇게 네트워크의 설계상에 커다른 약점이 있기 때문에 스니퍼에 의한 공격은 치명적이며 일부 OS를 제외하고는 찾아내기가 곤란한 경우가 많고 이를 막기 위해 많은 부담이 따른다. 게다가 스니퍼의 핵심을 이루는 코드는 대부분의 OS에서 독립된 프로토콜로서 지원을 하는데 SunOS의 NIT, IRIX의 SNOOP이 좋은 예이다. 잘만 이용하면 침입자들을 상대하는 관리자들에게 큰 무기가 될 수 있다. 즉, 네트워크를 감시하여 해커를 잡는 데 사용할 수 도 있다. 예를 들면 netlog라는 좋은 툴이 이미 있다.
(ftp://ftp.cert-kr.or.kr/pub/tools/etc/netlog/netlog -1.2.tar.gz)은 telnet과 ftp모듈이 제외되어 있는 것이 이툴의 성격을 잘 말해 주고 잇다. 패스워드 스니핑에 사용되는 것을 막기 위함일 것이다.
스니퍼는 일반적으로 다음과 같은 일련의 동작을 하는 코드로 구성된다.
1. 네트워크 디바이스를 열어서 "Promiscuous Mode"로 만든다.
2. 지나가는 모든 패킷을 읽는다.
3. 패킷을 필터링해서 발신 및 수신 주소, 서비스(telnet, rlogin, ftp, smtp등), 그리고 계정과 패스워드가 포함된 데이터를 구분해서 출력한다.
inetd(원영식,FreeBSD user group)
inetd는 super daemon이라고 합니다.
즉 여러 서버 프로그램들을 관리하는 서버 프로그램이라고 할까요... inetd는 메모리에 항상 떠 있으면서 클라이언트에서 요청이 있을 때마다 그에 적절한 서버 프로그램을 찾아서 실행시켜 주는 것입니다. 필요한 설정은 /etc/services와 /etc/inetd.conf 두 파일에 들어 있습니다. services는 서비스와 포트 번호를 설정하는 것이고, inetd.conf는 서비스와 해당 서버 프로그램을 설정하는 것입니다.
ftp를 inetd와 standalone 두 가지로 모드로 한다는 것은 말 그대로 ftp 서버를 inetd 관리 하에 둘 것인가, 아니면 inet와 관계 없이 독립적으로 실행할 것인가를 결정하는 것입니다. inet 모드로 운영하면 클라이언트로부터 요청이 있을 때마다(ftp 접속 요청이 있을 때마다) inet가 ftp 서버 프로그램을 찾아서 실행시켜 주고, ftp 접속이 끊어지면 다시 실행을 중단시킵니다. standalone 모드라면 부팅 후 항상 ftp 서버가 메모리에 상주하며 ftp 접속 요청이 생기면 직접 ftp 서비스를 시작합니다.
inet 모드의 장점은 쓸데없이 메모리를 잡아먹지 않아도 된다는 점이구요, standalone은 빠르다는 점입니다. 일반적으로 접속요구가 빈번한 웹서버는 standalone으로, 나머지 서비스는 inetd모드로 설정해 놓더군요.
DAEMON(정보통신용어사전)
컴퓨터 시스템의 운영에 관련된 작업을 후선(background) 상태로 동작하면서 실행하는 프로그램.
처리해야 할 작업 조건이 발생하면 자동으로 기동하여 필요한 작업을 실행한다. 예를 들면, 인터넷 웹 서비스를 제공하는 주 컴퓨터 시스템에서 웹 서버는 후선 상태로 동작하고 있다가 통신망상의 웹 브라우저로부터 자료 요청이 있으면 작업을 실행한다.
LKM(en.wikipedia.org/wiki/LKM)
Linux Loadable Kernel Modules, or LKM, are object files that contain code to extend the running kernel, or so-called base kernel. They are typically used to add support for new hardware, filesystems or for adding system calls. When the functionality provided by a LKM is no longer required, it can be unloaded, freeing memory.
리눅스 로더블 커널 모듈(Linux Loadable Kernel Modules), LKM은 소위 베이스 커널(base kernel)이라고 불리는 구동 커널을 확장하기 위한 코드를 포함한 객체 파일이다. 새로운 하드웨어나 파일시스템 또는 추가된 시스템 콜(system call)을 추가적으로 지원하기 위해 사용된다. LKM에 의해 제공되는 기능의 더이상 필요하지 않을 때, 언로드(unload)되고 메모리를 해제한다.

