풀이 날짜: 2026-09-16 (사용자 확정). 익스플로잇 성공은 2026-09-16 사용자 확인에 따른다. 아래 실행 결과는 보존된 원본 기록이며 이번 감사에서 새로 실행한 결과가 아니다.
main 밖의 검증을 찾는 문제
Cerberus의 입력 검증은 main의 반환에서 끝나지 않는다. REPORT는 ELF 초기화, 종료 콜백, 종료 배열과 자식 프로세스의 처리까지 분리해 분석한다. 키처럼 보이는 문자열의 출력과 종료 코드만 보면 실패 경로를 정답으로 오인할 수 있다.
제어 흐름과 자료구조
| 부분 | 분석에서 확인한 역할 |
|---|---|
| 초기화·환경 처리 | 실제 상태와 교란용 상태를 구분해 준비 |
| kennel.dat와 내장 사본 | 인증 범위와 키 파생에 쓰이는 자료를 구분 |
| main | 입력을 읽고 종료 처리를 등록 |
| 종료 callback/배열 | 저장 순서와 실제 역순 실행을 구분 |
| 자식의 검증 | 주 VM과 보조 판정을 수행 |
| 출력 | 판정에 따라 입력 또는 고정 문자열을 출력 |
ELF에는 섹션 테이블이 없으므로 도구가 해석한 섹션 정보보다 프로그램 헤더와 실제 바이트 범위를 우선했다. 파일 오프셋·RVA·Ghidra base가 섞이면 같은 코드를 다른 위치로 잘못 읽을 수 있다. 일부 SHA-256 호출의 출력 인자가 디컴파일에서 누락된 부분도 어셈블리 대조로 정정한 기록이다.
주 VM의 성공 조건을 모델링
입력은 끝의 CR/LF 제거 후 34바이트여야 한다. 주 VM은 48단계 바이트 변환을 수행하며, 최종 비교가 모든 34바이트를 검사하는 것은 아니다. REPORT는 실제 비교 위치가 8개라고 확인한다.
x: 정규화된 34바이트 입력
V(x): 주 VM 변환 결과
T: 저장된 목표 배열
I: 실제 비교하는 위치 집합, |I| = 8
주 판정: 길이 조건 AND 모든 i∈I에서 V(x)[i] = T[i]
이 모델은 입력을 변환한 결과와 목표를 비교한다. 목표 배열에 정방향 변환을 다시 적용해 입력이라고 부르는 것은 같은 연산이 아니다. 부분 비교를 전체 배열 일치로 잘못 요약해서도 안 된다. 정확한 정수 폭에서 절단하는 시점과 byte 순서는 모델의 의미에 포함된다.
보조 후보와 실패 출력을 분리
보조 경로에는 여러 중간 후보와 종료 후보의 비교가 따로 있다. 어느 로컬 경로가 입력을 출력했다고 해서 공식 원격에서도 수락되는지는 배포물만으로 알 수 없다. 두 판정이 실패해도 고정 문자열이 나올 수 있으므로 '무언가 출력됨'은 성공 조건이 아니다.
정적 문서의 확정 수준도 나눈다. 원본 바이트에서 확인한 제어 흐름·비교 조건과, 정상 환경을 가정해 계산한 상태·키 자료는 다르다. 조건부 정적 계산을 실제 대상 실행 관찰로 바꾸지 않는다.
후속 결과
REPORT 1~10절은 정적 분석 당시의 범위이며, 11절에는 사용자가 제공한 원격 제출 수락과 flag 반환 기록이 추가되어 있다. 현재의 정확한 결론은 '사용자 제공 원격 수락 기록이 존재한다'다. 작성자가 그 절을 갱신하면서 새로 접속한 것도, 이번 감사에서 재검증한 것도 아니다.
실제 제출 키·flag는 본문에 싣지 않는다. 해당 키가 수락됐다는 근거를 원격 검증기의 구현이나 정답의 유일성까지 입증한 것으로 확대하지 않는다. 초기 실패 가설과 후속 수락 근거는 함께 보존한다.
근거 자료
sources/Cerberus_astra/analysis/REPORT.ko.mdsources/Cerberus_astra/analysis/constants.jsonsources/Cerberus_astra/GATES.md
원본 문서·solver·검증 로그는 전달 staging에 보존되어 있다. 이 경로들은 provenance이며 CMS의 다운로드 첨부 링크가 아니다.