학습자료(~2017)/리눅스

[리눅스] 슈퍼 데몬 XINETD

단세포소년 2012. 1. 13. 18:35
반응형

인터넷 슈퍼 서버 : XINETD

필자 : 서정룡(dreamsoh@orgio.net)
원문 : http://linuxfocus.org/English/November2000

 

     

    xinetd(eXtended InterNET services daemon)은 침입에 대해 우수한 보안을 제공하며 서비스 부인(Denial of Services)공격의 위험을 감소시킨다. 이는 잘 알려진 inetd 와 tcpd 를 함께 사용하는 것과 같이 주어진 머신에 대한 접근 권한 설정을 가능케 하지만 더욱 많은 기능을 제공할 수 있다.

    이 기사에서는 xinetd 의 많은 특징을 다룰 것이다.

 

xinetd 란 무엇인가?

    inetd 는 컴퓨터로의 네트워크 접속 제어를 돕는데 inetd 가 관리하는 포트로 요청이 들어오면 inetd 는 곧 이를 tcpd 프로그램으로 전송한다.
    tcpd 는 요청의 승낙 여부를 hosts.allow 또는 hosts.deny 파일에 포함된 규칙에 따라 결정하며, 요청이 허용되면 해당 서버 프로세스(예를 들어 ftp)가 시작될 수 있다.
    이러한 메카니즘은 tcp_wrapper 라고도 부른다.

    xinetd 는 tcp_wrapper 와 유사한 접근 제어 능력뿐만 아니라 다음과 같이 더욱 확장된 능력을 제공한다:

    - TCP, UDP와 RPC 서비스들에 대한 접근 제어
      (RPC 서비스에 대해서는 지원이 미비한 실정이다.)
    - 타임 세그먼트에 기초한 접근 제어
    - 접속 성공 또는 실패에 대한 완전한 로깅
    - 서비스 부인 공격에 대한 효과적인 억제
    - 동시에 작동하는 동일 유형 서버 수에 대한 제한
    - 총 서버 수에 대한 제한
    - 로그 파일 크기에 대한 제한
    - 특정 인터페이스로의 서비스 바인딩; 예를 들면 임의의 서비스를 사설 네트워크에는
       허용하지만 외부 세계에는 허용하지 않을 수 있는데, 다른 시스템에 대한 대리인(프락시,
       proxy)으로 사용할 수 있으며 내부 네트워크에 도달하기 위해 IP 매스커레이딩
       (ip_masquerading, 또는 Network Address Translation-NAT)과 결합하여 사용하면
       매우 유용하다.

    주요 단점은 앞에서 언급했듯이 RPC 요청에 지원이 미비하다는 것이다. 그러나 xinetd 를 portmap 과 함께 사용한다면 이러한 문제점을 해결할 수 있다.

    이 기사의 첫 부분에서는 xinetd 작동 방법을 설명하는데, 서비스 설정 및 특정 옵션(인터페이스로의 바인딩, 리디렉션) 에 대해 약간의 예와 함께 설명할 것이다. 두 번째 부분은 작동중인 xinetd 및 생성된 로그를 보이며 유용한 팁으로 마무리한다.

 

컴파일 및 설치

    xinetd 는 www.xinetd.org 에서 얻을 수 있는데, 이 기사에서는 2.1.8.9pre10 버전을 사용할 것이다.
    컴파일과 설치는 일반적인 방식대로 ./configure; make; make install 과 같이 일련의 명령을 통해 이루어지는데 컴파일시 다음 세가지 옵션을 이용할 수 있다.

    1. --with-libwrap : 이 옵션을 통해 xinetd 는 tcpd 설정 파일인 /etc/hosts.allow 와
                                /etc/hosts,deny 를 조사하여 접근이 허용되면 자신의 고유 접근 루틴을
                                사용한다. 이 옵션이 작동하기 위해서는 tcp_wrapper 와 그 라이브러리가
                                설치되어 있어야 한다(Author’s note: wrapper 로 할 수 있는 것은 모두
                                xinetd 로 할 수 있는데, 이러한 호환성을 허용하는 것은 config 파일을
                                복잡하게 만들어 관리를 어렵게 만든다. 따라서 저자는 이를 추천하지
                                않는다.);

    2. --with-loadavg : 이 옵션은 xinetd 가 max_load 설정 옵션을 다룰 수 있게 하는데, 이는
                                 컴퓨터가 과부하 상태일 때 어떤 서비스가 비활성화될 수 있도록 한다.
                                 따라서 서비스 부인 공격을 예방하는데 있어 필수적인 옵션이며 표 1의
                                 max_load 속성을 보길 바란다;

    3. --with-inet6 : 이 옵션은 IPv6 사용을 지원하는데 IPv4 와 IPv6 접속을 관리할 수 있으며
                             IPv4 주소가 IPv6 포맷으로 변경된다.

    xinetd 를 구동하기 전에 inetd 를 중지할 필요는 없는 반면 inetd 를 중지시키지 않음으로써 두 데몬이 예기치 않게 동작할 수 있음을 유념하기 바란다.

    다음의 시그널들을 사용하여 xinetd 동작을 변경할 수 있다:

    SIGUSR1 : 소프트웨어 재설정 : 설정 파일이 다시 읽혀지고 이에 따라 서비스 매개변수가
                    변경된다.
    SIGUSR2 : 하드웨어 재설정 : 위와 동일하나 오래된 (outdated) 데몬이 종료된다.
    SIGTERM : xinetd 와 이 데몬이 생성한 데몬을 종료시킨다.

    약간의 다른 시그널들이 있는데, SIGHUP 은 /tmp/xinetd.dump 가 아닌 /var/run/xinetd.dump 파일에 그 덤프를 작성한다.

    위에 언급한 세가지 시그널들은 start, stop, restart, soft, hard 옵션을 포함하는 작은 스크립트를 통해 쉽게 관리될 수 있다(soft 와 hard 옵션은 각각 SIGUSR1 과 SIGUSR2 에 해당한다).

 

설정

    xinetd 데몬에 대한 디폴트 설정 파일은 /etc/xinetd.conf 파일로 커맨드 라인 옵션은 다른 설정 파일 경로를 허용한다. xinetd 설정은 그다지 복잡하지 않지만 지루한 작업일 수 있으며 불행히도 설정 파일 구문이 이전 inetd 의 것과 매우 다르다.

    itox 와 xconv.pl 두 유틸리티가 xinetd 와 함께 제공되는데 이들을 이용해 /etc/inetd.conf 파일을 xinetd 설정 파일로 변환할 수 있다. 그러나 wrapper 설정에 지정된 규칙들이 무시되기 때문에 이러한 변환이 충분하지 않음은 명백하다. 또한 itox 프로그램은 아직도 유지되고 있지만 더 이상 개발되지 않고 있어 xconv.pl 프로그램이 더욱 나은 해결책을 제시할 수 있다. 물론 inetd 가 제공하는 특징 외에 xinetd 만이 제공하는 특징들 때문에 변환 결과는 수정되어야 한다:

            >> /usr/local/sbin/xconv.pl < /etc/inetd.conf > /etc/xinetd.conf

    설정 파일은 디폴트 절로 시작하는데 이 속성들은 xinetd 가 다루는 모든 서비스들에 사용된다. 디폴트 절 다음에 각각의 서비스에 해당하는 절들이 있는데 각각의 절들에서 디폴트 옵션 중 특정 옵션을 재정의 할 수 있다.

    디폴트 절은 다음과 같다:

            defaults
            {
                attribute operator value(s)
                ...
            }

    이 절에 정의된 각 속성은 이후에 기술되는 모든 서비스에 대해 제공된 값을 유지하는데 따라서 only_from 속성에 서버에 접속할 수 있는 인가된 주소들을 열거할 수 있다:

            only_from = 192.168.1.0/24 192.168.5.0/24 192.168.10.17

    이후에 선언된 모든 서비스는 목록에 포함된 주소의 머신으로부터의 접근만을 허용할 것이다. 그러나 이러한 디폴트 값은 각 서비스에 대해 수정될 수 있는 반면(밑부분에 설명된 연산자를 체크해라) 매우 위험하다. 사실 간단하고 안전하게 서비스를 제공하기 위해서는 디폴트 값을 정의하지 않고 각 서비스 내에서 추후 이들을 변경하는 것이 더욱 좋다. 예를 들면 접근 권한의 경우 가장 간단한 정책은 모든 서비스에 대한 접근을 거절하고 다음에 서비스를 원하는 이들에게만 각 서비스에 대해 접근을 허용하는 것이다(tcp_wrapper를 이용할 때 이는 ALL:ALL@ALL을 포함하는 hosts.deny 파일과 단지 인가된 서비스 및 주소를 제공하는 hosts.allow 파일을 사용해서 이루어진다).

    설정 파일의 서비스를 기술하는 각 절은 다음과 같다:

            service service_name
            {
                attribute operator value(s)
                ...
            }

    ‘=’, ‘+=”과 “-=” 세 연산자가 허용가능한데 대부분의 속성들은 이에 고정된 값을 할당하는데 사용되는 “=” 연산자만 지원한다. “+=” 연산자는 값들의 목록에 조항을 추가하는 반면 “-=” 연산자는 이 조항을 제거한다.

    <표 1>은 이러한 속성들을 간략히 기술하는데 추후 몇 가지 예를 통해 이들의 사용법을 알아볼 것이다. 더욱 많은 정보를 얻기 위해서는 xinetd.conf 매뉴얼 페이지를 참조하기 바란다.

    < 표 1. xinetd 속성 >

    속 성

    값 및 설명

    flags

    대부분의 현재 값들만이 여기 언급되는데 새로운 값들은 참고문서를 보기 바란다.
    °IDONLY : 식별 서버를 갖는 클라이언트로부터의 접속만을 허용한다;
    °NORETRY : 실패한 경우 새로운 프로세스의 분기를 피한다;
    °NAMEINARGS : server_args 속성의 첫 번째 인수를 server 에 대한
                            argv[0] 로 사용하는데, 이는 inetd 에서와 같이
                            server 속성을 tcpd 로 하고 다음에 서버 이름 및
                            그 인수로 server_args를 써놓음으로써 tspd사용을
                            허용한다.

    log_type

    xinetd 는 디폴트로 syslogd 와 daemon.info 선택자를 사용한다.
    °SYSLOG selector [level] : syslogd 가 daemon, auth, user 또는
                                           local0-7 중에서 선택할 수 있도록 한다;
    °FILE[max_size[absolute_max_size]] : 지정된 파일이 로깅 정보를 받는데, 두 옵션은 파일 크기 한계를 설정한다. 파일 크기가 한계값에 도달하면 우선 메시지를 syslogd에 보내고 다음에 이 서비스에 대한 로깅을 중지한다(일반적인 파일 또는 디폴트로 고정되어 있다면 다양한 서비스들이 관련될 수 있다.)

    log_on_success

    서버가 구동할 때 여러 가지 정보가 기록될 수 있다:
    °PID : 서버의 PID(내부 xinetd 서비스라면 PID 는 0의 값을 갖는다) ;
    °HOST : 클라이언트 주소 ;
    °USERID : 식별 프로토콜을 정의하는 RFC1413 에 따른
                   원격 사용자의 아이덴티티 ;
    °EXIT : 프로세스 종료 상태 ;
    °DURATION : 세션 지속 기간

    log_on_failure

    xinetd 는 서버가 자원 부족 또는 접근 규칙 때문에 구동할 수 없을 때 다양한 정보를 기록할 수 있다.
    °HOSTID, USERID : 위와 동일 ;
    °ATTEMPT : 접근 시도를 기록하며 다른 값이 저공되자마자 실행되는
                      자동 옵션 ;
    °RECORD : 클라이언트에 대한 얻을 수 있는 모든 정보를 기록한다 ;

    nice

    nice 명령어와 같이 서버 우선권을 변경한다.

    no_access

    이 서비스에 접근할 수 없는 클라이언트 목록

    only_from

    인가된 클라이언트 목록. 이 속성에 값이 부여되지 않는다면 서비스에 대한 접근이 거절된다.

    port

    서비스와 관련된 포트. /etc/service 파일에 정의되어 있다면 이들 포트 넘버는 서로 일치되어야 한다.

    protocol

    지정된 프로토콜은 /etc/protocol 파일에 존재해야 하는데 프로토콜이 지정되지 않으면 디폴트 프로토콜이 사용된다.

    server

    서버 경로.

    server_args

    서버에 주어지는 인수.

    socket_type

    stream(TCP), dgram(UDP), raw(IP direct access) 또는 seqpacket()

    type

    xinetd 는 세가지 유형의 서비스를 다룰 수 있다 :
    1. RPC : /etc/rpc 파일에 정의되어 있는데 그다지 잘
                 작동되지 않는다 :
    2. INTERNAL : echo, time, daytime, chargen 및 discard 와 같은
                          xinetd 가 직접적으로 다루는 서비스
    3. UNLISTED : /etc/rpc 또는 /etc/service파일에 정의되어 있지 않은
                         서비스 ; servers, servicce 와 xadmin 내부 서비스들을
                         다룰 것인데 다양한 값들을 결합하는 것이 가능함을
                         주목하기 바란다.

    wait

    쓰레드에 대한 서비스 동작을 정의하는데 두 가지 값이 허용될 수 있다 :
    °yes : 단일 쓰레드 서비스로 이 유형의 접속은 단 하나만이 서비스될
             수 있다 ;
    °no : 정의된 최대 한계에 따라 각각의 새로운 서비스 요청에 대해
            xinetd는 새로운 서버를 구동한다(디폴트로 이 한계는 무제한임
            을 유의하기 바란다.)

    cps

    들어오는 접속 수를 제한하는데, 첫 번째 인수는 숫자 자체이다. 한계숫자를 넘을 때 두 번째 인수로 제공되는 주어진 시간(초) 동안 서비스가 비활성화된다.

    instances

    동시에 작동할 수 있는 동일 유형 서버의 최대수를 정의한다.

    max_load

    서버에 대한 최대 부하(예를 들어 2 또는 2.5)를 나타내는데, 이 한계를 넘는 경우 이 서버에 대한 요청은 거절된다.

    per_source

    동일 호스트로부터의 서버 접속수를 제한하는 정수 또는 UNLIMITED


    표 1의 마지막 4가지 속성들은 서버에 따른 자원들의 제어를 허용한다. 이는 서비스 부인공격으로부터 서버를 보호하는데 효과적이다.

    이 절에서는 약간의 xinetd 특징을 나타내었는데 다음 절에서는 xinetd 사용 방법을 설명하고 이것이 적절히 작동하게 하는 약간의 규칙을 설명한다.

 

접근 제어

    앞 절에서 보았듯이 IP 주소를 이용하여 리눅스 박스에 대한 접근을 승낙하거나 금지할 수 있는데 xinetd 는 더욱 많은 특징을 허용한다:

    ·호스트 네임 분석을 통해 접근 제어를 할 수 있는데, xinetd 는 _for_every connection_ 에
      명시된 호스트 네임을 검색하여 접속 주소를 호스트 네임에 대해 반환된 주소와 비교를 한다;

    ·.domain.com 에 의해 접근 제어를 할 수 있는데, 클라이언트가 접속할 때 xinetd 는
       연결 주소를 역 검색하여 지정된 도메인내에 존재하는 지를 검사한다.

    서비스를 최적화하기 위해서는 명백히 IP 주소를 이용하는 것이 더욱 좋으며 이럼으로써 그 서비스로 들어오는 접속에 대한 네임 검색을 피한다.
    호스트 네임을 이용해 접근 제어를 해야 한다면, 로컬 네임 서버(적어도 캐싱 서버) 를 운영하는 경우 상당한 속도 향상을 이룰 수 있다. 주소 검색을 수행하기 위해 도메인 소켓을 사용하는 것이 더욱 더 좋다(/etc/resolv.conf 파일에 nameserver 엔트리를 넣지 말기 바란다).

 

Service defaults

    디폴트 절에서 많은 속성들의 값을 설정할 수 있는데 전체 목록은 관련 문서를 확인하기 바란다. only_from, no_access, log_on_success, log_on_failure 등 어떤 속성들은 이 절 및 각 서비스 절에 제공된 값들을 동시에 보유한다.

    디폴트로 머신에 대한 접근을 거절하는 것이 가장 신뢰할만한 보안 정책의 첫 단계인데 이 다음에 각 서비스에 기초하여 접근 허용을 설정한다. IP 주소에 기초하여 머신에 대한 접근을 제어하는 only_from 과 no_access 두 속성이 있는데 우선 후자를 이용하여 다음과 설정한다:

            no_access = 0.0.0.0/0

    이는 서비스 접근을 완전히 막는다. 그러나 모든 사람에게 예를 들어 echo(ping) 접근을 허용하려면 echo 서비스를 다음과 같이 설정한다:

            only_from = 0.0.0.0/0

    다음은 이 설정을 통해 얻는 로깅 메시지이다:

            Sep 17 15:11:12 charly xinetd[26686] : Service=echo-
            stream: only_from list and no_access list match equally
            the address 192.168.1.1.

    명확하게 접근 제어가 두 속성에 포함된 주소 목록을 비교함으로써 이루어진다. 클라이언트 주소가 두 목록 모두에 일치할 때는 덜 일반적인 속성 값에 의해 접근 제어가 이루어진다. 위와 같이 속성 값이 동일한 경우 xinetd 는 접속 선택 및 거절을 할 수 없으며, 이러한 모호함을 피하기 위해서는 다음과 속성을 설정해야 한다:

            only_from = 192.0.0.0/8

    더욱 손쉬운 해결방법은 다음과 같은 속성 설정을 통해 접근 제어를 하는 것이다:

            only_from =

    속성 값을 주지 않았다고 해서 모든 접속이 실패하는 것은 아니며, 따라서 모든 서비스는 이와 동일한 속성에 의해 접근을 허용한다.

    필수적이지는 않지만 중요한 사항 : 주어진 서비스 절에 only_from 또는 no_access 와 같은 접근 규칙이 없는 경우 서비스에 대한 접근은 허용된다.

    다음은 디폴트 절의 예이다:

    defaults
    {
      instances       = 15
      log_type        = FILE /var/log/servicelog
      log_on_success  = HOST PID USERID DURATION EXIT
      log_on_failure  = HOST USERID RECORD
      only_from       =
      per_source      = 5
      disabled = shell login exec comsat
      disabled = telnet ftp
      disabled = name uucp tftp
      disabled = finger systat netstat

      #INTERNAL
      disabled = time daytime chargen servers services xadmin

      #RPC
      disabled = rstatd rquotad rusersd sprayd walld
    }

    내부 서비스(주석 처리된 INTERNAL 라인) 중에서 servers, services 와 xadmin 은 xinetd 관리를 허용하는데, 이는 후에 더욱 자세히 다룬다.

 

서비스 설정하기

    서비스 설정을 위해 특별히 더욱 할 것은 없는데 사실 모든 것은 디폴트 절의 값들에 의해 작동한다. 단지 서비스를 다루기 위해 속성과 값을 정확히 해야 하는데 이는 각 서비스에 대해 디폴트 값 변경, 또는 다른 속성을 의미한다.
    어떤 속성들은 INTERNAL, UNLISTED, 또는 RPC 등 서비스 유형에 따라 존재해야 한다:

    < 표 2. 필요 속성들 >

    속 성

    해 설

    socket-type

     모든 서비스

    user

     비 서비스에 대해서만

    server

     비 서비스에 대해서만

    wait

     모든 서비스

    protocol

     모든 서비스 및 에 포함되지 않은 서비스

    rpc_version

     모든 서비스

    rpc_number

     에 포함되지 않은 모든 서비스

    port

     모든 서비스 및 에 포함되지 않은 서비스


    다음 예는 서비스 정의 방법을 보여준다:

    service ntalk
    {
      socket_type   = dgram
      wait          = yes
      user          = nobody
      server        = /usr/sbin/in.ntalkd
      only_from     = 192.168.1.0/24
    }
    service ftp
    {
      socket_type  = stream
      wait         = no
      user         = root
      server       = /usr/sbin/in.ftpd
      server_args  = -l
      instances    = 4
      access_times = 7:00-12:30 13:30-21:00
      nice         = 10
      only_from    = 192.168.1.0/24
    }

    ntalk 및 ftp 서비스가 단지 로컬 네트워크상(192.168.1.0/24) 에서만 허용됨을 주목하자. FTP 서비스와 관련해서는 단지 4 개의 인스턴스 생성이 허용되며 일정 시간동안만 서비스가 허용 가능하여 따라서 서비스에 대해 보다 많은 제한을 한다.

    포트 바인딩: bind 속성

    이 속성은 특정 IP 주소로의 서비스 바인딩을 허용하는데 컴퓨터가 적어도 두개의 네트워크 인터페이스를 갖고 있을 때만 유용하다. 예를 들면 로컬 네트워크의 일부분으로 별개의 인터페이스를 통해 인터넷에 접속된 컴퓨터의 경우이다.

    예를 들어 한 회사가 직원들이 내부 문서에 접근해서 이를 읽을 수 있도록 FTP 서버를 설치하려고 하며 또한 외부 클라이언트에게는 회사 제품에 대한 FTP 접근을 제공한다고 할 때 bind 속성이 사용된다. 이에 대한 해결방법은 공개 접근 및 내부 회사 접근만을 위한 두 별개의 FTP 서비스를 정의하는 것이다. 그러나 xinetd 가 이들을 구별할 수 있어야 하는데, 이는 id 속성을 사용함으로써 해결할 수 있다. 이는 서비스를 유일한 방식으로 정의한다(서비스내에서 id 속성이 정의되지 않을 때 디폴트 값은 서비스 이름이다).

    service ftp
    {
      id           = ftp-public
      wait         = no
      user         = root
      server       = /usr/sbin/in.ftpd
      server_args  = -l
      instances    = 4
      nice         = 10
      only_from    = 0.0.0.0/0 #allows every client
      bind         = 212.198.253.142 #public IP address for this server
    }
    service ftp
    {
      id           = ftp-internal
      socket_type  = stream
      wait         = no
      user         = root
      server       = /usr/sbin/in.ftpd
      server_args  = -l
      only_from    = 192.168.1.0/24 #only for internal use
      bind         = 192.168.1.1  #local IP address for this server (charly)
    }

    bind 속성의 사용은 패킷의 목적지에 따라 해당 데몬을 요청할 수 있도록 한다. 따라서 이 설정에 대해 로컬 네트워크상의 클라이언트는 내부 데이터에 접근하기 위해 로컬 주소(또는 관련 이름) 를 주어야 한다.

    로그 파일은 다음과 같을 것이다:

    00/9/17@16:47:46: START: ftp-public pid=26861 from=212.198.253.142
    00/9/17@16:47:46: EXIT   : ftp-public status=0 pid=26861 duration=30(sec)
    00/9/17@16:48:19: START: ftp-internal pid=26864 from=192.168.1.1
    00/9/17@16:48:19: EXIT   : ftp-internal status=0 pid=26864 duration=15(sec)

    첫 번째 부분은 ftp 212.198.253.142 명령, 두 번째 부분은 charly 라는 로컬 네트워크상에서 ftp 192.168.1.1. 명령에 대한 것이다.
    머신이 두개의 정적 IP 주소가 없는 경우 문제가 생길 것은 명백하다. 이는 ppp 접속, 또는 dhcp 프로토콜을 사용할 때 발생할 수 있는데, 주소보다는 인터페이스에 서비스를 바인딩하는 것이 더욱 좋을 듯 하다. 그러나 이는 아직까지 xinetd에서 지원되지 않으며 실제 문제가 된다(예를 들어 인터페이스 또는 주소에 접근할 수 있는 C 모듈을 작성하는 것은 OS 에 의존하며 xinetd 는 많은 OS 에서 지원되기 때문). 스크립트 사용이 이러한 문제를 해결한다:

            #!/bin/sh
            PUBLIC_ADDRESS=`/sbin/ifconfig $1 | grep “inet addr” |
            awk ‘{print $2}’| awk -F: ‘{print $2}’`     sed s/PUBLIC_ADDRESS/”$PUBLIC_ADDRESS”/g /etc/xinetd.base
            > /etc/xinetd.conf

    이 스크립트는 동적 주소를 대신하는 PUBLIC_ADDRESS 로 올바르게 설정된 /etc/xinetd.base 파일에서 PUBLIC_ADDRESS 문자열을 스크립트에 인수로 넘겨지는 인터페이스와 관련된 주소로 수정하여 /etc/xinetd.conf 파일에 이를 변경한다. 다음이 스크립트에 대한 요청은 접속 유형에 의존하는데 가장 간단한 것은 정확한 ifup-* 파일에 대한 호출을 추가하여 xinetd를 재시동하는 것이다.

    다른 머신에 대한 서비스 리디렉션: redirect 속성

    xinetd는 redirect 속성을 이용하여 일종의 투명 프락시로 사용될 수 있는데, 다른 머신에 대한 서비스 요청을 원하는 포트로 보낼 수 있게 한다.

            service telnet
            {
              flags  = REUSE
              socket_type = stream
              wait  = no
              user  = root
              server = /usr/sbin/in.telnetd
              only_from = 192.168.1.0/24
              redirect = 192.168.1.15 23
            }

    어떻게 작동되는지 지켜보자:

            >>telnet charly
            Trying 192.168.1.1...
            Connected to charly.
            Escape character is ‘^]’.
            
            Digital UNIX (sabrina) (ttyp1)
            
            login:

    우선 접속이 charly 상에서 이루어진 듯 하지만 sabrina(알파 머신, “Digital UNIX”) 에서 이 접속이 이루어졌음을 보인다. 이 메카니즘은 유용한 반면 위험하다. redirect 속성을 갖고 설정할 때 접속 양단 모두에 대해 로깅이 이루어져야 한다. 더구나 이러한 유형의 서비스에 대해서는 DMZ 과 방화벽 사용을 강력히 추천한다.

 

특별 서비스

    세가지 서비스는 xinetd 만이 수행하는데 이들은 /etc/rpc 또는 /etc/services 파일에서 찾을 수 없기 때문에 UNLISTED flag 를 가져야 한다(물론 xinetd 서비스임을 알리는 INTERNAL flag 도 또한 가져야 한다).

       1. servers: 사용 중인 서버에 대해 알려준다;
       2. services: 허용가능한 서비스, 이들의 프로토콜 및 포트에 대해 알려준다.
       3. xadmin: 1 과 2 서비스의 기능을 결합한다.

    이들 서비스는 중요한 정보를 제공하기 때문에 컴퓨터를 더욱 공격당하기 쉽게 하는 것은 명백하다. 현재 이들의 접근은 보호받지 못하는데(예를 들면 패스워드에 의한 보호), 이들은 설정시에만 사용해야 한다.
    다음 디폴트 절에서 다음과 같이 이들의 사용을 거절해야 한다:

    defaults {
      ...
      disabled = servers services xadmin
      ...
    }

    이들을 활성화하기 전에 미리 예방조치를 취해야 한다:

       1. xinetd 를 운영하는 머신만이 이러한 서비스에 접속할 수 있어야 한다.
       2. 인스턴스의 수를 하나로 제한한다.
       3. 서버를 운영하는 머신으로부터의 접근만을 허용한다.

    xadmin 서비스를 예를 들어보자.
    (나머지 두 서비스도 포트 넘버를 제외하고는 이와 동일한 방식으로 설정될 수 있다)

    service xadmin
    {
      type  = INTERNAL UNLISTED
      port  = 9100
      protocol = tcp
      socket_type = stream
      wait  = no
      instances = 1
      only_from = 192.168.1.1  #charly
    }

    xadmin 서비스는 다섯 개의 명령을 갖고 있다:

       1. help ...
       2. show run: servers 서비스와 같이 현재 작동하는 서버에 대해 알려준다.
       3. show avail: servers 서비스와 같이 허용가능한 서비스에 대해 알려준다
           (약간 더 많은 정보).
       4. bye or exit ...

    이러한 서비스가 존재하지만 이들을 사용하지 않는 것이 좋다. 이러한 서비스가 없더라도 netstat, fuser, lsof 등등의 명령어를 사용하여 컴퓨터에서 무엇이 진행되고 있는지를 확인할 수 있다. 물론 이러한 서비스를 사용할 때 공격당하기는 쉽지 않다.

    Starting with a riddle

    지금까지 잘 따라온 독자를 위해 작은 연습 문제가 있는데, 우선 이에 사용된 설정을 설명할 것이고, 다음 무엇이 발생했는지, 왜 잘 작동하지 않는지를 이해하려고 할 것이다.

    단지 finger 서비스만을 다룬다:

            service finger
            {
              flags  = REUSE NAMEINARGS
              server = /usr/sbin/tcpd
              server_args = in.fingerd
              socket_type = stream
              wait  = no
              user  = nobody
              only_from = 192.168.1.1  #charly
            }

    xinetd 는 --with-libwrap 옵션없이 컴파일되었다.(server 속성을 조사해라).
    디폴트 절은 앞서 제공한 것과 동일한데, charly 에의 모든 접근은 접속이 어디서 오든 모두 거절된다. 그럼에도 불구하고 finger 서비스는 활성화되어 있다.:

            pappy@charly >> finger pappy@charly
            [charly]
            pappy@charly >>
            pappy@bosley >>  finger pappy@charly
            [charly]

            pappy@bosley >>

    인가된 머신인 charly(192.168.1.1) 뿐만 아니라 bosley(192.168.1.10) 로부터의 요청도 잘 작동한 것처럼 보인다. 로그 파일을 한번 보자:

            /var/log/servicelog :
            00/9/18@17:15:42: START: finger pid=28857 from=192.168.1.1
            00/9/18@17:15:47: EXIT: finger status=0 pid=28857 duration=5(sec)
            00/9/18@17:15:55: FAIL: finger address from=192.168.1.10

    처음 두 라인인 charly 로부터의 요청은 xinetd 에 따라 적절히 작동되어, 즉 접근이 허용되어 요청에 걸린 시간은 5초이다. 반면에 bosley 로부터의 요청은 거절된다(FAIL).
    finger 서비스의 설정을 본다면 사용된 서버가 실제로는 in.fingerd가 아니라 tcp_wrapper tcpd 서비스임을 알 수 있는데, wrapper 로그는 다음과 같다:

            /var/log/services :
            Sep 18 17:15:42 charly in.fingerd[28857]: refused connect from 192.168.1.1

    위의 두 요청과 일치하는 로그는 단지 한 라인으로 bosley 로부터의 두 번째 요청은 xinetd 에 의해 차단되어 로그에서 찾을 수 없는 것이 정상이다. 실제 위의 wrapper 로그는 xinetd 가 허용한 charly 로컬 네트워크상에서의 요청으로 시간과 pid 과 동일함을 알 수 있다:

    요약하면 다음과 같다:

       1. xinetd는 요청을 허용했다;
       2. finger 요청이 tcpd 를 통해 이루어진다;
       3. in.fingerd 가 이 요청을 거절했다.

    어떻게 진행되었는가? xinetd 가 허용한 요청이 특정 서버(여기서는 tcpd) 에 보내졌지만 tcpd 는 이 접속을 거절하였다. 따라서 hosts.allow 와 hosts.deny 파일을 살펴보아야 한다.
    /etc/hosts.deny 파일에는 ALL:ALL@ALL 만 포함하고 있는데 이것이 wrapper 에 의해 요청이 거절된 것을 설명한다.

    server 및 server_args 서비스 라인이 정의된 방식에 따라 wrapper 특징은 아직도 사용할 수 있다(xinetd 의 banner, spawn, twist 등). --with-libwrab 컴파일 옵션은 hosts.allow 와 hosts.deny 파일을 이용하여 xinetd 프로세스가 시작하기 전에 접근 권한에 대한 제어만 추가함을 기억하기 바란다. 위 예에서 이러한 설정을 통해 tcp wrapper 특징을 계속해서 사용할 수 있음을 알 수 있다.

    이러한 특징 중복 (overlapping of features) 은 작동된다고 하더라도 이상한 동작으로 이끄는 것은 당연한데, inetd 및 portmap 과 함께 xinetd 를 사용하기 위해서는 이러한 슈퍼 데몬 중 단 하나를 이용해 서비스를 다루는 것이 더욱 좋다.

    chroot a service

    어떤 서비스의 필드 제한 또는 새로운 환경의 생성이 종종 제시되는데 chroot 명령은 명령 (또는 스크립트) 에 대한 루트 디렉토리 변경을 허용한다:

            chroot [options] new_root

    이는 bind/DNS 또는 ftp 와 같은 서비스를 보호하는데 종종 사용된다. xinetd 특징을 통해 득을 보는 동시에 이 동작을 재현하기 위해서는 chroot 를 server 로서 선언해야 한다. 그 뒤에 server_args 속성을 통해 다른 인수들을 전달해야 한다.

            service ftp
            {
              id           = ftp
              socket_type  = stream
              wait         = no
              user         = root
              server       = /usr/sbin/chroot
              server_args  = /var/servers/ftp /usr/sbin/in.ftpd -l
            }

    따라서 이 서비스로 요청이 올 때 사용되는 첫 명령은 chroot 이다. 다음에 이 서비스에 전달되는 인수는 server_args 라인의 앞 부분으로 새로운 루트이다. 마지막으로 뒷 부분의 서버가 구동된다.

     

결론

    xinetd 또는 inetd 를 이용해서 서비스에 필요한 데몬을 선택할 수 있을 것이다. xinetd 는 더욱 많은 특징을 제공하는 반면 각 배포판에 디폴트로 포함(현재 대부분의 배포판은 이를 포함하고 있다) 될 때까지는 더욱 신중한 관리를 필요로 한다.

    가장 안전한 해결방법은 공개 접근을 허용하는 머신에서 xinetd 를 사용하는 것인데 xinetd 는 더욱 더 견고한 방어 수단이 될 수 있다. 로컬 네트워크에 대해서는 inetd 를 사용하는 것만으로도 충분하다.

    pop3 server

    xinetd를 사용한 pop3 서버의 설정은 다음과 같다.

            service pop3
            {
                 disable = no
                 socket_type             = stream
                 wait                    = no
                 user                    = root
                 server                  = /usr/sbin/ipop3d
            #    log_on_success          += USERID
            #    log_on_failure           += USERID
            }

    물론 server 속성에는 각자 데몬의 경로를 넣어주어야 한다.

    xinetd 를 통해 pop3 서비스를 제공한다면 사용하는 로깅 옵션 값에 따라 매우 곤란스러울 것이다. 예를 들어 USERID 를 사용하면 xinetd 로부터의 요청은 pop 클라이언트에서 호스트되는 identd 서버로 보내지는데 그러한 서버가 없다면 타임아웃되는데 30초 정도의 시간이 걸린다.

    따라서 누군가가 메일을 받아 올 때 identd 서버가 응답하지 않는다면 적어도 30초 정도를 기다려야 한다. 여러분은 다음 중에서 선택해야 한다:

       1. 모든 클라이언트에 identd 서버를 설치해서 로그 과정을 매우 빠르게 한다
           (identd 가 제공하는 정보가 변경될 수 있음에 주의하자).

       2. 사용자가 그들의 메일을 빠르게 얻을 수 있도록 이 서비스에 대한 로깅 속성을
           감소시킨다.

    레드햇 7.0, 맨드레이크 7.2 및 여타 다름 배포판에서의 좋지 않은 설정

    bug 24279 send to bugzilla.

    /etc/xinetd.d 에 설정되어 있는 다음의 서비스들은 /etc/services 파일에 정의되어 있지 않다.

            [pappy@rootdurum xinetd.d]# grep service *udp
            chargen-udp:service chargen-udp
            daytime-udp:service daytime-udp
            echo-udp:service echo-udp
            time-udp:service time

    레드 햇 사에서는 이것이 chkconfig 및 ntsysv 와 같은 도구와 함께 사용할 때 문제가 발생할 수 있다고 하지만, 필자는 이러한 도구와 xinetd 사이에 선택을 한다면 주저 않고 xinetd를 선택할 것이다.


반응형