2026년 10월 21일, PHP 개발팀이 인증되지 않은 공격자의 원격 코드 실행(RCE)을 허용할 수 있는 치명적인 보안 취약점 2건을 수정한 업데이트를 공개했습니다. 취약점은 CVE-2026-109618과 CVE-2026-109619이며, PHP2Shell이라는 이름으로도 알려져 있습니다. 두 취약점 모두 CVSS v4.0 기준 9.2점(Critical)으로 평가되었습니다. 이번 문제는 WordPress 플러그인이나 테마가 아닌 PHP 실행 엔진 자체의 취약점이라는 점에서 특히 주의해야 합니다. 취약한 환경에서 공격에 성공하면 웹셸 설치, 홈페이지 변조, 데이터 유출, 시스템 손상으로 이어질 수 있습니다.
저 역시 이번 발표 직후 직접 관리하는 Debian 12 기반 WordPress 서버 두 대를 점검하고 PHP 보안 업데이트를 적용했습니다. 이 글에서는 실제 대응 과정에서 사용했던 명령어와 실행 결과를 바탕으로 PHP 취약 버전 확인, 안전한 업데이트, PHP-FPM 재시작, WordPress 정상 동작 검증 및 침해 흔적 점검 방법을 정리합니다.
핵심 요약: PHP 8.2는 8.2.35 이상, PHP 8.3은 8.3.36 이상, PHP 8.4는 8.4.27 이상, PHP 8.5는 8.5.12 이상으로 업데이트해야 합니다. 단, 배포판이 보안 수정사항을 백포트한 경우에는 전체 패키지 버전과 보안 공지를 확인해야 합니다. 업데이트 후 실제 웹 요청을 처리하는 PHP 프로세스를 반드시 재시작하세요.
1. PHP2Shell 취약점은 무엇인가요?
PHP2Shell은 PHP의 HTTP 요청 처리 과정에서 발생하는 메모리 관련 취약점 두 건을 가리키는 명칭입니다. 일반적인 웹사이트 공격은 로그인 기능, 게시판, 플러그인처럼 개별 애플리케이션의 취약점을 노리는 경우가 많습니다. 그러나 이번 문제는 그보다 아래 계층인 PHP 런타임 자체에서 발생합니다.
CVE-2026-109618 — 메모리 부족 처리 과정의 취약점
PHP가 요청을 처리하는 중 메모리 부족(OOM) 상황을 만나 비정상적으로 처리를 중단하면, 일부 메모리 상태가 올바르게 정리되지 않을 수 있습니다. 이후 요청 종료 과정에서 잘못된 메모리 상태를 사용하면서 원격 코드 실행으로 이어질 가능성이 있습니다. 특히 Apache의 mod_php 구성에서는 애플리케이션 코드가 실행되기 전에도 영향을 받을 수 있다는 점이 중요합니다.
CVE-2026-109619 — 이전 요청의 메모리 상태 재사용 문제
PHP 작업 프로세스가 이전 HTTP 요청의 메모리를 해제한 후에도 일부 내부 상태를 잘못 유지할 수 있습니다. 동일한 프로세스가 후속 요청을 처리하면서 이미 해제된 메모리를 참조하는 문제(Use-after-free)가 발생하며, 특정 조건에서 원격 코드 실행으로 이어질 수 있습니다. 이 두 취약점은 서로 다른 결함이지만, 결과적으로 취약한 PHP 웹 실행 환경을 공격자가 악용할 수 있다는 공통점이 있습니다. 중요한 것은 PHP-FPM을 사용한다고 해서 자동으로 안전해지는 것은 아니라는 점입니다. PHP-FPM, Apache mod_php, PHP-CGI 등 실제 사용 중인 실행 환경에 수정 패치를 적용해야 합니다.
2. 영향을 받는 PHP 버전과 해결 버전
PHP 개발팀이 2026년 10월 21일 공개한 수정 버전은 다음과 같습니다.
| PHP 계열 | 취약한 공식 버전 범위 | 최초 수정 버전 |
|---|---|---|
| PHP 8.2 | 8.2.35 미만 | 8.2.35 |
| PHP 8.3 | 8.3.36 미만 | 8.3.36 |
| PHP 8.4 | 8.4.27 미만 | 8.4.27 |
| PHP 8.5 | 8.5.12 미만 | 8.5.12 |
위 수정 버전은 CVE-2026-109618과 CVE-2026-109619 모두에 적용됩니다. PHP 8.1 이하는 공식 보안 지원이 종료된 상태이므로 지원 중인 PHP 계열로 전환하는 것이 필요합니다. 또한 PHP 8.2는 2026년 12월 31일 보안 지원 종료가 예정되어 있습니다. 당장 PHP 8.2.35로 취약점을 수정하더라도 장기적으로 PHP 8.3 이상으로 전환할 계획을 세우는 것이 좋습니다. Ubuntu·Debian 등의 배포판은 기존 버전 번호를 유지하면서 보안 수정사항을 반영하는 백포트(Backport)를 제공하기도 합니다. 따라서 표시되는 PHP 버전만으로 취약 여부를 단정해서는 안 됩니다.
3. 실제 서버에서 PHP 버전 확인하기
이제 SSH로 Linux 서버에 접속해 점검해 보겠습니다. 이 글의 명령어는 주로 Debian 12와 Ubuntu의 APT 패키지 기반 Apache + PHP-FPM 환경을 대상으로 합니다. Bitnami에 자체 포함된 PHP, Docker, cPanel, Plesk 또는 다른 호스팅 환경에서는 업데이트 방법이 다를 수 있습니다.
3-1. 서버 운영체제 확인
hostname
cat /etc/os-release예시 출력:
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
VERSION_ID="12"
운영체제를 먼저 확인해야 적절한 패키지 관리 방식과 저장소를 선택할 수 있습니다.
3-2. PHP CLI 버전 확인
php -v예시:
PHP 8.5.11 (cli) (built: Sep 24 2026) (NTS)
이 경우 공식 PHP 8.5 계열의 수정 버전인 8.5.12보다 낮으므로 보안 업데이트가 필요합니다. 하지만 여기서 끝내면 안 됩니다. php -v는 명령행(CLI) PHP 버전이지 실제 웹 서버의 PHP 버전이라는 보장은 없습니다.
3-3. 실제 PHP-FPM 프로세스 확인
ps -eo pid,comm,args | grep '[p]hp-fpm'실제 점검 당시 확인한 예시입니다.
49586 php-fpm8.5 php-fpm: master process
331229 php-fpm8.5 php-fpm: pool www
331315 php-fpm8.5 php-fpm: pool www
이 결과는 PHP 8.5-FPM이 실행 중임을 의미합니다.
서비스 상태도 확인합니다.
systemctl list-units --type=service --all \
| grep -Ei 'php.*fpm|apache2|nginx'예시:
apache2.service loaded active running
php8.5-fpm.service loaded active running
Apache와 PHP-FPM이 모두 실행되고 있음을 확인할 수 있습니다.
3-4. Apache가 어떤 PHP를 사용하는지 확인
sudo apache2ctl -M 2>&1 \
| grep -Ei 'php|proxy_fcgi|mpm_'예시:
mpm_event_module (shared)
proxy_fcgi_module (shared)
이는 Apache가 FastCGI 프록시 모듈을 사용하도록 구성되었다는 의미입니다. 다만 이 출력만으로 특정 사이트가 어느 PHP-FPM 버전에 연결되었는지 확정할 수는 없습니다.
실제 연결 설정을 추가로 확인합니다.
sudo grep -RhsE \
'SetHandler|ProxyPassMatch|proxy:unix:' \
/etc/apache2/sites-enabled \
/etc/apache2/conf-enabled \
2>/dev/null예시:
SetHandler "proxy:unix:/run/php/php8.5-fpm.sock|fcgi://localhost"
이 경우 Apache는 해당 설정이 적용되는 PHP 요청을 PHP 8.5-FPM 소켓으로 전달합니다. 서버에 여러 사이트가 있다면 각 가상호스트의 설정을 따로 확인해야 합니다.
3-5. 설치된 PHP 패키지 전체 확인
dpkg-query -W \
-f='${binary:Package} ${Version}\n' \
2>/dev/null \
| grep -E '^(php8\.|libapache2-mod-php8\.)'예시:
php8.5-cli 8.5.11-1+0~debian12
php8.5-common 8.5.11-1+0~debian12
php8.5-fpm 8.5.11-1+0~debian12
php8.5-mysql 8.5.11-1+0~debian12
실제 서비스에 사용되지 않는 PHP도 별도로 설치되어 있을 수 있습니다. 제 경우 한 서버에는 PHP 8.2와 PHP 8.3이 함께 설치되어 있었고, 다른 서버는 PHP 8.5만 사용하고 있었습니다. 각각의 설치 상태를 확인한 후 필요한 버전만 업데이트했습니다.
4. PHP 업데이트 전 백업 및 저장소 확인
운영 중인 웹사이트에서는 보안 패치가 긴급하더라도 업데이트 전에 복구 수단을 확보하는 것이 좋습니다. 가능하다면 클라우드 인스턴스 스냅샷과 WordPress 파일·데이터베이스 백업을 생성하세요. PHP와 Apache 설정은 다음 명령으로 별도 보관할 수 있습니다.
BACKUP="/root/php-config-$(date +%Y%m%d-%H%M%S).tar.gz"
sudo tar -czf "$BACKUP" \
/etc/php \
/etc/apache2
sudo ls -lh "$BACKUP"예시 출력:
-rw-r--r-- 1 root root 118K php-config-20261022-013837.tar.gz
이 백업에는 PHP 및 Apache 설정만 포함됩니다. WordPress 파일과 데이터베이스까지 백업되는 것은 아닙니다.
이어서 APT 저장소 목록을 갱신합니다.
sudo apt-get update설치 가능한 PHP 버전을 확인합니다.
apt-cache policy php8.5-fpm예시:
php8.5-fpm:
Installed: 8.5.11-1+0~20260924...
Candidate: 8.5.12-1+0~20261021...
Installed는 현재 설치된 패키지이고 Candidate는 APT가 설치 후보로 선택한 버전입니다. 이 경우 PHP 8.5.12로 업데이트할 수 있습니다. 반대로 수정 버전이 표시되지 않는다면 저장소 구성이나 공급업체의 백포트 여부를 먼저 확인해야 합니다.
5. PHP를 안전하게 업데이트하는 방법
이번 대응에서 가장 주의했던 부분입니다. 처음에 설치된 여러 PHP 계열의 패키지를 한꺼번에 업데이트하려고 시뮬레이션했더니 예상하지 못한 PHP 8.4와 PHP 8.5가 신규 설치 대상으로 나타났습니다. 특히 php, php-mysql, libapache2-mod-php 등 버전이 고정되지 않은 메타 패키지가 다른 PHP 계열의 신규 설치를 유발할 수 있습니다. 운영 중인 서버에서는 이런 변경이 서비스 구성에 영향을 줄 수 있습니다. 따라서 기존에 설치된 PHP 계열의 패키지만 선택하여 업데이트하는 방식으로 진행했습니다.
5-1. 업데이트 대상 버전 지정
예를 들어 PHP 8.5를 업데이트한다면 다음과 같이 설정합니다.
PHP_VERSION="8.5"서버에서 PHP 8.3을 사용한다면 8.3으로 변경합니다.
5-2. 해당 PHP 계열의 설치 패키지 수집
mapfile -t PHP_PKGS < <(
dpkg-query -W \
-f='${binary:Package} ${db:Status-Abbrev}\n' \
2>/dev/null |
awk -v v="$PHP_VERSION" '
$2 == "ii" && (
$1 == "php" v ||
index($1, "php" v "-") == 1 ||
$1 == "libapache2-mod-php" v
) { print $1 }
'
)
printf '%s\n' "${PHP_PKGS[@]}"이렇게 하면 현재 설치된 PHP 8.5 패키지 목록을 확인할 수 있습니다.
예시:
php8.5-cli
php8.5-common
php8.5-fpm
php8.5-curl
php8.5-gd
php8.5-mysql
php8.5-redis
php8.5-imagick
libapache2-mod-php8.5
목록은 서버마다 다릅니다.
5-3. 반드시 업데이트 시뮬레이션 실행
실제 설치하기 전에 다음 명령으로 패키지 변경사항을 확인합니다.
sudo apt-get -s install --only-upgrade \
"${PHP_PKGS[@]}"Mindmapia 서버에서 확인했던 핵심 결과는 다음과 같았습니다.
The following packages will be upgraded:
libapache2-mod-php8.5 php8.5-cli
php8.5-common php8.5-fpm ...
13 upgraded, 0 newly installed,
0 to remove and 3 not upgraded.
여기서 확인해야 할 항목은 다음과 같습니다.
- 필요한 PHP 패키지가 목표 버전으로 업그레이드되는가?
- 원하지 않은 PHP 버전이 신규 설치되지 않는가?
- PHP-FPM 또는 주요 확장 모듈이 삭제되지 않는가?
- 다른 패키지의 의존성 변경이 발생하는가?
0 newly installed, 0 to remove는 해당 환경에서 변경 범위가 제한되어 있음을 보여줍니다. 다만 신규 의존성이 필요할 수도 있으므로 이 숫자가 항상 0이어야 한다는 의미는 아닙니다.
특히 예상하지 못한 패키지 삭제나 PHP 계열 변경이 보이면 실행을 중단하고 원인을 확인하세요.
5-4. 실제 PHP 업데이트 진행
시뮬레이션 결과를 검토했다면 다음 명령으로 업데이트합니다.
sudo apt-get install --only-upgrade \
"${PHP_PKGS[@]}"예상 출력:
13 upgraded, 0 newly installed,
0 to remove and 3 not upgraded.
Unpacking php8.5-fpm (8.5.12...)
over (8.5.11...)
Setting up php8.5-common (8.5.12...)
Setting up php8.5-cli (8.5.12...)
Setting up php8.5-fpm (8.5.12...)
업데이트 중 기존 php.ini 설정을 유지할지 묻는 화면이 나타날 수 있습니다.
기존 서버에서 업로드 제한, 메모리 제한, 타임존 등을 사용자 정의했다면 설정 차이를 검토하고 기존 설정을 유지할지 결정하세요.
저는 실제 서버의 기존 설정을 유지한 뒤, 업데이트 후 설정 파일의 차이를 확인했습니다.
6. 업데이트 후 PHP-FPM 재시작 및 서비스 검증
패키지를 업데이트했다고 모든 작업이 끝나는 것은 아닙니다.
기존 PHP 프로세스가 메모리에 남아 있으면 수정된 바이너리가 실제 요청에 반영되지 않을 수 있습니다.
6-1. PHP-FPM 버전 확인
PHP 8.5 기준:
php8.5 -v | head -n 1
sudo /usr/sbin/php-fpm8.5 -v | head -n 1실제 확인한 결과:
PHP 8.5.12 (cli)
PHP 8.5.12 (fpm-fcgi)
CLI와 PHP-FPM 모두 수정 버전이 표시됩니다.
6-2. PHP-FPM과 Apache 설정 검사
sudo /usr/sbin/php-fpm8.5 -t
sudo apache2ctl configtest정상 결과:
configuration file ... test is successful
Syntax OK
6-3. PHP-FPM 재시작
설정 검사 결과가 정상이라면 PHP-FPM을 재시작합니다.
sudo systemctl restart php8.5-fpm서비스 상태를 확인합니다.
systemctl is-active php8.5-fpm
systemctl is-active apache2정상 결과:
active
active
PHP 8.3 환경이라면 php8.3-fpm으로 변경하세요.
Apache mod_php를 실제 사용하는 환경은 Apache 재시작이 필요하고, 다른 PHP 실행 방식은 해당 서비스를 재시작하거나 컨테이너를 재배포해야 합니다.
6-4. 홈페이지 응답 확인
다음 명령에서 주소를 본인이 운영하는 사이트로 바꾸세요.
curl -sS -o /dev/null \
-w 'HTTP: %{http_code}\nTotal: %{time_total}s\n' \
https://example.com/Mindmapia에서 확인한 결과:
HTTP: 200
Total: 0.124659s
HTTP 200은 홈페이지가 요청에 정상 응답했다는 의미입니다.
다만 HTTP 200만으로 PHP 업데이트가 완벽하게 성공했다고 판단하면 안 됩니다. 정적 페이지나 캐시가 응답했을 가능성도 있기 때문입니다.
WordPress 관리자 화면의 도구 → 사이트 건강 → 정보 → 서버에서 실제 웹 PHP 버전도 확인하는 것이 좋습니다.
7. WordPress 사이트라면 추가로 검증하세요
WordPress 사이트는 PHP 버전을 업데이트한 뒤 플러그인, 데이터베이스, 캐시가 함께 정상 작동하는지 확인해야 합니다.
7-1. WordPress 코어 무결성 검사
WP-CLI가 설치된 서버에서는 다음 명령을 사용할 수 있습니다.
sudo -u www-data wp \
--path=/var/www/html \
--skip-plugins --skip-themes \
core verify-checksums정상 결과:
Success: WordPress installation verifies against checksums.
저 역시 이번 점검에서 WordPress 7.1.3의 공식 체크섬 검증에 성공했습니다.
이 검사는 WordPress 코어 파일을 공식 배포본과 비교하지만, 플러그인이나 테마 전체의 안전성까지 보증하는 것은 아닙니다.
7-2. 데이터베이스 연결 확인
sudo -u www-data wp \
--path=/var/www/html \
--skip-plugins --skip-themes \
db query 'SELECT 1 AS db_ok;'정상 결과:
db_ok
1
WordPress의 DB 연결이 정상인지 간단하게 확인할 수 있습니다.
7-3. 플러그인 상태 확인
sudo -u www-data wp \
--path=/var/www/html \
--skip-plugins --skip-themes \
plugin list \
--fields=name,status,version,update \
--format=table예시:
name status version update
redis-cache active 3.0.0 none
wp-mail-smtp active 4.10.3 none
PHP 확장 모듈 업데이트 이후 플러그인이 활성화되어 있는지 확인합니다.
7-4. Redis Object Cache 확인
Redis Object Cache 플러그인을 사용한다면 다음 명령으로 상태를 확인할 수 있습니다.
sudo -u www-data wp \
--path=/var/www/html \
redis status실제 점검 결과의 일부입니다.
Status: 연결됨
Client: PhpRedis (v6.3.0)
Drop-in: Valid
Ping: 1
Errors: []
PHP Version: 8.5.12
Redis Version: 7.0.15
PHP 업데이트 이후에도 Redis 연결과 오브젝트 캐시 기능이 정상 상태라는 것을 확인했습니다.
참고로 WordPress의 wp-config.php는 반드시 /var/www/html에 있어야 하는 것은 아닙니다. 실제 제 서버처럼 한 단계 상위 디렉터리에 위치할 수도 있습니다. WP-CLI 점검 시 설정 파일 위치를 잘못 판단하지 않도록 주의하세요.
8. 업데이트 후 침해 흔적과 서버 로그 점검
PHP 보안 패치를 완료했다는 사실과 과거에 침해된 적이 없다는 사실은 서로 다릅니다.
한국인터넷진흥원(KISA)은 최소한 2026년 10월 20일 이후의 기록을 점검하고 가능하다면 이전 로그도 확인할 것을 권고했습니다.
8-1. PHP-FPM 오류 로그 확인
PHP 8.5-FPM 기준:
sudo journalctl \
-u php8.5-fpm \
--since "2026-10-20 00:00:00" \
-p warning \
--no-pager점검 구간에 경고 로그가 없으면 다음과 같이 표시될 수 있습니다.
-- No entries --
이는 해당 조건에 맞는 로그가 없었다는 뜻이지, 침해가 없었다는 확정적인 증거는 아닙니다.
8-2. Apache 오류 로그 확인
sudo grep -Ei \
'segfault|out of memory|oom|fatal error|proxy_fcgi' \
/var/log/apache2/error.log \
| tail -n 30이상 종료, PHP 메모리 부족, FastCGI 관련 오류가 발생했는지 확인합니다.
로그 경로와 형식은 웹 서버 설정에 따라 다를 수 있습니다.
8-3. HTTP 500 오류 확인
Apache 기본 Combined 로그 형식을 사용하는 경우:
sudo awk '$9 ~ /^(500|502|503)$/ {print}' \
/var/log/apache2/access.log \
| tail -n 20예를 들어 업데이트 전후로 HTTP 500이나 502가 집중적으로 발생했다면 해당 시간대의 PHP-FPM 로그와 함께 확인합니다.
8-4. 업로드 폴더에서 의심스러운 PHP 파일 확인
WordPress의 uploads 폴더는 일반적으로 이미지와 첨부파일을 저장하는 곳입니다.
해당 위치에 의심스러운 PHP 파일이 생성되었는지 확인해 볼 수 있습니다.
sudo find /var/www/html/wp-content/uploads \
-type f -name '*.php' \
-newermt '2026-10-20' \
-print출력이 있다면 내용을 분석해야 합니다. PHP 파일이 발견되었다는 이유만으로 웹셸이라고 단정해서는 안 되며, 해당 파일을 즉시 삭제하기보다 생성 경위와 로그를 먼저 확인해야 합니다.
8-5. 의심스러운 접근은 실제로 차단되는가?
실제 운영 서버에서는 xmlrpc.php에 대한 외부 접근이 Apache 설정에 의해 거부된 로그도 확인했습니다.
[authz_core:error] AH01630:
client denied by server configuration:
/var/www/html/xmlrpc.php
이는 서버 설정이 해당 요청을 차단했다는 뜻입니다.
하지만 모든 Apache 오류 로그가 침해 흔적을 의미하는 것은 아닙니다. 정상적인 접근 차단 기록과 실제 공격 성공 흔적을 구분해야 합니다.
만약 실제 침해 정황이 발견되었다면, 무작정 서버를 재시작하거나 파일을 삭제하지 말고 네트워크 격리, 증거 보존, 침해사고 신고 및 복구 절차를 우선해야 합니다.
또한 외부에 노출되었던 서버의 DB 계정, API 키, 관리자 비밀번호 등 중요 인증정보도 위험도에 따라 교체를 검토해야 합니다.
9. 즉시 업데이트할 수 없다면?
PHP 공식 보안 권고와 KISA 대응 수칙에서는 즉시 수정 버전을 적용하기 어려운 경우 임시 완화 조치를 제시하고 있습니다.
대표적으로 다음 설정을 검토할 수 있습니다.
session.upload_progress.enabled = 0
PHP 8.5에서는 다음 설정도 특정 공격 경로에 대한 임시 완화 수단으로 언급됩니다.
fatal_error_backtraces = 0
이 밖에도 HTTP 요청 크기 제한, multipart 업로드 제한, WAF 규칙 적용, PHP 메모리 설정 조정 등이 제시되어 있습니다.
단, 이런 설정을 임의로 변경하면 파일 업로드, 세션 처리, 오류 분석 또는 서버 메모리 사용에 영향을 줄 수 있습니다.
특히 memory_limit = -1은 메모리 제한을 제거하므로 운영 서버에서 무분별하게 적용하면 서비스 안정성을 해칠 수 있습니다. PHP 공식 권고의 조건과 서버 자원을 검토해야 합니다.
임시 설정 변경이나 WAF만으로 이번 취약점을 완전히 해결할 수는 없습니다. 최종 대응은 수정 패치 적용입니다.
10. 실제 운영 서버 두 대의 업데이트 결과
이번 취약점 발표 이후 직접 관리하는 두 WordPress 서버에서 보안 업데이트를 진행했습니다.
| 구분 | 업데이트 이전 | 업데이트 이후 |
|---|---|---|
| WordPress 서버 A | PHP 8.2.34 | PHP 8.2.35 |
| WordPress 서버 A | PHP 8.3.35 | PHP 8.3.36 |
| Mindmapia 서버 | PHP 8.5.11 | PHP 8.5.12 |
서버 A에서는 실제 웹 요청을 PHP 8.3-FPM으로 처리하고 있었으며, PHP 8.2도 별도로 설치되어 있었습니다. 두 버전 모두 취약 버전이어서 각각 패치했습니다.
Mindmapia는 PHP 8.5-FPM을 사용하고 있었으며 PHP 8.5.12로 업데이트했습니다.
각 서버에서 다음과 같은 항목을 확인했습니다.
- PHP CLI와 PHP-FPM 수정 버전 적용
- PHP-FPM 및 Apache 설정 검사 통과
- PHP-FPM 재시작 후 서비스 정상 실행
- 홈페이지 HTTP 200 응답
- WordPress 코어 공식 체크섬 검증 성공
- 데이터베이스 연결 정상
- Redis Object Cache 연결 정상
- 점검한 PHP-FPM 구간에서 경고 로그 없음
다만 이러한 점검 결과가 모든 침해 가능성을 배제하는 것은 아닙니다. 보안 패치와 별도로 과거 접근 로그 및 중요 인증정보 점검을 지속해야 합니다.
직접 대응하면서 배운 점
이번 경험에서 가장 중요하게 느낀 것은 세 가지입니다.
첫째, CLI에 표시된 PHP 버전만 믿으면 안 됩니다. 실제 웹 요청을 처리하는 PHP-FPM 또는 다른 PHP 실행 환경을 확인해야 합니다.
둘째, 보안 업데이트에도 사전 시뮬레이션이 필요합니다. 긴급하다고 무작정 전체 PHP 패키지를 업그레이드하면 사용하지 않는 PHP 계열까지 신규 설치될 수 있습니다.
셋째, 업데이트 후 서비스 검증이 중요합니다. PHP 버전뿐 아니라 WordPress, DB, Redis, 플러그인, 로그까지 확인해야 실제 운영 장애를 줄일 수 있습니다.
11. 자주 묻는 질문(FAQ)
Q1. PHP2Shell에 취약한 PHP 버전은 무엇인가요?
PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12보다 낮은 해당 계열의 공식 PHP 빌드는 취약합니다. PHP 8.1 이하는 공식 보안 지원이 종료되어 별도 대응이 필요합니다. 배포판의 백포트 패키지는 공급업체 보안 공지를 기준으로 확인해야 합니다.
Q2. PHP 버전은 어떻게 확인하나요?
php -v로 CLI 버전을 확인하고, ps -eo pid,comm,args | grep '[p]hp-fpm' 명령으로 실제 실행 중인 PHP-FPM을 확인할 수 있습니다. Apache의 PHP 처리 설정과 패키지 버전도 함께 확인하는 것이 좋습니다.
Q3. WordPress만 최신 버전으로 업데이트하면 해결되나요?
아닙니다. 이번 취약점은 WordPress가 아니라 PHP 실행 엔진 자체에 존재합니다. WordPress와 플러그인을 최신 버전으로 유지하더라도 PHP가 취약한 버전이라면 별도로 PHP 보안 업데이트를 적용해야 합니다.
Q4. PHP 업데이트 후 Apache도 재시작해야 하나요?
서버 구성에 따라 다릅니다. PHP-FPM을 사용하는 경우 해당 PHP-FPM 서비스를 재시작해야 합니다. Apache mod_php를 사용하는 경우 Apache를 재시작해야 합니다. 컨테이너 기반 환경에서는 패치된 이미지를 재배포해야 합니다.
Q5. PHP-FPM을 사용하면 PHP2Shell 공격에서 안전한가요?
아닙니다. 공격이 성립하는 구체적인 조건과 경로에는 차이가 있지만 PHP-FPM도 보안 점검 및 패치 대상입니다. PHP-FPM이라는 이유만으로 수정 버전 적용을 생략하면 안 됩니다.
Q6. PHP 버전이 업데이트되면 해킹된 흔적도 사라지나요?
아닙니다. PHP 보안 패치는 해당 취약점의 악용을 방지하기 위한 조치입니다. 이미 설치된 웹셸이나 유출된 비밀번호를 자동으로 복구하지 않습니다. 침해 정황이 있다면 별도의 사고 조사와 복구가 필요합니다.
Q7. PHP를 업데이트했는데 php -v 결과가 이전 버전이면 어떻게 하나요?
하나의 서버에 여러 PHP 버전이 설치되어 있거나 CLI 기본 버전이 다른 실행 파일을 가리킬 수 있습니다. command -v php, 설치된 패키지 목록, 실제 PHP-FPM 버전을 구분해 확인해야 합니다.
마무리
PHP2Shell은 PHP를 사용하는 웹사이트 운영자라면 반드시 확인해야 하는 심각한 취약점입니다.
이번 사례를 통해 다시 확인한 사실은 보안 업데이트는 단순히 패키지 버전을 높이는 작업이 아니라 운영 서비스의 실행 환경과 정상 동작을 검증하는 과정까지 포함한다는 점입니다.
WordPress, Drupal, Joomla 등의 CMS를 운영한다면 애플리케이션 업데이트뿐 아니라 PHP, 웹 서버, 운영체제 패키지의 보안 공지도 정기적으로 확인하는 습관이 필요합니다.
이번 기회에 직접 운영하는 서버뿐 아니라 사용하지 않는 테스트 서버와 오래된 웹사이트까지 함께 점검해 보시기 바랍니다.
공식 참고 자료
- PHP 공식 보안 업데이트 — 2026년 10월 21일
- PHP 공식 보안 권고 — CVE-2026-109618
- PHP 공식 보안 권고 — CVE-2026-109619
- KISA 보호나라 — PHP2Shell 기업 보안 대응 수칙
- 네덜란드 NCSC — PHP2Shell 대응 정보
작성 및 점검 기준: 2026년 10월 22일. 본문의 실행 예시는 Debian 12 기반 Apache·PHP-FPM 환경에서 확인한 작업을 바탕으로 정리했으며, 실제 운영 환경에서는 설치 경로와 패키지 구성을 먼저 확인해야 합니다.