풀이 날짜: 2026-09-16 (사용자 확정). 익스플로잇 성공은 2026-09-16 사용자 확인에 따른다. 아래 실행 결과는 보존된 원본 기록이며 이번 감사에서 새로 실행한 결과가 아니다.
PHP 함수 이름과 runtime 정의의 경계
Executable의 첫 경계는 입력으로 선택한 함수를 호출한다는 점이다. index.php에서 관련 부분을 발췌하면 다음과 같다. 중간의 함수 정의·비밀번호 비교는 생략했다.
$name = $_REQUEST['name'] ?? 'leakme';
$name();
이 호출의 허용 대상이 고정된 함수 목록으로 제한되어 있지 않다. 비밀번호 조건 안에서 정의되는 함수가 있으므로 정적 코드의 함수 선언 위치와 PHP 런타임의 함수 식별·호출 의미를 구분해야 한다.
초기 결론을 왜 정정했는가
ASTRA_ANALYSIS 상단의 후속 정정은 '고정 SHA-256 preimage가 반드시 필요하다', '정상 이름으로 함수가 정의되는 경로만 가능하다'는 두 결론을 폐기한다. 후속 런타임 관찰에서 PHP 7.4의 조건부 함수 runtime-definition 의미가 초기 모델과 달랐기 때문이다.
따라서 처음 정적 문서에 solver나 우회가 없었다는 문장을 최종 상태로 복사하면 안 된다. 반면 실제 동적 호출에 사용한 식별자와 입력을 싣지 않고도, 정적 이름 모델이 충분하지 않았다는 정정의 이유는 코드 경계와 함께 설명할 수 있다.
서버 조건과 브라우저 조건은 별개
| 구성 | 실제 역할 |
|---|---|
| index.php | 사용자 입력에 따른 callable 선택 |
| secret 파일 | 별도 비밀 비교에 사용 |
| flag.php | loopback 요청 여부와 secret 일치를 검사 |
| 봇 | 로컬 브라우저에서 페이지 방문 |
| 클라이언트 페이지 | DOMPurify 결과를 DOM에 삽입 |
브라우저 쪽의 source는 다음 sink를 포함한다.
document.getElementById('result').innerHTML = DOMPurify.sanitize(xss);
정화 함수의 호출이 있다는 사실과 전체 페이지의 모든 데이터 흐름이 안전하다는 결론은 같지 않다. 하지만 이 줄만으로 특정 우회가 성공했다고 주장해서도 안 된다. secret 접근, 봇이 받은 응답, 제출자에게 관찰된 결과를 별도 근거로 확인해야 한다.
최종 구현과 검증
GATES는 뒤 단계의 결과 관찰, standalone solver 인터페이스, 두 번의 clean restart와 로컬 요청 범위를 구분한다. solve.py.before-control은 비교용 이전 snapshot이고 최종 solve.py와 같은 상태로 소개하지 않는다.
사용자는 익스플로잇 성공을 확인했으며 기존 GATES에는 최종 로컬 성공 기록이 있다. 공식 원격 성공 근거는 미확인이다. Dockerfile의 개별 패치 버전과 Chrome 버전이 모두 고정된 것도 아니므로 다른 재빌드 환경의 결과로 일반화하지 않는다. 이번 감사에서 PHP·브라우저·solver를 실행하지 않았다.
근거 자료
sources/executable/Executable/html/index.phpsources/executable/Executable/html/flag.phpsources/executable/ASTRA_ANALYSIS.mdsources/executable/GATES.md
원본 문서·solver·검증 로그는 전달 staging에 보존되어 있다. 이 경로들은 provenance이며 CMS의 다운로드 첨부 링크가 아니다.