PHP2Shell 긴급 보안 이슈
PHP 취약점 두 개가 웹 인프라 전체의 문제가 된 이유
PHP 애플리케이션을 최신으로 유지해도 그 코드를 실행하는 PHP 런타임이 취약하면 위험은 남는다.
2026년 10월 20~21일, PHP 보안 업데이트를 앞두고 여러 국가의 보안기관과 서비스 운영사들이 긴급 대응에 나섰다.
이번 이슈는 PHP2Shell이라고 불리는 두 취약점이다.
- CVE-2026-109618: 메모리 부족 처리 과정에서 발생하는 메모리 손상
- CVE-2026-109619: 요청이 끝난 뒤 남은 내부 상태를 다음 요청에서 사용하는 문제
조건이 충족되면 인증되지 않은 공격자가 원격으로 코드를 실행할 수 있다. 두 취약점 모두 PHP 프로젝트 기준 CVSS v4.0 9.2, Critical로 평가됐다. PHP 공식 권고, NHS England 보안 공지
1. 언제 무슨 일이 있었을까?
먼저 사전 경고와 실제 패치 공개를 나눠 볼 필요가 있다.
| 10월 20일 | PHP 프로젝트가 긴급 보안 릴리스를 사전 예고 |
| 10월 21일 | 취약점 상세와 수정 버전 공개 |
| 10월 21일 이후 | 보안기관, 호스팅사, 제품 공급사가 영향 확인과 업데이트 안내 |
ENISA 공동 성명에 따르면 PHP 보안 업데이트는 10월 21일 13:40 UTC, 한국 시간으로 10월 21일 오후 10시 40분에 공개됐다. ENISA 공동 성명
공개 전에는 운영 환경을 파악하고 업데이트를 준비하라는 경고가 중심이었다. 공개 이후에는 실제 수정 버전을 적용하는 단계로 넘어갔다.
따라서 ‘패치가 곧 나온다’는 초기 공지만 읽고 대응을 기다려서는 안 된다. 현재는 수정 버전과 배포판별 보안 패키지를 확인할 수 있다.
2. 왜 PHP 사이트 운영자들이 긴장했을까?
이번 문제는 특정 플러그인의 기능 하나에 한정된 취약점이 아니다. PHP 런타임의 요청 처리와 메모리 관리에 관련된 문제다.
구조를 단순화하면 다음과 같다.

외부 HTTP 요청
↓
웹 서버와 PHP 실행 환경
↓
PHP 내부의 요청 초기화·처리·정리
↓
애플리케이션 코드
특히 Apache의 mod_php에서 검증된 경로는 애플리케이션 코드가 시작되기 전에 공격이 발생할 수 있다.
로그인 검사나 프레임워크의 입력 검증이 실행되기 전 단계가 문제가 될 수 있다는 뜻이다.
PHP 공식 권고는 웹 요청을 처리하는 PHP 환경 전반을 점검 대상으로 안내하며 mod_php의 위험을 특히 높게 평가한다. PHP 공식 영향 범위
다만 모든 PHP 서비스에서 같은 요청 하나로 즉시 공격이 성공한다는 의미는 아니다. 실행 방식, 설정, 빌드, 확장 모듈, 애플리케이션 동작에 따라 구체적인 공격 조건이 달라진다.
3. CVE-2026-109618: 메모리가 부족해졌을 때
첫 번째 취약점의 공식 이름은 RCE via OOM corruption이다.
OOM은 Out of Memory, 메모리 부족을 뜻한다.
PHP는 요청을 처리하면서 필요한 메모리를 할당한다. 그런데 일부 내부 데이터는 완전히 초기화되기 전에도 다른 코드가 접근할 수 있는 상태가 된다.
이 시점에 메모리 부족으로 처리가 중단되면 다음 문제가 생길 수 있다.

내부 데이터 생성 시작
↓
초기화가 끝나기 전에 메모리 부족 발생
↓
현재 작업이 비정상적으로 중단
↓
요청 정리 코드가 불완전한 데이터를 정상 데이터처럼 사용
↓
메모리 손상
공식 권고는 PHP의 OOM 처리에 사용되던 longjmp()가 일부 문맥에서 안전하지 않은 조기 이탈을 일으키는 문제를 설명한다.
검증된 영향에는 웹 워커 계정 권한으로 실행되는 비인증 원격 코드 실행이 포함된다. mod_php에서는 기본 입력과 메모리 제한을 사용하는 환경에서도 HTTP를 통한 공격이 검증됐다. CVE-2026-109618 공식 기술 권고
메모리 부족이 왜 코드 실행으로 이어질까?
보통 메모리가 부족하면 요청이 실패하거나 프로세스가 종료될 것으로 예상한다.
하지만 불완전한 데이터를 정상적인 내부 구조로 해석하면 프로그램이 잘못된 메모리를 읽거나 그 값에 따라 동작할 수 있다. 즉, 공격자가 영향을 주는 입력과 메모리 배치가 결합하면 단순 장애를 넘어설 가능성이 생긴다.
이 취약점의 핵심은 요청 크기 자체보다 실패한 뒤에도 내부 상태를 안전하게 처리하는가에 있다.
4. CVE-2026-109619: 끝난 요청의 메모리를 다음 요청이 사용
두 번째 취약점은 RCE via stale global state다.
PHP 웹 워커는 하나의 요청을 처리한 뒤 다른 요청을 처리하도록 재사용될 수 있다. 각 요청의 메모리는 정리되더라도 워커 프로세스는 계속 살아 있는 구조다.
문제는 요청에 속한 데이터를 가리키는 내부 상태가 적절하게 초기화되지 않고 남는 경우다.

요청 A가 내부 상태 생성
↓
오류 등으로 정상적인 초기화, 정리 흐름 중단
↓
요청 A의 메모리는 해제
↓
워커에는 그 메모리를 가리키는 상태가 남음
↓
같은 워커가 요청 B를 처리
↓
이미 해제된 메모리를 사용
이런 문제를 Use-After-Free, 해제 후 사용이라고 부른다.
공식 권고에서는 메모리 노출과 원격 코드 실행을 확인했다. 공격을 일으키는 요청과 남은 상태를 사용하는 요청이 같은 워커에 도달해야 하는 등 조건이 존재한다. CVE-2026-109619 공식 기술 권고
이 문제는 두 사용자가 같은 애플리케이션 세션을 공유한다는 설명과 다르다. PHP 내부의 상태와 메모리 수명 관리가 요청 경계를 넘어 잘못 이어지는 문제다.
5. Apache와 PHP-FPM
공식 기술 권고는 실행 환경별 차이를 설명한다.
| Apache mod_php | 애플리케이션 실행 전 경로를 포함해 공격이 검증됨 |
| PHP-FPM | 초기화 실패 시 워커 종료 등 차이가 있지만 안전하다고 볼 수 없음 |
| FrankenPHP·LiteSpeed 등 | 실행 방식별 조건이 다르며 공식 권고상 점검 대상 |
첫 번째 취약점에서 FPM은 요청 시작 실패 시 자식 프로세스를 종료하기 때문에 mod_php와 똑같은 경로가 유지되지 않는다. 다만 애플리케이션 실행 단계의 메모리 부족 경로 등은 별도로 고려해야 한다. OOM 취약점의 환경별 설명
두 번째 취약점에서는 FPM에서도 세션 생명주기와 관련된 RCE가 검증됐다. 해당 경로는 적절한 애플리케이션 동작에 의존한다. 상태 재사용 취약점의 검증 범위
따라서 ‘Nginx와 FPM을 쓰니까 괜찮다’고 판단하면 안 된다. 반대로 모든 실행 환경에서 공격 재현 조건이 동일하다고 설명하는 것도 부정확하다.
6. 공격이 실제로 발생하고 있을까?
여기서는 세 가지를 나눠야 한다.
| 취약점 재현 | 연구자가 통제된 환경에서 공격 성공 |
| 공격 시도 관측 | 실제 네트워크에서 관련 공격 트래픽 확인 |
| 침해 확인 | 특정 시스템에서 공격 성공과 피해 확인 |
Cloudflare는 공개 전후에 관련 공격 트래픽을 관측했고, 공격자가 방어를 우회하려고 입력을 변경하는 움직임도 확인했다고 밝혔다. Cloudflare 대응 보고
이것은 현실의 공격 시도가 있다는 근거다. 그러나 그 사실만으로 모든 시도가 성공했거나 특정 규모의 사이트가 침해됐다고 단정할 수는 없다.
취약점이 존재하는 것과 내 서버가 이미 침해됐는지는 별도의 조사 문제다.
7. 어떤 버전으로 업데이트해야 할까?
이번 두 취약점을 수정한 PHP 프로젝트의 버전은 다음과 같다.
| PHP 8.2 | 8.2.35 |
| PHP 8.3 | 8.3.36 |
| PHP 8.4 | 8.4.27 |
| PHP 8.5 | 8.5.12 |
해당 계열에서는 이 수정 버전 또는 이후의 적절한 보안 릴리스를 적용해야 한다. NHS England 수정 버전 안내
배포판 버전은 숫자만 비교하면 안 된다
Ubuntu와 Red Hat 같은 공급사는 기존 버전에 보안 수정만 가져오는 백포트를 제공할 수 있다.
예를 들어 Ubuntu는 이번 문제에 대해 Ubuntu 24.04 LTS용 8.3.6-0ubuntu0.24.04.13 패키지를 수정 패키지로 안내한다. 앞부분이 8.3.6이라고 해서 곧바로 미패치라고 판단하면 안 되는 이유다. Ubuntu USN-8948-1
판단 기준은 다음 두 가지다.
직접 설치한 PHP
→ PHP 프로젝트의 수정 버전 확인
배포판·제품 공급사가 관리하는 PHP
→ 해당 공급사의 보안 공지와 패키지 전체 버전 확인
PHP 8.1 이하를 사용한다면?
PHP 프로젝트의 정규 지원은 끝났지만, 일부 배포판과 LTS 공급사는 백포트 수정을 제공한다.
이번에는 심각성을 고려해 PHP 7.4, 8.0, 8.1의 최소 소스 백포트도 별도로 제공됐다. 이는 해당 계열의 정규 지원이 재개됐다는 뜻은 아니다. 공급사 패치 여부를 확인하고 지원 버전으로 이전할 계획이 필요하다. PHP 공식 업데이트 안내
8. 우리 서비스에서 PHP를 어디에 쓰는지부터 찾아야 한다
직접 작성한 PHP 사이트만 확인하면 빠뜨리는 자산이 생길 수 있다.
점검 대상에는 다음이 포함될 수 있다.
- 웹서비스와 CMS
- 관리 콘솔과 내부 도구
- 컨테이너 이미지
- 상용·오픈소스 제품에 포함된 PHP
- 호스팅 사업자가 관리하는 실행 환경
- 오래된 테스트·스테이징 서비스
ENISA도 PHP를 직접 사용하는 것처럼 보이지 않는 제품에 PHP가 포함될 수 있다고 지적하며 공급사와 영향 여부를 확인하도록 권고한다. ENISA 영향 확인 지침
php -v만 확인하면 충분할까?
다음 명령은 기본적인 확인에 도움이 된다.
php -v
php --ini
각각 명령줄 PHP의 버전과 설정 파일 정보를 보여준다. PHP 명령줄 공식 문서
하지만 명령줄에서 실행되는 PHP와 실제 웹 요청을 처리하는 PHP가 다를 수 있다.
여러 버전이 설치됐거나 컨테이너, FPM 풀, 웹 서버 모듈이 분리된 환경에서는 특히 주의해야 한다. 확인할 대상은 현재 사용자 요청을 처리하는 프로세스와 이미지다.
phpinfo()로 설정을 확인할 수도 있지만 환경정보와 경로 등이 출력되므로 점검 정보를 공개 페이지로 노출하지 않도록 해야 한다. PHP phpinfo() 문서
9. 패키지 설치가 끝나면 대응도 끝날까?
업데이트 파일이 설치됐다는 사실과 실행 중인 워커가 수정된 코드를 사용한다는 사실은 다르다.
다음은 대응을 정리하기 위한 운영 흐름이다.
PHP 사용 자산 파악
↓
공급사 수정 패키지·이미지 확인
↓
업데이트 및 필요한 재배포
↓
기존 워커 교체·재시작 확인
↓
실제 서비스 환경 재확인
↓
기능·오류율·보안 로그 확인
컨테이너 환경에서는 새 이미지를 만들었더라도 기존 파드가 계속 서비스할 수 있다. 로드밸런서 뒤에 서버가 여러 대 있다면 일부 인스턴스만 업데이트됐을 수도 있다.
운영 기록에는 적어도 다음 내용을 남기면 좋다.
| 실행 버전 | 웹 요청을 처리하는 PHP의 실제 버전 |
| 수정 근거 | 공급사 공지·패키지·이미지 정보 |
| 적용 범위 | 서버·풀·컨테이너 전체 반영 여부 |
| 프로세스 | 이전 워커가 남아 있는지 |
| 기능 확인 | 로그인·업로드·배치 등 주요 기능 |
| 복구 계획 | 문제가 생겼을 때 사용할 안전한 대안 |
롤백이 필요하더라도 취약한 이전 버전을 외부에 그대로 재노출하는 결과가 되지 않도록 계획해야 한다.
10. 바로 업데이트하기 어렵다면 어떻게 해야 할까?
PHP 공식 권고는 업데이트만이 완전한 해결책이라고 명시한다.
일부 설정 변경은 특정 경로의 위험을 줄일 수 있지만 전체 취약점을 제거하지 못한다. 예를 들어 세션 업로드 진행률 기능 비활성화는 확인된 일부 경로에 대한 조치이며 다른 내부 상태 문제까지 해결하지 않는다. PHP 공식 완화 지침
ENISA와 영국 NCSC는 즉시 수정이 어려운 경우 노출된 시스템의 격리나 일시적인 오프라인 전환을 검토하도록 안내한다. ENISA 권고, NCSC 권고
또한 이번 문제에서는 일반적인 설정 직관을 그대로 적용하기 어렵다.
- 메모리 제한을 더 낮추면 안전하다고 단정할 수 없다.
- 오류 메시지를 숨기는 것은 내부 상태 오류를 해결하지 않는다.
- 애플리케이션 코드에서 설정을 바꾸기 전에 취약한 처리가 시작될 수 있다.
특히 OOM 관련 임시 설정은 가용성과 자원 제한에도 영향을 준다. 공식 권고의 전제와 한계를 함께 읽어야 한다.
WAF가 있으면 업데이트를 미뤄도 될까?
Cloudflare는 WAF 보호를 배포했다고 발표하면서도 PHP 패치를 적용하라고 권고한다.
WAF는 추가 방어 계층이다. 공격 변형과 서비스 경로를 고려해야 하며, 요청이 WAF를 우회해 원본 서버에 직접 도달하는 구조라면 보호 범위도 달라진다. Cloudflare의 보호 범위와 패치 권고
11. 어떤 로그를 살펴봐야 할까?
공식 기술 권고는 오류와 설정 점검을 함께 수행하도록 설명한다.
살펴볼 자료의 예시는 다음과 같다.
- PHP·웹 서버·리버스 프록시 오류 로그
- 메모리 부족과 워커 비정상 종료
- 반복되는 치명적 오류와 실행시간 초과
- 초기화나 종료 과정의 경고
- 특정 경로·입력 유형에 집중되는 실패
다만 이런 증상은 정상적인 장애에서도 발생할 수 있다. 오류가 있다는 사실만으로 침해를 확정할 수 없고, 오류가 없다고 안전을 보장할 수도 없다. 기록되기 전에 실패하거나 관련 로그 수준이 비활성화돼 있을 수 있다. 공식 로깅·설정 감사 지침
침해 징후가 있다면 취약점 수정과 사고 대응을 나눠 진행해야 한다.
업데이트는 앞으로 같은 취약점이 악용되는 경로를 막지만, 이미 변경된 파일이나 탈취된 비밀정보를 원래 상태로 돌리지는 않는다. 이 경우 로그와 증거를 보존하고 관련 계정과 키, 서버 상태를 조사하는 절차가 필요하다.
12. AI가 발견했다는 점은 어떻게 봐야 할까?
이번 사건이 크게 주목받은 이유 중 하나는 AI를 활용한 취약점 발견이다.
OpenAI의 공개 설명에 따르면 Calif가 AI를 활용해 취약점을 발견했고, Wiz도 두 취약점을 독립적으로 발견하고 보고했다. PHP 유지보수자들이 수정과 릴리스를 주도했으며 여러 연구팀과 보안 조직이 대응에 참여했다. OpenAI의 공동 대응 설명
이 사례에서 확인되는 것은 AI 기반 탐색과 사람이 함께 검증했다는 사실이다.
이것만으로 AI가 모든 취약점을 찾을 수 있다거나 사람이 보안 검토를 할 필요가 없어졌다고 결론 내릴 수는 없다.
운영 관점에서는 다른 질문이 중요해진다.
취약점 발견이 빨라졌을 때 우리 조직은 노출된 자산을 찾고 수정하는 속도도 따라갈 수 있을까?
13. 이번 사건에서 남는 운영 과제
PHP2Shell은 애플리케이션 코드 바깥의 런타임도 보안 관리 대상이라는 사실을 보여준다.
대응력을 점검하려면 다음 질문에 답할 수 있어야 한다.
| PHP가 어디에 있는가? | 자산과 실행 환경 관리 |
| 어떤 수정이 필요한가? | 공급사 권고·백포트 해석 |
| 전부 적용됐는가? | 프로세스·컨테이너·서버 검증 |
| 즉시 적용이 어려우면? | 노출 축소와 서비스 운영 결정 |
| 이미 악용됐다면? | 로그·탐지·사고 대응 |
| 다시 발생하면? | 반복 가능한 긴급 패치 절차 |
이번 사건의 우선순위는 실제로 웹 요청을 처리하는 PHP를 찾아 수정된 실행 환경으로 교체하는 것이다. 이후에는 패치가 모든 인스턴스에 반영됐는지 기존 노출 기간에 이상 징후가 있었는지까지 확인해야 한다.
참고 자료