Cron Ran curl at Three in the Morning
Reconstruct one hour of that night
한국어 원문으로 표시합니다.
목표
한 사건의 자료 네 종류를 받아 조사를 한 바퀴 돕니다. 세고, 집고, 보존하고, 타임라인으로 엮고, 축을 잡아 클러스터까지 따라가고, 조치 순서를 정하고, 사후 분석 보고서를 씁니다.
왜 중요한가
알림이 울린 뒤 30분 동안 무엇을 하느냐가 그 사건의 결말을 정합니다. 급한 마음에 파드를 지우고 노드를 재부팅하면 침입 경로가 함께 사라지고, 반대로 증거를 완벽하게 모으는 동안 유출된 자격증명으로 다른 네임스페이스가 털립니다.
그래서 대응은 "무엇이 옳은가" 가 아니라 "무엇을 먼저 하는가" 의 문제이고, 그 순서는 사건이 나기 전에 정해 두어야 합니다. 휘발성이 큰 것부터 모으고, 원본은 건드리지 않고, 시각은 UTC 로 통일하고, 자격증명 폐기는 미루지 않는다 — 이런 규칙들은 전부 누군가 한 번씩 잃어 보고 나서 생겼습니다.
이 실습의 자료는 합성한 것입니다. 대신 형식은 실제와 같습니다. Falco 의 JSON
출력, 커널 감사의 원본 레코드, journalctl -o json 의 필드, 쿠버네티스 감사
이벤트를 그대로 씁니다.
단계
- 자료 네 종의 줄 수를 세어
/root/ir/01-sources.tsv에 저장하세요. - 가장 이른 Falco 알림의 규칙 이름·시각·PID 를
/root/ir/02-first.json에 저장하세요. - 자료 네 종을
/root/ir/evidence/로 복사하고manifest.sha256을 남기세요. - 네 출처를 하나의 시간축에 올린 타임라인을
/root/ir/04-timeline.tsv에 8행 이상 쓰세요. - 축 네 개(
pid·cron-file·c2-host·k8s-identity)를/root/ir/05-pivot.tsv에 값과 근거로 적으세요. - 조치 여섯 가지의 시점과 근거를
/root/ir/06-containment.tsv에 적으세요. - 훔친 신원이 클러스터에서 한 일을
/root/ir/07-k8s.tsv에 적으세요. - 사후 분석 보고서를
/root/ir/08-postmortem.md에 쓰세요.
참고
- 자료는
/opt/lab/fixtures/detection/incident/아래에 있습니다:falco.jsonl,audit.log,cron.jsonl,kube-audit.jsonl. 그리고 로그가 아닌 참고 자료로host-facts.json이 있습니다. - 4단계의 출처 이름은
falco·auditd·cron·kube-audit넷 중 하나로 적습니다. 시각은2026-03-14T03:00:04Z꼴입니다. - 6단계의 조치 이름은
메모리 수집·네트워크 차단·프로세스 종료·예약 작업 제거·자격증명 폐기·노드 재설치여섯이고, 시점은지금·나중·안함중 하나입니다. - 7단계는 거부된(403) 요청도 행위입니다. 빼지 마세요.
- 흔한 실수: 커널 감사 원본의 시각은 에폭 초입니다.
date -u -d @<초>로 바꿔 보세요. - 흔한 실수: 원본 파일을 편집기로 열어 고치는 것. 원본은 읽기 전용으로 다루고 사본만 봅니다.
무엇이 있는지 센다
/opt/lab/fixtures/detection/incident/ 의 falco.jsonl·audit.log·cron.jsonl·kube-audit.jsonl 네 파일의 줄 수를 세어 /root/ir/01-sources.tsv 에 한 줄씩 파일이름<탭>줄수 로 저장하세요.
wc -l 이면 됩니다. 조사에서 이 단계를 건너뛰면 나중에 '그 로그도 있었네' 가 나옵니다.
최초 알림을 집는다
falco.jsonl 에서 가장 이른 알림을 찾아 규칙 이름·시각·PID 를 /root/ir/02-first.json 에 {"rule": …, "time": …, "pid": …} 로 저장하세요.
jq -s 'min_by(.time)' 로 가장 이른 것을 고를 수 있습니다. PID 는 output_fields 안에 있습니다. 시각은 파일에 적힌 값을 그대로 씁니다.
원본을 건드리지 않고 보존한다
자료 네 종을 /root/ir/evidence/ 로 복사하고, 그 디렉터리에서 sha256sum -c 로 검증되는 /root/ir/evidence/manifest.sha256 을 만드세요.
sha256sum <파일들> > manifest.sha256 은 상대 경로로 적습니다. 검증은 그 디렉터리 안에서 sha256sum -c manifest.sha256 으로 합니다.
하나의 시간축에 올린다
네 출처의 기록을 /root/ir/04-timeline.tsv 에 8행 이상, 시각<탭>출처<탭>행위자<탭>무슨 일 네 칸으로 시간 오름차순으로 쓰세요. 네 출처가 모두 한 번 이상 나와야 합니다.
출처 이름은 falco·auditd·cron·kube-audit 로 통일합니다. 커널 감사 원본의 에폭 초는 date -u -d @<초> +%Y-%m-%dT%H:%M:%SZ 로 바꿉니다. journald 의 __REALTIME_TIMESTAMP 는 마이크로초입니다.
축을 잡고 건너뛴다
/root/ir/05-pivot.tsv 에 네 줄을 축<탭>값<탭>근거 로 쓰세요. 축 이름은 pid·cron-file·c2-host·k8s-identity 이고, 근거에는 어느 파일의 무엇을 보고 그렇게 판단했는지를 10자 이상 적습니다.
pid 는 임시 디렉터리에서 실행된 프로세스의 것입니다. cron-file 은 그날 밤 새로 생긴 예약 작업이고 커널 감사 원본의 PATH 레코드에 있습니다. k8s-identity 는 감사 로그의 user.username 입니다.
무엇을 먼저 하는가
조치 여섯 가지를 /root/ir/06-containment.tsv 에 조치<탭>시점<탭>근거 로 적으세요. 시점은 지금·나중·안함 중 하나이고 근거는 20자 이상입니다.
휘발성이 큰 것부터 모읍니다. 그리고 노드를 꺼도 유효한 것이 하나 있습니다 — 그것은 미룰 수 없습니다.
훔친 신원이 클러스터에서 한 일
kube-audit.jsonl 에서 system:node:edge-07 이 한 요청을 전부 찾아 /root/ir/07-k8s.tsv 에 verb<탭>리소스<탭>네임스페이스<탭>이름<탭>응답코드 다섯 칸으로 쓰세요. 네임스페이스나 이름이 없으면 - 로 적습니다.
jq -r 'select(.user.username == …)' 로 걸러 냅니다. 거부된 요청(403)도 행위입니다 — 무엇을 시도했는지가 의도를 말해 줍니다.
다음 주를 바꾸는 글
/root/ir/08-postmortem.md 에 ## 요약·## 타임라인·## 영향·## 원인·## 탐지 공백·## 재발 방지 여섯 절을 쓰세요. 본문에는 명령제어 주소, 자격증명이 쓰인 네임스페이스, 붙잡힌 지속화 수단의 경로가 나와야 합니다.
## 탐지 공백 이 이 보고서에서 가장 중요한 절입니다. 규칙이 없었는지, 알림이 아무도 안 보는 곳으로 갔는지, 로그 자체가 없었는지는 전혀 다른 처방으로 이어집니다. 사람 이름으로 끝나는 보고서는 다음 주에 같은 사고를 부릅니다.