PHP는 워드프레스 같은 CMS부터 사내 업무 시스템까지 웹에서 동작하는 핵심 인프라 중 하나 입니다. 지금까지 PHP 관련 보안 이슈는 대부분 특정 프레임워크나 플러그인의 취약점이었습니다.
이번에 공개된 PHP2Shell은 PHP 엔진 자체에서 발견되었다는 점에서 성격이 전혀 다릅니다. 인증 없이 코드 실행이 가능한 취약점이며, 이는 비즈니스 로직이 실행되기도 전에 요청 한 번으로 공격이 시작될 수 있습니다.
이번 취약점은 공개 과정부터 이례적이었습니다. 엠바고 이전에 내용이 유출되면서 PHP 보안팀은 발표 후 약 하루 만에 수정 버전을 배포했습니다. 2개 취약점 모두 CVSS v4.0 기준 9.2점을 받았습니다. 취약점은 2026년 8월에 처음 발견되었고, 10월 21일 긴급 보안 릴리스로 이어졌습니다.
이번 글에서는 PHP2Shell의 원인을 CVE별로 정리합니다. 이어서 근본적인 대처 방안과, 당장 업그레이드가 어려운 환경에서 적용해야 할 임시 설정을 함께 살펴보겠습니다.
PHP 코어를 겨냥한 취약점
두 취약점 모두 PHP 코어에 존재합니다. 따라서 PHP로 웹 요청을 처리하는 모든 환경이 영향 범위에 들어갑니다. PHP 팀은 그중 mod_php를 가장 위험한 구성으로 보고 있습니다.
영향 버전: 8.5.12, 8.4.27, 8.3.36, 8.2.35 미만의 모든 버전이 영향을 받습니다.
취약점의 원인
두 취약점은 요청 처리 도중 비정상적으로 중단된 상태를 PHP가 제대로 정리하지 못한다는 공통점이 있습니다. 다만 문제가 드러나는 지점은 서로 다릅니다.
1) 취약점의 원인
PHP는 memory_limit을 초과한 요청을 longjmp()로 즉시 중단시킵니다. 이 중단은 파일 업로드 폼을 파싱하는 도중처럼 내부 요청 데이터가 일부만 초기화된 시점에 일어날 수 있습니다. 그러면 요청 정리(cleanup) 단계에서 잘못된 데이터를 정상으로 간주하고, 초기화된 적 없는 메모리를 해제하려 합니다.
이 메모리에는 공격자가 앞서 채워 넣은 데이터가 남아 있을 수 있습니다. 공격자가 메모리 부족을 유도하는 방법도 여러 가지입니다. 대표적인 예는 세 가지입니다.
첫째, Content-Length 없이 최초의 post_max_size 검사를 통과한 뒤 본문을 계속 보내는 요청입니다.
둘째, 전송량보다 PHP 내부에서 훨씬 많은 메모리를 차지하는 무제한 헤더를 가진 multipart 파트입니다.
셋째, max_file_uploads에 집계되지 않는 빈 파일 필드입니다. mod_php 환경에서는 파일 업로드가 아닌 일반 폼 전송(application/x-www-form-urlencoded)으로도 트리거된 사례가 보고되었습니다.
2) CVE-2026-109619, 오래된 전역 상태의 재사용
요청이 소유한 내부 상태는 치명적 오류 등으로 실제 메모리가 해제된 뒤에도 남아 있을 수 있습니다. 그러면 같은 워커가 처리하는 다음 요청이, 정상 초기화로 상태가 재설정되기 전에 이를 사용하게 됩니다. 전형적인 해제 후 사용(Use-After-Free) 구조입니다. 확인된 공격 경로 중 하나는 세션 업로드 진행률 기능입니다.
이 기능은 기본으로 켜져 있고, PHP가 요청 준비를 마치기 전에 세션 처리에 도달할 수 있어 공격 경로가 됩니다. PHP 8.5에서는 치명적 오류 백트레이스 기능이 가장 강력한 것으로 확인된 취약점의 경로입니다.
근본적인 대처: PHP 업그레이드
업데이트만이 이 취약점을 완전히 해결하는 방법입니다. 다음 사항을 순서대로 점검하는 것이 좋습니다.
- 패치 버전 적용: 8.5.12, 8.4.27, 8.3.36, 8.2.35로 업데이트합니다. 새 바이너리가 로드되도록 PHP-FPM과 웹 서버 워커도 반드시 재시작해야 합니다.
- 배포판 패키지 버전 확인: 리눅스 배포판과 LTS 벤더는 패치를 사전에 전달받았으므로 각 벤더의 업데이트 패키지를 확인해야 합니다. 조치 여부는 php -v 결과가 아니라 USN, DSA, RHSA 같은 벤더 보안 공지의 패키지 버전으로 판단해야 합니다.
- 10월 21일 시점에 Ubuntu와 Debian은 수정이 완료되었고, RHEL 8~10, SUSE, Alpine 등은 대기 상태였습니다. 현재 상태는 벤더 공지에서 다시 확인하시기 바랍니다.
- 컨테이너 이미지 재빌드: 컨테이너는 PHP 버전이 이미지 태그에 고정되어 있습니다. Docker 공식 php 이미지는5.12, 8.4.27, 8.3.36, 8.2.35 태그로 수정되었습니다. 호스트만 업데이트해서는 소용이 없으므로 이미지를 다시 빌드하고 컨테이너를 재배포해야 합니다.
- EOL 버전(8.1 이하): PHP는4, 8.0, 8.1용 최소 소스 백포트를 공개했지만 공식 릴리스는 없습니다. 백포트는 임시 조치로 보고 업그레이드 계획을 세워야 합니다.
- 침해 흔적 점검: 최근 웹 서버와 PHP-FPM 로그에서 원인 불명의 워커 크래시나 비정상적인 multipart 요청이 있었는지 확인하는 것이 좋습니다. 웹 서버나 PHP 워커가 셸을 자식 프로세스로 띄웠는지, 웹 루트에 새 파일이 생겼는지도 함께 살펴보아야 합니다.
업그레이드를 할 수 없을 때 해야 할 설정
운영 중인 서비스나 벤더 제품 의존성 때문에 즉시 업그레이드가 어려운 경우도 있습니다. 이때는 공격 경로를 줄이는 임시 설정을 적용할 수 있습니다. 다만 이 조치들은 특정 공격 경로에 대한 노출을 줄일 뿐, 환경을 안전하게 만들어 주지는 않습니다.
적용 위치와 재시작
설정은 php.ini, FPM 풀, 서버 설정처럼 요청 파싱 이전에 적용되는 곳에 넣고 모든 워커를 재시작해야 합니다. ini_set()이나 FPM의 .user.ini에 의존해서는 안 됩니다.
memory_limit = -1 (CVE-2026-109618)
PHP가 업데이트할 수 없을 때의 핵심 설정으로 꼽은 항목입니다.
post_max_size 축소 (CVE-2026-109618)
파일 업로드가 필요 없으면 8M, 업로드가 필요하면 32M으로 낮춥니다. upload_max_filesize는 post_max_size보다 작게 유지합니다.
웹 서버/프록시 단의 제한 (CVE-2026-109618)
웹 서버나 프록시에서 디코딩된 요청 크기, 입력 필드 수, multipart 파트 수, 헤더 수, 중첩 깊이를 제한하는 것을 고려해야 합니다.
이 제한은 Content-Length가 없는 요청에도 적용되어야 합니다. Nginx나 Apache의 기본 지시어로는 요청 본문 크기와 HTTP 헤더 정도만 제한할 수 있습니다. multipart 파트 수나 파트별 헤더 수까지 제어하려면 WAF 규칙이 필요합니다.
session.upload_progress.enabled = 0 (CVE-2026-109619)
확인된 세션 경로는 차단하지만 다른 변종까지 막지는 못합니다. 이 설정을 끄면 업로드 진행률 표시 기능은 동작하지 않습니다.
fatal_error_backtraces = 0 (CVE-2026-109619, PHP 8.5 전용)
확인된 치명적 오류 백트레이스 경로만 차단합니다.
초기화 전 진단 메시지 정리 (CVE-2026-109619)
확인된 치명적 오류 백트레이스 경로만 차단합니다.
도달 가능한 치명적 오류 수정 (CVE-2026-109619)
공격자가 유발할 수 있는 치명적 오류와 실행 시간 초과를 고쳐야 합니다. 콜백, 업로드·임포트 처리, 정리 단계에서의 실패도 포함됩니다.
인터넷 노출 차단
즉시 패치가 불가능하다면, 수정 사항을 적용하고 검증할 때까지 인터넷에 노출된 자원을 공용 네트워크에서 격리하는 것을 고려해야 합니다.
마치며
PHP2Shell은 PHP 엔진 자체의 결함입니다. 게다가 인증 없이 요청 한 번으로 코드 실행까지 이어질 수 있다는 점에서 가볍게 넘길 수 없는 취약점입니다. 문제가 애플리케이션 코드가 실행되기 전 단계에서 발생하므로, 코드를 아무리 안전하게 작성했더라도 개발 단계의 보안 점검만으로는 막을 수 없습니다.
가장 먼저 패치 버전으로 업그레이드하고, 워커를 재시작하고, 컨테이너 이미지를 다시 빌드해야 합니다.
memory_limit 해제나 세션 업로드 진행률 비활성화 같은 임시 설정은 알려진 공격 경로를 좁혀 줄 뿐입니다. 따라서 패치 전까지 시간을 버는 수단으로만 쓰고, 업그레이드 일정은 별도로 확정해 두는 것이 바람직합니다. 특히 memory_limit = -1은 컨테이너나 cgroup 메모리 제한과 함께 쓰지 않으면 가용성 문제를 새로 만들 수 있다는 점도 기억해야 합니다.
패치를 마쳤더라도 그 전에 이미 침입이 있었을 수 있습니다. 따라서 침해 흔적을 함께 점검하는 것이 좋습니다.
이번 대응을 계기로 PHP 자산 목록과 버전, 패치 경로를 정리해 두면, 다음에 엔진 수준의 취약점이 나왔을 때 훨씬 빠르게 움직일 수 있을 것입니다.





























