'capable(CAP_SYS_NICE)'에 해당하는 글 1건

출처 : http://croky.tistory.com/15


LIDS Internals

글쓴이 : 채효철


*INDEX*

1. 소개
2. 중요한 소스 분석
3. 예제
4. 결론

-----------------------------
1. 소개

LIDS 는 Linux Intrusion Detection System 의 약자로서 리눅스 기반의 IDS 이다.
중국의 해커 Huagang Xie 로 부터 시작되어
최고의 보안 도구로 각광 받고 있다. 아직 국내에는 까다라온 사용법 때문에 실제로
적용된 사례가 잘 없지만 외국에는 널리 쓰이고 있다고 한다.
하지만 이름과는 다르게 IDS 의 뜻과는 달리 리눅스의 보안 강화로 요즘 유행하는
Secure OS 을 지향하고 있다.

-현재 시스템의 문제는 무엇일까?
 
  * 현재 파일 시스템은 보호되지 못한다
  * 프로세스도 보호되지 못한다
  * Access Control 모델이 부족하다
  * root 권한이 너무 막강하다.

-모듈 방식 보다 좋은점은 무엇일까?

모듈 방식은 한계가 있는것으로 알려져 있다. 유지보수가 쉬운 이유로
모듈로 작성되고 있지만 모듈 만으로 커널의 모든 자료구조를 접근할수가
없다. 물론 커널을 컴파일 할 당시에 커널에서 쓰이는 자료구조나 변수들을
export 시킨다면 가능은 하겠지만 일반적으로 필요한 것만 export 시키기 때문에
그것은 논외로 하겠다.

- 중요한 기능들

LIDS 에 어떤 중요한 기능이 있는지 살펴보기 위해 커널에 패치된 파일과 새로
생성된 파일들을 살펴보겠다. 우리의 목적은 LIDS 의 내부를 살펴보는 것이기 때문에
사용하는 방법엔 관심이 별로 없다.(물론, 분석을 할려면 어느정도는 알아야 된다)

-패치된 파일

init/main.c       /* 시작 루틴이 있음 */

kernel/fork.c     /* 프로세스 생성하는 부분 */
kernel/ksym.c
kernel/signal.c   /* 프로세스 보호 */
kernel/exit.c

fs/buffer.c
fs/dcache.c
fs/exec.c
fs/namei.c
fs/namespace.c
fs/readdir.c
fs/super.c
fs/open.c

fs/proc/base.c    /* 프로세스 감추기 */
fs/proc/root.c

-추가된 파일
kernel/lids.c     /* lids 의 핵심적 소스, 파일을 ACL 에 연결시키는등 */
kernel/klids.c          /* lids thread 이다. 초기화시 kernel_thread() 를 통해서
실행됨 */
kernel/lids_mail_script.c /* 경고를 메일로 보낸다 */
kernel/lids_syslog_script.c
kernel/lids_net.c                   /* 네트워크 관련 보호루틴 */
kernel/lids_logs.c                  /* 로그 남기는 루틴 */

소스 파일명을 보면 알수있듯이

파일 시스템 보안과 프로세스 보안으로 나눌수 있다.
proc/ 파일 아래의 소스들은 프로세스를 보호하고
fs/ 디렉토리의 소스들은 파일 시스템이 ACL 에 의해 보호되는지
체크하고 실패하면 경고를 낸다.  kernel/ 디렉토리에서 새로 생성된 파일들은 관리자에게
메일로 경고를 하거나 로그를 남긴다.


종합해 보자면 LIDS 의 특징은 다음과 같다.

보호(Protection). LIDS는 여러분의 하드 디스크에 있는 중요한 파일을 보호할 수 있다.
이때 파일시스템의 타입은 문제가 되지 않는다. 루트를 포함한 누구든지 지정된 파일을
변경할 수 없게 된다. LIDS는 또한 중요한 프로세스에 대해 kill 되어지는 것을 방지할 수
있다. LIDS는 인증되지 않은 프로그램으로부터의 RAW IO operation을 보호할 수 있다.
여러분의 하드디스크를 포함하여 MBR까지 보호할 수 있다.

탐지(Detection). 누군가 여러분의 호스트를 스캔했을 때 LIDS가 그것을 탐지하여 관리자
에게 알려줄 수 있다. LIDS는 또한 규정을 어긴 시스템상의 행동을 알아 챌 수도 있다.

응답(Response). LIDS에 의해 보호되고 있는 시스템 상에서 누군가 시스템상의 규정을
어겼을 때(주로 해킹을 위해) LIDS는 그 규정을 어긴 행동에 대해 자세한 메세지를 시스템
로그 파일로 기록한다. LIDS는 또한 여러분의 메일박스로 로그 메세지를 보낼 수도 있다.
이런 경우 LIDS는 즉시 유저 세션을 셧다운 시킬 수 있다.

2. 중요한 소스 분석

이번 절에서는 LIDS 소스에서 핵심적인 부분 몇가지를 분석하겠습니다.

- (1) 예) sys_ioperm

이 시스템콜은 I/O Port 를 접근하기 위해 커널에 허가를 요청 합니다.
커널 내부에서 이 요청이 허가된 사용자 - 루트인지 - 를 체크하기 위해

  62     if (turn_on && !capable(CAP_SYS_RAWIO)) {
  63 #ifdef CONFIG_LIDS
  64             lids_security_alert("CAP_SYS_RAWIO violation: attempted to g
  65 #endif
  66         return -EPERM;
  67     }

capable 함수는 인라인 함수로써 내부에 아래의 소스로 치환된다.

  if(cap_raised(current->cap_effective,cap))
  {
          current->flags != PF_SUPERPRIV;
        return 1;
  }

  이 함수는 current 즉 현재 프로세스의 cap_effective 라는 디스크립터를 검사해서
  CAP_SYS_RAWIO - 로우레벨 I/O 작업의 권환이 있는지 - 를 검사해서
  있다면 현재 프로세스의 PF_SUPERPRIV 플래그를 할당한다.

다시 돌아가서, 만약 허가되지 않은 사용자가 io_perm 을 호출했다면 lids_security_alert 가 실행된다.
이 함수는 lids_log 라는 함수를 호출해서 아래와 같은 동작을 한다.

  1. 현재 프로세스의 매핑된 영역중 executable 한 영역을 찾아
     매핑된 파일의 directory entry 를 얻는다.
  2. 현재 프로세스의 tty 이름을 얻는다.
  3. directory entry 와 tty 이름과 pid uid 등의 정보를 모아 프린트를 한다.

이 함수는 관리자에게 경고를 보내는 것이다.

LIDS 의 설계 목표중 하나가 Linux kernel 의 capability 지원을 강화하기 위한 것이다.
capability 에는 아래와 같은 속성이 있다.

CAP_CHOWN : 파일과 그룹의 허가권의 변경제한을 무시한다.
CAP_DAC_OVERRIDE : 파일 접속 퍼미션을 무시한다.
CAP_DAC_READ_SEARCH : 파일과 디렉토리의 읽기와 검색 허가를 무시한다.
CAP_FOWNER : 파일 허가권을 무시한다.
CAP_FSETID : setuid 와 setgid 플래그의 제한을 무시한다.
CAP_KILL : 시그널 보낼때의 제한을 무시한다.
CAP_SETGID : setgid 플래그 조작을 허용한다.
CAP_SETUID : setuid 플래그 조작을 허용한다.
CAP_SETPCAP : 다른 프로세스 에게 허가된 능력(capabilities) 의 부여한다.
CAP_LINUX_IMMUTABLE : 추가 전용파일이나 일정한 파일의 변경을 허용한다.
CAP_NET_BIND_SERVICE : TCP/IP socket 을 1024 번 이하로의 바인딩을 허용한다.
CAP_NET_BROADCAST : 네트워크 브로드캐스팅과 멀티캐스트를 듣는것을 허용한다.
CAP_NET_ADMIN : 일반적인 네트워킹 관리를 허용한다.
CAP_NET_RAW : RAW/PACKET socket 의 사용을 허용한다.
CAP_IPC_LOCK : 페이지나 메모리 세그먼트의 잠금을 허용한다.
CAP_IPC_OWNER : IPC 의 소유권 검사를 생략한다.
CAP_SYS_MODULE : 커널 모듈을 삽입/삭제 를 허용한다.
CAP_SYS_RAWIO : ioperm 과 iopl 을 이용해 I/O 포트에 접근을 허용한다.
CAP_SYS_CHROOT : chroot() 를 허용한다.
CAP_SYS_PTRACE : 어떤 프로세스에서나 ptrace() 를 허용한다.
CAP_SYS_PACCT : 프로세스 계정의 설정의 허용한다.
CAP_SYS_ADMIN : 일반적인 시스템 관리를 허용한다.
CAP_SYS_BOOT : reboot() 를 허용한다.
CAP_SYS_NICE : nice() 의 제한을 무시한다.
CAP_SYS_RESOURCE : 여러 자원 사용의 제한을 무시한다.
CAP_SYS_TIME : 시스템 시간과 실시간 시간의 조작을 허용한다.
CAP_SYS_TTY_CONFIG : tty 장치의 설정을 허용한다.
CAP_HIDDEN : 이 기능은 LIDS 에서 추가되는 것으로 프로세스를 숨기는 것이다.
CAP_KILL_PROTECTED : 이 함수 역시 LIDS 에서 추가되는 것으로 프로세스를 보호한다.
CAP_PROTECTED : 위와 유사

예를들어 nice 시스템 콜이 해당 프로세스가 요청을 할 권한이 있는지 검사하기 위해
capable(CAP_SYS_NICE) 로 검사하면 된다.


- (2) 프로세스 감추기

이 기능은 LIDS 패치에 의해 추가된 기능이다.
유닉스의 전형적인 명령어인 ps 를 실행하면 아래와 같이 프로세스가 출력된다.

root         1  0.0  0.1  1368  420 ?        S    Sep05   0:06 init
root         2  0.0  0.0     0    0 ?        SW   Sep05   0:00 [keventd]
root         3  0.0  0.0     0    0 ?        SW   Sep05   0:00 [kapmd]
root         4  0.0  0.0     0    0 ?        SWN  Sep05   0:00 [ksoftirqd_CPU0]
root         5  0.0  0.0     0    0 ?        SW   Sep05   0:00 [kswapd]
root         6  0.0  0.0     0    0 ?        SW   Sep05   0:00 [bdflush]
root         7  0.0  0.0     0    0 ?        SW   Sep05   0:00 [kupdated]
root         8  0.0  0.0     0    0 ?        SW   Sep05   0:00 [mdrecoveryd]
root        12  0.0  0.0     0    0 ?        SW   Sep05   0:00 [kjournald]
chc       1624  0.0  3.4 22844 8904 ?        S    Sep05   0:00 kdeinit: kwrited
chc       1632  0.0  3.5 21808 9044 ?        S    Sep05   0:00 korgac --miniicon
chc       1643  0.0  3.2 21776 8368 ?        S    Sep05   0:00 kalarmd --login
chc       1681  1.5 11.0 66376 28320 ?       S    Sep05   2:05 /usr/lib/mozilla/

잠깐 왜 우리가 프로세스를 잠궈야 할까? 그것은 해커가 루트를 획득한후 프로세스들을 제거하여
웹 서비스 같은것을 중단시킬수 있기 때문인데 예를들어 kill -9 4 를 하면
kswapd 가 죽지 않고 Zombie 상태가 될것이다. 그렇게 되면 우리가 예상한것 보다
큰 문제가 발생할 것이다.

ps 를 하게되면 내부적으로 아래와 같을 것이다.

1. execve("/bin/ps");
2. proc 라이브러리 열기
3. /proc 안에 있는 디렉토리들을 차례대로 열어서 프로세스들의 정보를 얻어낸다.
4. 만약 open("/proc/1624") 를 한다면, proc 가상 파일시스템을 거쳐서 proc_pid_lookup
  함수까지 가게된다.
  이 함수는 ls /proc 명령을 치게 되면 pid 가 디렉토리 목록으로 나올것이다.

아래 소스는 proc_pid_lookup 함수중 프로세스를 하이드 하는 부분이다.

1021 #ifdef CONFIG_LIDS
1022     if (cap_raised(task->lids_cap,CAP_HIDDEN) && lids_load && lids_local_load)
1023         inode=NULL;
1024     else
1025 #endif

자세한 설명을 하자면, task 프로세스의 lids_cap 에서 현재 capability 가 hidden 라면
얻어낸 inode 를 NULL 로 저장하여 보이지 않게 한다.

그런데 LIDS 가 패치된 커널 소스 안에는 프로세스를 숨기는 코드가 보이질 않는데
이것은 lids-adm 이라는 유저레벨 관리툴이 있어서 그 관리 프로그램으로
커널과 통신하여 관리할수 있다.

- (3) 파일 보호

보통 리눅스에서 파일에 접근 하려면 -rwxrwxrwx 이러한 권한만 가지고 접근여부를
결정한다. 하지만 이런것에 헛점이 있을수 있다. 그래서 LIDS 자체에서
강력한 파일시스템 보안을 제공한다.

커널 소스에서 파일에 접근하기 전에 반드시 lids_check_base 라는 함수를 호출한다.
이 함수는 dentry 와 플래그를 입력 받는다.

이 함수의 동작의 예를 들어보면
어떤 시스템콜을 통해서 /etc/apache 디렉토리에 접근하려고 한다.
그리고 현재 /etc 에는 ACL(Access Control List)에 기반하여 보호가 된다고 가정하자.

잠깐 우선 어떻게 관리할 파일(아이노드)이 기술되는지 살펴보겠다.
LIDS 에서 사용되는 자료구조는

struct lids_acl {
      struct lids_acl *next;
      unsigned long int ino;
      kdev_t  dev;
      int     type;                  
};

위와 같으며

next 는 다음 acl 을 가리키고
ino 는 관리될 파일(아이노드)를 가리키며
dev 는 디바이스 타입을 가리킨다.
type 는 읽기전용,쓰기전용,추가전용,접근불가 이렇게 나뉘며
특히 추가전용 같은 경우 로그파일 같은곳에 유용하다.

다시 돌아가서..
lids_check_base 의 동작 방법을 알아본다면,

while(dentry)
{
        만약 현재 프로세스가 도메인을 체크한다면
                lids_check_acl(base,flag);
        dentry = dentry->d_parent;        
}

이 소스는 parent dentry 로 가면서 dentry 가 LIDS 시스템에 의해 보호되고 있는지
체크를 하는 부분이다.

lids_check_acl 함수의 동작부분을 요약해보면 아래와 같다.

acl = current->lids_sys_acl->lids_domain;

while(acl != NULL)
{
        if(acl->ino == inode->i_ino)
                return 보호되고 있다;
}

그 다음부분은 lids_data 라는 자료구조에 들어가 있는 아이노드와 비교하여
리턴한다.

- (4) 그 외

지금까지 LIDS 에서 가장 많은 비중을 차지한 함수들을 분석하였다.
그 외에는 LIDS 관리 프로그램인 lids-adm 과 통신을 하기 위한 코드들이다.

3. 예제

이해를 돕기 위해 예제를 들어 보겠다.

유저모드에서 아래와 같은 문장을 실행하게 되면 lids.conf 에 2번과 같은 문장이
추가 될 것이다.

1) lidsadm -A -r /sbin/
2) 0:0::1:0:80483:770:/sbin:0-0
  각 필드들은 타입,아이노드,디바이스번호,파일명 등이다.

그리고 리부팅을 해서 커널의 처음 시작 루틴에서 lids_load 를 1로 설정한다.
초기에 lids_init() 를 호출하면 아래와 같은 루틴이 작동한다.

filp = filp_open(LIDS_CONF_FILE,O_RDONLY,O_RDONLY);

즉 /etc/lids.conf 을 연다.

filp->f_op->read(filp,buffer,1024,&filp->f_pos);

설정 파일에서 1024 바이트만 읽는다. 물론 이 연산은 유저모드에서 커널모드로
복사해 오는것이기 때문에 더 복잡하다.

한줄씩 읽으면서 #으로 시작하면 넘어가고 아니면 lids_init_add_file 을 호출해서
한줄에 읽은 문자열을 넘겨줘서 분석을 하고 각 필드들을 메모리에 넣고
나머지 아이노드,타입,파일명 필드는 lids_get_info 함수에서 처리한다.
그런후에 얻어진 inode 번호등을 이용해 lids_add_acl 함수로 acl list 에 추가하게
되는 것이다. 그리고 앞에서 보았듯이 디렉토리에 접근 할때는 acl list 를
검사한다.

'Linux' 카테고리의 다른 글

우분투 종료방법 (ubuntu shutdown)  (1) 2011.03.04
리눅스에서 CD 굽기기  (0) 2011.03.04
__attribute__ __context__ sparse  (0) 2011.02.15
#define 활용, macro, preprocess (DEBUG, printf)  (0) 2010.12.07
linux directory dirent.h  (0) 2010.12.05

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,