본문으로 건너뛰기

21. CTF에서 로그 누출로 플래그 뽑는 법

로그 누출 문제의 핵심은 파일 경로를 맞히는 요령이 아니다. 애플리케이션이 어떤 입력을 어떤 보존 기간으로 기록하고, 그 기록을 누가 읽을 수 있는지 데이터 흐름을 복원하는 일이다. 아래 절차는 문제에서 명시된 컨테이너와 자기 소유 실습 환경에 한정한다.

기록 지점을 먼저 증명하기

서버가 반환하는 오류만 보고 로그가 있다고 단정하지 않는다. 로컬 실습에서는 요청에 고유한 마커를 넣고 애플리케이션 로그, 컨테이너 stdout, 프록시 로그를 각각 확인한다. User-Agent나 요청 ID처럼 원래 기록되는 필드에 LAB-MARKER-123을 넣으면 어떤 레이어가 값을 보존하는지 구별할 수 있다. 인증 헤더나 쿠키처럼 비밀일 수 있는 값은 실험에 사용하지 말고 가짜 토큰을 쓴다.

# 자기 소유 컨테이너에서만
podman logs --since 10m lab-web | grep 'LAB-MARKER-123'
# 로컬 파일 로그를 조사할 때
grep -R --line-number --fixed-strings 'LAB-MARKER-123' ./var/log

스택 트레이스는 디버그 모드에서 경로와 환경을 노출할 수 있지만, 모든 오류가 로그 파일에 남는 것은 아니다. 상태 코드, 상관관계 ID, 타임스탬프를 함께 기록해 응답과 기록을 연결한다.

읽기 경로와 경계를 확인하기

CTF에서는 의도적으로 제공된 로그 뷰어, 파일 읽기 기능, 백업 아카이브가 관문이 된다. 파일 경로를 조작하는 테스트는 서버의 허용 범위를 벗어나지 않도록 고정된 샘플 디렉터리와 무해한 파일로 시작한다. 성공 여부는 임의 파일을 읽었다는 사실이 아니라, 문제의 범위에서 기대한 마커가 정확히 반환되는지로 판단한다. 페이징 API는 limit, 커서, 정렬 기준이 실제로 서버에서 검증되는지도 관찰한다.

로그 포맷 자체도 단서다. JSON 로그라면 필드 경계와 이스케이프를, 줄 기반 로그라면 개행과 구분자 처리를 확인한다. 사용자 입력이 로그에 들어갈 때 개행으로 가짜 이벤트를 만들 수 있는 로그 인젝션은 운영 분석을 망가뜨리므로, 방어 측면에서는 구조화 로깅과 필드 정규화를 사용한다.

방어와 판단 기준

민감한 헤더·본문·토큰은 기본적으로 기록하지 말고, 디버그 로깅은 운영에서 끈다. 로그 디렉터리는 애플리케이션이 읽을 필요가 없도록 권한을 분리하고, 로그 뷰어는 allowlist 기반 식별자와 인증·감사를 적용한다. 보존 기간과 접근 기록도 로그 자체만큼 중요하다. 좋은 분석은 “플래그가 있었다”에서 끝나지 않고, 어떤 입력이 어느 경로를 거쳐 노출되었으며 어떤 최소 변경으로 차단되는지 설명한다.