서비스 · 프로세스 관리 50 / 50 · Part 5. 보안과 SOC
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정 analyst)

1. 들어가며

「서비스 · 프로세스 관리」 시리즈의 마지막 글이다. 50편에 걸쳐 프로세스의 생성과 상태, 시그널과 자원, systemd 서비스와 예약 작업, 로그와 감사, 그리고 관제 판단 기준과 점검 도구를 다뤘다. 이번 글에서는 이 모든 것을 하나의 대응 절차 로 연결한다.

훈련용 시나리오는 모두 무해한 항목으로 구성했다. analyst 계정이 임시 경로의 python 복사본으로 로컬 웹 서버를 띄우고, 실행 파일을 지우고, crontab과 사용자 unit을 등록 한 상황이다. 이를 정기 점검으로 탐지 하고, 조치 전에 증거를 수집 하고, 감사 로그와 journal로 타임라인 을 만들고, 격리·제거 한 뒤 재검증 하고, 마지막으로 보고서 로 정리한다.


2. 핵심 개념

2-1. 대응 절차와 이 시리즈의 도구

단계목적사용 도구편
0 준비감사 규칙, 기준선, 점검 스크립트auditd, baseline, soc-proc-audit.sh42·48·49
1 탐지이상 항목 식별점검 스크립트, 판단 기준41·49
2 증거 수집휘발성 정보 보존collect.sh, crontab·unit 사본43
3 타임라인언제 누가 무엇을ausearch, journalctl31·48
4 격리·제거동작 중지, 지속 항목 제거kill, crontab -r, unit 삭제12·13·45·46
5 검증제거 확인ss, crontab -l, 점검 재실행44·49
6 보고사실·근거·조치·개선보고서 템플릿40·50

2-2. 원칙

원칙이유
수집 → 조치조치하는 순간 휘발성 증거가 사라진다
모든 지속 항목 제거프로세스만 끄면 crontab·unit으로 다시 실행된다 (39편)
시각은 UTC로 통일여러 출처(audit, journal, 방화벽)를 합치기 위해
판단 근거 기록보고서는 "무엇을 봤고 왜 그렇게 판단했는가"를 담아야 한다

3. 동작 원리

종합 실습 흐름 — 시리즈의 도구로 완성하는 대응 절차

[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 항목만)

4. 명령어 실습

# 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

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 (auditd 수집 노드) · root@audit-collector — 0단계: 감사 규칙 적재 (48편 규칙)

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — 훈련 시나리오 준비 (무해한 항목: 로컬 웹 서버 · 로그 한 줄 기록)

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — 1단계 탐지: 정기 점검 스크립트

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — 2단계 증거 수집: 조치 전 휘발성 정보

실제 실행 결과 — Rocky Linux 9.8 (auditd 수집 노드) · root@audit-collector — 3단계 타임라인: 감사 로그 (auid=analyst 실행 기록)

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — 3단계 타임라인: 인증·cron 로그

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — 4단계 격리·제거 → 5단계 검증

텍스트 원본(실제 출력):

[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

6. 결과 해석

단계관찰의미
0감사 규칙 4개 적재행위 기록이 준비된 상태에서 시나리오가 시작되었다
1pid=3535 ... exe=/tmp/.svc-helper (deleted)임시 경로·삭제된 실행 파일 (섹션 1)
1127.0.0.1:7070 .svc-helper허용 목록 밖 대기 포트 (섹션 2). 두 경고가 같은 프로세스 를 가리킨다
1사용자 unit .../helper.service, crontab analyst: 1 줄지속 실행 항목 두 개
1WARN 7건 = 새 경고 4 + 사전 승인된 labapp 349편 결과와 비교하면 새로 생긴 항목만 추릴 수 있다
2PPID 1, Ss, cwd -> /tmp, session-74.scope, sessionid 74setsid로 분리된 세션 리더, analyst의 74번 로그인 세션에서 시작
2수집 파일 15개 (프로세스 13 + crontab·unit 사본)조치 전에 실행 파일 사본까지 확보했다
3audit 13:45:17.231 cp /usr/bin/python3 /tmp/.svc-helper → setsid ... 7070 → crontab - → /tmp/.svc-helper ... → mkdir ... → rm -f /tmp/.svc-helper셸 히스토리 없이도 실행 순서와 인자 가 복원되었다. 실행 파일을 지운 행위(rm)까지 남았다
3cron_change name=/var/spool/cron/#tmp.rocky9-lab.XXXX...crontab 명령은 임시 파일에 쓴 뒤 이름을 바꾸는 방식으로 저장한다. 감시 규칙이 그 쓰기를 잡았다
3journal Accepted publickey for analyst ... port 36530 (13:45:17)같은 시각의 로그인 — 행위의 출발점
3crontab[3537]: (analyst) REPLACE (analyst)crontab 변경의 애플리케이션 로그. 감사 로그와 시각이 일치한다
4·5포트 7070 없음, no crontab for analyst, WARN 3건지속 항목까지 제거되었고, 남은 경고는 사전 승인된 labapp 항목뿐이다

7. 보안 관점

주제내용
한 가지 증거로 끝내지 않기점검 결과(현재 상태), 수집물(휘발성), 감사 로그(과거 행위), journal(인증·애플리케이션)이 서로 같은 이야기 를 할 때 결론이 단단해진다
지속 항목프로세스만 종료했다면 10분 뒤 crontab이, 다음 로그인 때 사용자 unit이 다시 동작했을 것이다. 제거는 39편 경로 전체를 기준으로 한다
계정 조치실제 사고라면 해당 계정의 키·비밀번호 교체, 세션 종료, 다른 서버의 같은 계정 활동 확인까지 이어진다
재발 방지/tmp noexec 마운트 검토, 사용자 crontab 허용 제한(cron.allow), 사용자 unit·linger 정책, 감사 규칙 상시 운영

8. 보안관제 관점 — 보고서 템플릿

■ 개요
  대상: 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 정책 · 감사 규칙 상시 운영

9. 실무에서 자주 발생하는 실수

실수결과예방
탐지 즉시 프로세스 종료실행 파일 사본·연결 정보 소실수집 → 조치
프로세스만 제거예약 작업·unit으로 재실행자동 실행 경로 전체 점검
출처별 시간대 혼용타임라인 순서 오류UTC 통일
결론만 보고검토·재현 불가근거(명령·결과·해시) 포함
조치 후 재검증 생략잔존 항목 방치점검 스크립트 재실행

10. 실습 체크리스트

[ ] 감사 규칙을 적재한 상태에서 시나리오를 시작했다
[ ] 점검 스크립트로 4개의 새 경고를 탐지했다
[ ] 조치 전에 휘발성 증거와 crontab·unit 사본을 수집했다
[ ] 감사 로그와 journal 로 UTC 타임라인을 만들었다
[ ] 프로세스와 지속 항목을 모두 제거하고 재점검으로 검증했다
[ ] 보고서 템플릿에 탐지·증거·타임라인·판단·조치·검증을 정리했다

11. 핵심 정리

  • 대응 절차는 준비 → 탐지 → 증거 수집 → 타임라인 → 격리·제거 → 검증 → 보고 다.
  • 현재 상태(점검), 휘발성 정보(/proc), 과거 행위(audit), 인증·애플리케이션 로그(journal)를 교차 확인한다.
  • 조치는 수집 이후에, 제거는 프로세스와 모든 지속 항목을 대상으로 한다.
  • auid·ses와 UTC 시각이 서로 다른 출처를 하나의 타임라인으로 묶는다.
  • 보고서에는 결론뿐 아니라 근거·조치·검증·재발 방지를 담는다.

12. 시리즈를 마치며

50편 동안 프로세스와 서비스를 운영자의 눈 과 관제 요원의 눈 으로 함께 보았다. 흐름을 정리하면 다음과 같다.

Part 1 프로세스 기초        → 프로세스가 무엇이고 어디서 정보를 읽는가
Part 2 시그널·자원·세션      → 프로세스를 멈추고, 제한하고, 떼어 내는 원리
Part 3 systemd와 서비스      → 서비스가 어떻게 정의되고 실행되는가
Part 4 로그·스케줄링·운영    → 무엇이 자동으로 실행되고 어디에 기록되는가
Part 5 보안과 SOC           → 이상을 찾고, 증거를 남기고, 판단하고, 보고하는 절차

다음 시리즈는 「리눅스 시스템 기초」의 로드맵에 따라 네트워크 영역을 같은 방식(Rocky·Ubuntu 실측, 관제 관점)으로 다룰 예정이다.


참고 자료


시리즈 이동

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

0개의 댓글