리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.

리눅스 시스템 기초 31 / 50 · Part 4. 프로세스·서비스·리소스
실습 환경: Rocky Linux 9 (10.0.0.200) · 좀비·고아·스레드는 실습 환경에서 재현한 실제 출력
이전 글: 30. Linux 명령어를 활용한 보안 점검

1. 들어가며

Part 4 「프로세스·서비스·리소스」를 시작한다. 지금까지 프로세스는 여러 번 나왔다. 4편에서 커널 스레드 위장을, 5편에서 fork/execve를, 29편에서 의심 프로세스 분석을 다뤘다. 이번 글은 프로세스라는 개념 자체를 정리한다.

관제에서 프로세스를 정확히 이해해야 하는 이유는 "지금 서버에서 무엇이 실행되고 있는가"가 침해 판단의 핵심 증거 이기 때문이다. 로그는 과거를 보여주지만, 프로세스는 현재 진행 중인 공격 을 보여준다.

이번 글에서 답할 질문:

  • 프로그램, 프로세스, 스레드는 무엇이 다른가?
  • 프로세스는 어떤 상태(R, S, D, T, Z)를 거치는가?
  • 좀비 프로세스와 고아 프로세스는 무엇이고, 보안상 무엇을 의미하는가?

2. 핵심 개념

2-1. 프로그램 · 프로세스 · 스레드

구분정의예
프로그램디스크에 저장된 실행 파일 (정적)/usr/sbin/sshd
프로세스메모리에 올라가 실행 중인 프로그램 (동적), 자기만의 주소 공간·PID 보유PID 812의 sshd
스레드프로세스 안에서 실행되는 흐름 단위, 주소 공간을 공유httpd의 작업 스레드

같은 프로그램을 여러 번 실행하면 프로세스가 여러 개 생긴다. 한 프로세스는 스레드를 여러 개 가질 수 있다.

비교프로세스스레드
메모리독립된 가상 주소 공간 (4편)같은 프로세스의 메모리를 공유
식별자PIDTID(LWP). 같은 프로세스의 스레드는 같은 TGID(=PID)
생성 비용큼 (fork)작음 (clone + 공유 플래그)
하나가 죽으면다른 프로세스는 영향 없음보통 프로세스 전체가 종료
확인ps -efps -eLf, /proc/PID/task/

Linux 커널 내부에서는 프로세스와 스레드 모두 task 라는 같은 구조로 관리된다. 차이는 메모리·파일 등을 얼마나 공유하느냐다.

2-2. 프로세스를 구성하는 정보

정보의미확인 위치
PID프로세스 번호ps, /proc/PID
PPID부모 프로세스 번호/proc/PID/status
UID / EUID실행 계정 / 권한 검사 계정 (16편)/proc/PID/status
상태R, S, D, T, Zps STAT
실행 파일실제 경로/proc/PID/exe
명령줄실행 인자/proc/PID/cmdline
열린 파일파일·소켓/proc/PID/fd/
작업 디렉터리cwd/proc/PID/cwd

2-3. 프로세스 상태

STAT이름의미
RRunning실행 중이거나 CPU를 기다리는 중
SSleeping이벤트를 기다리는 중 (깨울 수 있음) — 대부분의 프로세스
DUninterruptible sleep디스크·NFS I/O 대기 — 시그널로도 깨울 수 없음
TStoppedSIGSTOP, Ctrl+Z로 정지
ZZombie종료됐지만 부모가 종료 상태를 회수하지 않음
IIdle유휴 커널 스레드

3. 동작 원리

프로세스 상태 전이와 프로세스 vs 스레드

3-1. 생성과 종료

  1. 부모가 fork()로 자신을 복제한다 (새 PID, PPID = 부모).
  2. 자식이 execve()로 다른 프로그램으로 바뀐다 (1·5편).
  3. 자식이 exit()로 끝나면 커널은 종료 코드를 보관하고 부모에게 SIGCHLD 를 보낸다.
  4. 부모가 wait()로 종료 코드를 회수하면 프로세스 정보가 완전히 사라진다.

3-2. 좀비와 고아

구분발생 조건상태해결
좀비 (Zombie)자식은 끝났는데 부모가 wait()를 안 함Z, 자원은 거의 없고 PID 항목만 남음부모가 회수하거나, 부모가 종료되면 PID 1이 회수
고아 (Orphan)부모가 먼저 종료자식은 계속 실행, PPID가 1(systemd)로 바뀜정상적으로 계속 실행

실습 환경에서 두 상황을 재현한 실제 결과다.

== 좀비: 자식은 종료, 부모(659)는 wait() 안 함
  PID  PPID STAT COMMAND
  661   659 Z    python3

== 고아: 부모 bash가 먼저 종료 → PID 1이 입양
  PID  PPID STAT COMMAND
  664     1 S    sleep

좀비는 kill -9로도 없앨 수 없다. 이미 죽은 프로세스이기 때문 이다. 부모를 종료시키면 PID 1이 입양해서 회수한다.


4. 실습

# 1) 프로세스 개수, 스레드 수 포함 개수
ps -e --no-headers | wc -l
ps -eL --no-headers | wc -l

# 2) 상태별 분포
ps -eo stat --no-headers | cut -c1 | sort | uniq -c

# 3) 특정 프로세스 상세
P=$(pgrep -o sshd)
grep -E '^(Name|State|Tgid|Pid|PPid|Uid|Threads)' /proc/$P/status
ls -l /proc/$P/exe /proc/$P/cwd

# 4) 스레드 보기
ps -o pid,nlwp,comm -C httpd       # NLWP = 스레드 수
ps -L -o pid,lwp,comm -p $P
ls /proc/$P/task

# 5) 좀비·D 상태 찾기
ps -eo pid,ppid,stat,comm | awk '$3 ~ /^[ZD]/'

# 6) 고아처럼 PID 1이 부모인 사용자 프로세스
ps -eo pid,ppid,user,comm | awk '$2==1 && $3!="root"'

5. 결과 분석

① 스레드 확인 (실습 환경 실제 결과)

$ ps -o pid,nlwp,comm -p 668
  PID NLWP COMMAND
  668    4 python3

$ ps -L -o pid,lwp,comm -p 668
  PID   LWP COMMAND
  668   668 python3
  668   670 python3
  668   671 python3
  668   672 python3

$ grep -E '^(Tgid|Pid|PPid|Threads)' /proc/668/status
Tgid:   668
Pid:    668
PPid:   656
Threads:        4

PID는 668 하나지만 스레드(LWP)는 4개다. 첫 번째 스레드의 LWP는 PID와 같다(메인 스레드). ps -ef에는 한 줄로, ps -eLf에는 네 줄로 나온다.

② 상태별 판단

관찰해석
대부분 S정상 (이벤트 대기)
R이 CPU 수보다 많이 지속CPU 부족, 채굴 악성코드 가능성 (33·39편)
D가 오래 지속디스크·NFS 장애, 시그널로 종료 불가
Z가 계속 쌓임부모 프로그램의 버그 — 대량이면 PID 고갈 위험
모르는 T누군가 SIGSTOP으로 멈춰 둔 프로세스 (분석 중일 수도)

6. 보안 관점

관찰보안 의미
고아 프로세스(PPID 1) + 사용자 계정 + /tmp 실행공격자가 부모를 끝내고 백그라운드로 남긴 프로세스 (29편 사례: PPID 1, /tmp/.cache/kw)
이중 fork(double fork)데몬화 기법 — 부모를 끊어 세션 종료 후에도 살아남게 함. 정상 데몬도 쓰지만, 웹 서버 아래에서 발생하면 의심
스레드 수 급증채굴·DDoS 도구는 CPU 코어 수만큼 스레드를 만드는 경우가 많음
대량 fork (fork bomb)프로세스를 무한 생성해 서비스 거부 → ulimit -u, systemd TasksMax로 제한
프로세스 이름 위장이름은 바꿀 수 있음 → exe·PPID로 확인 (4·29편)

7. SOC / 보안관제 활용

7-1. 프로세스 기준 헌팅 쿼리

# PID 1이 부모인 비root 프로세스 (고아·데몬화된 사용자 프로세스)
ps -eo pid,ppid,user,etimes,args | awk 'NR==1 || ($2==1 && $3!="root")'

# 스레드가 많은 프로세스 상위
ps -eo pid,nlwp,user,comm --sort=-nlwp | head

# 좀비와 부모
ps -eo pid,ppid,stat,comm | awk '$3 ~ /^Z/ {print "zombie", $1, "parent", $2}'

etimes는 프로세스가 실행된 지 몇 초 지났는지다. 로그인 성공 시각(21편)과 비교하면 그 로그인 직후 시작된 프로세스 를 골라낼 수 있다.

7-2. 분석 흐름

[Event]   28편 리포트: 02:19 devuser 로그인 성공
   ↓
[프로세스] ps -eo pid,ppid,user,etimes,args
          → devuser 소유, PPID 1, 02:20 시작, /tmp 실행
   ↓
[판단]    로그인 세션이 끝나도 남도록 부모를 끊은 프로세스 → 지속 실행 목적
   ↓
[다음]    29편 방식으로 /proc/PID/exe · ss · lsof 분석

8. 핵심 정리

  • 프로그램 은 디스크의 파일, 프로세스 는 실행 중인 프로그램, 스레드 는 프로세스 안의 실행 흐름이다.
  • 스레드는 같은 프로세스의 메모리를 공유한다. ps -eLf, /proc/PID/task로 확인한다.
  • 상태: R(실행) · S(대기) · D(I/O 대기, 시그널 무시) · T(정지) · Z(좀비).
  • 좀비 는 부모가 회수하지 않은 종료 프로세스라 kill로 없앨 수 없다.
  • 고아 는 부모가 먼저 끝난 프로세스로, PPID가 1이 된다. 사용자 계정의 고아 프로세스는 헌팅 대상이다.
  • etimes로 프로세스 시작 시각을 로그인 시각과 비교한다.

9. 다음 글

다음 글 「32. ps로 프로세스 분석」 에서는 이번 글의 정보를 실제로 뽑아내는 ps를 자세히 다룬다. BSD 형식(aux)과 UNIX 형식(-ef)의 차이, 각 컬럼의 의미, -o로 필요한 필드만 골라 헌팅용 출력을 만드는 방법 을 정리한다.


참고 자료

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글