시스템 보안 · 취약점 › I. 지속성 · 재침투 징후 · 39/50편 (전체 439/450)
학습 단계: SOC 탐지 연계
실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」이며, IP·계정·호스트명은 가상의 값입니다.
지속성 탐지의 결론은 결국 "이 서버에 자동 실행·접근 장치가 몇 개, 무엇이 있는가"라는 목록입니다. 이 목록을 지속성 인벤토리라고 하며, 사고 대응 초기에 반드시 만들어야 하는 산출물입니다.
지속성 인벤토리 구조
host | 분류 | 위치 | 항목 | 실행 대상 | 소유(패키지) | 해시 | 수정 시각
─────┼──────┼──────┼──────┼───────────┼─────────────┼──────┼─────────
web01| 스케줄 | /var/spool/cron/apache | */5 curl|bash | - | 미소유 | ... | 10-08 03:00
web01| 서비스 | dbus-helper.service | ExecStart | /usr/lib/.x/agent | 미소유 | ... | 10-08 03:02
↓
정렬 기준: 미소유 → 수정 시각(침투 이후) → 실행 대상 경로
핵심: 인벤토리는 "근절 체크리스트"이자 "근절 검증 기준"
인벤토리를 근절 전후로 두 번 만들어 비교하면, 근절이 실제로 무엇을 지웠고 무엇이 남았는지 객관적으로 확인할 수 있습니다.
| 분류 | 수집 대상 |
|---|---|
| 계정·인증 | passwd(UID 0·로그인 셸)·키 지문·sshd -T·PAM·sudoers |
| 스케줄 | crontab·cron.d·atq·timer |
| 서비스·부팅 | enabled 유닛·drop-in·rc.local·init.d·udev |
| 실행 환경 | profile.d·bashrc·ld.so.preload·modules-load.d |
| 통로 | LISTEN·외부 연결·웹 루트 신규 스크립트 |
# 지속성 인벤토리 스크립트 골격 (분석 방법, 읽기 전용)
OUT=/root/ir/persist-inventory-$(hostname)-$(date +%F_%H%M).tsv
row(){ f="$3"; own=$(rpm -qf "$f" 2>/dev/null || dpkg -S "$f" 2>/dev/null | cut -d: -f1 || echo "-")
[ -z "$own" ] && own="미소유"; h=$(sha256sum "$f" 2>/dev/null | cut -c1-16)
m=$(stat -c %y "$f" 2>/dev/null | cut -c1-16); printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$1" "$2" "$f" "$own" "$h" "$m"; }
{ for f in /etc/cron.d/* /var/spool/cron/*; do row 스케줄 cron "$f"; done
for f in /etc/systemd/system/*.service /etc/systemd/system/*.timer /etc/systemd/system/*.d/*.conf; do row 서비스 systemd "$f"; done
for f in /etc/rc.d/rc.local /etc/udev/rules.d/* /etc/ld.so.preload /etc/modules-load.d/*; do [ -e "$f" ] && row 부팅 boot "$f"; done
for f in /etc/profile.d/* /root/.bashrc /home/*/.bashrc; do row 셸 shell "$f"; done
for f in /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys; do [ -e "$f" ] && row 인증 sshkey "$f"; done
} | sort -t$'\t' -k6 -r | sudo tee "$OUT" >/dev/null
grep -P '\t미소유\t' "$OUT"
미소유 항목: 0
수정 시각 상위: 패키지 업데이트 시각(10-02 10:12)과 일치
미소유 항목이 없거나 승인 기록이 있고, 최근 수정 항목이 패키지 업데이트·배포 시각으로 설명되는 상태가 정상입니다.
스케줄 cron /var/spool/cron/apache 미소유 3f9a.. 2026-10-08 03:00
서비스 systemd /etc/systemd/system/dbus-helper.service 미소유 a12c.. 2026-10-08 03:02
부팅 boot /etc/ld.so.preload 미소유 77be.. 2026-10-08 03:04
셸 shell /etc/profile.d/sys-locale.sh 미소유 c0d1.. 2026-10-08 03:01
인벤토리 활용 흐름입니다(가상의 예시).
[수집] 인벤토리 스크립트(읽기 전용) 실행
↓
[정렬] 미소유 → 수정 시각 → 실행 대상
↓
[판정] 각 항목 I08 판정 기준 적용
↓
[근절] 판정된 항목 = 체크리스트
↓
[검증] 근절 후 재수집 → 전후 diff → 남은 항목 0 확인
| 시점 | 목적 |
|---|---|
| 대응 초기 | 범위 파악 |
| 근절 직후 | 제거 확인 |
| 감시 기간 종료 | 재생성 없음 확인 |
인벤토리 스크립트는 읽기 전용이어야 하며, 증거 훼손을 막기 위해 결과는 원격(SIEM·증거 서버)으로도 보내 보관합니다.
<!-- 실습 예시 룰: 적용 전 wazuh-logtest 및 테스트 환경 검증 필요 -->
<group name="local,syssec_i,persistence,">
<rule id="108380" level="10">
<decoded_as>syslog</decoded_as>
<program_name>persist-inventory</program_name>
<match>미소유</match>
<description>지속성 인벤토리 점검에서 패키지 미소유 지속성 항목 발견</description>
<mitre><id>TA0003</id></mitre>
</rule>
</group>
인벤토리 스크립트가 미소유 항목을 logger -t persist-inventory로 남기면 Wazuh가 수집해 경보합니다. 이 룰은 auditd가 아닌 syslog 기반이므로 상위 auditd 룰(108000)에 묶지 않고 독립 룰로 작성했습니다.
| 요소 | 내용 |
|---|---|
| 형태 | 호스트·분류·위치·소유·해시·시각 |
| 정렬 | 미소유 → 수정 시각 |
| 용도 | 범위 파악·체크리스트·검증 |
| 원칙 | 읽기 전용·원격 보관 |
| 면접 포인트 | "지속성 대응의 산출물은 인벤토리 — 근절 전후 diff가 근절의 증명" |
다음 편 440. 지속성·재침투 — 지속성 기준선 diff 자동화와 정기 점검 에서는 I04 기준선과 I39 인벤토리를 systemd timer·Wazuh 명령 모니터링으로 자동 비교해 신규 지속성을 매일 찾아내는 운영 방법을 다룹니다.
이전 편: 438. 지속성·재침투 — 백도어·재침투 경로 종합 분석
📚 시리즈 전체 보기: 시스템 보안 · 취약점