
서비스 · 프로세스 관리 50 / 50 · Part 5. 보안과 SOC
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정analyst)
「서비스 · 프로세스 관리」 시리즈의 마지막 글이다. 50편에 걸쳐 프로세스의 생성과 상태, 시그널과 자원, systemd 서비스와 예약 작업, 로그와 감사, 그리고 관제 판단 기준과 점검 도구를 다뤘다. 이번 글에서는 이 모든 것을 하나의 대응 절차 로 연결한다.
훈련용 시나리오는 모두 무해한 항목으로 구성했다. analyst 계정이 임시 경로의 python 복사본으로 로컬 웹 서버를 띄우고, 실행 파일을 지우고, crontab과 사용자 unit을 등록 한 상황이다. 이를 정기 점검으로 탐지 하고, 조치 전에 증거를 수집 하고, 감사 로그와 journal로 타임라인 을 만들고, 격리·제거 한 뒤 재검증 하고, 마지막으로 보고서 로 정리한다.
| 단계 | 목적 | 사용 도구 | 편 |
|---|---|---|---|
| 0 준비 | 감사 규칙, 기준선, 점검 스크립트 | auditd, baseline, soc-proc-audit.sh | 42·48·49 |
| 1 탐지 | 이상 항목 식별 | 점검 스크립트, 판단 기준 | 41·49 |
| 2 증거 수집 | 휘발성 정보 보존 | collect.sh, crontab·unit 사본 | 43 |
| 3 타임라인 | 언제 누가 무엇을 | ausearch, journalctl | 31·48 |
| 4 격리·제거 | 동작 중지, 지속 항목 제거 | kill, crontab -r, unit 삭제 | 12·13·45·46 |
| 5 검증 | 제거 확인 | ss, crontab -l, 점검 재실행 | 44·49 |
| 6 보고 | 사실·근거·조치·개선 | 보고서 템플릿 | 40·50 |
| 원칙 | 이유 |
|---|---|
| 수집 → 조치 | 조치하는 순간 휘발성 증거가 사라진다 |
| 모든 지속 항목 제거 | 프로세스만 끄면 crontab·unit으로 다시 실행된다 (39편) |
| 시각은 UTC로 통일 | 여러 출처(audit, journal, 방화벽)를 합치기 위해 |
| 판단 근거 기록 | 보고서는 "무엇을 봤고 왜 그렇게 판단했는가"를 담아야 한다 |

[1 탐지] WARN: deleted exe(/tmp/.svc-helper) · 포트 127.0.0.1:7070 · 사용자 unit · analyst crontab
[2 수집] PID 3535 → /evidence/rocky9-lab_3535_<UTC>/ (15개 파일, 해시)
[3 타임라인] audit (auid=analyst, ses) : 13:45:17 cp → setsid → crontab → mkdir → rm
journal : 13:45:17 Accepted publickey for analyst · crontab REPLACE
[4 조치] 프로세스 종료 · crontab 삭제 · 사용자 unit 삭제
[5 검증] 포트 없음 · crontab 없음 · 점검 WARN 7 → 3 (사전 승인된 labapp 항목만)
# 0) (수집 노드) 48편 감사 규칙 적재
# 훈련 시나리오 준비 (analyst, 무해한 항목)
cp /usr/bin/python3 /tmp/.svc-helper; cd /tmp
setsid /tmp/.svc-helper -m http.server 7070 --bind 127.0.0.1 < /dev/null > /dev/null 2>&1 &
echo '*/10 * * * * /usr/bin/logger training-beacon' | crontab -
mkdir -p ~/.config/systemd/user; printf '... ExecStart=/usr/bin/logger training-user-unit\n' > ~/.config/systemd/user/helper.service
rm -f /tmp/.svc-helper
# 1) 탐지
/root/soc-proc-audit.sh "22 8082"
# 2) 증거 수집 (조치 전)
P=$(ss -tlnpH 'sport = :7070' | grep -oP 'pid=\K[0-9]+')
D=$(/root/collect.sh $P)
cp /var/spool/cron/analyst $D/crontab_analyst.txt; cp /home/analyst/.config/systemd/user/helper.service $D/
# 3) 타임라인
ausearch -k user_exec -ua analyst -i --start recent | grep '^type=EXECVE' | ... # (수집 노드)
ausearch -k cron_change -i --start recent | grep -oE 'item=1 name=/var/spool/cron/[^ ]+'
journalctl --since "-10min" -o short-iso _COMM=sshd-session -g 'Accepted.*analyst'
journalctl --since "-10min" -o short-iso -t crontab
# 4) 격리·제거 → 5) 검증
kill $P; crontab -u analyst -r; rm -f /home/analyst/.config/systemd/user/helper.service
ss -tlnH 'sport = :7070' | wc -l; crontab -u analyst -l
/root/soc-proc-audit.sh "22 8082" | tail -2







텍스트 원본(실제 출력):
[root@audit-collector ~]# RP=$(for p in $(pgrep -x systemd); do grep -qs rocky9-lab /proc/$p/root/etc/hostname && echo $p; done | head -1); sed "s#^-w /#-w /proc/$RP/root/#" /etc/audit/rules.d/50-soc-process.rules > /tmp/lab-mapped.rules; auditctl -D >/dev/null; auditctl -R /tmp/lab-mapped.rules >/dev/null 2>&1; auditctl -l | wc -l
4
[analyst@rocky9-lab ~]$ cp /usr/bin/python3 /tmp/.svc-helper; cd /tmp; setsid /tmp/.svc-helper -m http.server 7070 --bind 127.0.0.1 < /dev/null > /dev/null 2>&1 &
[analyst@rocky9-lab tmp]$ echo '*/10 * * * * /usr/bin/logger training-beacon' | crontab -
[analyst@rocky9-lab tmp]$ mkdir -p ~/.config/systemd/user; printf '[Unit]\nDescription=Training helper\n[Service]\nExecStart=/usr/bin/logger training-user-unit\n' > ~/.config/systemd/user/helper.service
[analyst@rocky9-lab tmp]$ rm -f /tmp/.svc-helper; echo "시나리오 준비 완료"
시나리오 준비 완료
[root@rocky9-lab ~]# /root/soc-proc-audit.sh "22 8082" | sed -n '/\[1\]/,$p' | grep -v '^$'
[1] 실행 파일이 삭제됐거나 임시 경로에서 실행 중인 프로세스
[WARN] pid=3535 user=analyst exe=/tmp/.svc-helper (deleted)
[2] 허용 목록(22 8082) 밖의 대기 포트
[WARN] 127.0.0.1:7070 .svc-helper
[3] systemd: 패키지 밖 unit · drop-in · 사용자 unit
[WARN] 미소유 /etc/systemd/system/labapp.service
[WARN] 미소유 /etc/systemd/system/labapp.service.d/50-sandbox.conf
[WARN] 미소유 /etc/systemd/system/labapp.service.d/override.conf
[WARN] 사용자 unit /home/analyst/.config/systemd/user/helper.service
[4] 예약 작업
[WARN] crontab analyst: 1 줄
[5] 실패 · 마스크된 unit
[6] CPU 80% 이상 프로세스
요약: WARN 7건
저장: /var/log/soc-audit/rocky9-lab_20260924T134517Z.txt
[root@rocky9-lab ~]# P=$(ss -tlnpH 'sport = :7070' | grep -oP 'pid=\K[0-9]+'); echo "대상 PID=$P"
대상 PID=3535
[root@rocky9-lab ~]# D=$(/root/collect.sh $P); ls $D | tr '\n' ' '; echo
00_collected_at_utc.txt 01_ps.txt 02_pstree.txt 03_links.txt 04_cmdline.txt 05_environ.txt 06_status.txt 07_maps.txt 08_cgroup.txt 09_fd.txt 10_sockets.txt 11_exe.bin SHA256SUMS
[root@rocky9-lab ~]# cat $D/01_ps.txt; grep -E 'exe|cwd' $D/03_links.txt; tail -1 $D/08_cgroup.txt; cat /proc/$P/sessionid; echo
PID PPID USER STARTED ELAPSED STAT COMMAND
3535 1 analyst Thu Sep 24 13:45:16 2026 00:01 Ss /tmp/.svc-helper -m http.server 7070 --bind 127.0.0.1
lrwxrwxrwx 1 analyst analyst 0 Sep 24 13:45 /proc/3535/cwd -> /tmp
lrwxrwxrwx 1 analyst analyst 0 Sep 24 13:45 /proc/3535/exe -> /tmp/.svc-helper (deleted)
0::/docker/5a46f907edb23397a00c52e8214c9c387f1cf283dd50c13b81f6c01a58252f3b/user.slice/user-1000.slice/session-74.scope
74
[root@rocky9-lab ~]# cp /var/spool/cron/analyst $D/crontab_analyst.txt; cp /home/analyst/.config/systemd/user/helper.service $D/; ls $D | wc -l
15
[root@audit-collector ~]# ausearch -k user_exec -ua analyst -i --start recent 2>/dev/null | grep -E '^type=EXECVE' | grep -vE 'a0=(sed|grep|awk|cut|head|tail|tr|ls|sleep|id|cat)' | sed 's/type=EXECVE msg=audit(//; s/) : argc=[0-9]*//' | tail -8
09/24/26 13:45:17.231:1387 a0=bash a1=/tmp/run_50_2.sh
09/24/26 13:45:17.231:1388 a0=cp a1=/usr/bin/python3 a2=/tmp/.svc-helper
09/24/26 13:45:17.235:1389 a0=setsid a1=/tmp/.svc-helper a2=-m a3=http.server a4=7070 a5=--bind a6=127.0.0.1
09/24/26 13:45:17.235:1390 a0=crontab a1=-
09/24/26 13:45:17.235:1391 a0=/tmp/.svc-helper a1=-m a2=http.server a3=7070 a4=--bind a5=127.0.0.1
09/24/26 13:45:17.239:1392 a0=/usr/sbin/unix_chkpwd a1=analyst a2=chkexpiry
09/24/26 13:45:17.243:1397 a0=mkdir a1=-p a2=/home/analyst/.config/systemd/user
09/24/26 13:45:17.247:1398 a0=rm a1=-f a2=/tmp/.svc-helper
[root@audit-collector ~]# ausearch -k cron_change -i --start recent 2>/dev/null | grep -oE 'item=1 name=/var/spool/cron/[^ ]+' | sort -u
item=1 name=/var/spool/cron/#tmp.rocky9-lab.XXXXO2c4LT
[root@rocky9-lab ~]# journalctl --since "-10min" --no-pager -o short-iso _COMM=sshd-session -g 'Accepted.*analyst' | tail -2 | cut -c1-120
2026-09-24T13:44:16+0000 rocky9-lab sshd-session[2943]: Accepted publickey for analyst from 172.17.0.1 port 55110 ssh2:
2026-09-24T13:45:17+0000 rocky9-lab sshd-session[3496]: Accepted publickey for analyst from 172.17.0.1 port 36530 ssh2:
[root@rocky9-lab ~]# journalctl --since "-10min" --no-pager -o short-iso -t crontab | tail -2
2026-09-24T13:43:02+0000 rocky9-lab crontab[2461]: (root) DELETE (analyst)
2026-09-24T13:45:17+0000 rocky9-lab crontab[3537]: (analyst) REPLACE (analyst)
[root@rocky9-lab ~]# kill $(ss -tlnpH 'sport = :7070' | grep -oP 'pid=\K[0-9]+'); crontab -u analyst -r; rm -f /home/analyst/.config/systemd/user/helper.service; echo "조치 완료"
조치 완료
[root@rocky9-lab ~]# sleep 1; ss -tlnH 'sport = :7070' | wc -l; crontab -u analyst -l 2>&1
0
no crontab for analyst
[root@rocky9-lab ~]# /root/soc-proc-audit.sh "22 8082" | tail -2
요약: WARN 3건
저장: /var/log/soc-audit/rocky9-lab_20260924T134519Z.txt
| 단계 | 관찰 | 의미 |
|---|---|---|
| 0 | 감사 규칙 4개 적재 | 행위 기록이 준비된 상태에서 시나리오가 시작되었다 |
| 1 | pid=3535 ... exe=/tmp/.svc-helper (deleted) | 임시 경로·삭제된 실행 파일 (섹션 1) |
| 1 | 127.0.0.1:7070 .svc-helper | 허용 목록 밖 대기 포트 (섹션 2). 두 경고가 같은 프로세스 를 가리킨다 |
| 1 | 사용자 unit .../helper.service, crontab analyst: 1 줄 | 지속 실행 항목 두 개 |
| 1 | WARN 7건 = 새 경고 4 + 사전 승인된 labapp 3 | 49편 결과와 비교하면 새로 생긴 항목만 추릴 수 있다 |
| 2 | PPID 1, Ss, cwd -> /tmp, session-74.scope, sessionid 74 | setsid로 분리된 세션 리더, analyst의 74번 로그인 세션에서 시작 |
| 2 | 수집 파일 15개 (프로세스 13 + crontab·unit 사본) | 조치 전에 실행 파일 사본까지 확보했다 |
| 3 | audit 13:45:17.231 cp /usr/bin/python3 /tmp/.svc-helper → setsid ... 7070 → crontab - → /tmp/.svc-helper ... → mkdir ... → rm -f /tmp/.svc-helper | 셸 히스토리 없이도 실행 순서와 인자 가 복원되었다. 실행 파일을 지운 행위(rm)까지 남았다 |
| 3 | cron_change name=/var/spool/cron/#tmp.rocky9-lab.XXXX... | crontab 명령은 임시 파일에 쓴 뒤 이름을 바꾸는 방식으로 저장한다. 감시 규칙이 그 쓰기를 잡았다 |
| 3 | journal Accepted publickey for analyst ... port 36530 (13:45:17) | 같은 시각의 로그인 — 행위의 출발점 |
| 3 | crontab[3537]: (analyst) REPLACE (analyst) | crontab 변경의 애플리케이션 로그. 감사 로그와 시각이 일치한다 |
| 4·5 | 포트 7070 없음, no crontab for analyst, WARN 3건 | 지속 항목까지 제거되었고, 남은 경고는 사전 승인된 labapp 항목뿐이다 |
| 주제 | 내용 |
|---|---|
| 한 가지 증거로 끝내지 않기 | 점검 결과(현재 상태), 수집물(휘발성), 감사 로그(과거 행위), journal(인증·애플리케이션)이 서로 같은 이야기 를 할 때 결론이 단단해진다 |
| 지속 항목 | 프로세스만 종료했다면 10분 뒤 crontab이, 다음 로그인 때 사용자 unit이 다시 동작했을 것이다. 제거는 39편 경로 전체를 기준으로 한다 |
| 계정 조치 | 실제 사고라면 해당 계정의 키·비밀번호 교체, 세션 종료, 다른 서버의 같은 계정 활동 확인까지 이어진다 |
| 재발 방지 | /tmp noexec 마운트 검토, 사용자 crontab 허용 제한(cron.allow), 사용자 unit·linger 정책, 감사 규칙 상시 운영 |
■ 개요
대상: rocky9-lab 탐지: 2026-09-24 13:45 UTC (정기 점검 soc-proc-audit.sh) 등급: 훈련
■ 탐지 내용
- 삭제된 임시 경로 실행 파일로 동작하는 프로세스 PID 3535 (/tmp/.svc-helper, analyst)
- 허용 목록 밖 대기 포트 127.0.0.1:7070
- analyst crontab 1줄, 사용자 unit helper.service
■ 증거 (수집자 · UTC · 해시)
/evidence/rocky9-lab_3535_<UTC>/ (15개 파일, SHA256SUMS)
■ 타임라인 (UTC)
13:45:17 analyst SSH 로그인 (publickey, 172.17.0.1)
13:45:17 python3 를 /tmp/.svc-helper 로 복사 → 7070 포트로 실행
13:45:17 crontab 등록 (REPLACE) → 사용자 unit 디렉터리 생성 → 실행 파일 삭제
■ 판단
승인 기록 없음 · 지속 항목 2종 · 실행 파일 삭제 → 조치 대상
■ 조치
프로세스 종료, crontab 삭제, 사용자 unit 삭제 (수집 이후)
■ 검증
포트 7070 없음, crontab 없음, 점검 WARN 7 → 3 (잔여 3건은 승인된 labapp)
■ 재발 방지
/tmp noexec 검토 · cron.allow · 사용자 unit/linger 정책 · 감사 규칙 상시 운영
| 실수 | 결과 | 예방 |
|---|---|---|
| 탐지 즉시 프로세스 종료 | 실행 파일 사본·연결 정보 소실 | 수집 → 조치 |
| 프로세스만 제거 | 예약 작업·unit으로 재실행 | 자동 실행 경로 전체 점검 |
| 출처별 시간대 혼용 | 타임라인 순서 오류 | UTC 통일 |
| 결론만 보고 | 검토·재현 불가 | 근거(명령·결과·해시) 포함 |
| 조치 후 재검증 생략 | 잔존 항목 방치 | 점검 스크립트 재실행 |
[ ] 감사 규칙을 적재한 상태에서 시나리오를 시작했다
[ ] 점검 스크립트로 4개의 새 경고를 탐지했다
[ ] 조치 전에 휘발성 증거와 crontab·unit 사본을 수집했다
[ ] 감사 로그와 journal 로 UTC 타임라인을 만들었다
[ ] 프로세스와 지속 항목을 모두 제거하고 재점검으로 검증했다
[ ] 보고서 템플릿에 탐지·증거·타임라인·판단·조치·검증을 정리했다
50편 동안 프로세스와 서비스를 운영자의 눈 과 관제 요원의 눈 으로 함께 보았다. 흐름을 정리하면 다음과 같다.
Part 1 프로세스 기초 → 프로세스가 무엇이고 어디서 정보를 읽는가
Part 2 시그널·자원·세션 → 프로세스를 멈추고, 제한하고, 떼어 내는 원리
Part 3 systemd와 서비스 → 서비스가 어떻게 정의되고 실행되는가
Part 4 로그·스케줄링·운영 → 무엇이 자동으로 실행되고 어디에 기록되는가
Part 5 보안과 SOC → 이상을 찾고, 증거를 남기고, 판단하고, 보고하는 절차
다음 시리즈는 「리눅스 시스템 기초」의 로드맵에 따라 네트워크 영역을 같은 방식(Rocky·Ubuntu 실측, 관제 관점)으로 다룰 예정이다.