428. 지속성·재침투 — 스케줄·서비스·부팅 지속성 종합 분석

changseop lee·2026년 10월 9일

시스템 보안 · 취약점

목록 보기
428/450

시스템 보안 · 취약점 › I. 지속성 · 재침투 징후 · 28/50편 (전체 428/450)
학습 단계: 스케줄·서비스·부팅 지속성 탐지
실습 표기: 이 글의 명령어·출력·로그는 로컬 VMware 테스트 VM(Rocky Linux 9 / Ubuntu 22.04) 기준의 「실습 예시」이며, IP·계정·호스트명은 가상의 값입니다.

선행 학습

1. 개념

스케줄·서비스·부팅 지속성은 "언제 다시 실행되는가"의 문제입니다. 아홉 가지 기법을 트리거별로 묶으면 점검 순서와 제거 순서가 명확해집니다.

트리거별 지속성 지도
 [시간]   cron(I19) · at(I20) · systemd timer(I22)
 [부팅]   systemd service(I21) · drop-in/generator(I23) · rc.local/init(I24)
 [로그인] 셸 초기화 파일(I25)
 [이벤트] udev 규칙(I26)
 [모든 실행] ld.so.preload(I27)
   ↓
 재생성 관계: 시간 트리거가 부팅·로그인 지속성을 다시 설치하는 구조가 흔함

핵심: 제거 순서는 "재생성 장치(시간 트리거) → 나머지"

실제 사고에서는 cron이 systemd 유닛을 다시 만들고, 유닛이 ld.so.preload를 복구하는 식의 상호 재생성 구조가 자주 보입니다.

2. 왜 중요한가

  • 트리거 하나만 점검하면 나머지 트리거로 지속성이 남습니다.
  • 재생성 관계를 모르고 제거하면 제거한 항목이 다시 생깁니다.
  • 트리거별 감사 키를 통일하면 SIEM에서 한 번에 조회할 수 있습니다.

3. 핵심 명령어 / 설정

트리거기법감사 키룰 ID
시간cron·atpersist_cron108180·108190
시간·부팅systemd service·timerpersist_svc108200·108210
부팅drop-in·rc.localpersist_svc·persist_boot108220·108230
로그인셸 초기화persist_shell108240
이벤트udevpersist_boot108250
모든 실행ld.so.preloadpersist_preload108260

4. 실습 (실습 예시)

# 트리거별 지속성 일괄 점검 (분석 방법)
echo "[시간]";   sudo ls -la /etc/cron.d /var/spool/cron 2>/dev/null; sudo atq; systemctl list-timers --all --no-legend | wc -l
echo "[부팅]";   systemd-delta --type=extended --no-pager | wc -l; ls -l /etc/rc.d/rc.local 2>/dev/null
echo "[로그인]"; sudo grep -lE 'nohup|alias sudo|/dev/tcp' /etc/profile.d/* /root/.bashrc /home/*/.bashrc 2>/dev/null
echo "[이벤트]"; sudo grep -rl 'RUN+=' /etc/udev/rules.d/ 2>/dev/null
echo "[실행]";   ls /etc/ld.so.preload 2>/dev/null
echo "[변경 이벤트 집계]"; sudo ausearch -k persist_cron -k persist_svc -k persist_boot -k persist_shell -k persist_preload -ts this-week 2>/dev/null | grep -c 'type=SYSCALL'

5. 정상 상태

[시간] 패키지 cron만, atq 비어 있음, timer 9개(패키지)
[부팅] EXTENDED 1(승인), rc.local 실행 권한 없음
[로그인]/[이벤트]/[실행] 해당 없음

모든 트리거 위치가 기준선과 일치하고, 이번 주 변경 이벤트가 승인된 작업으로 설명되는 상태가 정상입니다.

6. 이상 상태

[시간] apache crontab(curl|bash), update-check.timer(미소유)
[부팅] dbus-helper.service, sshd.service.d/override.conf
[로그인] /etc/profile.d/sys-locale.sh
[실행] /etc/ld.so.preload 존재
  • 다섯 트리거 모두에 지속성 → 다중·상호 재생성 구조
  • cron이 5분마다 스크립트 재설치 → 먼저 제거하지 않으면 복구됨
  • preload까지 존재 → 호스트 도구 결과 신뢰 불가

7. 로그 분석 (분석 방법)

트리거별 종합 분석·근절 흐름입니다(가상의 예시).

[전수 점검] 시간 → 부팅 → 로그인 → 이벤트 → 실행
   ↓
[재생성 관계] 각 항목이 무엇을 다시 설치하는지(스크립트 내용) 확인
   ↓
[근절 순서]
  ① 시간 트리거(cron·at·timer) 중지
  ② 부팅·이벤트 트리거(유닛·drop-in·rc.local·udev) 비활성화
  ③ 로그인·실행 트리거(셸 파일·preload) 제거
  ④ 공통 바이너리 격리 → 재부팅 후 재점검
단계이유
시간 먼저재설치 차단
재부팅 후 재점검부팅 트리거 잔존 확인
공통 바이너리여러 트리거가 같은 파일 실행

여러 트리거가 같은 바이너리(/usr/lib/.x/agent)를 실행하는 경우가 많으므로, 바이너리 해시로 다른 위치를 역검색하면 놓친 트리거를 찾을 수 있습니다.

8. SOC 관제 포인트

  • 트리거별 감사 키를 persist_ 접두어로 통일해 한 번에 조회합니다.
  • 하나의 바이너리를 여러 트리거가 참조하면 자동으로 인시던트를 묶습니다.
  • 근절 후 재부팅 재점검을 표준 절차로 둡니다.

9. 탐지 규칙

<!-- 실습 예시 룰: 적용 전 wazuh-logtest 및 테스트 환경 검증 필요 -->
<group name="local,syssec_i,persistence,">
  <rule id="108270" level="14">
    <if_matched_group>persistence</if_matched_group>
    <same_field>agent.id</same_field>
    <different_field>audit.key</different_field>
    <timeframe>3600</timeframe>
    <description>동일 호스트 1시간 내 서로 다른 트리거의 지속성 이벤트(다중 지속성)</description>
    <mitre><id>TA0003</id></mitre>
  </rule>
</group>

different_field로 감사 키가 서로 다른 지속성 이벤트가 같은 호스트에서 이어지면 다중 지속성으로 판단합니다. different_field 지원 여부는 Wazuh 버전별로 확인합니다.

10. 대응 방법

  1. 초기 확인 — 다섯 트리거 위치를 모두 점검해 목록화합니다.
  2. 범위 확인 — 항목 간 재생성 관계와 공통 바이너리를 확인합니다.
  3. 증거 확보 — 트리거별 파일 사본과 감사 기록을 보존합니다.
  4. 차단/조치 — 시간 트리거부터 순서대로 제거하고 재부팅 후 재점검합니다.
  5. 재발 방지 — 트리거별 감사 키·룰과 점검 절차를 표준화합니다.

11. 핵심 정리

트리거기법
시간cron·at·timer
부팅service·drop-in·rc.local
로그인셸 초기화
이벤트·실행udev·preload
면접 포인트"지속성은 서로를 되살린다 — 시간 트리거부터 끊고 재부팅 후 다시 본다"

12. 다음 편 예고

다음 편 429. 지속성·재침투 — 리버스 셸 재접속 시도 탐지 에서는 지속성이 주기적으로 띄우는 리버스 셸 재접속 시도를 connect 감사·방화벽 차단 로그·프로세스 계보로 탐지하는 방법을 다룹니다.


이전 편: 427. 지속성·재침투 — ld.so.preload·동적 라이브러리 지속성 탐지
📚 시리즈 전체 보기: 시스템 보안 · 취약점

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

0개의 댓글