posted by 구름너머 2006. 8. 17. 09:40

10. 프로세스와 시그널 프로세스는 무엇인가?

수행되는 프로그램.(시스템 자원을 요구하는 하나의 스레드와 주소공간)

프로세스의 구조

각각의 프로세스는 프로세스 식별자로 구분한다.

grep 명령에 의해 수행되는 프로그램 코드는 디스크상에 파일로 저장되어 있다가 읽기만 가능한 메모리상으로 올라온다.

시스템 라이브러리도 공유된다.

프로세스는 함수에서 사용되는 지역변수, 함수의 호출과 반환을 제어하기 위한 목적으로 자신만의 스택을 가지고 있다. 또한 자신의 사용목으로 환경변수를 포함하는 환경영역을 가지고 있다.

  • 프로세스 테이블

현재 적재된 모든 프로세스를 나타내는 데이터구조가 프로세스 테이블이다.

PID, 터미널형태, 프로세스 상태와 명령등으로 구성되고, ps명령에 의해 볼 수 있다.

보통은 256 프로세스로 제한이 되어 있다. 그러나 최근엔...(?)

  • 프로세스 살펴보기

ps 명령으로 현재 수행되고 있는 프로세스를 살펴볼 수 있다.

-x 옵션은 전체프로세스의 상황을 보여주며, -a 옵션은 모든 사용자가 수행하고 있는 프로세스 정보를 보여준다. 그 외에는 man을 참고하자.

  • 시스템 프로세스

$ ps -ax

init 는 모든 프로세스의 조상이며, 다른 시스템 프로세스는 init에서 파생된다.

  • 프로세스 스케줄링

상태(STAT)가 S이면 Sleep 상태이며, R이면 다른 프로세스가 작업을 마치기를 기다리지 않고 있거나 입출력이 완료되기를 기다리고 있는 상태라는 뜻이다.

유닉스 시스템은 다음 시간에 어떤 프로세스를 할당할 지를 결정하기 위해서 프로세스 스케줄러를 사용한다. 이것은 프로세스의 우선순위에 기반한다.

nice 프로그램은 프로그램의 우선순위를 변경할 수 있고, renice는 해당 프로세스의 우선순위를 10만큼 감소시킬 수 있다.

우선순위의 기본은 0이며 높은 우선순위는 음수값을 낮은 우선순위는 양수값을 갖는다. 현재 활성화된 프로세스의 우선순위값은 ps -l 로 볼 수 있다.

 

새로운 프로세스를 수행하기

system함수는 하나의 프로그램 내부에서 다른 프로그램을 실행시킨다.

system함수는 해당명령이 종료할 때 까지 기다린다. 즉, 호출한 프로세스가 끝날 때까지 기다린다. system함수가 다른 명령을 호출한 즉시 리턴되도록 하려면 끝에 '&'를 붙여 백그라운드로 실행시키도록 한다.

system함수는 쉘상에서 'sh -c string' 와 같다.

[예제. p397]

  • 프로세스 이미지의 대체

exec류의 함수들은 현재의 프로세스를 주어진 인자에 따라 생성되는 또 다른 프로세스로 대체한다.

함수는 exec, execlp, execle, execv, execvp, execve 등이 있다.

[예제. p400] execlp 호출

  • 프로세스 이미지의 복사

fork를 사용하면 새로운 프로세스를 만들 수 있다.

생성된 자식 프로세스는 부모 프로세스의 데이터 공간(변수), 열려진 파일 기술자, 디렉토리 복사본 등을 보유한다.

[예제. 10.402]

  • 프로세스를 기다리기

wait를 사용하면 부모 프로세스는 자식 프로세스가 종료하기를 기다린다

[예제. 404]

  • 좀비 프로세스

자식 프로세스가 종료하더라도, 부모 프로세스가 정상적으로 종료하거나 wait를 호출할때 까지 자식은 완전히 죽지 않고 시스템에서 잔류한다.

이럴경우 자식은 좀비 프로세스로 바뀐다.

[예제. p406]

waitpad 시스템 호출은 특정한 자식프로세스가 종료하기를 기다리는데 사용할 수 있다.

  • 입력과 출력의 리다이렉션

[예제. p408]

  • 스레드

스레드는 '중량' 프로세스와 대비되는 '경량' 프로세스라고 할 수 있다.

프로세스는 서로 영향을 미치지 않지만 스레드는 다른 스레드에게 치명적인 영향을 줄 수 있다.

시그널

시그널은 어떠한 조건에 대응하여 유닉스 시스템이 발생시키는 일종의 사건이다.

시그널은 쉘이나 시그널을 발생시키는 터미널 처리기에 의해 발생한다.

하나의 프로세스에서 다른 프로세스에게 정보를 전달하거나, 행동을 변경시키기 위해 시그널을 보낼 수 있다.

시그널은 생성되거나 포착되거나 무시될 수 있다.

시그널(을 받는) 함수는 signal이며 sig와 func의 두개의 매개변수를 받는다.

sig에는 포착하거나 무시할 시그널을 명시하고, func는 해당 시그널을 받을 때 호출할 함수이다. func함수는 하나의 int인자를 가져야 하며 형은 void이어야 한다. func함수는 이전의 sig시그널에 설정된 함수를 반환하거나 SIG_IGN(시그널무시), 또는 SIG_DEL(기본액션저장)을 반환해야 한다.

[예제. p413]

  • 시그널을 보내기

프로세스는 raise를 호출하여 자기 자신에게 시그널을 보낼 수 있다.

하나의 프로세스는 kill 호출을 사용하여 다른 프로세스에게 시그널을 보낼 수 있다.

시그널은 사용자에게 유용한 알람시계를 제공하는데, alarm 호출은 해당 프로세스가 SIGALRM시그널을 예약하는데 사용될 수 있다.

[예제. p416] 알람시계..

getpid() - 현재프로세스의 PID

getppid() - 부모프로세스의 PID

pause() - 시그널이 발생할 때까지 프로그램 실행 중단

  • 튼튼한 시그널 인터페이스

시그널을 포착해서 지정한 함수를 실행중일 때 같은 시그널이 또 발생한다면 결과는 예측하기 어렵다. 이것이 임계 타이밍의 문제이며 프로그래머가 해결해야 한다.

그래서 좀더 튼튼한 새로운 프로그래밍 인터페이스로서 sigaction 을 추천한다.

sigaction 은 시그널이 발생해서 해당 함수가 실행되는 동안 그 시그널을 블럭시킨다.

sigaction 함수는 구조체로 sigaction을 포함하고 있는데, 매개변수로 시그널 sig가 포착되었을 때 실행되는 액션을 정의한다.

[예제. p419] sigaction으로 SIGINT를 처리한다.

  • 시그널 집합

signal.h 에는 'sigset_t'형과 시그널 집합을 처리하는 함수들이 정의되어 있다.

sigemptyset - 시그널 집합을 텅비게 한다.

sigfillset - 정의된 모든 시그널을 시그널 집합에 포함하도록 설정한다.

sigaddset, sigdelset - 지정한 시그널(signo)을 시그널 집합에 추가하거나 제거한다.

sigismember - 지정한 시그널이 시그널 집합의 멤버인지 검사한다.

sigprocmask - 프로세스의 시그널 마스크를 설정하거나 검사한다.

sigpending - 현재 블록되어 미결인 채로 남아있는 시그널을 검사한다.

sigsuspend - 프로세스를 시그널 집합 중 하나가 도착할 때까지 수행을 중단시킨다.

sigaction 플래그

sigaction에서 사용되는 sigaction구조체의 sa_flags 필드는 시그널의 행동을 수정하기 위해 다음과 같은 값을 포함할 수 있다.

-> SA_NOCLDSTOP, SA_RESETHAND, SA_RESTART, SA_NODEFER

  • 공통적인 시그널

유닉스 프로그램에서 전형적으로 필요로 하는 시그널들은 다음과 같다.

존재하는 시그널의 목록

이름

signal - 존재하는 시그널의 목록

설명

리눅스는 아래 나열된 시그널을 지원한다. 몇몇 개의 시그널 번호는 아키텍쳐 의존적이다.

먼저 POSIX.1에서 설명하는 시그널이다.

시그널

번호

행동

설명

SIGINT

2

A

키보드로부터의 인터럽트(interrupt) 시그널

SIGQUIT

3

C

키보드로부터의 종료(quit) 시그널

SIGILL

4

C

잘못된 명령어(Illegal Instruction)

SIGABRT

6

C

abort(3)로부터의 중단(abort) 시그널

SIGFPE

8

C

부동 소수점 예외(exception)

SIGKILL

9

AEF

kill 시그널

SIGSEGV

11

C

잘못된 메모리 참조

SIGPIPE

13

A

깨진 파이프: 수신자가 없는 파이프에 쓰기

SIGALRM

14

A

alarm(2)으로부터의 타이머 시그널

SIGTERM

15

A

종료(termination) 시그널

SIGUSR1

30,10,16

A

사용자 정의 시그널 1

SIGUSR2

31,12,17

A

사용자 정의 시그널 2

SIGCHLD

20,17,18

B

자식 프로세스가 중단 또는 종료

SIGCONT

19,18,25

중단되었다면 재개(continue)

SIGSTOP

17,19,23

DEF

프로세스 중단

SIGTSTP

18,20,24

D

터미널에서의 중단 시그널

SIGTTIN

21,21,26

D

백그라운드 프로세스에 대한 터미널 입력

SIGTTOU

22,22,27

D

백그라운드 프로세스에 대한 터미널 출력

다음은 POSIX.1의 시그널은 아니지만 SUSv2에서 설명하고 있는 것이다.

시그널

번호

행동

설명

SIGPOLL

A

폴링(poll) 이벤트 (Sys V). SIGIO와 같다.

SIGPROF

27,27,29

A

프로파일링(profiling) 타이머 시그널

SIGSYS

12,-,12

C

루틴에 잘못된 인자 (SVID)

SIGTRAP

5

C

trace/breakpoint 트랩

SIGURG

16,23,21

B

소켓에 대한 긴급(urgent) 상황 (4.2 BSD)

SIGVTALRM

26,26,28

가상 알람 클럭 (4.2 BSD)

SIGXCPU

24,24,30

C

CPU 시간 제한 초과 (4.2 BSD)

SIGXFSZ

25,25,31

C

파일 크기 제한 초과 (4.2 BSD)

(SIGSYS, SIGXCPU, SIGXFSZ와 몇몇 아키텍쳐에서는 SIGBUS의 기본 행동은 SUSv2에서 C(종료와 코어 덤프)로 나와있지만 현재 리눅스(2.3.27)에서는A(종료)이다)

다음은 여러 가지 다른 시그널.

시그널

번호

행동

설명

SIGEMT

7,-,7

SIGSTKFLT

-,16,-

보조프로세서의 스택 오류

SIGIO

23,29,22

A

현재 I/O가 가능 (4.2 BSD)

SIGCLD

-,-,18

SIGCHLD와 같다.

SIGPWR

29,30,19

A

전원 문제 (System V)

SIGINFO

29,-,-

SIGPWR와 같다.

SIGLOST

-,-,-

A

파일 락(lock) 손실

SIGWINCH

28,28,20

B

윈도우 크기 변경 시그널 (4.3 BSD, Sun)

SIGUNUSED

-,31,-

A

사용되지 않는 시그널 (SIGSYS가될 것이다)

(여기서 -는 시그널이 없음을 나타낸다. 세 가지 값이 있다. 첫번째 것은 대개 alpha sparc에서, 중간의 것은 i386, ppc sh에서, 마지막 것은 mips에서 유효한 값이다. 29번 시그널은 alpha에서는 SIGINFO / SIGPWR이지만 sparc에서는 SIGLOST이다.)

"행동" 컬럼의 문자는 다음과 같은 의미이다:

A 기본 행동이 프로세스를 종료하는 것이다.

B 기본 행동이 시그널을 무시하는 것이다.

C 기본 행동이 프로세스를 종료하고 코어를 덤프한다.

D 기본 행동이 프로세스를 멈추는 것이다.

E 핸들러를 둘 수 없는 시그널이다.

F 무시할 수 없는 시그널이다.

호환

POSIX.1

버그: SIGIOSIGLOST는 같은 값을 갖는다. 후자는 커널 소스에서 주석 처리되었지만, 몇몇 소프트웨어의 프로세스는 여전히 29번 시그널을 SIGLOST로 생각한다.

'UNIX' 카테고리의 다른 글

간단한 network 명령외... for DOS and UNIX  (0) 2006.08.31
[unix]압축-compress 사용법  (0) 2006.08.22
안전한 유닉스 프로그래밍을 위한 지침서 V.0.7  (0) 2006.08.17
Dynamic SQL의 사용  (1) 2006.08.11
UNIX 고급  (0) 2006.08.11
posted by 구름너머 2006. 8. 17. 09:33
안전한 유닉스 프로그래밍을 위한 지침서 V.0.7

2001. 1.
박현미/CERTCC-KR
hmpark@{certcc,kisa}.or.kr

시작하면서

이 지침서는 안전한 프로그램을 위한 프로그래머가 지켜야할 설계와 구현 방법에대한 지침서로 어플리케이션 프로그램과 웹 어플리케이션(CGI), 네트워크 서버, setuid/setgid 프로그램 등의 보안 영역(Security Boundary)에 대하여 설명한다.

또한 이 지침서는 프로그래머가 실제 프로그램을 개발하면서 참조할 수 있는 실용적인 지침서로 리눅스나 유닉스 시스템을 기본 템플릿으로 한다. 이 지침서를 읽는 독자는 기본적인 유닉스 시스템의 보안과 C 언어에 대한 이해가 요구되며 이 지침서의 목표가 안전한 프로그래밍(Secure Programming)임을 기억해야 한다.

지침서는 계속 업데이트되며 수정하거나 추가할 사항이 있으면 언제든지 cert@certcc.or.kr이나 hmpark@certcc.or.kr로 연락주기 바란다.

Ⅰ. 프로세스 보안

유닉스 시스템은 윈도우 시스템과는 달리 파일이나 프로세스의 권한을 설정하는 특별한 속성들을 가지고 있다. 이러한 속성들은 안전한 프로그램을 작성하는데 직접적으로 영향을 미치므로 유닉스의 속성에 대하여 이해하고 이것을 안전하게 프로그램에 작성하는 것이 필요한다.

1. SUID/EUID 보안

1.1 SUID와 EUID, SUID

(1) Real UID, effective UID와 saved UID

유닉스 시스템에서 파일과 프로세스의 권한을 나타낸 것으로 다음과 같은 속성이 있다.

? Real UID와 GID(RUID와 RGID)

프로세스가 실행될 때 사용자의 실제 UID와 GID를 나타내는 용어로 특히 RUID가 0인 것은 파일시스템에 대한 모든 권한을 가진 사용자로 root라고 한다. root는 대부분의 중요한 보안 사항을 체크하고 수정하고 시스템을 관리할 수 있으므로 다른 RUID보다 더 큰 권한을 가지고 있기 때문에 보안상으로 중요하다.

? Effective UID와 GID(EUID와 EGID)

누구의 권한으로 프로세스가 실행하는가를 나타내는 용어로 이것은 프로세스가 실행될 때 누구의 권한으로 실행되는지를 나타내므로 보안에서 특히 문제가 되는 부분이다. /sbin/passwd 프로그램처럼 EUID가 root로 실행될 경우에 주의해야 한다.

? Saved UID와 GID(SUID와 SGID)

프로그램에 의해 변하기 전의 UID를 나타내는 것으로 권한 교환을 허용하고 허용하지 않음을 지원하기 위하여 사용한다.

(2) SUID와 SGID 프로그램

프로그램들이 파일과 프로세스들에 접근하는 것을 허락하는 것으로 setuid는 사용자의 권한을 임시적으로 바꿔준다. 즉, 권한이 없는 사용자가 특별한 권한을 요구하는 작업을 해야할 경우에 사용한다. 이러한 특별한 권한은 이 프로그램이 실행하는 동안에만 영향을 받고 프로그램이 끝나면 원래의 사용자 권한으로 돌아오게 된다. SUID/SGID 프로그램은 setuid/setgid 비트 s로 표시한다.

(예제 1) SUID/SGID 프로그램 - 패스워드 프로그램

패스워드 프로그램에서 패스워드 파일은 root만이 수정할 수 있다. 그런데 일반 사용자가 자신의 패스워드를 수정하기 위해서는 root의 권한이 필요하다. 이 때 패스워드 프로그램을 SUID 프로그램으로 하여 일반사용자도 잠시동안 root의 권한을 가져 패스워드 파일을 수정할 수 있게 한다.

[cert:root]:/user/staff> ls -la /etc/passwd

-rw-r--r-- 1 root sys 2657 10월 5일 14:08 /etc/passwd


[cert:root]:/user/staff> ls -la /bin/passwd

-r-sr-sr-x 3 root sys 96796 1997년 7월 16일 /bin/passwd*

1.2 SUID/SGID 프로그램의 위험성

SUID 프로그램은 실행될 때 프로그램 소유자의 권한으로 수행되므로 잘 못 사용될 경우에 위험할 수도 있다. /bin/sh은 쉘을 실행하는 프로그램으로 일반적으로 사용자가 로그인하였을 때 실행되어 사용자는 쉘 상에서 유닉스 명령어를 사용할 수 있다.

다음은 setuid 된 /bin/sh 프로그램의 실행을 보여주는 예이다. 처음 사용자의 권한은 일반사용자 hmpark을 가지지만 setuid 된 /bin/sh을 실행하고 난 후에는 /bin/sh의 소유자의 권한인 root로 실행되는 것을 확인할 수 있다.

[hmpark@linux80 ~]$ whoami

hmpark

[hmpark@linux80 ~]$ ls -la /bin/sh

-rwsr-xr-x 1 root root 378024 10월 8 1999 /bin/sh*

[hmpark@linux80 ~]$ /bin/sh

[hmpark@linux80 hmpark]# id

uid=504(hmpark) gid=504(hmpark) euid=0(root) groups=504(hmpark)

[hmpark@linux80 hmpark]# whoami

root


위에서 보는 바와 같이 setuid 비트가 설정되어 있는 프로그램이 실행하는 경우 그 프로세스의 UID는 실제 파일을 실행하는 사용자의 권한을 가지지만 프로세스의 EUID는 setuid 된 프로그램을 실행한 사용자의 권한을 가지는 것을 알 수 있다.(uid=504(hmpark), euid=0(root)) 즉, 위의 /bin/sh이라는 프로세스는 hmpark라는 UID를 가지지만 EUID는 /bin/sh의 실제 소유자의 권한을 가지므로 root가 되는 것이다. 그래서 이 쉘 프로세스는 root의 권한으로 실행된다는 것을 알 수 있다.

위와 같은 상황에서 SUID 프로그램에서 발생할 수 있는 위협에 대하여 생각해 보아야 한다. root 권한을 가진 쉘이 실행될 때 쉘이 끝내기 전까지는 root로 setuid된 상태가 계속된다. 이때 공격자는 root 권한으로 할 수 있는 모든 작업을 할 수 있기 때문에 시스템에 치명적인 피해를 입힐 수도 있다.

1.3 안전한 SUID/SGID 프로그램 원리

? UID와 GID를 가능한 제한한다.

setuid 프로그램을 실행할 때 가능한 UID와 GID가 낮은 권한을 가지도록 해야 한다. root로 setuid된 프로그램이 침범 당하면 모든 시스템을 파괴할 가능성이 있지만 일반 사용자로 setuid된 프로그램은 일반 사용자의 권한만을 침범당하므로 피해가 적기 때문이다.

? exec를 호출하기 전에 effective UID와 GID를 재 설정한다.

일반적으로 popen이나 system과 같은 라이브러리 서브루틴이 실행될 때 내부적으로 exec 함수가 호출된다. 그런데 대부분의 프로그래머는 이러한 사실을 인식하지 못한채 그냥 서브루틴 함수를 사용하는 경우가 있다. 이 프로그램이 setuid root인 프로그램이라면 여기에서 실행되는 쉘도 권한이 root인 쉘이 실행될 것이다. 그러므로 exec 함수가 호출되기 전에 effective UID와 GID를 재 설정하는 것이 중요하다.

? exec를 호출하기 전에 모든 파일 기술자를 닫는다.

setuid 프로그램이 중요한 파일을 읽을 경우에 exec된 프로그램도 그 중요한 파일을 읽을 수가 있다. 그러므로 이것을 방지하기 위해서는 exec가 발생할 때마다 중요한 파일을 닫도록 하는 flag를 설정해야 한다. 이 flag는 파일이 열리자마자 즉시 설정되어야 한다.

즉 sfd가 중요한 파일의 기술자인 경우

fcntl(sfd, F_SETFD, 1)

ioctl(sfd, FIOCLEX, NULL)

의 명령들은 exec가 실행될 때 파일을 닫도록 한다.

? root가 확실하게 제한되어있는지 다시 확인하라.

chroot()는 새로운 루트 디렉토리를 설정하여 chroot된 프로세스가 디렉토리의 상위 디렉토리에 접근할 수 없게 해주는 역할을 하는 함수이다.

chroot("/usr/riacs")

이 함수를 사용하여 프로세스가 접근할 수 있는 영역을 미리 제한하여 파일 시스템의 임의의 파일을 읽거나 쓸 수 있는 문제점에 대한 보안 환경을 제공해 준다.

ln -s /usr/demo /usr/riacs/demo

그런데 /usr/demo를 /usr/riacs/demo에 링크시키면 제한되어 있는 디렉토리까지 침범할 수 있는 위험이 있으므로 주의해야 한다. 즉, 위의 링크에서 /usr/riacs는 "/"로 해석되기 때문에

cd /demo

cd ..

명령 후에 /usr 디렉토리에 접근할 수 있게 된다. 그러므로 chroot하여 생긴 새로운 루트 디렉토리의 서브디렉토리에서는 링크된 디렉토리를 사용하지 않아야 한다.

? 실행될 프로세스의 환경을 검사하라.

많은 환경변수은 부모 프로세스로부터 상속된 PATH나 IFS, umask와 같은 변수들에 의해 좌우된다.

? 최소한의 권한 원리

권한을 일시적으로 낮추거나 권한을 완전히 제거하는 것은 잘못된 권한 설정으로 인하여 발생할 수 있는 결점을 최소화 할 수 있는 방법이다.

? 외부의 입력값을 믿지 말아라.

외부에서 입력된 값은 충분하게 검사하고 필요없는 값들을 지운 후에 유효한 값으로 평가되었을 경우에 사용하도록 한다.

2. 새로운 프로세스의 생성 보안

2.1 프로세스 실행시 위험성

생성한 프로세스는 exec 계열 시스템 함수를 이용하여 새로운 프로그램을 실행시키는데 특히 system(), popen() 함수는 새로운 프로그램을 실행시킬 때 setuid나 네트워크 서비스처럼 특별한 권한을 요구하는 프로그램인 경우에는 특별히 유의해야 한다.

2.2 안전한 프로그램 원리

? system(), popen() 함수를 사용하지 않는다.

SUID 프로그램이나 네트워크 서비스 프로그램은 특별한 권한을 가지고 실행된다. 그런데 system(), popen() 함수는 쉘 인터프리터인 /bin/sh를 실행하여 다른 프로그램을 실행하기 때문에 위험하다. 그러므로 대신 execl()이나 execv() 시스템 함수를 사용해야 한다.

? 모든 파일 기술자를 닫았는지 꼭 확인한다.

새로 생성된 자식 프로세스는 부모 프로세스로부터 파일 기술자의 복사본을 가지므로 부모 프로세스가 중요한 파일(ex, /etc/passwd)을 열었을 경우 이 파일의 파일 기술자 상속받기 때문에 파일이 노출될 수 있다. 그러므로 파일 기술자를 열었을 경우에는 자식 프로세스가 생성되기 전에 모든 파일 기술자를 닫아야 한다.

? 프로그램을 실행할 때 전체 경로 이름을 사용하는지 확인한다.

상대 경로를 사용하여 프로그램을 실행하였을 경우에 임의의 프로그램이나 트로이잔 프로그램을 실행될 수 있기 때문에 꼭 절대 경로를 사용하도록 한다.

? 자식 프로세스에 전달된 환경변수를 확인한다.

자식 프로세스는 부모 프로세스로부터 환경변수를 상속받는다. 그런데 환경변수가 수시로 정의될 수 있으므로 위험하다. 그러므로 환경변수를 상속받을 경우에는 꼭 필요한 환경변수를 상속받도록 하고 다른 환경변수는 깨끗한지 확인하도록 한다.

Ⅱ. 파일시스템 보안

1. 디폴트 권한 설정 보안 - umask

1.1 umask의 위험성

생성된 파일이나 실행되는 프로그램은 디폴트 파일 권한을 가지고 설정된다. 이러한 디폴트 권한은 프로세스 umask에 의해서 설정되는데 이 권한은 부모 프로세스나 로그인 쉘에의해 상속받는다. 그런데 umask가 안전하지 않은 권한으로 설정된 경우 허가되지 않은 사용자에게까지 파일이나 프로세스에 접근을 허락하여 보안 문제를 야기할 수 있다.

1.2 안전한 umask 사용 원리

디폴트로 umask는 022로 설정되어 있는데 umask를 수정하기 위해서는umask()라는 라이브러리 호출 함수를 사용한다.

umask
사용자 접근
그룹 접근
다른 사용자
0000
all
all
all
0002
all
all
read, execute
0007
all
all
none
0022
all
read, execute
read, execute
0027
all
read, execute
none
0077
all
none
none

[표-1] 일반적인 umask 설정값

2. 입력 시간 제한

특히 네트워크에서 들어오는 자료에는 타임 아웃과 로드 한도를 제한해야 한다. 만약 그렇지 않으면, 서비스를 끊임없이 요청하는 서비스 거부 공격을 쉽게 초래할 수 있을지도 모른다.

3. 안전한 임시 파일 사용 보안

3.1 임시(tmp) 파일의 위험성

임시 파일은 /tmp 디렉토리에 저장되는 파일로 이 파일에 접근하기 위해 특별한 권한이 필요하지 않고 또한 이름을 예측하기 쉽고 잘 알려져 있다. 그래서 프로그램들은 이 파일에 접근하여 파일을 연 후 파일안에 어떤 데이터들을 삽입하기 쉽다.

(예제 2) 임시 파일을 이용한 공격

① root로 실행되는 시스템 프로그램을 공격자가 실행시킨다. 이 시스템 프로그램은 tmp 디렉토리 안의 임시 파일(/tmp/program.temp)을 연다.

② 공격자는 이 임시 파일을 중요한 파일(권한있는 사용자가 소유한 파일, /etc/passwd)에 링크를 건다.

> ln -s /etc/passwd /tmp/program.temp

이렇게 링크를 걸면 공격자가 임시파일에 임의의 데이터를 쓸 경우에 링크에의해 실제 써지는 파일은 /etc/passwd 파일이 되어 passwd 파일에 악의적인 정보가 삽입되게 된다.

(예제 3) 임시 파일을 이용한 공격

① 임시 파일을 처리하는 권한이 없는 프로그램을 실행시킨다.

② 중요한 파일에 링크를 건다.

> ln -s /etc/passwd /tmp/program.temp

③ 신뢰할 수 있는 사용자가 이 프로그램을 실행한다.

이렇게 하면 공격 (예제 2)에서처럼 임시파일에 쓰나 실제로는 중요한 파일(/etc/passwd) 파일에 써지게 된다. 공격 (예제 1)과 (예제 2)의 차이점은 프로그램이 (예제 1)에서는 root의 권한으로 실행되고 (예제 2)에서는 일반 사용자의 권한으로 실행된다는 것이다.

3.2 안전한 임시파일 사용 프로그램 원리

? /tmp 디렉토리안에 임시 파일을 생성하지 말아라.

? 임시파일을 생성하는 인터페이스를 제공하는 시스템을 사용한다.

임시파일을 생성하기 위한 많은 함수들이 제공되는데 발생할 수 있는 보안 문제에 대비하기 위하여 주의깊게 사용해야 한다.

- tmpfile()의 사용

FILE *tmpfile(void);

tmpfile() 함수는 임시 파일을 생성하여 파일 스트림에 파일 기술자를 리턴한다. 특히 tmpfile() 함수는 mkstemp() 함수를 이용하여 임시 파일을 생성하고 바로 파일을 unlink() 하기 때문에 레이스컨디션의 발생을 피할 수 있다.

? 임시 파일의 이름을 예측할 수 있는 이름으로 생성하지 말고 랜덤하게 생성하라.

- mkstemp() 함수의 사용

int mkstemp(char *template);

mkstemp() 함수는 매개변수로 임시 파일의 형식을 입력받아 랜덤한 값을 이용하여 랜덤한 임시 파일 이름을 생성한다.

fd = mkstemp("/tmp/tempfileXXXXXX");

또한 이 함수는 임시 파일이름의 생성과 파일의 열기 사이에서 발생할 수 있는 레이스컨디션 오류를 방지할 수 있다.

- mktemp() 함수의 사용

char *mktemp(char *template);

mktemp() 함수도 mkstemp() 함수와 같이 임시 파일의 형식을 매개변수로 입력받안 랜덤한 파일 이름을 생성한다. 그러나 대부분의 시스템이 랜덤값으로 PID를 사용하기 때문에 파일의 이름을 쉽게 예측할 수 있어 레이스컨디션 공격을 받기 쉽다.

filename = mktemp("/tmp/tempfileXXXXXX");

또한 이 함수는 임시 파일을 생성한 후 바로 이 파일을 열어야 한다. 만약 다음과 같은 호출로 파일을 열었을 경우

open(filename, O_WRONLY|O_CREAT, 0644);

파일이 이미 존재할지라고 파일을 생성하기 때문에 위험하다. 그렇기 때문에

open(filename, O_WRONLY|O_CREAT|O_EXCL, 0644);

은 파일이 이미 존재할 때 호출이 실패하기 때문에 더 안전한 프로그램을 작성할 수 있다.

? 임시 파일을 생성하기 위한 /tmp 디렉토리 안에 추가 디렉토리를 생성한다. mktemp() 함수를 이용하여 임시 파일을 생성할 때 파일 이름을 디렉토리 이름으로 사용할 수 있다.

3.3 /tmp 디렉토리 보안

가. /tmp 디렉토리에서 발생할 수 있는 위험성

유닉스 시스템 /tmp 디렉토리에 임의의 크기를 가진 파일을 생성하도록 하는데 /tmp 디렉토리의 할당량을 검사하지 않아 한 사용자가 /tmp 디렉토리의 모든 용량을 사용하여 다른 사용자가 파일을 생성할 수 없도록 하는 문제점을 가지고 있다.

나. /tmp 디렉토리의 보안 원리

? /tmp 디렉토리의 용량을 검사하여 한 사용자가 /tmp 디렉토리 용량의 40% 이상을 차지할 수 없게 한다.

? /tmp 디렉토리를 모니터링하는 프로세스를 생성하여 시스템 관리자에게 통보할 수 있게 한다.

Ⅲ. 자원 보안

1. 시스템 자원의 할당과 자원 제한의 중요성

유닉스 시스템에서 자원에 대한 파일시스템 할당량(filesystem Quota)과 프로세스 자원 제한(process resource Limit)을 두는 것은 각 사용자가 사용할 수 있는 자원에 제한을 두는 것으로 저장(storage) 블록 수나 사용할 수 있는 유일한 파일(inode) 수를 제한하여 사용자나 그룹에 대한 한계를 설정할 수 있다. 이러한 제한은 의미상으로 약간의 차이가 있는 'hard'와 'soft' 제한으로 나눌 수 있는데 'hard'는 제한에 대하여 한계를 넘을 수 없는 제한이고 'soft' 제한은 한계을 임시적으로 넘을 수 있는 것이다. quota(), quotactl(), quotaon()과 같은 함수를 이용할 수 있다.

시스템 자원에 대한 할당량을 제한하는 것은 서비스 거부 공격(Denial of Service Attack)을 막을 수 있게 하는 이점이 있다. 또한 파일의 크기(file size)나 자식 프로세스(child process)의 수, open file의 수 등의 프로세스에 대한 할당을 지원하는 rlimit 메커니즘이 있는데 getrlimit(), setrlimit(), getrusage() 함수를 이용하여 사용할 수 있다.

2. core 파일 보안

보통 core 파일은 유닉스 시스템에서 예외 상황이 발생했을 때 생성되는 파일로 core나 program.core라는 이름을 가진다. 예외가 발생하는 상황은 다음과 같다.

- 프로그램 메모리에 침범당한 경우

- 프로그램 스택에 침범당한 경우

- 유효하지 않은 메모리에 접근하는 경우

- 잘못 정렬된 구조체에 접근하는 경우

core 파일은 운영체제에 의해 실행 프로그램의 메모리가 디스크 파일에 쓰여진다. core 파일은 보통 파괴된 프로그램의 상태를 점검하는데 이용한다.

2.1 core 파일의 위험성

? 프로그램의 모든 메모리 내용이 이 파일에 쓰여지므로 중요하고 결정적인 정보등을 저장하고 있다.

? 과거의 어떤 운영체제에서는 core 파일을 점검할 수 없었다. 그래서 core 파일을 중요한 파일에 링크를 걸어 높은 권한을 가진 파일을 SUID/SGID 프로그램을 실행시킴으로써 중요한 파일을 가져올 수 있었다.

2.2 안전한 core 파일 원리

? 예외가 발생했을 경우 core 파일을 생성하지 못하게 제한하는 setrlimit() 함수를 사용한다.

int setrlimit(int recource, const struct rlimit *rlp);

이 함수는 RLIMIT_CORE라는 자원의 타입을 사용하여 생성되는 core 파일의 크기를 설정할 수 있다. 그래서 파일의 크기를 0으로 설정하면 core 파일은 생성되지 않는다.

<프로그램-1> core 파일이 생성되지 않는 프로그램

int nocore()

{

struct rlimit rlp;

rlp->rlim_cur = 0;

rlp->rlim_max = 0;

return(setrlimit(RLIMIT_CORE, &rlp));

}

Ⅳ. 입력값 평가

입력된 값으로 인하여 공격자로부터 공격을 받을 수 있다. 그래서 입력된 값은 그 값이 사용되기 전에 제거되어야 하는데 이 장에서는 신뢰할 수 없는 값이 입력되는 방법을 알아보고 각 입력을 처리하여 안전한 프로그램을 작성할 수 있도록 하는 방법을 제시하고자 한다.

입력값을 처리하기 위해서는 먼저 어떤 값이 적합한지 규칙을 정해야 한다. 그래서 입력값이 정의된 규칙에 맞지 않으면 제거하고 규칙에 합당한 값만을 입력받아야 한다. 그런데 역으로 적합하지 않은 값을 정하고(what is illegal?) 규칙에 맞지 않는, 적합한 값을 제거하는 방법은 생각하지 못했던 치명적인 오류들을 그냥 지나칠 수 있으므로 이런 방법으로 규칙을 정하지 않아야 한다. 또 생각해야 할 것은 입력되는 값의 최대 길이에 제한을 두는 것이다. 제한을 두지 않은 입력값은 대표적인 공격 방법인 버퍼오버플로우 취약점의 원인이 될 수 있기 때문이다.

1. 명령어 라인 보안

많은 프로그램은 인수(argument)로 전달된 입력값을 받아들이는 명령어 라인(command line)을 제공한다. 그런데 SUID/SGID 프로그램은 신뢰할 수 없는 사용자가 명령어 라인 인터페이스를 사용할 수 있으므로 안전하지 않을 수 있다. 그러므로 SUID/SGID 프로그램은 명령어 라인 입력값에 대하여 확인해야 하고 명령어 라인 매개변수에 의해 전달된 프로그램의 이름을 믿지 말아야 한다.

2. 리턴 값 보안

에러 상태를 리턴할 수 있는 모든 시스템 호출 함수는 제한된 자원을 요구하거나 사용자가 자원에 영향을 미칠 수 있으므로 항상 에러 상태를 검사해야 한다.

이러한 보안 기능으로 Setuid/Setgid 프로그램은 자원의 사용을 제한하는 함수인 setrlimit()나 스케줄링 우선권(priority)을 조절하여 명령어를 실행하는 nice() 함수를 프로그램상에서 사용할 수 없도록 제한한다. 또한 서버프로그램의 외부 사용자와 CGI 스크립트는 많은 request 요구하여 자원이 고갈되도록 할 수 있으므로 이에 대한 처리도 해주어야 한다.

3. 유효값(Valid Value) 제한

popen()이나 system()과 같은 시스템 호출 함수는 명령어 쉘(command shell)을 호출하여 실행되는데 이 함수들은 메타문제(metacharacter)에 의해 영향을 받는다. 또한 execlp()와 execvp() 함수도 쉘이 호출된다. 쉘이 호출되면 메타문자는 특별한 의미를 가지고 해석된다. 그래서 이런 메타문자가 입력되어 쉘에 보내지면 프로그램을 파괴할 수 있으므로 메타문제를 제거해야 한다. 쉘에서 특별한 의미를 갖는 메타문자는 다음과 같다.

& ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r

!

!은 "not"의 의미를 가지고 또 명령어 history에 접근할 수 있게 해준다. bash에서는 상호모드에서 실행하지만 tcsh에서는 스크립트로 인식되므로 문제가 될 수 있다.

#

주석문으로 모든 텍스트가 무시된다.

-

옵션으로 잘못 인식될 수 있도 있고 만약 파일의 이름에서 사용된다면 쉘이 공백문자로 인식할 수 있어 문제가 될 수 있다.

' '

공백문자는 파일이름을 여러개의 인수(argument)로 인식할 수 있다.

'.'과 '='

현재 쉘에서 실행된다는 의미의 '.'과 변수 설정시 사용되는 '='의 사용이 문제가 될 수 있다.


Ⅴ. 환경변수 보안

프로그램에서 환경변수를 사용할 때에는 환경변수에 의존해서는 안된다. 즉, 환경변수의 값을 가정하지 말아야 하고 아니면 모든 환경변수를 설정하는 것이 안전하다. 또한 프로그램에 정보(환경변수)를 전달해야 한다면 필요한 환경변수를 테스트하고 사용후에는 완전히 삭제하도록 한다.

1. 환경변수 설정의 위험성

? 버퍼오버플로우 보안 문제가 발생할 수 있다.

환경변수에 의한 버퍼오버플로운 보안 문제가 가장 흔하게 발생하는 보안 문제로

<프로그램-2> 환경변수 사용의 버퍼오버플로우

...

char *s, buf[128];

if(!(s = getenv("HOME")))

return -1;

strcpy(buf, s);

...

이 프로그램은 환경변수 HOME의 크기를 고려하지 않고 그냥 128 byte 버퍼에 복사함으로 버퍼오버플로우 보안 문제가 발생할 경우를 보여주고 있다.

? 상속에 의한 문제가 발생할 수 있다.

일반적으로 자식 프로세스에게 환경변수가 상속되므로 환경변수를 자식 프로세스에게 전달할 때 주의해야 한다.

? 잘못 사용한 경우 위험할 수 있다.

IFS는 command line에서 인수(argument)들을 분리하는 문자를 나타내는 환경변수로 흔히 " "(공백문자)를 사용하는데 사용자들에게 친근하지 않은 문자로 설정된 경우 쉘을 호출하는 명령(C에서의 system, popen이나 Perl에서 back-tick 명령어)을 실행하여 쉘을 파괴할 수 있다.

? 문서화가 제대로 되지 않아서 시스템에 익숙하지 않은 사용자는 이런 환경변수를 잘 모르는 경우가 있다.

? 문서화가 잘 되어 있더라도 환경변수가 수정될 수 있어 위험하다.

2. 환경변수 저장 형식

프로그램이 환경변수에 접근하기 위해서는 표준 접근 방법을 사용한다. getenv(), putenv(), setenv(), unsetenv()과 같은 함수들을 이용하여 환경변수를 수정하거나 설정할 수 있는데 execve() 함수를 이용하여 프로그램에 전달되는 환경변수의 데이터 영역을 제어할 수 있어서 위험하다. Linux 시스템의 environ 변수는 환경변수가 어떻게 작동하는지 보여주는 변수로

extern char **environ;

위와 같은 형식을 가지고 있다. 이 environ 변수에 저장되는 값은 NAME=value라는 형태의 스트링인데 환경변수의 이름들이 = 사인을 포함하지 않을 수도 있고 이름(NAME)이나 값(value)이 NIL 문자를 내포하고 있지 않을 수도 있어 위험하다. 또한 같은 이름을 가지고 다른 값을 갖는 변수들이 존재하여 execve()를 사용하여 위험한 상황이 실행되게 할 수도 있다.

3. 환경변수 문제의 보안 원리

안전한 SUID/SGID 프로그램을 작성하기 위해서는 입력값으로 입력되는 환경변수들을 제거하고 모든 환경변수를 삭제한 후 필요한 환경변수는 안전하게 다시 설정해야 한다. 모든 안전하지 않은 환경변수를 알 수 있는 방법이 없기 때문에 프로그램의 소스 코드를 다 확인한다 하더라도 다시 수정될 수 있으므로 안전하지 않다.

3.1 환경변수를 지우는 방법

? environ 변수를 NULL로 설정한다.

environ 변수는 unistd.h에 정의되어 있고 이 헤더파일의 environ 변수를 수정하여 실행하도록 한다.

? clearenv() 함수를 사용한다.

clearenv()는 stdlib.h 헤더파일에 정의되어 있고 사용전에 _USE_MISC이 #define 되어야 한다.

Ⅵ. 버퍼오버플로우 보안

대부분 발생하는 보안 결점은 버퍼오버플로우 문제이다. 버퍼오버플로우는 기술적으로 프로그램 내부의 실행 문제에서 발생하는데 이 문제는 가장 일반적이면서도 심각한 문제이기도 한다. CERT에서는 1998과 1999년부터 계속 논의되어 왔고 Bugtraq에 올라오는 응답의 2/3가 버퍼오버플로우 문제일만큼 오래되고 잘 알려졌지만 계속해서 이슈가 되고 있는 문제이다.

버퍼오버플로우는 고정된 길이의 버퍼에 값을 쓸 때 버퍼의 경계값을 넘어서면서 발생하는데 사용자 입력 값을 읽을 때나 프로그램내에서 처리하는 중간에 발생하기도 한다. 안전한 프로그램이 이런 버퍼오버플로우를 허용하면 C와 같은 언어에서는 공격자가 작성한 악의적인 코드를 강제로 실행하게 치명적인 피해를 입을 수 있다. 버퍼오버플로우 취약점을 "stack smashing"이라고 부르고 힙버퍼에서 발생하는 오버플로우도 간간이 발생하고 있다.

대부분의 프로그래밍 언어는 버퍼오버플로우 문제에 대한 면역기능을 가지고 있다. Perl은 자동으로 배열의 크기를 다시 계산하고 Ada95는 버퍼오버플로우를 탐지하여 막는다. 그러나 C 언어와 C++는 버퍼오버플로우 문제에 대하여 어떠한 보호기능도 제공하지 않아서 문제가 되고 있다.

1. 안전한 함수 사용으로인한 해결책

C언어나 C++의 구조상 경계값을 넘는 것을 차단하지 못하므로 프로그래머는 경계값을 체크하는 않는 함수를 사용하지 않아야 한다.

strcpy(), strcat(), sprintf()(vsprintf()), gets()와 같은 함수는 경계값 체크를 하지 않으므로 strncpy(), strncat(), snprintf(), fget()과 같은 함수로 대체해야 한다. 또한 scanf 계열의 함수들오 위험하므로 최대 입력받을 수 있는 스트링의 길이 제한 없이 사용하지 말아야 한다. realpath()나 getopt()과 같은 함수도 최소한의 PATH_MAX 바이트 길이를 정해주는 getwd() 함수를 사용하는 것이 안전하다.[표 ]

취약한 함수

대체 함수

strcpy()

strcat()

sprintf()(또는 vsprintf())

gets()

strncpy()

strncat()

snprintf()

fget()

scanf() fscanf() sscanf() vscanf() vsscanf() vfscanf()


realpath() getopt() getpass() streadd() strecpy() strtrns()

getwd()

[표-2] 취약한 함수와 대체 함수


2. 각 함수의 안전한 사용

? strcpy()

strcpy() 함수는 버퍼의 크기를 평가하지 않아 문제가 발생하므로 복사할 데이터의 크기를 미리 검사하는 strncpy() 함수를 대신 사용할 수 있다. strncpy() 함수는 NULL 문자로 끝내야 하는데 소스의 버퍼 크기가 복사할 버퍼보다 크거나 같으면 NULL로 끝나지 않을 수 있기 때문이다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

strcpy(buffer, str);

return;

}

void func(char *str)

{

char buffer[256];

strncpy(buffer, str, sizeof(buffer)-1);

buffer[sizeof(buffer)-1] = 0;

return;

}

<프로그램-3> strcpy() vs. strncpy()

? strcat()

strcat() 함수도 strcpy() 함수와 비슷하게 첨가할 스트링의 길이를 검사하지 않아 문제가 발생하고 대신 strncat() 함수를 사용하여 명시한 길이만큼 원래의 스트링에 덧붙인다. 그리고 NULL 문자로 끝난다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

strcat(buffer, str);

return;

}

void func(char *str)

{

char buffer[256];

strncat(buffer, str, sizeof(buffer)-1);

return;

}

<프로그램-4> strcat() vs. strncat()

? sprintf()

sprintf() 함수는 포맷 스트링 변수가 사용될 때 버퍼오버플로우 문제가 발생할 수 있고 버퍼에 출력되는 데이터의 길이를 제한하기 위해 snprintf() 함수를 사용한다. 이 함수는 데이터의 길이가 버퍼보다 더 크면 버퍼에 어떤 것도 기록하지 않는다. snprintf() 함수의 리턴값을 확인하여 버퍼에 쓰여진 값을 확인할 수 있다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

sprintf(buffer, "%s", str);

return;

}

void func(char *str)

{

char buffer[256];

if(snprintf(target, sizeof(target)-1, "%s", string) > sizeof(target)-1)

/*....*/

return;

}

<프로그램-5> strcpy() vs. strncpy()

? gets()

gets() 함수는 길이를 명시하는 부분이 나와 있지 않으므로 오버플로우 문제가 항상 발생할 수 있다. 이 함수는 new-line이나 EOF를 만나거나 버퍼가 다 찰 때까지 표준 입력값을 읽는다. fgets() 함수는 n-1 개의 문자를 읽는다.

Incorrect

Correct

void func(char *str)

{

char buffer[256];

gets(buffer);

return;

}

void func(char *str)

{

char buffer[256];

fgets(buffer, sizeof(buffer)-1, stdin);

return;

}

<프로그램-6> gets() vs. fgets()


? scanf(), sscanf(), fscanf()

지정된 크기의 버퍼를 읽어들이는데 읽어들일 수 있는 최고의 버퍼 길이를 명시해야 한다.

Vulnerable

Safe

char buffer[256];

int num;

num = fscanf(stdio, "%s", buffer);

char buffer[256];

int num;

num = fscanf(stdio, "%255s", buffer);

<프로그램-7> scanf(), sscanf(), fscanf()

? memcpy()

외부의 자료에의해서 memcpy() 함수에서 명시된 길이가 바뀔 때 버퍼오버플로우 문제가 발생할 수 있다.

Incorrect

unsigned long copyaddress(struct hosten *hp) {

unsigned long address;

memcpy(&address, hp->h_addr_list[0], hp->h_length);

}

Correct

unsigned long copyaddress(struct hosten *hp) {

unsigned long address;

if(hp->h_length > sizeof(address))

return 0;

memcpy(&address, hp->h_addr_list[0], hp->h_length);

return address;

}

<프로그램-8> memcpy() 함수

이것은 실제로 BIND에서 나타난 취약점으로 hp->h_length의 길이만큼 address 변수에 복사하는데 hp->h_length 변수는 인터넷 주소의 크기이므로 4 byte이다. 그런데 공격자가 위조된 DNS reply를 스푸핑할 수 있다면 h_length의 값은 더 커져서 address 변수에 더 많은 데이터가 복사되어 버퍼오버플로우가 발생할 수 있다. 이것을 위의 표에서처럼 길이를 검사한 후 복사한다면 해결할 수 있다.

3. 더 생각해야 할 문제

위의 [표-2]에서처럼 취약한 함수를 안전한 대체 함수로 바꿨다고 버퍼오버플로우의 모든 문제가 해결되는 것은 아니라는 사실을 알아야 한다.

? snprintf()와 같은 함수는 ISO 1990(ANSI 1989)의 표준 C 함수가 아니다. 그래서 대부분의 시스템이 sprintf()함수는 지원하더라도 snprintf() 함수는 지원하지 않을 수 있고 지원한다고 하더라도 snprintf() 함수가 바로 sprintf() 함수를 호출하도록 되어 있어 버퍼오버플로우 문제에 대한 보호기능을 제대로 해주지 못하는 경우도 있다. 어떤 버전의 snprintf() 함수에서는 NULL 문자로 끝나도록 보장하지 않아 긴 스트링이 입력되면 NULL 문자로 끝나지 않을 수도 있는데 glib 라이브러리에서는 항상 NULL 문자로 끝나는 g_snprintf() 함수를 지원한다.

? strlen() 함수는 NULL 문자를 만날 때까지 문자열의 수를 계산하는데 NULL 문자로 끝나지 않는 문자열을 입력받을 때는 처리하지 못할 수 있으므로 주의해야 한다.

4. C++의 버퍼오버플로우 문제

C++ 언어도 부가적인 보안 문제점을 가지고 있는데 C 코드의 gets() 함수와 같은 버퍼오버플로우 공격이 발생할 수 있다.

char buf[128];

cin >> buf;

위의 함수는 문자를 읽을 때 어떤 길이 검사도 하지 않아서 버퍼오버플로우 보안 문제가 발생할 수 있다. 버퍼의 최대 입력 길이를 알기 위해서는 cin.width() 멤버함수를 사용할 수 있다.

Ⅶ. 레이스컨디션 보안

접근 권한을 파괴하거나 파일 생성을 파괴할 수 있는 문제를 가지는 경쟁 상태가 보안 문제를 발생시킬 수 있다. 이러한 경쟁 상태는 다음과 같은 상황에서 발생한다.

- 접근 권한 체크나 상태 체크는 파일명을 이용할 때 발생한다.

- 파일 명령은 같은 파일이름의 명령어를 통해 실행된다.

여기서 일어나는 문제는 첫 번째와 두번째 명령어 사이에 접근 권한이나 상태 체크를 체크하거나 다른 파일이 파일 명령어를 참조할 때 공격자가 파일을 위조할 수 있다는 것이다.

일반적으로 이 타입의 공격은 프로그램의 불안정을 이용하기 위해 심볼릭 링크를 이용한다. 불안정한 setuid 있는 루트 프로그램 소스코드의 일부분을 예로 보자.

<프로그램-9> 레이스컨디션이 발생할 수 있는 프로그램

int unsafeopen(char *filename)

{

struct stat st;

int fd;

if (stat(filename, &st) != 0)

return -1;

if (st.st_uid != 0)

return -1;

fd = open(filename, O_RDWR, 0);

if (fd < 0)

return -1;

return fd;

}

위의 프로그램은 다음과 같은 특징을 가지고 있다.

① 파일명이 존재하는지 체크하고, 그 파일이 루트 소유가 확실하면 파일을 만든다.

② 파일을 연다.

두 개의 분리된 시스템 호출이 일어나는데 두 개의 명령 사이에 시간 지연있다. 이 시간 지연내에서 파일과 시스템 특징을 바꾸는 것이 가능하다. 공격자는 아래의 방법으로 가능하게 된다.

① 루트 권한의 파일(/etc/passwd)을 심볼릭 링크(/tmp/filename)로 생성할 수 있다.

② stat()는 심볼릭 링크를 통해 호출한다. 그리고 /etc/passwd의 정보를 되돌린다.

③ 공격자는 심볼릭 링크를 해제한다. 그리고 파일을 자신의 권한으로 한다.

④ 프로그램에서 현재 우연히도 /tmp/filename이 열려 있으면, 루트 권한의 또 다른 프로세스의 파일의 데이터 대신에 자신의 데이터를 읽는다.

<프로그램-10> 레이스컨디션이 발생하지 않는 프로그램

int safeopen(char *filename)

{

struct stat st, st2;

int fd;

if (lstat(filename, &st) != 0)

return -1;

if (!S_ISREG(st.st_mode))

return -1;

if (st.st_uid != 0)

return -1;

fd = open(filename, O_RDWR, 0);

if (fd < 0)

return -1;

if (fstat(fd, &st2) != 0) {

close(fd);

return -1;

}

if (st.st_ino != st2.st_ino || st.st_dev != st2.st_dev) {

close(fd);

return -1;

}

return fd;

}


위의 프로그램은 안전하게 작성된 프로그램으로 stat() 대신에 lstat()를 사용한다. 만일 지정된 파일이 심볼릭 링크면 이것은 링크의 상태를 돌려준다. 다음 파일을 열고, 열린 파일의 상태를 얻는다. 상태 정보의 inode와 device number는 비교되어 그들이 동일하니 않으면 중지된다.

Ⅷ. chroot()의 보안

유닉스 시스템은 운영체제의 관점에서 프로그램을 제한함으로써 외부에 노출되는 것을 막을 수 있는 능력이 있는데 이러한 기능을 chroot() 함수가 수행한다.

int chroot(const char *path);

chroot() 함수에서의 path는 새로운 파일시스템의 root 디렉토리로 인식되어 파일시스템의 다른 부분에 대한 접근은 제한된다

if (chroot("/jail") < 0 || chdir("/") < 0)

perror("Failure setting new root directory");

chroot() 함수를 사용하는 것도 수퍼유저의 권한을 제한하는 좋은 방법이기도 한다.

Ⅸ. 최소한의 권한 원리

1. 최소한의 권한의 필요성

대부분의 프로그램은 root나 특별한 권한을 가진 사용자가 소유하고 있는 시스템 자원에 접근하기 위해서는 특별한 권한을 가져야 한다. 네트워크 서비스와 같은 경우 일반사용자는 사용할 수 없는 권한있는 TCP나 UDP 포트를 할당하기 위해서 특별한 권한이 필요하다. 로컬 권한이 있는 프로그램은 메모리나 디스크, 시스템 구성 정보 등의 제한된 시스템 자원을 사용할 수 있다. 특히 모든 자원들에 대해 초기화하고 권한을 낮추는 것은 특별한 권한을 가지고 실행되는 프로그램에서는 중요하다.

2. 최소한의 권한 설정 방법

권한을 낮추기 위해서는 프로세스의 EUID와 EGID를 더 낮은 권한으로 설정해야 한다. 임의로 권한을 낮추거나 제거하기 위해서는 seteuid()와 setegid() 함수가 필요하고 영구적으로 권한을 제거하기 위해서는 setuid()와 setgid() 함수를 사용해야 한다.

2.1 네트워크 서비스에서 권한 낮추기

네트워크 서비스의 권한을 낮추기 위해서는 프로그램이 실행되자마자 권한을 낮추어야 한다. 보통 최소한의 접근 권한을 가진 사용자를 "nobody"로 사용한다.

<프로그램-11> 최소한의 권한

int drop()

{

struct passwd *pep = getpwnam("nobody");

if(!pep)

return -1;

if(setgid(pep->pw_gid) < 0)

return -1;

if(setuid(pep->pw_uid) < 0)

return -1;

return 0;

}

특히 위의 프로그램에 setuid를 설정하기 전에 setgid를 먼저 설정할 것을 볼 수 있다. 이것은 setuid를 먼저 설정하였을 경우 권한이 gid가 가지고 있는 권한보다 낮아져 권한을 수정할 없게 될 수 있기 때문에 setgid 먼저 설정한다.

2.2 로컬 setuid 프로그램에서 권한 낮추기

권한있는 SUID/SGID 프로그램을 실행하는 경우 프로세스의 RUID와 RGID는 프로그램을 실행한 사용자의 uid와 gid이지만 EUID와 EGID, saved UID, saved GID은 파일의 소유자나 그룹의 권한으로 설정된다.

이런 SUID 프로그램는 권한을 임시로나 영구적으로 권한을 수정할 수 있다.

? 권한을 영구적으로 낮추기

권한을 영구적으로 낮추기 위해서는 프로그램의 EUID, EGID SUID와 SGID를 RUID와 RGID로 설정해야 한다. setuid()와 setgid() 함수를 이용하여 RUID/RGID로 설정하면 EUID/SUID/RUID는 모두 변한다.

<프로그램-12> 영구적으로 권한 낮추는 프로그램

if(setgid(getgid()) < 0)

return -1;

if(setuid(getuid()) < 0)

return -1;

? 권한을 임시로 낮추기

임시로 권한을 낮추기 위하여 EUID의 값을 원하는 값으로 설정한다. EUID은 시스템 함수나 권한 검사를 수행할 때 사용되므로 다음에 사용하기 위하여 이 값을 저장해 놓는다.

<프로그램-13> 임시적으로 권한을 낮추는 프로그램

struct passwd *pep = getpwnam("nobody");

uid_t saved_uid;

gid_t saved_gid;

if (!pep)

return -1;

saved_uid = geteuid();

saved_gid = getegid();

if (setegid(pep->pw_gid) < 0)

return -1;

if (seteuid(pep->pw_uid) < 0)

return -1;

/* perform desired unprivileged operations then revert back */

if (setegid(saved_gid) < 0)

return -1;

if (seteuid(saved_uid) < 0)

return -1;


마치며

지금까지 전반적으로 유닉스 프로그램 작성시 유의해야 할 사항과 어떻게 작성해야 안전한 프로그램을 작성할 수 있는가에 대하여 알아보았다. 위에서 설명한 것과 같이 프로그램을 작성했다고 완전하게 안전한 프로그램은 아니다. 다만 안전성을 고려하지 않은 프로그램보다는 약점이나 헛점이 없는 프로그램을 작성하자는 의도에서 이 지침서 작성한 것이다. 대부분 해킹 공격의 원인이 되는 취약점들이 운영체제나 시스템 프로그램등의 안전성을 고려하지 않은 코드에서 나온다고 할 수 있기 때문에 이 지침서는 실제 프로그램을 개발하는 프로그래머에게 유용하게 사용될 수 있다.

또한 해킹 공격 방법이 설명한 방법들에만 머무르지 않고 계속 변화하고 개발되어지므로 안전한 소스코드 지침서도 그에 따라 수정되고 버전업되어야 할 필요성이 있다.

<참고문헌>

[1] Simson Garfinke and Gene Spafford, "Practical UNIX & Internet Security", O'Reilly & Associates, Inc., 2nd Edition, April 1996.

[2] Nemeth·Snyder·Seebass·Hein, "Unix System Administration Handbook", A Division of Simon & Schusyer, Inc., Third Edition, October 1998.

[3] Grahan Glass 저. 조경산 역, "프로그래머와 사용자를 위한 UNIX 완성", 이한출판사, March 1998.

[4] David A. Wheeler, "Secure Programming for Linux and Unix HOWTO", 1999.

[5] whitefang.com, "Secure UNIX Programming FAQ", 1999.

[6] M. Bishop, "Writing Safe Privileged Programs," Network Security 1997.

[7] M. Bishop, "How to Write a Setuid Program," 1986.

[8] ``Secure Programming Guidelines''. FreeBSD, Inc. 1999.

[9] AUSCERT and O'Reilly, "Lab Engineers Check List for Writing Secure Unix Code.", 1996

[10] NCSA "Secure Programming Guidelines".

[11] SETUID manual page.

'UNIX' 카테고리의 다른 글

[unix]압축-compress 사용법  (0) 2006.08.22
프로세스와 시그널 프로세스는 무엇인가?  (0) 2006.08.17
Dynamic SQL의 사용  (1) 2006.08.11
UNIX 고급  (0) 2006.08.11
hp-ux manual  (0) 2006.08.11
posted by 구름너머 2006. 8. 11. 17:29

오라클 9i용 함수를 사용해서

static SQL로 컴파일하니 다음과 같은 에러가 발생하여

dynamic SQL로 변환하여 적용하니 정상 컴파일이 된다.

단, dynamic sqlfh 사용시는 값이 정해져야 한다.

tip ==> 값이 스트일인 경우는 스트링 기호를 붙여준다.

예)"하나"===>'하나'

tip ==> Like문으로 %를 사용하는 경우.

예) like 'damool%' ==> like 'damool%%'

PRO*C에서 Dynamic SQL의 사용 | Others

2006/01/10 16:15
http://blog.naver.com/sevengoe/90000781140
Dynamic SQL의 사용
보통의 어플리케이션 프로그램에서는 SQL문이 확정된 후 프로그램에 적용한다. 
그러나, 다이나믹 SQL의 사용하는 경우는 사용자의 입력에 의거해서 SQL문이 작성되거나 
다른 STATIC SQL문의 결과에 의해서 SQL문이 생성되는 경우 다이나믹SQL을 사용하게 된다. 
    비교될 컬럼이 변경되는 경우(WHERE절), 참조할 테이블이 변경되어야 하는 경우, INSERT, UPDATE시의 컬럼이 변경되는 경우
 이 있다. 
Method
SQL문
1
QUERY문이 아니면서 호스트 변수가 없는 경우
2
QUERY문이 아니면서 호스트 변수가 정해지지 않은 경우
3
호스트 변수와 SELECT컬럼이 정해진 QUERY문인 경우
4
호스트 변수와 SELECT컬럼이 정해지지 않은 QUERY문인 경우
 
    < Method 1 >
 이 방법은 Dynamic SQL문을 작성하고 “EXECUTE IMMEDIATE”를 사용하여 즉시 실행한다. 
SQL문은 QUERY문이 아니어야 하고 - (SELECT문)- 입력용 호스트 변수가 존재하지 않아야 한다.
Method 1은 SQL문이 매번 실행될 때마다 PARSING을 한다. 
    'DELETE FROM EMP WHERE DEPTNO = 20' 'GRANT SELECT ON EMP TO scott'
 
    < Method 2 >
 이 방법은 Dynamic SQL문을 작성한 후 “PREPARE”와 “EXECUTE” 명령에 의해 실행한다. 
SQL문은 QUERY문이 아니어야 하고, 여기에서 사용된 호스트변수는 프리컴파일 시점에서는 
데이타 타입과 위치는 정해져 있어야 한다. 
    'INSERT INTO EMP (ENAME, JOB) VALUES (:emp_name, :job_title)' 'DELETE FROM EMP WHERE EMPNO = :emp_number
 이 방법에서는 SQL문은 단 한번만 PARSING하게 되고 호스트 변수의 값을 달리하고 여러번 
실행시킬 수 있다. CREATE나 GRANT같은 DDL 문은 PREPAREd된 후에 실행 할 수 있다. 
    < Method 3 >
 이 방법은 Dynamic SQL문을 작성한 후 
“PREPARE”, “DECALRE”, "OPEN", "FETCH", "CLOSE" 와 같은 커서 명령으로 실행한다.
 SELECT-LIST와 입력 호스트변수의 데이타타입과 위치는 프리컴파일 시점에서는 정해져야 한다. 
이 방법은 query문이어야 한다. 
    'SELECT DEPTNO, MIN(SAL), MAX(SAL) FROM EMP GROUP BY DEPTNO' 'SELECT ENAME, EMPNO FROM EMP WHERE DEPTNO = :dept_number'
 
    < Method 4 >
 이 방법은 실행 시점까지 SELECT-LIST와 호스트변수의 데이타 타입과 갯수, 
위치를 모를 경우 사용하는 방법이다. 
    'INSERT INTO EMP () VALUES ()' 'SELECT FROM EMP WHERE DEPTNO = 20'
 위의 네가지 방법 모두 Dynamic SQL문을 charactor string에 저장하고, 
"EXEC SQL"과 ";"는 생략한다. Method 2와 3은 입력 호스트변수의 위치와
 데이타타입을 프리컴파일 시점까지 정해져 있어야 한다. 
Method 4는 가장 유연성이 좋다. 
반면에 복잡한 코딩이 들어가도 Dynamic SQL의 개념을 알고 있어야 하기 때문에 
잘 사용하지 않는다. 
보통 Method 4는 Method 1, 2, 3으로 해결 할 수 없는 경우에 사용한다. 
만약 프리컴파일 옵션을 DBMS=V6나 DBMS=V6_CHAR인 경우 SQL문을 배열에 저장하기 전에 
BLANK를 채워줘야 한다. 그렇게 함으로서 변수를 CLEAR해 준다. 
특히 배열을 다른 SQL문에서 다시 사용할 경우에는 특히 중요하다.
 항상 SQL문을 저장하기 전에 호스트 스트링을 초기화 해야 한다. 
오라클에서는 NULL-TERNIMATE는 스트링의 마지막이라고 인식하지 못하고 SQL문의 일부로 
인식하기 때문에 사용하여서는 안된다. 만일 프리컴파일 옵션을 DBMS=V7로 했을 경우, 
스트링의 값은 "PREPARE", 또는 "EXECUTE IMMEDIATE"하기 전에 NULL-TERNIMATE로 
끝을 맺어줘야 한다. 
DBMS옵션의 값을 개의치 않을 경우에는 다이나믹 SQL문을 저장할 변수로 VARCHAR를 쓸 경우, 
VARCHAR의 length를 "PREPARE"나 "EXECUTE IMMEDIATE"를 실행하기 전에 
정확하게 SET해주어야 한다.> 
    1. Method 1
 결과값이 단순히 SUCCESS나 FAILURE인 간단하고 호스트변수를 사용하지 않는 
다이나믹 SQL문일 경우 사용한다. 이 방법은 "EXECUTE IMMEDIATE"를 사용하여 
다이나믹 SQL문을 실행시킨다. 
    EXEC SQL EXECUTE IMMEDIATE {:host_string | string_literal }; char sql_stmt[132]; .... for (;;) { printf("Enter SQL statement: "); gets(sql_stmt); if(*sql_stmt == '\0') break; EXEC SQL EXECUTE IMMEDIATE :sql_stmt; } EXEC SQL EXECUTE IMMEDIATE 'REVOKE RESOURCE FROM MILLER';
 
    2. Method 2
 이 방법으로 실행할 경우 2번의 작업을 거쳐야 한다. 다이나믹SQL문은 QUERY문이어서는
 안되고 첫번째로 PREPARE하고 EXECUTE되어 진다. SQL문에는 호스트변수와 
INDICATOR변수를 가질 수 있다. PREPARE문은 한번만 수행하면 되고 EXECUTE문은 
다른 호스트 변수값으로 여러 번 수행할 수 있다.. 더 나아가서 COMMIT이나 ROLLBACK문장을
 수행하고 나서도 다시 PREPARE할 필요가 없다.(LOG OFF이나 RECONNECT가 아닌 경우) 
    EXEC SQL PREPARE statement_name FROM {:host_string | :string_literal };
 PRAPARE 명령은 SQL문을 PARSING하고 이름을 부여한다. 
위에서 statement_name은 호스트변수, 프로그램 변수가 아니고 프리컴파일러가 
사용할 임시적인 변수로 DECALRE SECTION에 기술할 필요가 없다. 
    EXEC SQL EXECUTE statement_name [USING host_variable_list]; :host_variable_list = :host_variable[:indicator1] [, :host_variable[:indicator2], ...]
 EXECUTE는 PARSING된 SQL문을 "USING" 절의 호스트변수를 이용하여 수행한다. 
실제로 사용되는 모습은 아래와 같다. 
    ... int emp_number; char delete_stmt[120], search_cond[40], temp[10]; ... strcpy(delete_stmt, "DELETE FROM EMP WHERE EMPNO = :n AND "); printf("다음의 SQL문에서 검색조건을 입력하여 완성하시오.\n"); printf("%s\n", delete_stmt); gets(search_cond); strcat(delete_stmt, search_cond); EXEC SQL PREPARE sql_stmt FROM :delete_stmt; for(;;) { printf("사원번호를 입력하세요: "); get(temp); emp_number = atoi(temp); if (emp_number == 0) break; EXEC SQL EXECUTE sql_stmt USING :emp_number; } ......
 USING절의 이용 SQL문이 EXECUTE될 때, USING절에 입력된 호스트변수의 값은 
PREPARE된 다이나믹 SQL문에서 대응되는 위치에 대치된다. PREPARE된 다이나믹SQL문에서 
각각의 변수 위치는 USING절의 각각의 다른 호스트변수와 대치되어야 한다. 
    3. Method 3
 이 방법은 Method 2와 비슷하나 PREPARE문장과 함께 커서를 선언하고 조작 하는게 필요하다.
 QUERY문을 사용할 수 있다. 
사실상 다이나믹SQL문이 QUERY문이면 Method3이나 4를 사용해야 한다. 
SELECT-LIST의 컬럼의 갯수와 호스트 변수의 갯수가 프리컴파일 시점에서는 정해져 있어야 한다. 
실행시점 전까지는 테이블명과 컬럼명등 데이타베이스 OBJECT의 이름은 정해져야 한다. 
데이타베이스 OBJECT의 이름은 호스트변수를 사용하지 못한다. 
조건절(WHERE)이나 GROUP BY절, ORDER BY절 역시 실행 시점까지 정해져야 한다. 
    EXEC SQL PREPARE statement_name FROM { :host_string | string_literal }; EXEC SQL DECALRE cursor_name CURSOR FOR statement_name; EXEC SQL OPEN cursor_name [USING host_variable_list ]; EXEC SQL FETCH cursor_name INTO host_variable_list; EXEC SQL CLOSE cursor_name;
 PREPARE는 다이나믹SQL문을 PARSING하고 이름을 부여한다. 
아래의 예제는 select_stmt문자열을 sql_stmt로 이름을 부여한다. 
    char select_stmt[132] = "SELECT MGR, JOB FROM EMP WHERE SAL < :salary"; EXEC SQL PREPARE sql_stmt FROM :select_stmt;
 보통 WHERE절은 실행 시점에서 터미널로부터 입력되거나 어플리케이션 프로그램에서 
자동으로 생성되게 한다. 
DECLARE명령은 PREPARE에 의해 붙여진 이름의 SQL문으로 커서를 정의한다. 
    EXEC SQL PREPARE sql_stmt FROM :select_stmt EXEC SQL DECLARE emp_cursor CURSOR FOR sql_stmt;
 위의 예에서 sql_stmt와 emp_cursor는 호스트변수나 프로그램의 변수로 선언할 필요가 없다. 
OPEN명령은 커서에 메모리를 할당하고, 입력된 호스트변수를 BIND하고, 
QUERY를 실행시키고, 실행에 의해 나오는 데이타를 active set으로 설정한다. 
OPEN명령은 커서를 ACTIVE SET의 첫번째 ROW에 위치하게 되고, 
sqlerrd[2]를 0으로 set한다. 
    EXEC SQL OPEN emp_cursor USING :salary;
 FETCH명령은 INTO절에 대응되는 호스트 변수에ACTIVE SET에서 ROW를 리턴한다. 
만약 더 이상의 데이타가 없으면 오라클은 
sqlca.sqlcode의 값을 1403을 설정하고 "no data found"를 리턴한다. 
    EXEC SQL FETCH emp_cursor INTO :mgr_number, :job_title;
 CLOSE명령은 커서를 무효화 시킨다. 커서를 CLOSE하고 난 후에는 더 이상 
FETCH는 실행되지 않는다. 
    EXEC SQL CLOSE emp_cursor;

'UNIX' 카테고리의 다른 글

프로세스와 시그널 프로세스는 무엇인가?  (0) 2006.08.17
안전한 유닉스 프로그래밍을 위한 지침서 V.0.7  (0) 2006.08.17
UNIX 고급  (0) 2006.08.11
hp-ux manual  (0) 2006.08.11
file 정보(stat) 와 종류 알아내기  (0) 2006.08.08
posted by 구름너머 2006. 8. 11. 10:22

0.0.0.1 서브 디렉토리까지 파일안의 문자열 모두 검색

find ./ -name "*" -exec grep 'abc' {} \; -print find . -name -print -exec grep abc {} \; grep -r abc * 

0.0.0.2 haha와 huhu가 동시에 들어있는 행 뽑기

grep haha foo.txt | grep huhu 

0.0.0.3 찾아서 지우기

find / -name "*.eml" -exec rm -f {} \;

0.0.0.4 공사중에 로그인 막기

시스템을 공사중일 때, root 이외의 다른 사용자를 로그인 못하게 해야 할 때가 있죠? 그럴 때는, /etc/nologin 이라는 파일을 만들어,공사중 또는 Under Construction이라는 공지를 넣으면 됩니다.

0.0.0.5 크기가 가장 큰 파일, 디렉토리 찾기

가장 큰 디렉토리를 찾으려면, du-S|sort-n

0.0.0.6 가장 큰 파일을 찾으려면

ls-lR|sort+4n

0.0.0.7 현재 디렉토리의 크기만을 파악할때

[root@dev2 local]# du -c -h --max-depth=0 * 6.4M apache 35M bin 43M dns 1.7M doc 42k etc 1.0k games 42k geektalkd 1.1M gnuws 1.1M include 41k info 19M jakarta-tomcat-3.2.3 0 jre 15M jre118_v3 25M lib 62k libexec 1011k man 1.3M mm.mysql.jdbc-1.2c 937k sbin 3.8M share 1.8M shoutcast-1-8-3-linux-glibc6 5.2M ssl 159M total 

0.0.0.8 시스템 정보 감추기

/etc/inetd.conf 파일을 열어서,

telnet stream tcp nowait root /usr/sbin/tcpd in.telnetd -h 

0.0.0.9 어떤 프로세스가 메모리를 가장 많이 잡아먹고 있는지 알아내기

ps-aux|sort+4n 또는 ps-aux|sort+5n

0.0.0.10 FTP로 들어온 사용자 확인하기

ftpwho,ftpcount

0.0.0.11 원하지 않는 사용자 죽이기

[root@dream/root]#skill-KILLsunny

위의 명령을 내리면 sunny 라는 사용자를 완전히 추방시킬수 있습니다. 그런데 이렇게 완전히 추방시키는게 아니구, 특정 터미널에 접속해있는 사용자만 추방시켜야 할 때도 있겠죠? 그럴때는

[root@dream/root]#skill-KILL-vpts/14

이런식으로 하면 된다 그럼 pts/14 에 연결되어 있는 사용자가 죽게 됩니다.

0.0.0.12 less 결과를 vi로 보기

less상태에서 v를 누르면 바로 vi로 감

<@NHN@LINEBREAKER@NHN@>

0.0.0.13 vi에서 블럭 설정하기

alt+v 하면, 라인 단위로 블럭 설정을 할 수 있으며, 해제 하시려면 Esc를 누르면 됩니다. 또한 ctl+v를 하시면, 블럭 단위로 블럭을 설정하실 수 있습니다.

블럭을 설정 하신 뒤,

삭제를 하려면 x 복사를 하려면 y 붙여넣기는 p

0.0.0.14 man 페이지 프린트하기

man-tvi>vi.ps

0.0.0.15 ping 무시하기

echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all 
echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all 

0.0.0.16 LILO 다시 살리기

boot:vmlinuzroot=/dev/hda6

0.0.0.17 특정 사용자 ftp 접근 막기

/etc/ftpusers 파일에 로그인 네임을 추가하면 됩니다.

0.0.0.18 X 윈도우에서 TV보기

리눅스에서 TV보기 위해서는 드라이버 파일과 TV를 보는 프로그램이 필요합니다. 이 글에서는 미지 리눅스 OS에 탑재된 bttv 칩셋을 사용하는 TV 카드를 기준으로 설명합 니다. 만일 커널을 새로 컴파일 하실 분은 반드시 Character devices -> Video For Linux -> BT848 Video For Linux 항목을 모듈화 시키거나 커널에 포함하십시오.

TV 카드를 리눅스에 인식시키기 위해서 /etc/conf.modules 파일에 다음과 같은 내용을 삽입하고 컴퓨터를 다시 시작합니다.

alias char-major-81 bttv # 필립스 튜너의 경우
pre-install bttv modprobe -k tuner # 알프스 튜너의 경우
pre-install bttv modprobe -k tuner type=9 

이제 kwintv나 xawtv 등의 TV 시청 프로그램으로 TV를 볼 수 있습니다. 만약 TV 장치를 찾지 못하는 오류가 있다면 bttv driver 디렉토리에 포함된 MAKEDEV 를 실행하십시오.

0.0.0.19 ls라는 파일이 포함된 rpm패키지 찾기

일단 ls의 절대경로를 알아야 한다. which lswhich로 알아낸 ls의 절대경로로 rpm질의를 한다.

rpm -qf /bin/ls 
[root@piruks /etc]# which ls /bin/ls 
[root@piruks /etc]# rpm -qf /bin/ls fileutils-4.0i-2mz 

0.0.0.20 현재 rpm패키지의 의존패키지

rpm-qR패키지명

0.0.0.21 현재 디렉토리크기

du-h--max-depth=1.

0.0.0.22 바로 이전 디렉토리로 가기

cd-

0.0.0.23 프로세스명으로 프로세스 죽이기

killall 프로세스명 kill -9 `pidof 프로세스명 

0.0.0.24 하드웨어 시계맞추기

배포본을 설치하고 나면 시간이 맞지 않는 경우가 많다. 간단히 어느정도 정확한 시간을 설정하는 방법이다.

[root@dev /down]# rdate -s time.kriss.re.kr [root@dev /down]# clock -w 

0.0.0.25 원격에서 리모트서버의 X application실행시

X윈도 app를 실행할때 다음과 같은 에러가 나면 조치

[kang@dev /home/kang] xclock Xlib: connection to "211.222.186.170:0.0"
refused by server Xlib: Client is not authorized to connect to Server Error: Can't open display: 211.222.186.170:0.0
export DISPLAY=211.222.186.170:0 xhost +211.222.186.170 

0.0.0.26 링크 파일

ln-sf링크할디렉토리링크로만들어질디렉토리 참고로 링크를 걸기만 한다고 접근가능한것은 아니고,링크가 걸린 디렉토리의 퍼미션도 허용으로 바꿔야 한다. 링크로 만들어질 디렉토리는 저절로 생성되고 퍼미션 777로 잡혔음. ln-sf/www/dir_1/r_photo/www/dir_2/r_photo

0.0.0.27 ^M 문자 없애기

a = 1^M def vartest(a):^M a = a + 1^M return a^M a = vartest(a)^M print a^M 

Unix류 기계에서는 그냥 ^J 하나만을 개행문자로 사용하는데 PC에서는 MJ 이렇게 두 제어문자가 연속으로 사용되어야 개행문자로 받아들이죠. (그래서 PC쪽에서 만들어진 txt문서를 유닉스 기계로 불러와 vi 등을 실행하면

    줄 끝마다 보기싫은 ^M이 붙습니다. 뭐 vi에서 요거 지우는건 간단하지만요.)

PC에서 Unix에서 작성한 텍스트 문서를 보통 ftp로 받아오거나 하면 워드패드 등에서 봤을 때 전혀 개행이 되어있지 않지요. 하지만 MS Word 등 좀더 강력한 편집기에선 대개 잘 처리해서 잘 보여줍니다.

위는 간단한 Python 소스입니다. 위의 경우 처럼 ^M문자가 있을때, dos2unix라는 유틸리티를 많이 사용하기도 하죠. 하지만 vi에서 간단하게 모두 삭제할수도 있습니다. dos2unix가 없거나 빠져나가서 지우는게 귀찮을때 좋겠죠. 명령은 :%s/(ctrl+v)M//g 입니다. (ctrl+v)M 이거는 ctrl과 v를 눌러준후, ctrl키를 떼지 말고 바로 m을 눌러주시믄 됩니다. 위는 정규표현식을 이용한것이고, 형식은 %s/이것을/요걸로/g 입니다 그럼 문서안의 모든 "이것을" "요걸로" 바꾸게 되죠. 단, M의 경우 ctrl+M의 뜻인데 단순히 문자로 M을 바꾸라도 해도 인식을 못하기 때문에, 위처럼 (ctrl+v)M 으로 해주셔야 합니다.

0.0.0.28 비어있는 행을 찾기

#grep-n'^$'filename 정규표현 의미 ^ 행의 처음 $ 행의 끝 . 임의의 한 문자

[...] ... 안의 임의의 한 문자. a-z,0-9 같은 범위도 사용 [^..] .. 안에 없는 임의의 한 문자. 범위 사용가능 r* 0회 이상 r 반복 r+ 1회 이상 r 반복 r? 0 혹은 1회의 r r{n,m} n회 이상 m회 이하 r 반복 r1|r2 r1 혹은 r2 (egrep 만) (r) r 의 정규표현(egrep 만) 

0.0.0.29 기타 명령어 떼

alias(명령어 간소화하기) apropos(관련된 명령어 찾기) arch(컴퓨터 종류 알기) arp(같은 서브넷의 IP 보여주기) at(작업 시간 정하기) atd(계획성 있는 작업 실행하기) awk(특정 패턴 문자 처리하기) a2p(펄 파일로 바꾸기) badblocks(배드 블럭 검사하기) bc(계산기) biff(메일 수신 소리로 확인하기) bg(후면작업; 배경화면 설정) bind(키나 함수 순서 결합하기) break(루프 빠져나가기) cal(달력보기) builtin(내부 명령어 알아보기) case(조건 처리하기) cat(화면상에서 파일 보기) cd(디렉토리 변경하기) cfdisk(디스크 설정하기) chattr(파일 속성 변경하기) chfn(사용자 정보 변경하기) chgrp(파일, 디렉토리가 속했던 그룹 바꾸기) chmod(파일 권한 바꾸기) chown(파일 주인 바꾸기) chsh(지정된 셸 바꾸기) cksum(CRC값을 점검한다) clear(화면 청소하기) clock(CMOS 시각을 조정하기) cmp(파일 비교하기) colcrt(문자 변환 필터) colrm(열 삭제하기) column(가로 정렬하기) comm(파일 비교 출력하기) command(명령어 알아보기) continue(루프 계속돌기) cp(파일 복사하기) cpio(복사본 만들기) crontab(cron을 관리한다) csplit(파일에 서식, 규칙 정하기) cut(필요한 필드만 출력하기) date(날짜 보기) dd(블럭장치 읽고 쓰기) debugfs(ext2 파일 시스템 디버깅하기) declare(변수 선언하기) df(파일 시스템의 사용량 보기) dirs(디렉토리 목록 표시하기) dmesg(부팅 메시지 보기) dnsdomainname(DNS 이름 출력) domainname(NIS 이름 출력&설정) du(디렉토리와 파일의 용량 파악하기) dumpe2fs(파일 시스템 정보 보기) echo(표준 출력하기) eject(장치 해제하기) elm(메일 관련) enable(내부 명령어 지정) env(환경변수 출력하기) eval(인수 읽기) exec(셸 명령어 실행하기) exit(종료하기) expand(탭을 공백으로 변환하기) export(변수 지정하기) e2fsck(파일 시스템 복구하기) fc(지정된 편집기 받기) fdformat(플로피 디스크 포맷하기) fdisk(파티션 나누기) fg(지정된 작업을 전면 프로세스로 시작하기) file(파일 종류 보기) find(파일 찾기) finger(사용자 정보 알기) fold(정형화하기) fmt(정형화하기) for(반복 실행하기) free(메모리 사용량 알아보기) fsck(파일 시스템 검사하기) fstab(파일 시스템에 대한 고정적인 정보 저장하기) ftp(파일 전송 프로그램) fuser(프로세스 ID 출력) getkeycodes(매핑 테이블 출력하기) grep(특정 문자(열) 검색하기) gzexe(실행 파일 압축하기) gzip(압축하기) halt(시스템 종료하기) hash(기억해 두기; index 역할) head(파일의 앞부분 출력하기) help(도움말 보여주기) host(호스트 정보 보기) history(사용 명령어 목록보기) hostname(서버 이름 알기) id(계정 정보 알기) if(조건문 실행하기) ifconfig(랜카드에 주소 할당하기) imolamod(모듈 설치하기) inetd(인터넷 서비스의 최상위 데몬) init(실행 단계 정하기) ispell(철자법 검사하기) jobs(수행중인 프로세스 알기) kbd_mode(키보드 모드 출력하기) kill(프로세스 죽이기) klogd(커널 로그 데몬) ldd(공유 라이브러리의 의존성 알기) less(페이지 단위로 출력하기) let(정규식 표현하기) lilo(부팅하기) ln(링크하기) locate(패턴에 맞는 파일 찾기) login(로그인하기) logger(시스템 로그 기록하기) logname(사용자 로그인명 보여주기) logout(로그인 셸 종료하기) look(특정 단어 검색하기) losetup(중복 장치 확인하기) lpd(프린트 데몬) lpq(현재 프린트 작업 상태 출력하기) lpr(출력하기) lprm(대기열에 있는 문서 삭제하기) ls(디렉토리 내용보기) lsattr(파일 시스템의 속성 보여주기) lsdev(하드웨어 장치 출력하기) lsmod(모듈 정보 출력하기) mail(메일 관련) make(컴파일하기) man(매뉴얼 보기) mattrib mbadblocks mcd mcopy mdel mdeltree mdir mesg(메시지를 받을 수 있는지 확인하기) mformat minfo mkdir (디렉토리 만들기) mke2fs(파일 시스템 생성하기) mkfs(파일 시스템 만들기) mknod(특수 파일 만들기) mkswap(스왑 영역 지정하기) mlabel mmd mmount mmove mpartition mount(장치 연결하기) more(화면 단위로 출력하기) mrd mren mtoolstest mtype mutt(메일 관련) mv(파일 옮기기) mzip netstat(현재 네트웍 상황 보기) nice(프로세스 우선 순위 변경하기) od(8진수로 파일 보기) passwd(암호 입력하기) pidof(실행중인 프로그램의 프로세스 ID 찾기) pine(메일 관련) ping(네트웍 확인하기) popd(pushd 취소) ps(프로세스 상태 알기) pstree(프로세스 상관관계 알기) pwd(절대경로 보여주기) quota(디스크 한계량 알기) rarp(rarp 테이블 관리하기) rcp(원격 호스트에 파일 복사하기) rdev(루트, 스왑장치, 램 크기, 비디오 모드를 조사하고 설정하기) rdate(네트웍으로 시간 설정하기) reboot(재부팅하기) rmmod(모듈 지우기) readonly(읽기 전용으로 표시하기) renice(프로세스 우선 순위 바꾸기) reset(터미널 초기화하기) restore(다시 저장하기) rlogin(바로 접속하기) rm(파일 지우기) rmdir (디렉토리 지우기) route(라우팅 테이블 추가/삭제하기) rpm(프로그램 추가/삭제) rpm2cpio(rpm을 cpio로 변환하기) rsh(원격으로 명령어 실행하기) rup(호스트 상태 출력하기) rusers(호스트에 로그인한 사용자 출력하기) rwall(호스트 사용자에게 메시지 뿌리기) script(기록하기) set(변수값 설정하기) setup(시스템 관련 설정하기) showmount(호스트의 마운트 정보 보여주기) shutdown(전원 끄기) sleep(잠시 쉬기) source(스크립트 번역하기) split(파일 나누기) ssh(암호화된 원격 로그인하기) stty(터미널라인 설정 보여주기) su(계정 바꾸기) suspend(셸 중단하기) swapoff (스왑 해제하기) swapon(스왑 활성화하기) sync(버퍼 재설정하기) syslogd(로그인 과정 설정하기) tac(거꾸로 보기) tail(문서 끝부분 출력하기) talk(이야기하기) tar(파일 묶기) tcpdchk(tcp wrapper 설정하기) tcpmatch(네트웍 요청에 대해 예측하기) tee(표준 입력으로부터 표준 출력 만들기) telnet(원격접속하기) test(테스트하기) times(셸에서의 사용자와 시스템 시간 출력하기) top(cpu 프로세스 상황 보여주기) tr(문자열 바꿔주기) true(종료 코드 리턴하기) type(유형 보기) ul(밑줄 처리해서 보여주기) ulimit(제한하기) umask(매스크 모드 설정하기) umount(장치 해제하기) unalias(별명 제거하기) uname(시스템 정보 보기) unexpand(공백 문자를 탭으로 변환하기) uniq(중복된 문장 찾기) useradd(사용자 계정 만들기) userdel(계정 삭제하기) usermod(사용자 계정정보 수정하기) unset(설정 변수 해제) uptime(시스템 부하 평균 보여주기) users(로그인된 사용자 보여주기) w(시스템에 접속한 사용자 상황 알아보기) wait(프로세스 기다리기) wall(모든 사용자에게 메시지 보내기) wc(문자, 단어, 라인수 세기) whatis(명령어의 간단한 설명보기) while(루프 명령어) who(사용자 알기) write(콘솔 상에서 간단한 메시지 보내기) xcopy(반복적으로 복사하기) XFree86 ypchfn(NIS에서 사용하는 chfn 명령어) ypchsh(NIS에서 사용하는 chsh 명령어) yppasswd(NIS에서 사용하는 passwd 명령어) zcat(압축 파일 보기) zcmp(압축 파일 비교하기) zforce(강제로 gz 만들기) zgrep(압축 상태에서 grep 실행하기) zmore(압축 상태에서 more 실행하기) znew(.Z 파일을 .gz로 다시 압축하기) 

0.0.0.30 각자가 사용하는 컴퓨터의 정보를 알고 싶을때

[root...]#more/proc/cpuinfo 위와 같이 치면 사용자의 컴퓨터 정보를 볼수 있으며, [root...]#more/proc/meminfo 라고 치면 사용자의 메모리 정보를 볼수 있습니다.

0.0.0.31 전체 메일

먼저 보낼 내용을 텍스트로 파일로 만들어야 합니다.어디에서든지 가능하지요! [root@aromi/root]#vinea 안녕하세요! 저희 서버에서는 웹서버를 오늘부터 시작합니다. 사용자 여러분의 많은 관심과 이용을 부탁드립니다.

 :wq [ root@aromi /root]# 

만약, 한글을 사용하지 못하면 윈도우95에서 먼저 쓴다음에 ftp를 이용해서 올리면 됩니다.

[ root@aromi /root]# mail -s "[공지]" `cat /etc/passwd|gawk ?F :'{print$1}'` 

[공지]-> 라고 쓴 것은 보낼 메일의 제목입니다. 'cat/etc/passwd|gawk-F:'{print$1}'' ->먼저 cat으로 passwd파일의 첫번째 나오는 내용을 출력하라는 소리입니다. nea라는 텍스트파일을 메일의 내용으로 보내라는 내용입니다.

0.0.0.32 디렉토리만 빠르게 검색

ls-al|grep"^d"

0.0.0.33 호스트 네임 바꾸기

/etc/HOSTNAME file은 부팅시 /etc/sysconfig/network file 의 HOSTNAME 부분을 참조하여 저장합니다. 호스트 네임을 바꾸고자 한다면 /etc/sysconfig/network file 의 HOSTNAME 부분을 바꿔주면 됩니다.

[ root@linux /root]# vi /etc/sysconfig/network NETWORKING=yes HOSTNAME="linux" GATEWAY="" GATEWAYDEV="" FORWARD_IPV4="yes" 

바꾸신후 시스템을 재부팅 하신거나, #/etc/rc.d/init.d/network restart 명령을 내리시면 됩니다.

0.0.0.34 틀린명령어 틀린글자만 바꿔서 실행

#./configure--prefax=/usr/local/apache 앗, 틀렸습니다. prefax가 아니라 prefix인데... 고쳐야지요...간단하게 화살표키로 왔다갔다 하면서 지워지고 바꿔주면 되겠지만 다른 방법이 있습니다. #^fax^fix^ 라고 하면... ->./configure--prefix=/usr/local/apache 라고 됩니다..

0.0.0.35 유닉스의 현재 버젼과 종류 그리고 라이센스등을 알려주는 명령어

[root@aromi/root]#uname-a

0.0.0.36 열려있는 포트 알아내기

netstat-anp|grepLISTEN

0.0.0.37 텔넷 모든 접속자에게 메세지 보내기

wall 내용... Ctrl-D

0.0.0.38 lsof는 열려있는 파일을 나타내 주는 옵션

여기에 보안 점검을 위하여, -i 옵션을 사용하면, 현재 열려 있는 포트와 링크되어 있는 서비스 또는 프로그램이 모두 나타나죠. 자신이 열어 놓지 않은 포트가 열려있다던지하면 한번쯤 의심해 봐도 되겠죠?

0.0.0.39 사용자가 어디에서 무엇을 하는지 알아내기

w라는 명령어를 사용하시면 된답니다. 이 때, w[-s] 를 붙여주시면 -s 옵션이 긴 정보 대신에 필요한 짧은 정보만 알려 준답니다.

0.0.0.40 텔넷 화면 수정

로그인화면: /etc/issue.net 로그인후화면: /etc/motd

0.0.0.41 하위 디렉토리 한꺼번에 만들기

mkdir-pmusic/koreanmusic/ost

0.0.0.42 특정디렉토리의 모든 파일 안의 특정 문자열 치환

for i in $*; do sed "s/paper/PAPER/g" < $i > $i.new mv -f $i.new $i done <chihwan.sh> find ./(chihwan.sh를 포함하지 않는 디렉토리면) -type f -exec chihwan.sh {} \; 

0.0.0.43 killall 명령 시뮬레이션 (프로세스명으로 죽이기)

psaux|grep프로세스명|grep-vgrep|awk'{print$w}'|xargskill-9

  • 모든 프로세스 나열
  • 지정한 프로세스만 뽑아냄
  • grep 명령이 포함된 라인 제거
  • awk로 두번째 필드만 뽑아냄
  • xargs에 의해 걸러진 아이디로 죽임

0.0.0.44 find와 grep

find.-name"H20021115.*"-execgrep-l'...;........;110100'{}\;

0.0.0.45 vi 검색, 치환

구호스트 서비스 오늘 날짜에서 분류코드가 110100인 파일 찾기 :%s/./\U&/g

모든문자->대문자 g/^$/d

0.0.0.46 파일내의 중복되는 행을 제거 : uniq

입력 파일에서 연속되는 행을 비교하여, 두 번째 이상의 동일한 행들을 제거하고 나머지는 출력파일로 출력 연속되어 표시되지 않으면 동일한 행이 존재할 수 있음.

sort 명령을 사용하여 정렬한 후 사용하는 것이 타당 사용법uniq [-cdu] [+|숫자] [입력파일 [출력파일]] -c : 각 행이 연속적으로 나타난 횟수를 행의 시작부분에 표시 -d : 연속적으로 반복되는 행만 출력 -u : 연속적으로 반복되지 않는 행만 출력 +숫자 : 행의 처음 '숫자' 만큼의 문자는 무시 -숫자 : 행의 처음 '숫자' 만큼의 필드는 무시

0.0.0.47 파일의 결합

여러 개의 텍스트 파일을 하나의 파일로 순차적으로 묶는데 사용

cat [파일명1] [파일명2] ... > [출력파일명] cat [파일명1] [파일명2] ... >& [출력파일명] cat [파일명1] [파일명2] ... >> [출력파일명] cat [파일명1] [파일명2] ... >>& [출력파일명] cat - [파일명1], [파일명2] .. >> [출력파일명] cat - [파일명1], [파일명2] .. >>& [출력파일명] % cat > file1 파일명 : file1 ^D % cat > file2 파일명 : file2 ^D % cat file1 file2 > file3 % cat file3 파일명 : file1 파일명 : file2 % 

행단위 결합 : paste 여러 파일에 대해여 행간 결합을 수행하거나 하나의 파일에 대해 연속되는 행들을 결합 둘이상의 파일에 대해서 테이블상의 하나의 열과 같이 취급하여 동일한 행번호 끼리 결합

 paste [파일명1] [파일명2].. paste -d리스트 [파일명1] [파일명2] ... paste -s [-d리스트] [파일명] d : 행간 결합시 행간 구분문자들의 리스트 s : 한파일의 연속되는 행을 결합 % cat > paste.data1 홍길동 이순신 김유신 % cat > paste.data2 부산 서울 대구 % paste paste.data1 paste.data2 홍길동 부산 이순신 서울 김유신 대구 % paste -d"\n" paste.data1 paste.data2 홍길동 부산 이순신 서울 김유신 대구 % paste -s -d"::\n" paste.data1 홍길동:이순신:김유신 % 

두 파일을 동일한 필드 값에 따라 행 단위 결합 : join

관계형 데이터 베이스에서의 join 연산과 동일 키로 사용할 필드에 대해 정렬된 두 파일의 각 행에 대해 동일한 키 값을 갖는 행들을 결합 입력으로 사용될 두 파일은 키 값에 대해 오름 차순으로 정렬되어 있어야 함 출력 결과는 기본적으로 키 값이 먼저 표시되고, 첫번째 파일에서 키를 제외한 나머지 필드, 두번테 파일에서 키를 제외한 나머지 필드가 표시 필드 구분은 공백, 탭, 개행문자가 기본, 연속적으로 나타날 경우 하나로 취급

% cat > join.data1 98001:서원일: 98002:홍길동: 98003:김유신: 98004:이순신: 98010:이상관: % cat > join.data2 부산:98001:441 울산:98002:89 대구:98003:99 서울:98004:120 김해:98010:44 % join -j1 1 -j2 2 -t: join.data1 join.data2 98001:서원일::부산:441 98002:홍길동::울산:89 98003:김유신::대구:99 98004:이순신::서울:120 98010:이상관::김해:44 % join -j1 1 -j2 2 -o 1.2 1.1 2.1 -t: join.data1 join.data2 서원일:98001:부산 홍길동:98002:울산 김유신:98003:대구 이순신:98004:서울 이상관:98010:김해 % 

0.0.0.48 파일의 암호화 : crypt

파일을 암호화 하여 키를 알지 못하는 사람은 내용을 볼 수 없도록 함 표준 입출력 사용

% cat > crypt.data test test 안녕하십니까? ^D % crypt <crypt.data > crypt.data1 Enter key: hello % ls -l crypt* -rw-r--r-- 1 wiseo pro 24 9월 24일 14:47 crypt.data -rw-r--r-- 1 wiseo pro 24 9월 24일 14:48 crypt.data1 % crypt < crypt.data1 Enter key:hello test test 안녕하십니까? % 

0.0.0.49 개행을 제외한 화면내의 보이지 않는 문자 출력

cat -v http://comp-cse.sch.ac.kr/~pl/lecture/linux/file2.html

0.0.0.50 화일내의 포함된 특정문자열로 찾아서 내용만 출력하기

grep -h '20030305......01' ./R00*

0.0.0.51 특정 파일의 화일명을 비슷하게 여러개 한꺼번에 바꾸기

ls *.* | awk '{print "mv",$1, $1 }' | sed "s/ \([a-zA-Z0-9]*\)\.\([a-zA-Z0-9]*\)$/ \1\.\_\2/g" 
  • 현재디렉토리의 모든 *.* 파일을 *._* 형식으로 바꾼다.
  • 더 간단하게 ls*.*|sed"s/\([a-zA-Z0-9]*\)\.\([a-zA-Z0-9]*\)/mv\1\.\2\1\.\_\2/g"

0.0.0.52 어제 날짜 구하기

$date-v-1d"+%Y-%m-%d" [컴퓨터분류]

0.0.0.53 원하지 않는 사용자 죽이기

[root@dream/root]#skill-KILLsunny

위의 명령을 내리면 sunny 라는 사용자를 완전히 추방시킬수 있습니다. 그런데 이렇게 완전히 추방시키는게 아니구, 특정 터미널에 접속해있는 사용자만 추방시켜야 할 때도 있겠죠? 그럴때는 [root@dream/root]#skill-KILL-vpts/14

이런식으로 하면 된다 그럼 pts/14 에 연결되어 있는 사용자가 죽게 됩니다.

0.0.0.54 UNIX상에서 한글출력이 깨져 나올경우

유닉스상에서 한글을 stdout출력할 경우 가끔 출력되는 문자들이 몽땅 깨져서 나오는 경우가 있다. 이때부터는 프로그램이 종료된 이후에도 쉘 프람프트를 비롯, 쉘에서 입력하는 모든 커맨드가 깨져서 나온다. 이는 ascii code 로 ^n 에 해당하는 문자가 출력될 때 나오는 현상으로 그 이후로는 MSB가 모두 켜지기 때문이다. 문자가 깨져나오는 이후부터 ascii code 로 ^o에 해당하는 문자를 출력하면 반대로 된다. 쉘 커맨드 상에서라면, #echo^v^o

라고 해야겠지만 커맨드가 깨져나오므로 shell이 해석을 못한다. 따라서, command line에서 ^v^o를 치고 enter 하면 된다

0.0.0.55 현재 디렉토리의 대량의 파일을 각자의 파일명가운데에 특정문자 추가하여 바꾸기

/bin/ls A?????.html | sed 's/A\(.....\)\.html/\1/g' | xargs -t -i mv 'A{}.html' 'A0{}.html' 

/bin/ls는 ls가 보통 -F로 파일 종류 표시(*, @등)까지 하기 때문에 그걸 막기 위한 것이고 xargs의 -t는 트레이스모드이다.

'UNIX' 카테고리의 다른 글

안전한 유닉스 프로그래밍을 위한 지침서 V.0.7  (0) 2006.08.17
Dynamic SQL의 사용  (1) 2006.08.11
hp-ux manual  (0) 2006.08.11
file 정보(stat) 와 종류 알아내기  (0) 2006.08.08
VI 에서 TAB 크기를 4로 설정하기  (1) 2006.07.28
posted by 구름너머 2006. 8. 11. 09:38

1.HP-UX 메뉴얼

http://docs.hp.com/ko/

'UNIX' 카테고리의 다른 글

Dynamic SQL의 사용  (1) 2006.08.11
UNIX 고급  (0) 2006.08.11
file 정보(stat) 와 종류 알아내기  (0) 2006.08.08
VI 에서 TAB 크기를 4로 설정하기  (1) 2006.07.28
UNIX FTP 사용법  (0) 2006.07.04
posted by 구름너머 2006. 8. 8. 12:42

http://www.joinc.co.kr/modules.php?name=News&file=article&sid=15&mode=nested

파일의 종류

Unix 에서는 디렉토리, 장치, 소켓, FIFO 등 모든것이 파일로 존재한다. 그러므로
우선 우리는 작업을 하고자 하는 파일이 어던 종류의 파일인지를 먼저 판단할수
있어야 한다. Unix 상에서 "ls -al" 을 이용하면 아래와 같은 결과물을 볼수
있을것이다.
[yundream@localhost test]# ls -al...-rw-r--r--    1 root     root          249  9월 10 11:25 wc.1drwxr-xr-x    2 root     root         4096 12월  5 18:01 web_installsrwxr-xr-x    1 root     root            0  1월 14 18:05 loging_socket...

위의 결과에서 가장 앞부분 10자리가 그 파일의 특성과 권한을 나타내는데, 그중
제일 앞부분이 파일의 종류를 나타내고, 우리는 가장 앞부분의 한바이트의 문자를
이용해서 어떤 종류의 파일인지를 알아낼수 있다.<br>
Unix 에서 자주 사용하는 파일의 종류를 아래 테이블에 정리해 두었으니 참고
바란다.
-일반 파일
s소켓파일
d디렉토리
pFIFO
l심볼링 링크된 파일
b블럭 디바이스
c캐릭터 디바이스

'UNIX' 카테고리의 다른 글

UNIX 고급  (0) 2006.08.11
hp-ux manual  (0) 2006.08.11
VI 에서 TAB 크기를 4로 설정하기  (1) 2006.07.28
UNIX FTP 사용법  (0) 2006.07.04
Unix 압축/해제 명령어 모음  (0) 2006.03.13
posted by 구름너머 2006. 7. 28. 16:28
VI 에서 TAB 크기를 4로 설정하기 | linux2005/09/09 12:43
http://blog.naver.com/gooddev/100017190212
VI 에서 TAB 크기를 4로 설정하기

VI 에서 TAB키를 누르면 기본 8문자 간격으로 공백이 생깁니다. 그러나 보통 4문자 정도로 많이 사용하게 되죠. 기본 공백 8문자를 4문자 크기로 바꾸는 팁입니다.

# vi ~/.vimrc

하셔서 .vimrc 파일 또는 .exrc 을 계정 홈 디렉토리>에 만듭니다.
그런 다음 아래와 같이 작성하거나 추가하고 저장하세요.
set tabstop=4 (또는 set ts=4)

다시 쉴 프롬프트 상에서 VI를 실행한 다음 TAB키를 누르면 4문자 간격으로 공백이 생깁니다.

그냥 필요할 때마다 탭을 설정해서 사용하시려면 VI를 실행한 다음 명령 모드에서,

:set tabstop=4 (또는 set ts=4)

라고 하셔도 됩니다.

'UNIX' 카테고리의 다른 글

hp-ux manual  (0) 2006.08.11
file 정보(stat) 와 종류 알아내기  (0) 2006.08.08
UNIX FTP 사용법  (0) 2006.07.04
Unix 압축/해제 명령어 모음  (0) 2006.03.13
unix timestamp  (0) 2005.12.30
posted by 구름너머 2006. 7. 4. 17:27

FTP 사용법을 정리해본다.

절차1. 접속시도

$>ftp xxx.xxx.xxx.xxx

ftp>id입력

ftp>pw입력

절차2.접속된 서버의 디렉토리 위치(현재) 확인:remote서버의 경로확인

ftp>pwd

절차3.접속을 시도한 로컬 위치(현재) 확인 :!pwd

ftp>!pwd <==unix shell의 pwd 실행.

ftp>! <==잠시 unix shell로 나들이

절차4.접속된 원격의 서버에서 경로이동:cd or cdup or cd .. or cd ~/src 등...

ftp>cd src <== remote 서버의 현재 위치에서 하위의 src 폴더로 이동.

로컬서버에서의 경로이동

ftp>lcd src <==local 서버의 현재 위치에서 하위의 src 폴더로 이동.

또는

ftp>!

$>cd src

$>exit

ftp>

절차5.화일 확인 및 전송 준비

ftp>pwd <==현위치 확인

ftp>ls <== 목록 확인

ftp>bin <== 전송모드 binary 전환

ftp>hash <==파일전송 도중에 "#"표시를 하여 전송중임을 나타낸다.(hash)

ftp>get 파일명 <== 파일명을 remote에서 local로 download

ftp>put 파일명 <== 파일명을 local에서 remote로 upload

절차6.ftp 종료:bye

ftp>bye

$>

ascii : 전송모드를 ASCII모드로 설정한다.(ascii또는 as)

binary : 전송모드를 BINARY모드로 설정한다.( binary또는 bi)

bell : 명령어 완료시에 벨소리를 나게한다.(bell)

bye : ftp접속을 종료하고 빠져나간다.(bye)

cd : remote시스템의 디렉토리를 변경한다.(cd 디렉토리명)

cdup : remote시스템에서 한단계 상위디렉토리로 이동한다.(cdup)

chmod : remote시스템의 파일퍼미션을 변경한다.(chmod 755 index.html)

close : ftp접속을 종료한다. (close)

delete : remote시스템의 파일을 삭제한다.(delete index.old)

dir : remote시스템의 디렉토리 내용을 디스플레이한다.(dir)

disconnect : ftp접속을 종료한다.(disconnect)

exit : ftp접속을 종료하고 빠져나간다.(exit)

get : 지정된 파일하나를 가져온다.(get index.html)

hash : 파일전송 도중에 "#"표시를 하여 전송중임을 나타낸다.(hash)

help : ftp명령어 도움말을 볼 수 있다.(help또는 help 명령어)

lcd : local시스템의 디렉토리를 변경한다.(lcd 디렉토리명)

ls : remote시스템의 디렉토리 내용을 디스플레이한다. (ls 또는 ls -l)

mdelete : 여러개의 파일을 한꺼번에 지울 때 사용한다.( mdelete *.old)

mget : 여러개의 파일을 한꺼번에 가져오려할 때 사용한다. ( mget *.gz)

mput : 한꺼번에 여러개의 파일을 remote시스템에 올린다.(mput *.html)

open : ftp접속을 시도한다.(open 168.126.72.51또는 open ftp.kornet.net)

prompt : 파일전송시에 확인과정을 거친다. on/off 토글 (prompt)

put : 하나의 파일을 remote시스템에 올린다.(put index.html)

pwd : remote시스템의 현재 작업디렉토리를 표시한다.(pwd)

quit : ftp접속을 종료하고 빠져나간다.(quit)

rstatus : remote시스템의 상황(version, 어디서, 접속ID등)을 표시한다.(rstatus)

rename : remote시스템의 파일명을 바꾼다.(remote 현재파일명 바꿀파일명)

rmdir : remote시스템의 디렉토리을 삭제한다.(rmdir 디렉토리명)

size :remote시스템에 있는 파일의 크기를 byte단위로 표시한다.(size index.html)

status : 현재 연결된 ftp세션모드에 대한 설정을 보여준다.(status)

type : 전송모드를 설정한다.(type 또는 type ascii 또는 type binary)

'UNIX' 카테고리의 다른 글

file 정보(stat) 와 종류 알아내기  (0) 2006.08.08
VI 에서 TAB 크기를 4로 설정하기  (1) 2006.07.28
Unix 압축/해제 명령어 모음  (0) 2006.03.13
unix timestamp  (0) 2005.12.30
Unix Shell  (0) 2005.11.25