요약

웹 요청을 처리하는 모든 PHP 서버는 즉시 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35로 올려야 한다. PHP 보안팀은 2026년 10월 21일, 인증 없이 원격 코드 실행(RCE)이 가능한 코어 취약점 2건(통칭 PHP2Shell)을 공개하고 패치를 배포했다. 두 건 모두 CVSS v4.0 9.2(Critical)다.

  • 영향 범위: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed 등 웹 요청을 받는 모든 설치. 위험도는 mod_php가 가장 높다. 애플리케이션 코드가 실행되기 전에 비인증 요청 하나로 공격이 성립하는 익스플로잇이 시연됐다.
  • 위협 상황: 세부 정보가 공식 공개 전에 유출됐고, watchTowr는 10월 21일부터 자사 허니팟에서 두 CVE에 대한 악용 시도를 관측했다고 밝혔다. PHP 공식 공지 자체는 실제 악용 여부를 언급하지 않는다.
  • 완화 조치의 한계: 설정 변경은 확인된 공격 경로 일부만 막는다. PHP 팀은 업데이트만이 완전한 해결책이라고 명시했다.
  • EOL 버전: PHP 8.1 이하는 공식 패치가 없다. 7.4·8.0·8.1용 최소 소스 백포트만 제공되므로, 배포판·LTS 벤더 패키지 또는 지원 버전으로의 업그레이드가 필요하다.

취약점 개요와 영향 범위

두 취약점은 서로 독립된 결함이지만, 모두 요청 수명주기 중 메모리 상태가 어긋나는 지점에서 발생한다.

항목 CVE-2026-109618 CVE-2026-109619
공식 명칭 RCE via OOM corruption RCE via stale global state
GitHub 권고 GHSA-w8hw-w9fx-j79w GHSA-6wmf-4rv5-p3rp
CVSS v4.0 9.2 (Critical) 9.2 (Critical)
원인 OOM 처리 중 부분 초기화된 요청 데이터를 정리 루틴이 유효한 것으로 취급 해제된 메모리를 가리키는 요청 소유 상태가 다음 요청까지 살아남음
인증 필요 없음 없음
고위험 SAPI mod_php (애플리케이션 코드 실행 전 발동, 익스플로잇 시연됨) 동일 워커가 여러 요청을 처리하는 모든 SAPI

영향받는 SAPI: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed. CLI 단독 실행처럼 웹 요청을 받지 않는 환경은 공지의 위험 대상에 포함되지 않는다.

영향받는 버전: 패치 버전 이전의 지원 브랜치(8.2–8.5) 전부. 일부 연구자는 PHP 5 이후 모든 버전이 영향을 받는다고 보고 있으며, 영국 NCSC도 구버전에 한정하지 말고 PHP 설치 전체를 식별하라고 권고했다.

기술 분석 1: CVE-2026-109618 (OOM 손상)

핵심은 PHP가 메모리 부족(OOM) 시 longjmp()로 요청 처리를 강제로 빠져나간다는 점이다. 할당 실패가 요청 데이터 초기화 도중 일어나면, 이후 요청 정리(cleanup) 단계가 반쯤 만들어진 데이터를 정상 데이터로 다루면서 메모리 손상이 생긴다.

공격 흐름

  1. 공격자는 PHP의 겉보기 제한(post_max_size, memory_limit) 안에 머무르면서도 OOM을 유발하는 요청을 만든다. 조작된 multipart 업로드가 대표적인 경로다.
  2. 요청 파싱 도중 할당이 실패하고 longjmp()로 이탈한다.
  3. 정리 루틴이 부분 초기화된 구조체를 참조하고, 공격자는 이를 힙 손상과 코드 실행으로 연결한다.

SAPI별 차이

  • mod_php: 요청 시작 단계에서 발동하므로 애플리케이션 코드, 인증, WAF 성격의 앱 레벨 방어가 개입하기 전에 공격이 끝난다. PHP 팀이 실제 익스플로잇을 시연한 경로다.
  • PHP-FPM: Rapid7은 소스 분석상 정상 기동 이후 FPM도 취약하다고 보지만, 공식 권고에는 FPM 대상 완성형 익스플로잇이 보고되지 않았다고 정리했다. 애플리케이션이 공격자 입력에 비례해 메모리를 할당하는 지점에서도 OOM이 유도될 수 있다.

패치 내용(공개 분석 기준)

  • longjmp() 기반 OOM 이탈을 제거하고, 다음 VM 안전 지점에서 처리하는 소프트 OOM과 더 높은 2차 임계치에서 _exit()로 즉시 종료하는 하드 OOM으로 대체했다.
  • multipart 파서(main/rfc1867.c)를 실패 가능 할당 방식으로 바꿔, 할당이 실패하면 전용 OOM 경로로 빠지도록 했다.

기술 분석 2: CVE-2026-109619 (만료된 전역 상태 UAF)

이 취약점은 하나의 워커가 여러 요청을 순차 처리하는 구조에서 생기는 Use-After-Free다. 요청이 끝나면 요청 메모리는 해제되지만, 일부 전역 상태는 해제된 메모리를 계속 가리킨 채 남는다. 같은 워커가 받은 다음 요청이 정상 초기화로 그 상태를 재설정하기 전에 이를 사용하면 해제된 메모리를 참조하게 된다.

공식 공지가 지목한 트리거 경로

  • 세션 업로드 진행률(session.upload_progress): 확인된 주 경로. Upwind 분석에 따르면 multipart 업로드 진행률 추적 시 바이트 카운터를 가리키는 zval 포인터 두 개가 해시테이블에 캐시되며, 이것이 요청 경계를 넘어 남는다.
  • 치명적 오류 백트레이스(PHP 8.5의 fatal_error_backtraces): 확인된 별도 경로.
  • 요청 초기화 전 진단 메시지: 요청별로 적용되는 잘못되었거나 폐기(deprecated)된 설정이 초기화 전에 경고를 내는 경우.
  • 공격자가 도달 가능한 치명적 오류와 실행 시간 초과: 콜백, 업로드·임포트 처리, 정리 과정의 실패 포함.

위험성

공격자는 힙 배치를 조작해 해제된 영역을 원하는 데이터로 다시 채우고, 이를 코드 실행으로 연결할 수 있다. 워커 재사용이 전제이므로 FPM, FrankenPHP 같은 상주형 SAPI에서도 문제가 된다. 공개 분석에서는 기본 설정의 PHP 8.4.4와 8.2.34에서 재현됐다는 독립 연구가 인용됐다.

참고: 일부 업체 분석은 두 CVE의 근본 원인을 하나로 묶어 설명하거나 109618을 세션 업로드 진행률과 연결하는 등 서로 엇갈린다. 원인 구분은 PHP 공식 공지와 GHSA 권고를 기준으로 삼는 것이 안전하다.

위협 동향과 타임라인

공식 공개 전에 정보가 유출되면서 패치와 동시에 악용이 시작된 것으로 보인다. 패치 지연 시간이 곧 노출 시간이라는 전제로 대응해야 한다.

일시 사건
10월 21일 watchTowr, 자사 허니팟 네트워크에서 두 CVE에 대한 악용 시도 관측 발표 (watchTowr FAQ)
10월 21일 14:00 UTC PHP 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 배포, 보안 공지 게시 (php.net)
10월 21일 13:48 UTC PHP CNA, 두 CVE 레코드 공개
10월 20일 CERT-EU 권고 2026-018, 두 CVE와 9.2 점수 명시
10월 20일 php.net 사전 공지("Upcoming Critical PHP Security Release"). 세부 정보가 SNS 등으로 먼저 유출되어 확산
10월 20일 watchTowr, 109618 재현 성공을 언급(세부는 비공개)

악용 현황 평가

  • 패치 직전까지 watchTowr와 Huntress는 실제 악용을 확인하지 못했고, Sansec은 패치 공개 후 15분 안에 대량 악용이 시작될 것으로 예측했다 (SecurityWeek).
  • 패치 이후 watchTowr는 악용 시도를 관측했다고 업데이트했다. 이는 허니팟 기반 관측이며, 대규모 침해 사례가 공개 확인된 단계는 아니다.
  • PHP 공식 공지는 악용 여부를 명시하지 않는다. 사전 공지에서 "악용 증거가 나오면 조기 배포할 수 있다"고만 밝혔고, 실제 배포는 예정 시각대로 이뤄졌다.

대응 1: 패치

각 브랜치의 아래 버전이 두 CVE를 모두 수정한다. 업데이트 후에는 모든 PHP 워커(FPM 풀, Apache, FrankenPHP 등)를 재시작해야 새 바이너리가 적용된다.

브랜치 직전 버전 패치 버전 비고
PHP 8.5 8.5.11 8.5.12 ChangeLog
PHP 8.4 8.4.26 8.4.27 ChangeLog
PHP 8.3 8.3.35 8.3.36 ChangeLog
PHP 8.2 8.2.34 8.2.35 2026-12-31 지원 종료, 이후 보안 패치 없음
PHP 8.1 이하 — 공식 릴리스 없음 7.4·8.0·8.1용 최소 소스 백포트 브랜치 제공

설치 경로별 조치

  • 소스·Windows: php.net 다운로드 페이지에서 받는다.
  • 리눅스 배포판·LTS 벤더: 패치를 사전에 전달받았으므로 벤더 패키지 업데이트를 확인한다.
  • rpms.remirepo.net 사용자: 자원봉사 운영 저장소라 당일 업데이트가 없다. PHP 팀은 배포판 패키지로 전환하거나 소스에서 빌드하라고 권고한다.
  • PHP 7.4 / 8.0 / 8.1: 공식 백포트 브랜치(7.4, 8.0, 8.1)로 직접 빌드하거나 LTS 벤더에 문의한다. 장기적으로는 지원 버전 업그레이드가 답이다.
  • 컨테이너 이미지: 공식 php 베이스 이미지 태그 갱신 여부를 확인하고, 이미지를 다시 빌드·재배포해야 한다. 기존 컨테이너는 재시작만으로 바뀌지 않는다.
  • PHP 5.x / 7.3 이하: 패치가 제공되지 않는다. 인터넷 노출을 즉시 차단하는 것을 우선 검토한다.

대응 2: 패치 불가 시 임시 완화

아래 조치는 특정 공격 경로의 노출만 줄인다. 적용해도 설치가 안전해지지 않으며, 패치까지의 시간을 버는 용도다. 모든 설정은 요청 파싱 전에 적용되는 위치(php.ini, FPM 풀, 웹서버 설정)에 두고, 적용 후 모든 워커를 재시작한다. ini_set()이나 FPM .user.ini에 의존하면 안 된다.

CVE-2026-109618 (OOM 손상)

조치 설정 예 효과와 한계
메모리 제한 해제 php_admin_value[memory_limit] = -1 공격자가 제어 가능한 PHP 메모리 제한 실패를 제거. 다른 풀·디렉터리·앱 설정이 유한값을 다시 넣지 않는지 확인 필요. 하위 할당 실패(mmap 등)는 여전히 취약 경로에 도달 가능
요청 크기 축소 업로드 불필요 시 post_max_size = 8M, 필요 시 32M. upload_max_filesize는 그보다 작게 공격 페이로드 크기 제한
프록시·웹서버 제한 디코딩 후 요청 크기, 입력 필드 수, multipart 파트 수, 헤더 수, 중첩 깊이 Content-Length가 없는 요청(chunked 등)에도 적용해야 함
컨테이너·cgroup 메모리 제한 영향받은 워커만 종료하는 정책 권장 가용성 경계 역할. RLIMIT_AS / RLIMIT_DATA로 대체 금지(오히려 취약한 할당 실패를 유발)

CVE-2026-109619 (만료된 전역 상태)

조치 설정 효과와 한계
세션 업로드 진행률 비활성화 session.upload_progress.enabled = 0 확인된 세션 경로 차단. 다른 변종은 막지 못함
치명적 오류 백트레이스 비활성화(8.5) fatal_error_backtraces = 0 확인된 백트레이스 경로만 차단
초기화 전 진단 메시지 제거 요청별로 적용되는 잘못된·폐기된 설정 정리 error_reporting, display_errors, @로 숨기는 것은 효과 없음
치명적 오류·타임아웃 수정 콜백, 업로드·임포트 처리, 정리 과정 공격자가 도달 가능한 실패 지점을 줄임

mod_php는 위험도가 가장 높으므로, 패치가 늦어지는 경우 PHP-FPM 전환이나 해당 호스트의 외부 노출 축소를 함께 검토할 만하다.

점검 체크리스트와 탐지 포인트

인터넷에 노출된 호스트부터, mod_php → 기타 SAPI 순으로 처리한다.

자산 식별과 패치

  • PHP가 설치된 모든 호스트·컨테이너 이미지 목록화 (구버전에 한정하지 말 것)
  • 호스트별 PHP 버전과 SAPI 확인 (php -v는 CLI 버전일 수 있으므로 웹 SAPI의 실제 버전을 phpinfo() 또는 패키지 관리자로 교차 확인)
  • 인터넷 노출 호스트와 mod_php 호스트 우선 패치
  • 패치 후 모든 워커 재시작, 컨테이너는 재빌드·재배포
  • EOL 버전(8.1 이하) 호스트의 백포트 적용 또는 격리 계획 수립

패치 전 임시 조치

  • session.upload_progress.enabled = 0 적용 및 워커 재시작
  • memory_limit, post_max_size 조정 및 프록시 단 요청 제한 적용
  • (8.5) fatal_error_backtraces = 0 적용

탐지·사후 점검

  • 비정상적으로 큰 multipart 요청, 파트·필드 수가 많은 요청, Content-Length 없는 업로드 요청의 급증
  • PHP 로그의 Allowed memory size ... exhausted 오류 급증, 워커의 비정상 종료(segfault)나 재시작 반복
  • PHP 워커 프로세스가 셸(sh, bash)이나 네트워크 도구를 생성하는 행위
  • 웹 루트의 신규·변조 .php 파일(웹셸), 예상치 못한 cron·사용자 계정 추가
  • 10월 20일 유출 이후 패치 전까지의 기간을 침해 가능 구간으로 보고 위 항목을 소급 점검

참고 자료

GHSA 권고 원문은 직접 열람하지 못했으며, 기술 세부는 PHP 공식 공지와 위 보안업체 분석을 교차 확인해 정리했다.