본문 바로가기
정보보안기사 필기/1. 정보보안 일반

정보보안기사 필기 4-4. 유닉스/리눅스 서버 보안(프로세스)

by kkmin93 2022. 4. 19.
반응형

정보보안기사 필기 4-4. 유닉스/리눅스 서버 보안(프로세스)

1. 프로세스 응용

 1) 프로세스 개요

  • 프로세스를 생성하게 되면 물리적인 메모리를 프로세스에 직접 할 당하는 것이 아닌 가상 메모리를 할당하며, User Area와 Kernel Area로 구분된다.
  • User Area : 사용자 프로세스가 사용하는 공간으로, 사용자 프로세스의 코드와 데이터, 프로세스를 관리하기 위한 자료구조가 위치한다.
  • Kernel Area : 커널이 동작하기 위한 코드와 데이터, 전역적인 자료구조가 위치한다.

[ 그림 1-1. 커널이 해당 프로세스를 관리하기 위한 자료구조 ]

 

  1-1) 프로세스 상태 전이도(Process State Transition)

[ 그림 1-2. 프로세스 상태 전이도 ]

  • 준비상태(Ready) : 생성된 프로세스가 동작할 준비가 다 완료된 상태지만, CPU 할당(제한된 자원)을 받지 못하여 기다리는 상태
  • [Dispatch] : 커널이 제공해주는 CPU 스케줄러에 의해서 준비상태인 프로세스가 CPU 할당을 받게된다.
  • 실행상태(Running) : 프로세스가 CPU를 차지하고 실행 중인 상태, User Mode와 Kernel Mode 반복하면서 프로그램이 동작하게 된다.
  • [System Call] : 커널에게 어떠한 작업(자원)을 해달라고 요청하여 User Mode에서 Kernel Mode로 변경된다.
  • [Blocking system call] : 다양한 I/O 함수 등 호출하게 되면 CPU 스케줄러는 해당 프로세스를 대기상태로 변경시킨 후 새로운 프로세스를 받아서 실행을 시킨다. 이러한 CPU 스케줄러에 의해 실행 중인 프로세스가 대기상태로 변경되어 CPU를 반환하고, 새로운 프로세스에 CPU가 할당되어 실행되는 이 과정을 문맥교환(Context Switching)이라고 한다.
  • [Wake up] : I/O 함수 등 작업을 종료하게 되면 대기상태에서 준비상태로 변경되어 CPU 할당을 기다린다.
  • [Terminated] : 해당 프로세스의 모든 작업이 종료되는 과정
※ I/O 함수 연산은 CPU 연산에 비해 매우 느린연산이기 때문에  I/O 함수 연산이 다 종료될 때 까지 CPU를 차지하고 있게되면 비효율적이게 되므로 대기상태로 변경시킨 후 처리하게 된다.

 

  1-2) PCB(Process Control Block)

프로세스가 생성되면 커널은 개별 프로세스별로 관리정보를 담고 있는 영역인 '프로세스 제어 블럭'을 생성한다.
  • 프로세스 상태(Process state) : 프로세스의 현재 상태정보(CPU 스케줄링)를 저장(Ready, Running, Blocked 등)
  • 프로세스 번호(Process number) : 프로세스를 식별하기 위한 번호(ID)
  • 프로그램 카운터(Program counter) : 문맥교환이 발생할 경우 다음에 다시 CPU를 차지하였을 때 어디서부터 실행을 시작하면 되는지에 대한 위치값 (실행할 명령어(Instruction, CPU에서 명령어를 수행하는 단위)의 위치값을 저장) 
  • 레지스터(Registers) : 문맥교환이 발생할 경우 현재 프로세스의 실행 상태정보(레지스터 정보)를 저장
레지스터 : CPU가 어떤 연산을 수행하기 위한 고속의 저장장치로 데이터나 명령어 등을 담아 CPU가 연산을 수행한다. (CPU가 연산을 진행시 물리적인 메모리에 직접 접근하는 것이 아니다.)
  • 메모리 정보(Memory limits) : 프로세스가 사용하는 메모리 page 또는 segment 테이블 정보

 

  1-3) FDT(File Descriptor Table)

프로세스가 생성되면 개별 프로세스별로 오픈한 파일을 관리하기 위한 파일 디스크립터 테이블이 생성된다.
  • 프로그램이 실행되어서 프로세스가 되면, 기본적으로 3개의 파일이 자동 오픈되며, 표준입력(stdin)은 표준입력장치(키보드 등)로부터의 입력을 의미하고, 표준출력(stdout)은 표준출력장치(모니터 등)로의 출력을 의미하고, 표준에러(stderr)는 오류 발생 시 출력을 의미한다.
  • 프로세스 내에서 오픈한 각각의 파일을 식별하기 위한 양의 정수값을 파일 디스크립터(FD : File Descriptor)라고 한다.

 

  1-4) System open-file tables

  • 커널/운영체제가 시스템 내에서 여러 프로세스들에 의해 오픈된 파일들을 관리하기 위한 자료구조이다.
  • process 100에 의해 오픈된 "test"파일은 FD를 할당받고 System open-file table에 하나의 엔트리로 존재하게 된다.
  • open_mode : 파일의 읽기/쓰기 모드
  • offset : 오픈된 파일에 대해 읽기, 쓰기 등의 작업을 수행하기 위한 위치값
  • reference_count : 해당 파일의 참조 갯수를 의미한다. 파일 복제(dup)가 발생하게 되면 reference_count가 증가한다. 오픈한 파일을 close()하였을 때, 커널은 reference_count를 확인하여 0이면 System open-file table을 삭제하고 0이 아니면 참조하고 있는 프로세스가 있는것으로 System open-file table 유지한다.

 

  1-5) Active vnode table

  • 다양한 파일시스템의 i-node 정보를 관리하기 위해 만들어진 자료구조체
  • 해당 파일의 i-node 정보를 가지고 있는 일종의 캐시역할을 수행한다.

 2) 프로세스 기본 조건

  2-1) 모든 프로세스는 부모 프로세스(Parent Process)를 가진다.

  • 시스템 부팅을 담당하는 boot 프로세스(0번 프로세스)를 제외한 모든 프로세스는 부모 프로세스를 가진다.
  • 자식 프로세스가 살아있는 상태에서 부모 프로세스가 종료하게 되면 자식 프로세스는 고아 프로세스(Orphan Process)가 되며, 이 경우 대리모 프로세스(pid가 1인 init Process)가 부모 역할을 수행한다.
※ init 프로세스
 - 운영체제가 부팅을 완료하고 나면 init 프로세스가 동작을 한다.
 - run-level의 설정되어 있는 초기 프로세스들을 기동시킨다. 즉, 운영체제가 작동되도록 시스템 초기화를 진행한다.
 - 대리모 역할을 수행한다.

[ 그림 1-3. init 프로세스의 대리모 프로세스 수행 ]

  2-2) 좀비 프로세스(Zombie Process)

  • 프로세스 종료 시에는 자신의 종료상태정보를 부모 프로세스에 반환해야 정상적으로 소멸할 수 있다.
  • 종료상태정보는 "PID, exit code, CPU time" 등의 정보를 말한다.
  • 프로세스 수행을 종료했지만 부모 프로세스가 종료상태정보를 확인하지 않아서 소멸하지 않고 남아있는 상태의 프로세스를 좀비 프로세스(Zombie Process)라 한다. 시스템/커널 입장에서 프로세스는 제한된 자원이므로 좀비 프로세스가 과도하게 많아지면 더 이상 프로세스를 생성하지 못하는 문제가 발생할 수 있다.
  • 모든 프로세스는 종료 후 일시적으로 좀비 프로세스 상태를 거친 후 소멸한다.
  • 좀비 프로세스는 프로세스의 실행은 종료했기 때문에 kill 시그널을 통해서도 소멸되지 않으므로, 시스템 리부팅을 통해 커널 정보를 초기화해주는 임시적 방법이 있지만, 근복적으로는 부모 프로세스 또는 커널을 해결해야 한다.

[ 그림 1-4. 자식 프로세스 소멸 과정 ]

  • ① 자식 프로세스가 모든 코드의 수행을 종료하게 되면 바로 소멸하는 것이 아닌 종료상태정보를 커널에게 보낸다.
  • ② 종료상태정보를 받은 커널은 PID 정보를 확인하여 부모 프로세스에게 "시그널(SIGNAL,SIGCHLD)"을 발생시켜 알려준다.
  • ③ 정상적인 부모 프로세스라면 작업 중 "시그널(SIGNAL)"이 발생하게 되면 Signal-handler이 만들어져 있어 System Call을 통해 Signal-handler가 종료상태정보를 커널에서 가지고 오게된다.
  • ④ 커널은 자식 프로세스에게 소멸해도 된다고 알려주고 가지고 있던 자식 프로세스의 관리정보를 지우게 된다.
  • ⑤ 자식 프로세스는 정상적으로 소멸하게 된다.
  • ① ~ ⑤ 과정까지 자식 프로세스는 관리정보를 남겨둔 소멸하지 않은 상태로 남아있는 상태인 좀비 프로세스 상태로 남아있게 되는 것이다. (좀비 프로세스는 "ps -l" 명령어로 보았을 때 CMD 부분에 "<defunct>"라고 표시된다.)
※ 부모 프로세스가 정상적이지 않은 경우(Signal-handler 등록X, 코딩 오류 등)
 - 만약 부모 프로세스에 Signal-handler를 등록을 안했거나 코딩이 잘못되었거나 하면 System Call을 발생시키지 못하며 종료상태정보를 못가져가는 경우가 발생하여 커널입장에서는 자식 프로세스를 소멸시킬수가 없게된다. 
 - 이런식으로 좀비 프로세스가 계속 생겨나는 경우에 시스템의 가용성에 문제가 생겨나게 된다.
※ 좀비 프로세스의 WCHAN은 exit(종료)로 나타난다.

 

 3) 프로세스 실행 과정

  3-1) 프로그램 실행 과정

  • 터미널 프로그램이 유닉스 시스템에 접속을 시도하게 되면 인증과정을 거쳐서 로그인에 성공을 하게되고 Login Shell이 기동이 된다. 이때 터미널 프로그램과 유닉스 시스템 사이의 논리적인 연결 상태를 의미하는 하나의 세션이 추가로 동시에 생성되고 하나의 세션이 생성되게 되면 세션을 식별하기 위한 SID(최초 Leader Process PID)가 부여가 된다.
  • 해당 세션 내에서는 하나의 포그라운드 프로세스 그룹하나 이상의 백그라운드 프로세스 그룹이 생성된다.
  • Login Shell이 하나의 프로세스로 기동이 되는것과 동시에 Process Group이라는 것도 생성이된다.
  • Process Group은 터미널 제어권의 관리 단위이다. 즉, 터미널 제어권은 Terminal Input(키보드 입력), Terminal Gernerated Signal(프로세스에게 발생시키는 신호)이 두 가지를 의미하며, 프로세스 단위로 관리되는게 아니라 프로세스 그룹의 단위로 관리가 된다.
  • Process Group과 동시에 생성된 Login Shell이 해당 그룹의 Leader Process가 되는것이다. 이때 Leader Process의 PID가 Process Group의 PGID가 된다. 따라서 PGID는 Login Shell의 PID가 되는 것이다. 여기까지가 유닉스 시스템에 로그인하여 로그인 쉘이 동작하고 있는 상태가 되는 것이다.
  • 이 후 'a.txt'라는 프로그램을 실행을 시키게 된다면 Login Shell이 fork() System Call을 통해 자신과 동일한 복사본 프로세스(Copy Process)를 생성한 다음 exec("a.txt")를 실행하여 쉘 이미지에서 실행 파일 이미지로 전이($ → a.txt)가 된다.
  • "a.txt" 프로세스가 생성이 됨과 동시에 Process Group도 하나 생성되게 되는 것이다. 
  • 쉽게 정리해 유닉스 시스템 체계에서는 "init Process(PID : 1)가 실행이 되면 init Process를 fork()를 하고 fork된 Copy Process를 exec()으로 덮어씌우도록 하여 프로세스를 계속 생성하는 방식"이다.
  • 터미널 제어권을 가지고 동작하는 모드를 포그라운드 모드(Foreground Mode), 터미널 제어권 없이 동작하는 모드를 백그라운드 모드(Background Mode)라고 한다.

  3-2) 프로세스 간 통신(시그널)

  • 시그널이란 프로세스에게 특정 상황이 발생했음을 알리기 위한 비동기적 통보(Asynchronous Notification)이다. 이러한 시그널의 주체는 '자기 자신, 커널, 다른 프로세스'등으로 다양하다.
  • 시그널 발생 상황
  • ① Terminal Gernerated Signal : SIGINT(Ctrl + C), SIGQUIT, SIGTSTP(Ctrl + Z, 백그라운드 모드로 실행되고 있으며 'jobs' 명령어로 확인 가능, 'fg %[job_num]' 중지시킨 프로세스 다시 동작)
  • ② 하드웨어적인 예외사항(에러사항) : 메모리 참조 오류(SIGSEGV), 산술연산 오류(SIGFPE)
  • ③ 소프트웨어적인 예외사항 : 자식 프로세스 종료(SIGCHLD)
  • ④ 'kill' 명령 / System Call
  • 시그널 처리방식은 프로세스 내 Handdler를 등록하여 Handdling하는 방식, Ignore(무시)하는 방식, Default 방식이 있게되며 그 중 'SIGKILL, SIGSTOP'은 관리목적의 시그널로 해당 시그널을 받은 프로세스는 임의로 무시하거나 처리할 수 없게되며 무조건 종료, 정지하게 된다.

2. 시스템 시작과 종료

 1) 부팅 관련 용어 정의

  1-1) 런 레벨(Run Level)

  • 시스템에서 런 레벨의 의미는 시스템의 운영 상태를 숫자 혹은 문자로 표현한 것이다. 
  • 부팅 프로세스(PID : 0)의 마지막 단계에서 init 프로세스(PID : 1)가 동작하여 시스템 운영 환경의 초기화작업을 진행한다. 
  • init 프로세스는 '/etc/inittab' 파일에 정의된 런 레벨에 따라 '/etc/rc.d/rc[N].d(N은 런 레벨 숫자)' 디렉터리에 나열된 스크립트를 실행하여 시스템의 운영 상태를 구성한다.
  • 유닉스/리눅스 시스템 관리자가 시스템 관리의 편의성을 중대하기 위해서 사용되는 것으로 필요시에는 유닉스 부팅을 변경하여 네트워크를 사용하지 못하게 하거나, 다른 사용자의 접근을 막는 역할을 수행할 수 있다.

  1-2) INIT 상태

  • 싱글 유저모드란 시스템을 유지보수하기 위한 모드이기 때문에 싱글 유저모드로 로그인하기 위해서는 root 사용자 암호가 필요하며, 시스템에 문제가 생기는 경우 자동으로 싱글 유저모드로 진입하게 된다.
  • 런 레벨 0은 PROM(Programmable Read-Only Memory)모드로 시스템 부팅 전 하드웨어 체크하는 모드이다.
  • 런 레벨 3은 일반적인 서버용 유닉스 시스템, 멀티 유저모드에서 운영된다.

 2) 시스템 시작

  2-1) 바이오스(BIOS) 과정

  • 시스템에 전원이 들어오면 BIOS는 시스템의 기본적인 하드웨어(CPU, 메모리 등)의 이상 유무를 점검하고 시스템의 하드웨어 정보를 수집한다.

  2-2) 부트(Boot) 프로그램 과정

  • 부트 프로그램은 하드디스크에서 커널을 읽어 들여 메모리상에 적재하고 시스템 제어권을 커널에 넘긴다.

  2-3) 커널(Kernel) 과정

  • 커널이 메모리상에 적재되면 그때부터 운영체제가 구동되기 시작한다.
  • 커널은 부팅 과정의 일부인 하드웨어 점검을 완료하고 내부 자료구조를 초기화하여 시스템을 운영하기 위한 부가적인 커널 모듈을 하드디스크에서 메모리상으로 적재한다.

  2-4) init 프로세스 과정

  • init 프로세스는 커널에 의해 생성되는 첫 번째 프로세스이다. 커널의 실행으로 운영체제가 하드웨어의 모든 기능을 제어하게 되었을 때 PID가 1인 init 프로세스가 실행된다.
  • 이 프로세스는 모든 프로세스의 부모 프로세스로서, 부팅 과정에서 사용자가 시스템을 사용할 수 있게 해주는 초기화 작업을 담당한다.

 3) 시스템 종료

  3-1) 시스템 종료시 주의사항

  • 접속 중인 사용자에게 시스템의 종료를 공지하여 작업을 마무리하도록 해야한다.
  • 운영 중인 프로세스를 안전하게 종료해야 한다.
  • 하드디스크를 갱신하여 파일 시스템의 무결성을 유지한다.
  • 시스템 종료는 'init 5, shutdown' 명령어로 실행한다.

  3-2) 하드디스크 동기화(SYNC)

  • 유닉스 시스템은 하드디스크의 입/출력에 대한 효율성을 높이기 위하여 파일 시스템에서 버퍼를 운영한다.
  • 이는 어떤 파일의 입/출력이 발생할 때마다 디스크에 바로 Write하게 되면 성능이 떨어지기 때문이다.
  • 만일 시스템이 비정상적으로 종료되면 버퍼에 있는 데이터가 하드디스크에 반영되지 않아서 파일 시스템에서 무결성 문제가 생기기 때문에 시스템 종료시 가장 중요한 작업이다.
  • 유닉스/리눅스 시스템 종료 시 'sync' 명령을 내려 버퍼의 내용을 하드디스크로 옮기기 위함이다.

 4) 사용자 관리

  4-1) 사용자 계정 추가(useradd)

  • 사용자 계정정보를 저장하는 "/etc/passwd"와 암호화된 비밀번호를 저장하는 "/etc/shadow"에 사용자 정보를 추가한다.
  • 그룹 파일 "/etc/group"에 그룹정보를 추가혀며, 새 새용자를 위한 홈 디렉터리를 생성하고 접근권한을 부여한다.
  • 계정 생성 시 참조하는 기본설정 정보파일
※ useradd 생성 시 참조하는 파일
 - /etc/login.defs (파일)
 - /etc/default/useradd (파일)
 - /etc/skel (디렉터리) : 사용자 홈 디렉터리 생성 시 필요한 설정파일들을 담고있으며, 계정 생성 시 /etc/skel에 있는 파일들을 생성되는 홈 디렉터리에 복사하게 된다.
옵션 설명
-u - 사용자 UID를 지정한다.
-g - 사용자의 기본그룹을 설정한다. 옵션을 사용하지 않을 시 기본적으로 계정명과 동일한 이름의 그룹 생성
-G - 사용자의 보조그룹을 생성한다.
-c - 계정에 대한 설명
-d - 계정의 홈 디렉터리를 설정한다.
-s - 계정의 로그인 쉘을 지정한다.
-p - 생성하는 계정의 패스워드를 지정
- /etc/shadow에 평문으로 저장되기 때문에 암호화를 수행해야 한다.
- 옵션 사용하지 않고, passwd 명령으로 나중에 패스워드를 암호화해 저장한다.
-e - 계정 만료일을 지정

  4-2) 로그인 불가 계정 설정

  • 시스템 계정, 애플리케이션 계정 등 로그인이 불필요한 계정의 경우 로그인이 불가능하도록 설정하는 것이 보안상 안전하다.
  • /etc/passwd 파일에 해당 계정의 로그인 쉘 항목을 "/sin/nologin 또는 /bin/false"로 설정하도록 한다.

[ 그림 2-1. /etc/passwd 내 kkmin 계정 비활성화 ]

 5) 프로세스 스케줄 관리

  5-1) 정기적 스케줄 관리(cron - 파일의 구조) 

  • cron 데몬 프로세스는 시스템에서 정기적인 작업을 지정시간에 처리하기 위해 사용하는 프로세스
※ cron 데몬 프로세스를 통한 처리가 효율적인 작업
 ① 일괄적으로 처리해야하는 작업의 경우
 ② 작업에 대한 요구가 불규칙하지 않은 경우
 ③ 우선순위가 낮은 작업이 일정시기에 처리해야 하는 경우
 ④ 작업 빈도가 낮아서 필요 시점에 처리하여 마무리하는 것이 자원관리상 효율적인 경우
  • cron 데몬 프로세스를 사용하려면 다음 세 가지 구성요소가 필요하다.
  • 정기적으로 처리할 작업 목록을 정의한 crontab 파일
  • crontab 파일을 제어(편집)하는 crontab 명령(cron.allow, cron.deny)
  • crontab 파일을 읽어서 내용에 정의된 대로 작업을 처리하는 cron 데몬 프로세스
  • crontab 파일의 각 행은 Space나 Tab키로 구분된 6개의 필드로 이루어진다.
구분 기술 방법
필드 의미
필드1 - 분은 0-59까지의 숫자로 기술한다.
필드2 - 시는 0-23까지의 숫자로 기술한다.
필드3 - 일은 1-31까지의 숫자로 기술한다.
필드4 - 월은 1-12까지의 숫자로 기술한다.
필드5 요일 - 요일은 0-6까지의 숫자로 기술한다.(0 : 일요일)
필드6 작업 - 지정 시간에 실행할 작업을 절대 경로로 기술하고 필요한 옵션 및 인수를 함께 나열한다.
  • [*] 기호는 필드의 범위에 해당하는 모든 값을 의미, [-] 기호는 값의 범위, [,] 기호는 값을 구분하는 의미, [/] 기호는 간격값을 지정할때 사용한다.
  • EX) 0 1 * * * batch.sh ☞ 매일 01시에 batch.sh 실행
  • EX) */5 * * * * batch.sh ☞ 매 5분 간격으로 batch.sh 실행

[ 그림 2-2. crontab 파일에 작업 등록 ]
[ 그림 2-3. root 계정으로 사용자 crontab 작업 목록 변경 ]

  5-2) 정기적 스케줄 관리(cron - 파일의 제어) 

  • crontab 파일은 사용자 계정별로 만들어지며, 시스템 관리자인 root는 사용자를 명시적으로 지정하여 다른 사용자의 crontab 파일을 편집할 수 있으며, 일반 사용자는 자신의 crontab 파일만 편집할 수 있다.
문법 - 리눅스 : crontab [-u user] [ -e | -l | -r ]
- 유닉스 : crontab [ -e | -l | -r ] [user]
옵션 - e : crontab 파일을 편집한다.
- l : crontab 파일을 출력한다.
- r : crontab 파일을 삭제한다.
예문 $ crontab -u kkmin -e ☞ kkmin 계정의 crontab 파일을 편집한다.
$ crontab -u kkmin -l ☞ kkmin 계정의 crontab 파일을 출력한다.
  • cron을 통해 자동으로 스케줄링 되는 작업은 모니터 출력(표준출력 및 표준에러)이 불필요한 경우가 많기 때문에 /dev/null 장치파일로 출력재지정을 하고(>/dev/null), 표준에러(2)도 표준출력(&1)으로 출력 재지정(2>&1)을 하여 표준출력과 동일하게 /dev/null 장치파일로 출력하여 버려지게 설정한다.
  • cron.allow, cron.deny 파일이 모두 존재하는 경우 cron.allow 파일이 우선하여 해당 파일에 등록된 사용자만이 crontab 명령을 실행할 수 있다. 권한또한 other에 제한을 두는 640이하의 권한을 권장하고 있다.
  • /var/log/cron에 crontab 파일의 작업내용을 수정한 로그들이 기록되고 있다.

[ 그림 2-4. cron 변경 작업에 대한 로그가 저장되는 모습 ]

  5-3) 일시적 스케줄 관리(at)

  • 작업을 정기적으로 스케줄링하는 cron 데몬 프로세스와 달리, at 명령은 정해진 시간에 한 번만 실행한다.
반응형