[시스템 관리에 필수, 보안] ① 시스템 보안 수칙

일반입력 :2008/09/11 10:43

홍석범 (오늘과내일)

시스템 보안이라 하면 추상적이기도 하고 방대하기도 해서 그 자체로도 책 몇 권의 분량이 될 수 있고 어디에서부터 시작해야 할지 막막한 것이 사실이다. 그러나 이 역시 변하지 않는 원칙은 있다.

누가 알려주지 않아도 시스템 관리자라면 자연스럽게 깨닫게 되는 이 불변의 원칙을 하나하나 찾아가 보도록 하자. 이번 글에서는 시스템 보안에 대한 원칙이다.

흔히들 시스템 관리는 아무런 사고 없이 잘 운영되면 당연한 것이고, 사고나 장애가 생기면 관리자 탓을 하는 것이 우리의 현실이다. 이러한 현실에서 보안은 흔히 실생활에서의 보험에 비유하곤 하는데, 평소에는 매달 보험료로 지불하는 비용이 아깝기도 해서 해지할까도 생각해 보지만 막상 사고를 당하면 보험만큼 아쉬울 때가 없는 것이 사실이다.

더군다나 사고라는 것이 자신만 조심한다고 해서 당하지 않으리라는 보장도 없지 않은가? 따라서 보안 역시 언제든 발생할 수 있는 ‘사고’ 에 대비한다는 차원에서 미리 준비를 한다면 만약의 사고를 예방하고 설사 발생한다 하더라도 그 피해를 최소화할 수 있을 것이다.

이 글에서는 시스템 보안, 네트워크 보안, 보안 프로그램 활용 등의 3단계로 나누어 효율적인 시스템 관리 방안에 대해 알아보도록 하자. 특히 국내에서 중소 규모의 서버로 가장 많이 사용되고 있는 윈도우 2000/2003 서버와 리눅스를 이용해 서비스 운영시 관리자에게 도움이 될 수 있는 보안 사항에 대해 살펴보자.

사용하지 않는 서비스 중지

간단한 가정용 PC부터 시작해서 네트워크 백본에서 사용되는 라우터까지 어떠한 OS든 초기 설치시에는 불필요하게 많은 서비스들이 작동하고 있다. 이처럼 사용하지 않는 서비스들은 마치 사용하지도 않는 대문을 여러 개 만들어 놓은 것과 같아 조금만 관심을 주지 않는다면 이 문을 통해 누구나 집에 들어올 수 있는 중대한 위협 요소가 될 수 있다. 따라서 시스템 설치 후에는 반드시 사용하지 않는 서비스에 대한 중지를 하도록 하여야 한다.

이는 만약에 있을지 모를 해당 서비스에 대한 취약성을 사전에 방지하는 것뿐만 아니라 시스템의 불필요한 자원을 낭비하지 않도록 하는 효과도 있다. 윈도우의 경우 『내 컴퓨터

ntsysv 실행

직접 터미널 상에서 ntsysv를 실행하거나 setup을 실행 후 ‘System services’를 선택하면 된다. 이때 <화면 2>와 같이 보이게 되는데, 여기에서 부팅시 자동으로 시작되기를 원하는 서비스를 선택하면 된다. 부팅시 시작되는 서비스에는 ‘*’ 표시가 붙게 되는데, 서비스를 선택하거나 선택을 해제하려면 스페이스바를 누르면 된다.

서비스명 확인

/etc/rc.d/rc3.d 디렉토리로 이동한 후 ls -la S*을 실행하여 S로 시작되는 서비스명을 확인해도 된다. 참고로 여기에서 rc3.d의 3은 Full multiuser mode로서 일반적으로 서버로 이용할 때 사용되는 런 레벨이며, S*의 S는 ‘start’의 의미로서 부팅시 작동할 서비스를 의미한다. 반대로 K는 kill의 의미로 작동하지 않을 서비스를 뜻한다. S로 시작되는 서비스명 중 부팅시 자동으로 시작되기를 원하지 않는 서비스는 K로 파일이름을 변경해주면 된다. 또는 아예 /etc/rc.d/init.d/ 디렉토리에 있는 관련 시작 스크립트 파일을 삭제해도 된다.

이외에도 chkconfig라는 명령어를 이용하면 각 런 레벨별로 어떤 서비스가 on, off가 되어 있는지 등 전체적인 설정을 확인할 수 있고 직접 설정을 변경할 수도 있다. 또한 service라는 명령어를 이용하면 특정 서비스의 상태를 조회하거나 가동하거나 멈추는 등 직접 제어할 수도 있다. 자세한 옵션은 man 페이지를 참고하기 바란다.

서비스 중인 포트 확인

포트(port)는 텔넷이나 ftp, smtp 등 클라이언트와 서버 사이의 tcp/ip 통신에서 각각의 서비스를 구분하기 위해서 사용되는 것으로, 시스템 운영시 어떠한 포트가 대기(listen)하고 있고 어떠한 서비스가 어떤 포트를 대기하고 있는지 확인하는 것은 매우 중요하다.

실제로 외부에서 nmap과 같은 프로그램으로 포트 스캔을 해보면 알지 못하는 많은 포트가 대기하고 있는데, 과연 어떤 프로그램이 해당 포트를 사용하고 있는지 혹은 백도어는 아닌지 궁금할 때가 많다. 이러한 경우에는 윈도우의 경우 fport라는 프로그램을 사용하거나 <화면 3>과 같이 active ports(http://www.snapfiles.com/get/activeports.html)라는 프로그램을 이용하면 실시간으로 사용되는 ip 및 포트 정보뿐만 아니라 어떤 포트에 어떤 프로그램이 대기하고 있는지 알 수 있으며 해당 프로세스를 바로 중지(kill)할 수도 있다.

리눅스의 경우 여러 명령어를 제공하고 있는데, 가장 간단한 명령어는 다음과 같이 터미널 상에서 netstat을 실행해 보면 된다. netstat에서는 많은 옵션을 제공하고 있는데, 현재 시스템 상에서 특정 포트를 점유하여 소켓 데몬 형태로 대기 중인 서비스에 대한 사항은 ‘listen’의 의미인 -l 옵션을 주면 된다. 더불어서 -p 옵션을 주면 해당 포트를 사용 중인 program 이름도 확인할 수 있다.

<화면 4>의 경우를 보면 좌측에 현재 대기하고 있는 포트를 알 수 있으며 우측에 있는 정보를 보면 해당 포트가 어떤 PID이며 어떤 프로그램인지 확인할 수 있다. 만약 포트 2265/tcp를 대기하고 있는 프로세스 정보를 알고자 한다면 pid가 587인 것을 알고 있으므로 다음과 같이 실행하면 된다.

# ls -la /proc/587/

total 0

dr-xr-xr-x 3 osiris osiris 0 Mar 10 20:52 ./

dr-xr-xr-x 145 root root 0 Mar 6 15:55 ../

-r--r--r-- 1 root root 0 Mar 10 20:52 cmdline

-r--r--r-- 1 root root 0 Mar 10 20:52 cpu

lrwxrwxrwx 1 root root 0 Mar 10 20:52 cwd -> //

-r-------- 1 root root 0 Mar 10 20:52 environ

lrwxrwxrwx 1 root root 0 Mar 10 20:52 exe -> /usr/sbin/osirisd*

dr-x------ 2 root root 0 Mar 10 20:52 fd/

-r--r--r-- 1 root root 0 Mar 10 20:52 maps

-rw------- 1 root root 0 Mar 10 20:52 mem

-r--r--r-- 1 root root 0 Mar 10 20:52 mounts

lrwxrwxrwx 1 root root 0 Mar 10 20:52 root -> //

-r--r--r-- 1 root root 0 Mar 10 20:52 stat

-r--r--r-- 1 root root 0 Mar 10 20:52 statm

-r--r--r-- 1 root root 0 Mar 10 20:52 status

이중 ‘exe->’ 부분을 보면 이 프로세스를 실행하고 있는 프로그램은 /usr/sbin/osirisd인 것을 알 수 있다. 그렇다면 해당 프로세스를 중지하고 싶다면 어떻게 하여야 할까? 많은 사람들이 /etc/services 파일에서 해당 포트 부분을 주석으로 처리하면 된다고 알고 있는데, /etc/services 파일은 단지 80<->http와 같이 포트 번호와 서비스명을 맵핑시켜 주는 것일 뿐 직접적인 서비스 제공과는 관계가 없으며 포트를 닫으려면 해당 포트를 사용 중인 프로세스의 pid를 찾아 kill pid를 실행하면 된다. 즉 이런 경우 ‘kill -9 587’을 실행하여야 해당 프로세스가 중지하게 된다.

외부에서 포트 스캔을 하면 포트에 대한 정보가 보이는데, netstat 등으로 확인하면 포트에 대한 정보가 보이지 않는 경우가 있다. 이는 공격자가 시스템을 해킹하여 netstat이나 ps 등을 변조하거나 커널 백도어인 LKM 등을 이용하여 특정 프로세스를 보이지 않도록 설정한 것이다. 이러한 경우에는 chkrootkit(http://www.chkrootkit.org/)을 이용하여 해당 프로세스의 pid를 찾을 수 있다.

반대로 netstat에는 보이지만 포트 스캔에는 보이지 않는 경우가 있는데, 이는 방화벽으로 차단되어 있거나 127.0.0.1 등 local 인터페이스에 대기하고 있기 때문이다.

업데이트 자동화

어떠한 시스템이든 보안에 완벽할 수 없는 만큼 시스템 및 패키지 패치와 업데이트는 서버 운영의 기본 사항이다. 윈도우의 경우 windowsupdate라는 것을 통해 브라우저로 접속하는 것만으로 쉽게 업데이트가 가능하지만, 리눅스 등 유닉스 계열은 CLI 기반이다 보니 업데이트가 쉽지 않은 것이 사실이다.

따라서 리눅스에서도 윈도우와 같이 편하게 자동으로 업데이트할 수는 없을까 고민하게 되는데, 이때 가장 권장할 만한 서비스는 바로 YUM(Yellow dog Updater, Modified)이다. YUM은 미국의 듀크 대학에서 파이썬 언어로 개발되고 있는데, YUM에 대한 자세한 내용은 http://linux.duke.edu/projects/vum을 참고하기 바란다.

앞의 사이트에서 제공되는 YUM을 설치한 후 간단히 YUM을 실행하면 현재 시스템이 설치되어 있는 rpm 버전 정보와 최신 업데이트 버전 정보를 비교하여 업데이트 여부를 확인 후 업데이트하게 된다. 이때 /etc/yum.conf에 지정되어 있는 서버에 접속하여 rpm의 헤더 파일을 비교하여 다운로드하게 되는데, 듀크 대학뿐만 아니라 여러 곳에서 여러 버전의 서버를 제공하고 있으므로 적당한 서버를 지정하여 사용하면 된다. 물론 서버를 많이 운영하고 있다면 자신이 직접 YUM 서버를 운영할 수도 있을 것이다.

만약 아무런 옵션 없이 YUM을 실행하면 사용할 수 있는 옵션을 제공하는데, 일반적으로 업데이트와 인스톨을 많이 사용한다. 다음과 같이 ‘yum -y update’를 실행하면 현재의 시스템에 설치되어 있는 rpm 헤더 정보를 비교하여 최신의 rpm으로 패치를 하게 된다.

여기에서 -y는 일일이 설치 여부를 묻지 않고 업데이트를 한다는 의미로 이때 문제될 수 있는 것이 바로 의존성(dependency) 문제인데, YUM은 이 문제를 자동으로 해결하므로 의존성 관련 문제는 걱정하지 않아도 된다. 다음은 YUM을 실행한 결과인데, 현재 모든 패키지가 업데이트되어 있다는 것을 알 수 있다.

# yum -y update

Gathering package information from servers

Getting headers from: Red Hat Linux 7.3 base

Getting headers from: Red Hat Linux 7.3 updates

Finding updated packages

Downloading needed headers

No Packages Available for Update

No actions to take

이처럼 ‘yum -y update’를 /etc/cron.daily/ 등에 설정하여 두면 매일 자동으로 업데이트 여부를 확인하여 자동 업데이트를 하므로 언제나 최신의 패치된 상태를 유지할 수 있을 것이다. 다음은 lsof라는 rpm이 설치되어 있지 않을 때, 인스톨을 실행하여 자동으로 설치하는 예를 보여주고 있다.

# yum install lsof

Gathering package information from servers

Getting headers from: Red Hat Linux 7.3 base

Getting headers from: Red Hat Linux 7.3 updates

Finding updated packages

Downloading needed headers

Resolving dependencies

Dependencies resolved

I will do the following:

[install: lsof.i386]

Is this ok [y/N]: y

Calculating available disk space - this could take a bit

lsof 100 % done

Installed: lsof.i386

Transaction(s) Complete

사용자 암호 관리

추측하기 어려운 암호를 사용하는 것은 보안의 가장 기본이라 할 수 있다. 그럼에도 불구하고 아이디와 동일한 암호를 사용하거나 1234 등 단순한 숫자를 암호로 사용하는 경우가 여전히 많다. 따라서 리눅스나 윈도우 등 OS에 관계없이 암호가 아예 없거나 단순한 암호를 사용하는 계정에 대한 무작위 대입을 통한 스캔 방식이 예전부터 꾸준히 발생하고 있어 암호 보안은 여전히 보안 이슈가 되고 있다.

실제로 적지 않은 해킹이 고급 기술을 사용하기보다는 단순 암호 추측을 통한 사례가 적지 않은 것이 사실이다. 따라서 현재의 시스템에서 사용되는 계정 중 쉬운 암호를 사용하는 계정을 찾아 어려운 암호로 수정할 경우 일정 정도 보안을 강화할 수 있을 것이다. 이러한 프로그램으로는 ‘John the ripper’라는 것을 사용하게 되는데, http://www.openwall.com/john/에 접속한 후 소스 파일을 다운로드해 컴파일을 설치하면 된다.

[root@server root]# tar zxvfp john-1.6.tar.gz // 압축 해제

[root@server root]# cd john-1.6/src // john-1.6/src 디렉토리로 이동

[root@server src]# make linux-x86-any-elf // 컴파일

[root@server src]# cd ../run/ // run 디렉토리로 이동

[root@server run]# ./unshadow /etc/passwd /etc/shadow > passwd_list

// 암호화된 암호가 저장된 passwd_list 파일 생성

[root@server run]# ./john passwd_list // 암호해독 시작

test (test)

saram1 (saram)

kim (kim)

v3 (v3)

123 (dream)

1111 (ftlog)

.....

앞의 결과에서 우측에 ‘()’로 쌓인 부분이 계정 이름이고 좌측이 계정의 암호인데, 보는 바와 같이 아이디와 암호를 동일하게 사용하거나 추측하기 쉬운 암호를 사용하는 계정이 적지 않다는 것을 알 수 있다. 아마 여러분의 시스템에서 실행해 보아도 비슷한 결과를 확인할 수 있을 것이다. 특히 이러한 스캔 결과는 john.pot 파일에 암호화되어 저장되는데, 새롭게 확인하려면 이 파일을 삭제 후 다시 실행하면 된다.

이를 활용하면 계정이 같거나 쉬운 암호를 사용하는 사용자에 대해서는 자동으로 암호를 변경하도록 경고 메일을 발송하도록 할 수 있는데, cron에 걸어두어 매주 또는 매달 실행하도록 해두면 유용할 것이다. 이를 위해서는 다음과 같이 mailer라는 스크립트를 만들면 되는데, 기존의 mailer 파일을 약간 수정하면 된다.

#!/bin/sh

#

if [ $# -ne 1 ]; then

echo Usage: $0 PASSWORD-FILE

exit 0

fi

# There's no need to mail users with these shells

SHELLS=-,/bin/false,/dev/null,/bin/sync

# Look for John in the same directory with this script

DIR=`echo $0

# Let's start

$DIR/john -show $1 -shells:$SHELLS

(

SENT=0

while read LOGIN; do

echo Sending mail to $LOGIN...

# You'll probably want to edit the message below

mail -s '[필독] 암호를 변경해 주세요.' $LOGIN << EOF

안녕하세요. 서버 관리자입니다.

현재 $LOGIN 님의 암호가 아이디와 동일하거나 추측하기가 쉬워

보안상 문제가 될 수 있습니다.

따라서 본 이메일을 받으신 후에는 $LOGIN의 암호를

추측하기 어렵게 수정하여 주시기 바랍니다.

감사합니다.

EOF

SENT=$(($SENT+1))

done

echo $SENT messages sent

)

이후 이메일을 보내려면 다음과 같이 실행하기만 하면 된다. 다음은 암호가 동일한 3명의 사용자에게 이메일이 발송되었음을 알 수 있다.

[root@server run]# ./mailer passwd_list

Sending mail to test...

Sending mail to kim...

Sending mail to v3...

3 messages sent

물론 이런 과정 역시 다음과 같이 간단한 스크립트로 만들 수 있다.

#!/bin/sh

cd /root/john-1.6/run/

rm -f john.pot restore passwd_list

./unshadow /etc/passwd /etc/shadow > passwd_list

./john passwd_list

./mailer passwd_list

유닉스 계열의 경우 외부에서 해킹을 할 때 직접 시스템의 root 권한을 획득하는 경우는 그다지 흔하지 않다. 일단 일반 유저 권한을 획득한 후에 각종 공격 코드나 여러 기법을 활용하여 root 권한 획득을 시도하는데, 이때 일반 사용자 권한을 획득하기 위해서 가장 많이 사용하는 방법이 바로 암호 무작위 대입법이다. 따라서 root 암호 관리도 물론 중요하지만 일반 유저에 대한 암호 관리 역시 매우 중요하다고 할 수 있다.

시스템 보안 설정 점검

마지막으로 시스템 전반적인 보안 설정을 점검해야 할 차례이다. 이때 유용하게 사용할 수 있는 것으로 rootcheck 라는 프로그램이 있는데, 시스템 내부의 보안 점검을 할 때 유용하게 활용할 수 있으며 프로그램을 실행하면 다음과 같은 스캔을 진행한다.

◆ LKM rootkit에서 사용되는 숨겨진 포트나 파일 점검

◆ 인터페이스의 promisc 여부 점검

◆ passwd 파일 점검

- /etc/passwd의 개수와 /etc/shadow 개수가 동일한지 확인

- 암호가 없는 계정이 있는지 확인

- 셸이 있는 시스템 계정이 있는지 확인

◆ httpd.conf나 inetd.conf, xinetd.conf, sshd_conf 등의 설정 파일 점검

- 설정 파일에 수상한 목록이 있는지 확인

- 잘못 설정되어 있는지 확인

- 설정 파일의 퍼미션이 잘못 지정되어 있는지 확인

◆ 삭제된 로그파일 등 로그 파일 관련 수상한 점 점검

◆ /proc과 ps를 점검하여 숨김 프로세스 여부 점검

◆ 알려진 루트킷 존재 여부 확인

◆ 백도어 디렉토리로 자주 사용되는 /dev 디렉토리 내 파일 존재 여부 점검

◆ 기타 수상한 파일이나 디렉토리 및 퍼미션 등 점검

- 파일이름이 ‘.’로 시작되는 파일

- 파일이름에 @, &, %와 같은 문자가 포함되었는지 확인

- suid/sgid 파일 점검

- history 파일이 /dev/null 등에 링크되어 있는지 확인

- 몇몇 바이너리의 변경 날짜 확인

또한 rootcheck의 홈페이지(http://www.ossec.net/rootcheck/)에 접속한 후 최신 버전의 패키지를 다운로드 및 설치하면 된다.

압축 후 설치된 디렉토리에서 다음과 같이 실행하면 사용할 수 있는 옵션이 나온다.

[root@server rootcheck-0.4]# ./rootcheck.pl --help

RootCheck 0.4

Options available:

--help 현재 화면을 보여준다.

--checkfiles 오직 파일만 체크한다.

--checkbin 오직 바이너리만 체크한다.

--checkports 오직 포트만 체크한다.

--checkif 오직 인터페이스만 체크한다.

--checkpasswd 오직 passwd db만 체크한다.

--checklogs 오직 logs만 체크한다.

--checkprocess 오직 process만 체크한다.

--logfile=xx 결과를 특정 파일에 저장한다.

--html 로그를 html 형식으로 저장한다.

--silent 어떠한 것도 출력하지 않는다.

--terminal 터미널에 출력한다.

--email=xx@xx.com

결과를 이메일로 발송한다.

--smtpserver=xx.com 이메일 발송시 smtp를 별도로 지정한다.

.

각자 환경에 맞게 적당한 옵션을 주어 스캔한 결과는 현재 디렉토리에 저장된다. suid 파일에 대한 정보는 suidfiles.txt에, 모든 파일은 logfiles.txt에, 시스템 배너는 banners.txt에, 스캔 결과는 result.txt에 저장된다. 종합적인 결과는 result.txt에 저장되므로 이 파일을 살펴서 시스템의 무결성 여부를 확인하면 된다. 그리고 관리하는 시스템이 많다면 매번 로그인해서 체크하기가 번거로우므로 실행 결과는 메일로 발송되도록 간단한 스크립트를 이용하면 상당 부분의 업무를 자동화할 수 있을 것이다.

보안의 핵심 프로세스는 지속적인 관리

지금까지 보안을 강화하기 위한 여러 가지 방법과 절차에 대해 간단히 소개했지만 어떤 OS든 관계없이 보안의 가장 중요한 부분은 역시 지속적인 관심과 관리라는 것을 느꼈을 것이다.

당장 전문적인 관리자가 아니더라도 자신의 시스템에 관심을 갖고 시스템에서 발생하는 현상에 관심을 기울인다면 조금씩 자신의 시스템에 익숙해지는 자신을 발견할 수 있을 것이다. 다음 글에서는 시스템과 뗄 수 없는 관계인 네트워크 보안 강화 방안에 대해 알아보도록 하자. @

* 이 기사는 ZDNet Korea의 제휴매체인 마이크로소프트웨어에 게재된 내용입니다.