안녕하세요, 흘러간 하가와입니다.
오늘(2026년 10월 21일) 일본 시간 23시 00분, 전 세계적으로 예고되었던 PHP의 심각한 보안 패치가 예정대로 전 세계 동시 출시되었습니다.
사전 정보에서는 심각도 점수 CVSS v4.0 “9.2”라는 극히 이례적인 높이 때문에 “php2shell(원격 코드 실행)”로 인해 큰 혼란이 있었지만, 공개된 수정 커밋과 보안 경고를 통해 “구체적으로 어떤 문제가 있었으며, 공식 업데이트가 무엇을 어떻게 해결했는가”의 전말이 밝혀졌습니다.
골목길에서는 “php.ini로 파일 업로드 진행 상황을 비활성화하면 막을 수 있다”는 임시 조치에 대한 소문이 떠돌아다니기도 했지만, 왜 그것으로는 막을 수 없고 PHP 코어 본체의 업데이트가 필수였던 것인가?
이번 업데이트에서 적용된 2대 주요 메모리 방어 기술적 메커니즘을 엔지니어와 보안 담당자를 위해 명확하고 심층적으로 설명합니다!
23시에 공개된 공식 수정 버전 목록
이번에 공개된 보안 수정 버전은 다음과 같습니다. 지원되는 모든 주요 시리즈에 대해 긴급 패치가 백포팅되었습니다.
- PHP 8.5.12
- PHP 8.4.27
- PHP 8.3.36
- PHP 8.2.35
대상으로 되어 있는 CVE 번호는 다음과 같습니다:
- CVE-2026-109618: 메모리 부족(OOM) 오류 발생 시 미초기화 메모리 오인식으로 인한 RCE
- CVE-2026-109619: Use-After-Free 메모리 참조를 통한 RCE(원격 코드 실행) 가능성 있는 치명적인 오류 처리 취약점
2. 취약점 ① (CVE-2026-109618)의 기원과 패치 적용 방안
무엇이 버그였던 걸까? (초기화되지 않은 메모리의 오인)
PHP는 C언어에서 구현되어 있습니다. 스크립트 실행 중에 메모리 제한(memory_limit)에 도달하여 메모리 부족(OOM: Out-Of-Memory)이나 치명적인 오류가 발생하면, PHP 내부에서는 C언어의 longjmp() 함수를 사용하여 오류 핸들러로 강제 전역 점프합니다.
문제는 “요청 관련 내부 데이터 구조를 구성하는 과정에서” longjmp() 호출로 인해 데이터 구조가 초기화되지 않거나, 중도에 포인터를 가진 채로 방치되는 현상이었던 것입니다.
이후 정리 작업 과정에서 이 “불완전한 쓰레기 데이터”를 정상적인 객체로 오인하여 참조하면서 메모리 손상(Heap Buffer Overflow / Type Confusion)이 발생했다. 공격자는 이를 이용하여 메모리 상의 실행 포인터를 덮어쓰고 임의의 쉘 코드를 실행(RCE)할 수 있는 상황이 연출되었다.
공식 패치는 어떻게 해결했나요?
- 미초기화 포인터의 사전 제로 클리어(Safe Nullification)
데이터 구조를 할당한 직후, 포인터를 반드시 NULL로 초기화하도록 절차를 엄격하게 준수한다.
longjmp()로 인해 중단이 발생했을 경우, 후속 클린업 처리가 미완료된 데이터를 건너뛰는 것을 방지하기 위한 안전 플래그를 설치하고, 불법적인 메모리 참조를 완전히 차단했습니다.
3. 취약점 ② (CVE-2026-109619)의 정체와 패치 적용 방안
무엇이 버그였던 걸까? (워커 프로세스 간의 Use-After-Free)
현대의 PHP 환경(특히 PHP-FPM)에서는 성능 향상을 위해 하나의 워커 프로세스가 여러 HTTP 요청을 연속적으로 처리(프로세스 재사용)합니다.
그러나 이전 요청에서 치명적인 오류가 발생했을 때, 이미 해제된 힙 메모리 영역을 가리키는 오래된 포인터가 워커 프로세스의 글로벌 공간에 남아있는 문제가 있었습니다.
공격자는 동일한 워커에 대해 연속적으로 요청을 보내는 행위로 인해 프로세스가 오래된 해제된 메모리의 잔해를 잘못 재사용(Use-After-Free)하는 버그를 유발할 수 있습니다. 공격자는 이를 통해 조작된 데이터를 배치하여 의도한 대로 원격 코드 실행을 성공적으로 수행할 수 있었습니다.
공식 패치는 어떻게 해결했습니까?
- 요청 경계 상태 완전 초기화 (강제 노후 상태 플러시)
오류 종료 시점 및 요청 종료 처리의 최저 단계에서 워커 프로세스가 보유하는 모든 글로벌 포인터를 강제로 리셋 및 해제하는 클린업 루틴을 삽입한다.
- 이전 요청이 어떤 비정상 종료를 맞이하더라도 다음 요청에는 깨끗한 백지 상태로 진행되도록 엄격하게 적용되었습니다.
왜 “php.ini 설정 변경”만으로는 막을 수 없었던 문제일까?
사전 루크 단계에서는 “파일 업로드 진행 상황을 기록하는 session.upload_progress.enabled = 0으로 설정하면 막을 수 있다”는 정보가 유출되었습니다.
그러나 패치 분석 결과 밝혀진 진실은 “세션 업로드 진행률은 이 미초기화 메모리 버그를 외부에서 쉽게 발생시키기 위한 ‘유발 요소’ 중 하나였다”ということです.
근본적인 원인은 PHP 코어의 “전역 점프(longjmp) 시 메모리 라이프사이클 관리의 오류” 였습니다.
결론적으로, 업로드 기능을 비활성화해도 공격자가 다른 방법(대량의 POST 데이터 전송이나 정규 표현식 백트래킹을 통한 OOM 유발 등)으로 치명적인 오류를 일으켜 메모리 파괴나 Use-After-Free를 재현할 수 있었습니다.
그것은 PHP 공식 보안 팀이 설정 변경이 아닌 “PHP 본체의 버전 업그레이드”를 강력히 촉구했던 이유입니다.
요약: 패치 적용 후 점검점
이번 패치는 PHP 내부의 극도로 깊은 오류 처리 및 메모리 안전성을 강화한 것입니다.
- 오늘도 여러분 모두 즐겁게 감상하실 수 있도록 『별의 정원사』 낭독 이벤트를 생중계하고 있습니다. 오노데라 유스케 씨의 낭독으로 『별의 정원사』 (저: 앙투안 드 몽테큐베리)를 진행합니다. 오노데라 유스케 씨는 다양한 작품에서 쌓아온 낭독 경험과 풍부한 표현력으로 정원사의 말을 더욱 깊이 있고 따뜻하게, 그리고 부드럽게 우리에게 전달해 줍니다. 이번 기회를 통해 『별의 정원사』의 세계에 빠져보시길 바랍니다.
회사의 PHP가 수정판(8.3.36, 8.2.35, 8.4.27, 8.5.12) 또는 각 리눅스 배포판에서 배포된 수정 패키지(Backport 패치)로 업데이트되었는지 `php -v` 명령어를 통해 확인하십시오.
패키지 업데이트만으로는 메모리에 기존 PHP 프로세스가 계속 남아있게 됩니다. 반드시 systemctl restart php-fpm 또는 systemctl restart apache2를 실행하여 프로세스를 재시작해 주십시오.
이번 수정은 핵심 버그 수정이며, 함수의 사양 변경(Breaking Changes)은 포함되어 있지 않아 기존의 워드프레스 플러그인이나 라라벨 애플리케이션의 호환성 위험은 극히 낮습니다. 안심하고 업데이트를 적용해 주세요.
인터넷을 지탱하는 PHP의 근간을 흔들었던 “php2shell”이지만, 원인이 밝혀지고 견고한 패치가 출시되었습니다.
사이트 관리자 및 엔지니어 여러분께서는 신속하게 운영 환경에 패치를 적용하여 안전한 웹 운영을 유지해 주십시오!
출처: note 원문
번역: Gemma 3(.44) 초벌 + 교정 29청크
원문 보기 | 출처: note.com