풀이 날짜: 2026-09-14 (사용자 확정). 익스플로잇 성공은 2026-09-16 사용자 확인에 따른다. 아래 실행 결과는 보존된 원본 기록이며 이번 감사에서 새로 실행한 결과가 아니다.

확장자와 실제 문서 형식의 불일치

Unexecutable은 PHP 업로드와 JavaScript가 비활성화된 브라우저 봇을 결합한다. SOLUTION의 provenance는 Dreamhack 패치 버전 / YISF 2023이다. unexcutable은 source 경로의 철자이며 제목은 Unexecutable로 유지한다.

업로드 경계의 실제 코드

upload.php는 사용자 입력으로 stream wrapper 문자열을 만들고 결과를 Base64 디코딩해 저장한다. 중간 필터 검사를 생략한 핵심 발췌는 다음과 같다.

$img = file_get_contents("php://filter/$filter/resource=basedpng.txt");
$img = base64_decode($img);

이 코드는 파일이 올바른 이미지인지 디코더로 검사하거나 재인코딩하는 절차가 아니다. 이름에 이미지 확장자를 붙이는 것, 문자열에서 일부 문자를 거부하는 것, 실제 이미지 형식을 검증하는 것은 서로 다르다.

check_valid는 각 문자에 대한 허용 목록 검사 후 true를 반환한다. 입력 길이가 0이면 반복문의 본문이 실행되지 않는다. 따라서 '모든 문자가 허용 목록에 있다'는 조건과 '허용된 문자가 최소 하나 존재한다'는 조건은 같지 않다. 후속 SOLUTION은 이 입력 계약과 서버의 MIME 처리 차이를 실제 환경에서 대조했다.

서버와 브라우저의 판단을 분리

층위 원본·기존 기록이 확인한 대상 같은 것으로 취급하면 안 되는 주장
PHP POST 파싱, wrapper 해석, 저장 bytes 화면에 보이는 form 이름이 그대로 서버 key가 됨
저장 파일 이름과 실제 데이터 확장자가 곧 콘텐츠 검증 결과임
Apache 실제 응답 Content-Type 모든 파일 이름에서 같은 MIME 결정이 적용됨
Chromium sniffing, XML/XSLT 처리 JavaScript 비활성화가 모든 문서 기능 비활성화임

SOLUTION은 source에서 직접 확인한 사실, 기존 작성자 README의 설명, 로컬 관찰을 따로 표시한다. 이번 본문도 wrapper와 브라우저 동작의 연결이 원본 source만으로 완전히 입증된 것처럼 쓰지 않는다. 실제 입력 우회 문자열·XML payload·요청 절차는 옮기지 않는다.

후속 정정과 환경 의존성

초기 ASTRA_HANDOFF보다 후속 SOLUTION/GATES의 검증을 우선한다. 기존 로컬 환경은 PHP 7.4.33, Apache 2.4.54, Node 18과 Chromium 115를 사용한다. 최신 브라우저로 다시 만든 환경에서는 기존 풀이 전제가 유지되지 않았다는 제한이 있다. 이는 모든 브라우저에 일반화된 결과가 아니라 특정 런타임 조합에서 관찰한 문서 처리 차이다.

결과

사용자는 익스플로잇 성공을 확인했다. 기존 자료에는 세 번의 clean restart와 서로 다른 주입 flag의 일치 결과가 있다. 실제 값은 싣지 않으며 이 결과를 공식 원격 수락으로 바꾸지 않는다. 이번에는 외부 작성자 사이트 재조사, 이미지 빌드·실행, solver 실행을 수행하지 않았다.

근거 자료

  • sources/unexcutable/html/upload.php
  • sources/unexcutable/SOLUTION.md
  • sources/unexcutable/ASTRA_HANDOFF.md
  • sources/unexcutable/GATES.md

원본 문서·solver·검증 로그는 전달 staging에 보존되어 있다. 이 경로들은 provenance이며 CMS의 다운로드 첨부 링크가 아니다.