PHP2Shell 소식을 접하고 개인적으로 운영하는 PHP 서비스들의 실행 환경을 정리했다. 보안 패치가 들어간 지원 버전으로 옮기면서 오래된 코드의 호환성을 고치고, 실제 웹 요청이 새 환경으로 연결되는지도 확인했다. 보안 업데이트와 레거시 유지보수가 함께 따라온 작업이었다.
대응 과정에서 손이 많이 간 부분은 오래된 서비스가 새 환경에서도 제 역할을 하는지 확인하는 일이었다. 내부 주소나 서버 구성도는 빼고, 비슷한 서비스를 운영할 때 참고할 만한 확인 과정을 남긴다.
PHP2Shell은 어떤 문제인가
PHP2Shell은 CVE-2026-109618과 CVE-2026-109619를 함께 부르는 이름이다. 인증되지 않은 원격 공격자가 코드를 실행할 수 있는 PHP 핵심부의 취약점 두 건으로, 공식 발표는 2026년 10월 21일에 나왔다. 싱가포르 사이버보안청은 두 건의 심각도를 CVSS v4.0 기준 9.2로 안내했다. 보안기관 공지
하나는 메모리 부족 오류를 처리하다가 내부 상태가 불완전하게 남는 문제이고, 다른 하나는 요청이 끝나 해제된 메모리를 다음 요청에서 다시 참조할 수 있는 문제다. 특정 게시판의 입력값 검증 실수에만 한정된 이야기가 아니다. PHP 자체가 요청을 처리하는 과정에 문제가 있다는 점 때문에 실행 환경부터 확인해야 했다. 메모리 부족 처리 취약점 · 요청 사이에 남는 상태의 취약점
PHP 공식 공지는 PHP-FPM을 포함한 여러 웹 실행 방식을 대상으로 명시한다. mod_php에서 위험이 특히 크다고 해서 다른 방식은 확인하지 않아도 된다는 뜻은 아니다. 이 두 취약점의 수정 버전은 PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12다. 오래된 버전은 배포판이나 장기 지원 업체의 백포트 여부까지 확인해야 하므로, 버전 계열 이름만 보고 안전하다고 판단할 수 없다. PHP 공식 보안 공지
먼저 어느 PHP가 웹 요청을 처리하는지 봤다
한 서버에서 오래 운영한 서비스라고 해서 전부 같은 PHP로 동작하는 것은 아니었다. 기본 설정을 따라가는 사이트도 있고, 호환성 때문에 별도 버전을 지정해 둔 사이트도 있었다. 기본 PHP만 바꾸면 일부 서비스는 예전 실행 환경에 그대로 남을 수 있는 구조였다.
그래서 실제로 활성화된 웹서버 설정, 사이트별 처리 규칙, 실행 중인 PHP 프로세스를 함께 확인했다. 명령행에서 출력되는 버전과 브라우저 요청을 처리하는 버전은 따로 대조했다. 설치 파일이 남아 있는 것과 웹 요청에 사용되는 것도 구분했다.
이번 작업의 완료 기준은 대상 서비스가 패치된 지원 버전으로 연결되고, 구버전으로 웹 요청을 보내는 설정이나 실행 중인 구버전 처리기가 남지 않는 것이었다. 새 PHP가 설치됐다는 사실만으로 전환을 끝내지는 않았다.
원본을 기준으로 호환성을 비교했다
기존 소스와 설정을 먼저 보존하고 별도 시험 환경에서 실행했다. 처음부터 여러 부분을 한꺼번에 고치면 문제가 사라져도 무엇 때문인지 알기 어렵다. 우선 원본의 동작을 확인하고, 새 PHP에서 달라지는 부분을 좁혀 나갔다.
오래된 서비스에서는 제거된 문법이나 함수, 더 엄격해진 함수 호출과 타입 처리처럼 실행 환경 변화에 걸리는 부분이 나왔다. 실제로 필요한 호환성 수정을 적용했고, 기존 코드가 지키던 인증과 데이터 처리 동작도 함께 살폈다.
로그인, 글 편집, 첨부파일처럼 데이터를 쓰는 기능은 복제한 시험 환경에서 확인했다. 시험을 위해 운영 계정의 비밀번호를 바꾸거나 실제 게시물을 덮어쓰는 방식은 쓰지 않았다. 시험 환경의 DB 동작 조건도 운영과 맞춰, 환경 차이로 생긴 오류를 PHP 호환성 문제로 잘못 분류하지 않도록 했다.
이전부터 실패하던 경로와 새 버전에서 생긴 오류도 따로 비교했다. 이번 전환 때문에 생긴 문제는 수정했고, 별도로 손본 기존 오류는 그 사실을 구분해 기록했다. 오래된 서비스의 모든 오류를 업데이트 탓으로 돌리면 원인도 수정 범위도 흐려진다.
응답이 왔다는 것만으로는 부족했다
HTTP 200이 돌아와도 본문이 비어 있을 수 있다. JSON이어야 하는 응답에 다른 내용이 들어가도 상태 코드만 보면 놓친다. 실제로 데이터를 받아 쓰는 기능은 본문을 파싱하고 기대한 구조가 있는지 확인해야 했다.
반대로 인증되지 않은 요청에 접근을 거절하거나 잘못된 입력에 오류를 반환하는 것은 정상 동작일 수 있다. 성공 코드의 개수를 세기보다 원래 그 요청에서 기대한 결과와 맞는지를 봤다.
| 확인한 것 | 그 결과로 알 수 있는 범위 |
|---|---|
| 새 PHP의 설치와 구문 검사 | 실행 파일과 소스 문법의 준비 상태 |
| 실제 웹 요청의 실행 환경 | 사이트가 새 PHP로 연결됐는지 |
| 응답 본문과 기대한 데이터 구조 | 검사한 API가 필요한 결과를 돌려주는지 |
| 격리 환경의 로그인·편집·업로드 | 시험한 쓰기 흐름이 새 환경에서도 동작하는지 |
API 데이터가 나온 결과, 실시간 연결이 성립한 결과, 브라우저에서 기능을 끝까지 사용한 결과도 각각 구분했다. 어느 하나가 통과했다고 전체 기능을 확인한 것으로 묶지는 않았다.
후속 공지는 적용 조건을 다시 대조했다
10월 23일에는 세션 업로드 진행률 기능에 관한 후속 공지가 나왔다. 초기 세션 직렬화 설정과 애플리케이션 실행 중의 설정 변경이 특정하게 조합돼야 하는 문제였다. PHP 세션 업로드 진행률 후속 공지
이 부분은 현재 PHP 설정과 배포된 소스를 다시 읽고, 실행 중인 PHP에 보내는 비공개 진단 요청으로 확인했다. 점검한 운영·시험 환경에서는 공지의 발생 조건에 해당하지 않았다. 따라서 이 후속 문제 때문에 추가 설정을 바꾸거나 서비스를 재시작하지 않았다.
일반 파일 업로드와 PHP가 세션에 업로드 진행률을 기록하는 기능도 나눠서 봤다. 후속 점검에서는 작은 파일을 이용해 PHP의 기본 업로드 처리를 확인했으며, 이것을 운영 게시물에 첨부파일을 쓰는 전체 시험으로 표현하지는 않았다. 임시 진단 파일은 확인 후 제거했다.
이번 대응을 마친 기준
대상 서비스들을 보안 패치가 포함된 지원 PHP 환경으로 전환했고, 기존 구버전이 웹 요청을 계속 처리하지 않는 것까지 확인했다. 호환성 수정과 시험을 거쳐 운영에 반영했으며, 이후의 후속 공지도 현재 구성에 대조했다. 웹서버 보안 업데이트도 별도로 진행했다.
이 기록은 PHP2Shell 대응과 그에 따른 서비스 전환에 관한 것이다. 과거 침해가 없었다는 조사 결과나 모든 애플리케이션의 보안 감사를 뜻하지는 않는다. 운영 서버에 공격 코드를 실행해 확인하는 방식도 사용하지 않았다.
오래된 서비스는 실행 환경을 바꾸는 순간 코드의 호환성 문제가 한꺼번에 드러날 수 있다. 이번에는 원본과 바뀐 환경을 비교하고, 데이터를 쓰는 시험은 분리하고, 실제 웹 요청이 새 환경을 사용하는 데까지 확인했다. 변경 내역과 되돌릴 지점도 별도로 남겨 두었다.