2026년 10월 21일 PHP가 인증 없이 원격 코드 실행이 되는 취약점 두 건을 고친 긴급 보안 릴리스를 냈다. 공격 체인은 'PHP2Shell'이라는 이름으로 불린다. 웹 요청을 처리하는 PHP는 PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed까지 모두 대상이다. 이 글은 수정판 번호, 그리고 CentOS 7·록키 리눅스·윈도우에서 수정판을 받는 방법을 정리한다. 각 저장소에 수정판 패키지가 실제로 올라와 있는지는 2026년 10월 24일에 저장소 메타데이터를 직접 받아 확인했다.
무엇이 문제인가
| CVE | 내용 | CVSS v4 |
|---|---|---|
| CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) | 메모리 부족(OOM)으로 요청이 중단될 때, 초기화가 덜 된 요청 메모리를 종료 처리 과정이 그대로 읽는다. 공격자는 multipart 요청을 조작해 post_max_size 안에서 memory_limit를 넘기게 만들 수 있다. | 9.2 |
| CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp) | 요청이 끝나고 메모리가 해제된 뒤에도 전역 상태가 그 메모리를 가리킨 채 남는다. 같은 워커가 받은 다음 요청이 이 상태를 쓰면 해제 후 사용(use-after-free)이 된다. | 9.2 |
PHP 공식 권고문에 따르면 mod_php가 가장 위험하다. 애플리케이션 코드가 한 줄도 실행되기 전, 요청 본문을 파싱하는 단계에서 공격이 성립하는 것이 확인됐다. FPM에서는 세션 업로드 진행률 경로를 통한 원격 코드 실행이 검증됐다.
Cloudflare는 공개 9시간 전인 10월 21일 03:02(UTC)부터 WAF 규칙을 배포했고, 이후 이 취약점을 노리는 공격 트래픽과 규칙을 우회하려고 바꿔 가는 페이로드를 관측했다고 밝혔다. 10월 23일에 갱신된 CISA KEV(실제 악용 취약점) 목록에는 아직 두 CVE가 없다. WAF는 보조 수단일 뿐이다. Cloudflare도 session.upload_progress.name을 바꾼 사이트는 규칙이 막지 못한다고 적었다.
올려야 할 버전
| 쓰는 계열 | 이 버전 이상 |
|---|---|
| 8.5 | 8.5.12 |
| 8.4 | 8.4.27 |
| 8.3 | 8.3.36 |
| 8.2 | 8.2.35 |
| 8.1 이하 | PHP 공식 수정판 없음. 배포판이나 LTS 업체의 백포트를 받거나 8.2 이상으로 올린다. |
PHP 보안팀은 직접 빌드하는 사람을 위해 7.4·8.0·8.1용 최소 소스 백포트를 따로 공개했다. 배포판 패키지는 버전 번호를 올리지 않고 패치만 넣는 경우가 많다. 그래서 버전 번호만 볼 게 아니라 아래처럼 패키지 변경 이력에 CVE 번호가 있는지 확인해야 한다.
php -v # CLI
php-fpm -v # FPM (CLI와 다를 수 있다)
httpd -M 2>/dev/null | grep -i php # mod_php 를 쓰는지
rpm -q --changelog php-common | grep -m3 -E '109618|109619|8\.[2-5]\.[0-9]+'
CLI와 웹이 다른 PHP를 쓰는 서버가 흔하다. 웹 쪽 실제 버전은 phpinfo()나 FPM 바이너리로 확인한다.
록키 리눅스: AppStream 또는 remi
록키는 레드햇이 고친 패키지를 그대로 다시 빌드한다. AppStream에 올라온 수정판은 다음과 같다.
| 록키 | 스트림 | 수정 패키지 |
|---|---|---|
| 8 | php:8.2 | php-8.2.35-1.module+el8.10.0 |
| 8 | php:7.4 | php-7.4.33-8.module+el8.10.0 (변경 이력에 CVE-2026-109618·109619 백포트) |
| 9 | php:8.3 | php-8.3.36-1.module+el9.8.0 |
| 9 | php:8.2 | php-8.2.35-1.module+el9.8.0 |
| 9 | 기본 8.0 | php-8.0.30-8.el9_8.1 (레드햇 RHSA-2026:87151) |
| 9 | php:8.1 | 8.1.32 그대로, 수정판 없음 |
| 10 | 기본 8.3 / php8.4 | php-8.3.36-1.el10_2, php8.4-8.4.27-1.el10_2 |
dnf module list php # 지금 켜진 스트림 확인 ([e] 표시)
dnf upgrade 'php*'
systemctl restart php-fpm httpd # 쓰는 쪽만
록키 9에서 php:8.1 스트림을 쓰고 있다면 AppStream으로는 고칠 수 없다. 8.2나 8.3 스트림으로 옮기거나 remi를 쓴다.
remi 저장소는 록키 8·9·10 모두 8.2.35, 8.3.36, 8.4.27, 8.5.12를 올려 두었다. 지원이 끝난 계열인 8.1.34-6, 8.0.30-21에도 "Mitigation fix Avoid state corruption via bailout CVE-2026-109618, CVE-2026-109619" 이력이 붙어 있다.
dnf module reset php
dnf module enable php:remi-8.3
dnf upgrade 'php*'
systemctl restart php-fpm
CentOS 7: remi 대신 GetPageSpeed 저장소
CentOS 7은 2024년 6월에 지원이 끝났고 remi도 EL7 빌드를 멈췄다. GetPageSpeed 패키지 변경 이력에는 "Remi's EL7 build stopped at 8.3.8-1"이라고 적혀 있다. remi 패키지(.el7.remi로 끝나는 것)를 쓰고 있다면 그대로는 이번 수정을 받을 수 없다.
GetPageSpeed가 remi의 패키지 이름과 구조를 그대로 따라 EL7용 PHP를 다시 빌드해 내놓았다. 계열별 채널의 저장소 메타데이터를 받아 보니 아래 패키지가 올라와 있었다.
| 채널 | 확인한 최신 패키지 (10월 24일) | 수정 방식 |
|---|---|---|
| getpagespeed-extras-php83 | php-common-8.3.36-3.el7 | 8.3.36 상위 릴리스 |
| getpagespeed-extras-php74 | php-fpm-7.4.33-36.el7 | 백포트 |
| getpagespeed-extras-php73 | php-common-7.3.33-27.el7 | 백포트 (변경 이력에 GHSA·CVE 번호 명시) |
판매사 안내에 따르면 5.6부터 8.4까지 채널이 있다. 8.4는 소프트웨어 컬렉션(php84-php-*)으로만 나온다. 개인·개발·평가 용도는 무료이고, 상업 운영 환경에는 유료 구독(GetPageSpeed Ultra)이 필요하다고 한다.
# 기본 이름 패키지 (php-common-…el7.remi 를 쓰던 경우)
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum --enablerepo=getpagespeed-extras-php83 upgrade 'php-*'
systemctl restart php-fpm
# 소프트웨어 컬렉션 (php83-php-common-…el7.remi 를 쓰던 경우)
yum upgrade 'php83-php*'
systemctl restart php83-php-fpm
# 확인: 릴리스가 .el7.remi 가 아니어야 한다
rpm -qa 'php*-common' --qf '%{NAME}-%{VERSION}-%{RELEASE}\n'
CentOS 7 기본 저장소의 PHP 5.4는 레드햇 CVE 페이지에서 RHEL 7이 "Not affected"로 분류돼 있다. 다만 5.4는 다른 취약점이 수없이 쌓인 버전이라 이걸 이유로 남겨 둘 일은 아니다.
윈도우: windows.php.net 또는 php-builder-windows
윈도우용 공식 바이너리는 windows.php.net에 8.2.35, 8.3.36, 8.4.27, 8.5.12로 올라와 있다(releases.json 확인). IIS의 FastCGI처럼 php-cgi로 돌리는 경우도 대상이다.
GitHub의 shivammathur/php-builder-windows 릴리스에서도 같은 수정판을 받을 수 있다. 예를 들어 php8.3 릴리스에는 php-8.3.36-nts-Win32-vs16-x64.zip 같은 정식판이 있고, 8.3.37-dev 스냅숏도 같이 있다. 함께 올라오는 Get-Php.ps1 스크립트로 설치까지 할 수 있다.
# 관리자 PowerShell
$php_dir = 'C:\tools\php'
New-Item -Path $php_dir -Type Directory -Force
Invoke-WebRequest -UseBasicParsing -Uri https://github.com/shivammathur/php-builder-windows/releases/latest/download/Get-Php.ps1 -OutFile $php_dir\Get-Php.ps1
. $php_dir\Get-Php.ps1 -Architecture x64 -ThreadSafe $False -Path $php_dir -Version 8.3
. $php_dir\php -v
지원이 끝난 계열도 여기서 받을 수 있다. 이 빌드를 관리하는 setup-php 관리자가 10월 21일 공지(setup-php 이슈 #1139)를 올렸다. 공지에 따르면 CVE-2026-109618·109619를 막은 빌드를 리눅스·macOS·윈도우용으로 PHP 5.3부터 8.7까지 냈고, 지원이 끝난 계열에는 보안 완화를 백포트해 넣었다. 대신 지원이 끝난 계열은 버전 번호를 원래대로 둔다. 예를 들어 php7.3 릴리스의 파일 이름은 여전히 php-7.3.33-…이다.
이름이 같아서 옛 파일과 헷갈리기 쉬우므로 직접 대조해 봤다. php7.3 릴리스의 php-7.3.33-nts-Win32-VC15-x64.zip과 windows.php.net 보관소의 같은 이름 파일은 해시가 달랐다. php7.dll에 박힌 빌드 시각은 공식판이 2021년 11월 16일, php-builder-windows 판이 2026년 10월 20일이었다. php8.1 릴리스의 8.1.34도 2026년 10월 20일에 다시 빌드된 파일이다. 받은 파일이 새 빌드인지는 php -i의 Build Date 줄로 확인한다.
php -i | findstr /C:"Build Date"
:: Build Date => Oct 20 2026 … 이면 다시 빌드된 판, Nov 16 2021 이면 옛 공식판
당장 올릴 수 없다면
공식 권고문은 업데이트만이 완전한 해결책이라고 못 박는다. 그 전까지 공격 경로를 줄이는 설정은 다음과 같다. 모두 php.ini, FPM 풀 설정의 php_admin_value, 아파치 설정처럼 요청을 파싱하기 전에 적용되는 곳에 넣는다. ini_set()이나 .user.ini로는 소용이 없다. 넣은 뒤에는 모든 워커를 재시작한다.
; CVE-2026-109619: 확인된 세션 경로 차단 (기본값은 1)
session.upload_progress.enabled = 0
; PHP 8.5만: 확인된 치명적 오류 백트레이스 경로 차단 (기본값은 1)
fatal_error_backtraces = 0
; CVE-2026-109618: 업로드가 필요 없으면 8M, 필요하면 32M 정도로
post_max_size = 8M
위 두 설정의 기본값은 PHP 8.5.4에서 php -n(설정 파일 없이)으로 확인했고, 둘 다 1이다. 즉 기본 설정 그대로인 서버는 이 경로가 열려 있다.
권고문은 memory_limit=-1도 109618의 주요 완화책으로 든다. 하지만 요청 하나가 서버 메모리를 다 쓸 수 있게 되므로, 컨테이너나 cgroup 메모리 제한을 같이 걸어야 한다. RLIMIT_AS·RLIMIT_DATA로 제한하면 오히려 취약한 경로를 타므로 쓰지 말라고 적혀 있다.
올린 뒤에도 남겨 둘 설정
10월 23일 php.net은 세션 업로드 진행률 기능에서 원격 코드 실행이 될 수 있는 문제(CVE-2026-115560)를 하나 더 공지했다. 이번 수정판(8.5.12 등)에도 남아 있고, 다음 정기 릴리스에서 고친다. 이 문제는 설정에서 session.serialize_handler를 php_binary나 php_serialize로 두고, 실행 중에 ini_set()으로 php로 바꾼 뒤 session_start()를 부르는 드문 조합에서만 생긴다. 그래도 php.net은 다음 릴리스까지 session.upload_progress.enabled=0을 권한다. 업로드 진행률 기능을 쓰지 않는다면 수정판으로 올린 뒤에도 꺼 두면 된다.
grep -rn "serialize_handler" --include=*.php . # 이 조합을 쓰는지 확인
참고
- PHP 보안 권고: GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp (php/php-src 저장소), php.net 10월 21일·23일 공지
- 레드햇 CVE 데이터(access.redhat.com), 록키 AppStream·remi·GetPageSpeed 저장소 메타데이터(primary·other.xml)를 10월 24일에 직접 받아 확인
- Cloudflare 블로그 "Cloudflare deploys protections against php2shell vulnerability"
- 윈도우 바이너리: windows.php.net의
releases.json, shivammathur/php-builder-windows 릴리스, setup-php 이슈 #1139
패키지를 실제 서버에 설치하고 업그레이드하는 과정은 이 글을 쓰면서 돌려 보지 않았다. 적용하기 전에 스테이징 서버에서 먼저 확인하기를 권한다.