
서비스 · 프로세스 관리 43 / 50 · Part 5. 보안과 SOC
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정analyst)
41·42편에서 확인이 필요한 프로세스를 찾았다. 다음 단계에서 가장 흔한 실수는 바로 종료하는 것 이다. 프로세스를 종료하는 순간 /proc/PID 아래의 실행 파일 링크, 환경변수, 메모리 매핑, 열린 파일, 네트워크 연결 정보가 모두 사라진다. 특히 디스크에서 이미 지워진 실행 파일은 프로세스가 살아 있는 동안에만 되살릴 수 있다.
이번 글에서는 조치 전에 수집해야 할 휘발성 정보를 순서대로 정리하고, 이를 읽기 전용·해시 포함·UTC 시각 기록 원칙으로 수집하는 스크립트를 만든다. 실행 파일이 삭제된 테스트 프로세스를 대상으로 수집하고, 수집물의 무결성을 검증한다.
| 순위 | 대상 | 사라지는 시점 |
|---|---|---|
| 1 | CPU 레지스터, 캐시 | 즉시 |
| 2 | 메모리 — 프로세스 목록, 네트워크 연결, 열린 파일 | 프로세스 종료·재부팅 |
| 3 | 임시 파일 시스템 (/tmp, /run, tmpfs) | 재부팅 |
| 4 | 디스크 | 삭제·덮어쓰기 |
| 5 | 원격 로그, 백업 | 보존 정책 |
/proc 기반 수집은 2번 영역이다. 디스크 이미지보다 먼저 해야 한다.
| 파일 | 출처 | 알 수 있는 것 |
|---|---|---|
01_ps.txt | ps -o ... -ww | PID·부모·계정·정확한 시작 시각·전체 인자 |
02_pstree.txt | pstree -ps | 조상 체인 |
03_links.txt | exe, cwd, root | 실제 실행 파일, 작업 디렉터리, chroot 여부 |
04_cmdline.txt | cmdline | 실행 인자 |
05_environ.txt | environ | 환경변수 (LD_PRELOAD 등) |
06_status.txt | status | UID 4종, Capability, 메모리 |
07_maps.txt | maps | 로드된 라이브러리·매핑 파일 |
08_cgroup.txt | cgroup | 소속 서비스·세션 |
09_fd.txt / 10_sockets.txt | fd/, ss -tanp | 열린 파일·소켓 |
11_exe.bin | cp /proc/PID/exe | 실행 파일 사본 (삭제된 경우도) |
SHA256SUMS | sha256sum * | 수집물 무결성 |
| 원칙 | 이유 |
|---|---|
| 읽기 전용 | 대상 시스템을 바꾸면 증거 가치가 떨어진다 |
| UTC 시각 기록 | 여러 서버·로그와 시간을 맞추기 위해 |
| 해시 즉시 생성 | 수집 이후 변경되지 않았음을 증명 |
| 수집 경로 분리 | 대상 프로세스가 쓸 수 없는 곳(/evidence, 권한 제한), 가능하면 외부 저장소 |
| 명령 기록 | 무엇을 어떻게 수집했는지 재현 가능해야 한다 |

collect.sh 1318
→ /evidence/<host>_<PID>_<UTC>/ 생성
→ 00 수집 시각 → 01~10 /proc·ps·ss 정보 → 11 exe 사본
→ sha256sum * > SHA256SUMS → chmod -R a-w (쓰기 금지)
→ 조치(종료 등)는 수집이 끝난 뒤
cp /proc/PID/exe가 삭제된 파일을 복구할 수 있는 이유는 15편에서 본 것과 같다. 이름(링크)은 지워졌지만 프로세스가 inode를 잡고 있어 데이터가 남아 있기 때문이다.
# 1) (analyst) 수집 대상: 실행 후 디스크에서 지운 테스트 프로세스 (sleep 복사본)
cp /usr/bin/sleep /tmp/lab-sample && cd /tmp && LAB_TOKEN=demo setsid /tmp/lab-sample 900 < /dev/null > /dev/null 2>&1 &
rm -f /tmp/lab-sample
# 2) (root) 수집 스크립트 /root/collect.sh — 내용은 실행 결과 화면 참고
D=$(/root/collect.sh $(pgrep -f lab-sample)); ls -l $D
# 3) 수집 결과 확인
cat $D/01_ps.txt; cat $D/03_links.txt
grep -E '^(LAB_TOKEN|PWD)=' $D/05_environ.txt
sha256sum $D/11_exe.bin /usr/bin/sleep # 복구한 사본의 정체 확인
cd $D && sha256sum -c SHA256SUMS --quiet && echo "수집 파일 무결성 OK"



텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ cp /usr/bin/sleep /tmp/lab-sample && cd /tmp && LAB_TOKEN=demo setsid /tmp/lab-sample 900 < /dev/null > /dev/null 2>&1 &
[analyst@rocky9-lab ~]$ sleep 0.3; rm -f /tmp/lab-sample; pgrep -a -f lab-sample
1318 /tmp/lab-sample 900
[root@rocky9-lab ~]# cat > /root/collect.sh <<'EOF'
> #!/bin/bash
> # 사용법: collect.sh PID — 읽기 전용 수집, 결과는 /evidence/<host>_<PID>_<시각>/
> P=$1; T=$(date -u +%Y%m%dT%H%M%SZ); D=/evidence/$(hostname)_${P}_$T; mkdir -p $D; cd $D
> date -u +%FT%TZ > 00_collected_at_utc.txt
> ps -o pid,ppid,user,lstart,etime,stat,args -ww -p $P > 01_ps.txt
> pstree -ps $P > 02_pstree.txt
> ls -l /proc/$P/exe /proc/$P/cwd /proc/$P/root > 03_links.txt 2>&1
> tr '\0' ' ' < /proc/$P/cmdline > 04_cmdline.txt
> tr '\0' '\n' < /proc/$P/environ > 05_environ.txt
> cp /proc/$P/status 06_status.txt; cp /proc/$P/maps 07_maps.txt; cat /proc/$P/cgroup > 08_cgroup.txt
> ls -l /proc/$P/fd > 09_fd.txt 2>&1; ss -tanp 2>/dev/null | grep "pid=$P," > 10_sockets.txt
> cp /proc/$P/exe 11_exe.bin 2>/dev/null
> sha256sum * > SHA256SUMS; chmod -R a-w $D; echo $D
> EOF
[root@rocky9-lab ~]# chmod 700 /root/collect.sh
[root@rocky9-lab ~]# D=$(/root/collect.sh $(pgrep -f lab-sample)); ls -l $D
total 76
-r--r--r-- 1 root root 21 Sep 24 13:40 00_collected_at_utc.txt
-r--r--r-- 1 root root 162 Sep 24 13:40 01_ps.txt
-r--r--r-- 1 root root 30 Sep 24 13:40 02_pstree.txt
-r--r--r-- 1 root root 220 Sep 24 13:40 03_links.txt
-r--r--r-- 1 root root 20 Sep 24 13:40 04_cmdline.txt
-r--r--r-- 1 root root 2339 Sep 24 13:40 05_environ.txt
-r--r--r-- 1 root root 1447 Sep 24 13:40 06_status.txt
-r--r--r-- 1 root root 3544 Sep 24 13:40 07_maps.txt
-r--r--r-- 1 root root 1055 Sep 24 13:40 08_cgroup.txt
-r--r--r-- 1 root root 188 Sep 24 13:40 09_fd.txt
-r--r--r-- 1 root root 0 Sep 24 13:40 10_sockets.txt
-r-xr-xr-x 1 root root 32224 Sep 24 13:40 11_exe.bin
-r--r--r-- 1 root root 959 Sep 24 13:40 SHA256SUMS
[root@rocky9-lab ~]# D=$(ls -d /evidence/* | tail -1); cat $D/01_ps.txt; cat $D/03_links.txt
PID PPID USER STARTED ELAPSED STAT COMMAND
1318 1 analyst Thu Sep 24 13:40:17 2026 00:01 Ss /tmp/lab-sample 900
lrwxrwxrwx 1 analyst analyst 0 Sep 24 13:40 /proc/1318/cwd -> /tmp
lrwxrwxrwx 1 analyst analyst 0 Sep 24 13:40 /proc/1318/exe -> /tmp/lab-sample (deleted)
lrwxrwxrwx 1 analyst analyst 0 Sep 24 13:40 /proc/1318/root -> /
[root@rocky9-lab ~]# grep -E '^(LAB_TOKEN|PWD)=' $D/05_environ.txt
LAB_TOKEN=demo
PWD=/tmp
[root@rocky9-lab ~]# sha256sum $D/11_exe.bin /usr/bin/sleep | awk '{print $1, $2}'
6f6167444e074f544a5bc61fea96b774c8c57aa58d27b4ea7ea27a57f176b73c /evidence/rocky9-lab_1318_20260924T134019Z/11_exe.bin
6f6167444e074f544a5bc61fea96b774c8c57aa58d27b4ea7ea27a57f176b73c /usr/bin/sleep
[root@rocky9-lab ~]# cd $D && sha256sum -c SHA256SUMS --quiet && echo "수집 파일 무결성 OK"
수집 파일 무결성 OK
[root@rocky9-lab rocky9-lab_1318_20260924T134019Z]# pkill -u analyst -f lab-sample; true
| 관찰 | 의미 |
|---|---|
수집 폴더 rocky9-lab_1318_20260924T134019Z | 호스트·PID·UTC 시각으로 이름을 붙여 여러 수집물을 구분한다 |
모든 파일이 -r--r--r-- | 수집 직후 쓰기 권한을 제거했다 |
10_sockets.txt 크기 0 | 이 프로세스는 네트워크 연결이 없었다. 빈 결과도 증거 다 |
01_ps.txt: PPID 1, Ss, /tmp/lab-sample 900 | setsid로 분리된 세션 리더, 시작 시각 13:40:17 |
exe -> /tmp/lab-sample (deleted), cwd -> /tmp | 실행 파일은 지워졌고, /tmp에서 실행되었다 |
environ LAB_TOKEN=demo, PWD=/tmp | 실행 당시의 환경변수. 명령줄에 보이지 않는 설정·자격 증명이 여기에 있을 수 있다 |
11_exe.bin 해시 = /usr/bin/sleep 해시 | 지워진 실행 파일을 복구했고, 해시 비교로 정체를 확인 했다. 실무에서는 이 해시로 위협 인텔리전스·패키지 DB를 조회한다 |
sha256sum -c → 무결성 OK | 수집 이후 파일이 바뀌지 않았다 |
첫 시도에서는 테스트 프로세스를 셸의 일반 백그라운드 작업으로 띄워, 실습 세션이 끝날 때 SIGHUP으로 함께 종료되었다(10편). 그 결과 수집 스크립트가 빈 PID로 실행되었다. 수집 전에 대상이 살아 있는지(
kill -0) 확인 하는 단계가 필요한 이유다.
| 주제 | 내용 |
|---|---|
| 조치 순서 | 수집 → 격리(네트워크 차단·kill -STOP) → 종료 → 제거. 순서를 바꾸면 증거가 사라진다 |
| 민감 정보 | environ·maps에는 자격 증명·토큰이 포함될 수 있다. 수집물은 접근 통제된 저장소 에 보관하고 공유 범위를 제한한다 |
| 도구 신뢰성 | 침해된 서버의 ps·ss는 변조되었을 수 있다. /proc 직접 읽기를 병행하고, 가능하면 신뢰할 수 있는 정적 바이너리를 쓴다 |
| 메모리 전체 | 이 스크립트는 프로세스 메타데이터 수준이다. 메모리 전체 수집은 검증된 전용 도구와 절차로 별도 수행한다 |
| 증거 연속성 | 누가, 언제, 어떤 명령으로 수집했는지 기록해야 보고서·법적 절차에서 증거로 쓸 수 있다 |
[트리거] 41편 점검에서 우선순위 1 프로세스 발견
↓
[사전 확인] kill -0 <PID> && echo alive ← 대상이 살아 있는가
↓
[수집] /root/collect.sh <PID> ← 5분 이내 완료 목표
추가: 관련 unit·crontab 사본 (45·46편)
↓
[보관] tar czf evidence_<host>_<UTC>.tgz <폴더> ; sha256sum *.tgz
관제 저장소로 전송 → 서버 사본 보관 여부는 정책에 따름
↓
[기록] 티켓에 수집자·UTC 시각·명령·해시 기재 → 44편(네트워크) · 50편(보고서)
| 체크 | 확인 |
|---|---|
| 수집 전 대상 생존 확인 | kill -0 |
| 시각 기준 | UTC, 서버 시계 동기화 상태(timedatectl) |
| 해시 | 수집 직후 생성, 전송 후 재확인 |
| 실수 | 결과 | 예방 |
|---|---|---|
| 확인 즉시 kill | exe·environ·연결 정보 소실 | 수집 후 조치 |
| 수집물을 /tmp에 저장 | 대상 프로세스가 덮어쓸 수 있음 | 권한 제한 경로·외부 저장 |
| 해시를 나중에 생성 | 수집 후 변경 여부를 증명 못 함 | 수집 직후 해시 |
| 로컬 시간만 기록 | 다른 로그와 시간 불일치 | UTC 병기 |
| 빈 결과 파일 삭제 | "연결 없음"이라는 사실까지 사라짐 | 빈 결과도 보존 |
[ ] 휘발성 순서와 /proc 수집이 먼저인 이유를 설명할 수 있다
[ ] 수집 항목 11가지와 각각의 의미를 정리했다
[ ] 삭제된 실행 파일을 /proc/PID/exe 로 복구했다
[ ] 복구한 사본의 해시로 정체를 확인했다
[ ] SHA256SUMS 로 수집물 무결성을 검증했다
[ ] 수집 전 대상 생존 확인이 필요한 이유를 실습으로 확인했다
/proc/PID의 모든 정보가 사라진다. 수집 → 격리 → 종료 순서를 지킨다.cp /proc/PID/exe로 복구할 수 있다.다음 글 「44. 프로세스 네트워크 연결 점검」 에서는 대기 포트와 연결을 소유 프로세스·실행 경로·허용 목록 과 함께 한 표로 만드는 점검 스크립트를 작성한다. 허용 목록 밖 포트와 임시 경로 실행 파일을 동시에 표시해 확인 우선순위를 정한다.