본문 바로가기
Infra2026년 10월 22일20분 읽기

PHP2Shell 총정리: 10월 21일 패치된 PHP 원격 코드 실행 취약점(CVE-2026-109618·109619), 내 서버 점검과 대응법

YS
김영삼
조회 16
PHP2Shell 총정리: 10월 21일 패치된 PHP 원격 코드 실행 취약점(CVE-2026-109618·109619), 내 서버 점검과 대응법

PHP2Shell은 2026년 10월 21일 PHP 개발팀이 긴급 패치한 두 개의 PHP 원격 코드 실행 취약점(CVE-2026-109618, CVE-2026-109619)을 부르는 별칭이다. 로그인 없이 보낸 HTTP 요청만으로 서버에서 코드를 실행할 수 있고, 심각도는 둘 다 CVSS v4.0 기준 9.2점이다.

문제는 워드프레스 플러그인이나 게시판 코드가 아니라 PHP 엔진 자체에 있다. 그래서 어떤 프로그램을 돌리든, PHP로 웹 요청을 받는 서버라면 일단 점검 대상이다. 어제 밤 패치가 나왔고, 나도 오늘 아침 내 서버부터 확인했다. 그 과정과 함께 지금 해야 할 일을 순서대로 정리한다.

3줄 요약
  • 영향 범위는 PHP 5.4부터 8.5.11까지다. 고친 버전은 8.5.12, 8.4.27, 8.3.36, 8.2.35이고, 8.1 이하는 공식 패치가 없다.
  • PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed 등 웹 요청을 처리하는 모든 방식이 대상이다. 가장 위험한 건 mod_php다.
  • 업데이트만이 완전한 해결책이다. 리눅스 배포판 패키지는 버전 숫자가 그대로여도 패치가 들어가 있을 수 있으니 버전이 아니라 패키지 변경 기록으로 확인해야 한다.
9.2
CVSS v4.0 점수 (두 건 모두 Critical)
2건
OOM 손상 · 해제된 메모리 재사용
5.4~
영향받는 가장 오래된 버전 계열
10/21
패치 공개일 (한국시간 23시)

PART 01무슨 일이 있었나: 나흘간의 타임라인

이번 사건은 진행 순서가 조금 꼬였다. 원래 PHP 개발팀은 패치를 준비한 뒤 정해진 날에 한꺼번에 공개하려 했다. 그런데 공개 전에 CVE 번호와 일부 정보가 먼저 퍼졌고, 결국 일정을 하루 앞당겼다. 아래는 PHP 공식 공지와 Tenable, Patchstack, 국내 보도를 맞춰 본 흐름이다.

10월 17일
공개 전 공격 시도 포착
Amazon 위협 인텔리전스가 자사 허니팟(MadPot)에서 PHP2Shell을 노린 시도를 봤다고 밝혔다. 공식 공개보다 나흘 이르다. 공격자가 어떻게 정보를 얻었는지는 아직 밝혀지지 않았다.
10월 20일
CVE 번호 유출, 긴급 패치 예고
CVE 번호가 해커뉴스와 SNS에 돌기 시작했다. PHP 개발팀은 "10월 21일 14:00 UTC에 치명적 보안 릴리스를 낸다"고 예고했다. 유출 정보에는 CVSS 10.0이 붙어 있었는데, PHP 재단은 이 점수가 틀렸다고 했다.
10월 21일 낮
국내외 선제 조치
네덜란드 정부 사이트 등 일부 기관이 사이트를 내렸다. Cloudflare는 WAF 규칙을 배포했다. 국내 호스팅사 카페24는 오전 11시 30분부터 서버별로 session.upload_progress.enabled를 끄는 완화 작업을 했다. KISA도 업데이트를 권고했다.
10월 21일 23시(KST)
패치 공개
PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35가 나왔다. 7.4~8.1용 최소 소스 패치도 따로 공개됐다. 배포판과 LTS 업체는 미리 패치를 받아 자체 패키지를 냈다.
10월 21~22일
공격 시도 확산, 평가는 엇갈림
Amazon은 "광범위하게 악용되고 있다"며 여러 공격 집단이 움직이는 정황을 밝혔다. 반면 watchTowr는 공개된 공격 도구가 실제 공격에 쓰이고는 있지만 아직 성공 사례는 없다고 했고, PHP 보안팀도 공개 시점에 살펴본 공격 코드 중 실제로 동작하는 것은 없었다고 밝혔다.

보도마다 "이미 뚫린 곳이 많다"와 "아직 확인된 침해는 없다"가 엇갈린다. 내 판단은 단순하다. 둘 중 어느 쪽이 맞든 할 일은 똑같다. 패치하고, 패치 전에 이상한 흔적이 없었는지 본다.

영삼
영삼의 한마디
이번 건에서 제일 불편했던 건 공개 순서다. 원래라면 패치가 먼저 나오고 세부 내용이 뒤따른다. 이번엔 번호와 과장된 점수가 먼저 퍼지고, 공격 시도가 그보다 더 먼저 있었다. 관리자 입장에서는 "뭘 해야 하는지 모르는 상태로 겁만 먹는" 하루가 생긴 셈이다. 이런 날일수록 공식 공지(php.net)와 내 서버의 실제 상태, 이 두 가지만 보고 움직이는 게 낫다.

PART 02두 취약점은 어떻게 동작하나

세부 공격 코드는 다루지 않는다. 다만 원리를 알아야 임시 완화책이 왜 그런 설정인지 이해된다. PHP 공식 보안 권고(GHSA)에 적힌 설명을 쉽게 풀면 이렇다.

CVE-2026-109618: 메모리 부족 순간을 노린다

PHP는 요청을 받으면 내부 데이터를 하나씩 준비한다. 그런데 준비가 반쯤 끝난 순간 메모리가 바닥나면 처리가 중간에 끊긴다. 이후 정리 단계에서 PHP가 이 덜 만들어진 데이터를 정상 데이터로 착각하는 게 문제다. 공격자는 일부러 큰 요청을 보내 메모리 한도를 넘기는 식으로 이 상황을 만든다. 그래서 임시 완화책에 memory_limit과 post_max_size가 등장한다.

CVE-2026-109619: 앞 요청의 흔적이 다음 요청에 남는다

PHP-FPM 같은 방식은 작업 프로세스 하나가 여러 요청을 차례로 처리한다. 이 취약점은 앞 요청이 쓰던 내부 상태가 메모리가 해제된 뒤에도 남아 있다가, 같은 프로세스가 받은 다음 요청에서 다시 쓰이는 문제다. 흔히 말하는 use-after-free다. 코드 실행뿐 아니라 메모리 내용이 새어 나가는 것도 확인됐다고 PHP는 밝혔다. 메모리에는 DB 비밀번호나 API 키가 있을 수 있으니, 코드 실행까지 안 가더라도 가볍게 볼 일이 아니다.

PHP 공식 보안 권고(GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp) 기준
구분CVE-2026-109618CVE-2026-109619
한 줄 요약메모리 부족(OOM) 중 덜 만들어진 데이터를 정상으로 처리해제된 요청 상태를 다음 요청이 재사용
유형예외 상황 처리 오류use-after-free (오래된 전역 상태)
인증 필요없음없음
확인된 영향원격 코드 실행원격 코드 실행 + 메모리 노출
임시 완화 핵심memory_limit=-1, post_max_size 축소session.upload_progress.enabled=0
심각도CVSS v4.0 9.2CVSS v4.0 9.2

두 문제 모두 애플리케이션 코드가 실행되기 전, PHP가 요청을 받아 해석하는 단계에서 터진다. 특히 Apache mod_php 구성에서는 애플리케이션 코드가 돌기도 전에 인증 없는 요청 하나로 공격이 시연됐다. 보안 연구팀 Calif는 워드프레스, 드루팔, 줌라, 마젠토의 특정 버전에서 로그인 없는 원격 코드 실행을 확인했다고 밝혔다. 플러그인을 아무리 최신으로 유지해도 이번엔 소용없다는 뜻이다.

PART 03내 서버는 위험한가: 영향 버전 한눈에 보기

php.net 10월 21일 보안 공지, Tenable FAQ 기준
PHP 계열안전한 버전상태
8.58.5.12 이상공식 패치 있음
8.48.4.27 이상공식 패치 있음
8.38.3.36 이상공식 패치 있음
8.28.2.35 이상공식 패치 있음 (2026년 12월 31일 지원 종료 예정)
7.4 ~ 8.1공식 릴리스 없음최소 소스 패치만 공개, 직접 빌드하거나 배포판·업체 패키지 확인
5.4 ~ 7.3없음지원 종료. 업그레이드 말고는 답이 없다

PHP 공식 공지는 "웹 요청을 처리하는 모든 PHP 설치"가 위험하다고 적었다. PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed가 모두 들어간다. 명령줄에서만 돌리는 스크립트는 공지에서 따로 언급되지 않았지만, 같은 서버에서 웹도 돌린다면 결국 업데이트 대상이다.

국내 서비스라면 특히 확인할 것
그누보드·XE(라이믹스)·워드프레스 같은 PHP 기반 사이트가 오래된 PHP 7.x 위에서 그대로 돌고 있는 경우가 적지 않다. Detectify 연구원은 PHP 사이트의 절반가량이 오래된 버전을 쓴다고 추정했다. 이런 서버는 공식 패치 자체가 없다. 호스팅을 쓰고 있다면 호스팅사 공지부터 확인하고, 직접 운영하는 서버라면 이번 기회에 8.2 이상으로 올리는 계획을 바로 잡자.

PART 04오늘 아침 내 서버 점검기

현장 기록
php -v에 "8.5.4"가 찍혔다

기사를 보자마자 서버에 접속해 php -v부터 쳤다. 결과는 PHP 8.5.4. 안전한 버전은 8.5.12라고 했으니 숫자만 보면 한참 뒤처진 상태다. 순간 등이 서늘했다. 이 서버엔 PHP-FPM 풀이 여러 개 떠 있고, 모두 외부 요청을 받는다.

그런데 바로 업데이트를 돌리기 전에 패키지 변경 기록을 열어 봤다. 우분투 패키지 버전은 8.5.4-0ubuntu1.5였고, 변경 기록 맨 위에 "SECURITY UPDATE: Remote RCE via state corruption issue"와 함께 CVE-2026-109618, 109619 패치 파일들이 올라와 있었다. 배포판이 PHP 버전 숫자는 그대로 두고 수정 코드만 가져다 붙이는 방식(백포트)이다.

dpkg 로그를 보니 이 패키지는 오늘 새벽 6시 23분에 자동 보안 업데이트(unattended-upgrades)로 설치됐다. PHP-FPM 프로세스 시작 시각도 6시 23분 30초. 패치 설치와 재시작이 같이 끝나 있었다. 결과적으로 내가 한 일은 확인뿐이었다.

교훈은 두 가지다. 첫째, 배포판 패키지는 php -v 숫자만 보고 판단하면 안 된다. 둘째, 반대로 숫자가 높아 보여도 직접 빌드한 PHP나 오래된 도커 이미지는 패치가 안 됐을 수 있다. 결국 "어디서 온 PHP인지"를 먼저 알아야 한다.

PART 055분 점검 명령어 모음

아래는 내가 실제로 쓴 순서다. 우분투·데비안 기준이고, 레드햇 계열은 rpm -q --changelog로 바꿔 보면 된다.

1) 어떤 PHP가 돌고 있는지부터

# 명령줄 PHP 버전 (참고용일 뿐, 웹용 PHP와 다를 수 있다)
php -v

# 웹 요청을 받는 PHP 프로세스 확인
systemctl list-units --type=service | grep -Ei "php|apache|httpd|lsws|frankenphp"
ps -eo pid,lstart,cmd | grep -E "php-fpm|httpd|apache2" | grep -v grep

# 설치된 PHP 패키지 전부
dpkg -l | grep -E "^ii\s+(php|libapache2-mod-php)"

2) 버전 숫자 말고 패치 여부를 확인

# 배포판 패키지 변경 기록에 CVE가 들어 있는지
zcat /usr/share/doc/php8.5-fpm/changelog.Debian.gz | grep -m3 -E "CVE-2026-10961[89]"

# 패키지가 언제 설치됐는지
zgrep -h "php8.5-fpm" /var/log/dpkg.log* | sort | tail -3

php8.5-fpm 부분은 내 서버의 패키지 이름으로 바꾸면 된다. CVE 번호가 검색되면 패치가 들어간 패키지다. 아무것도 안 나오면 아직 이전 패키지다.

3) 패치 후 재시작까지 됐는지

# FPM 마스터 프로세스 시작 시각 — 패키지 설치 시각보다 뒤여야 한다
ps -o lstart= -p "$(cat /run/php/php8.5-fpm.pid)"

# 재시작이 안 됐다면
sudo systemctl restart php8.5-fpm

패키지를 깔아도 이미 떠 있는 작업 프로세스는 옛날 코드를 메모리에 들고 있다. 특히 109619는 작업 프로세스가 요청을 이어 받는 구조를 노리므로 재시작이 빠지면 패치 효과가 없다.

4) 잊기 쉬운 곳

점검 체크리스트
  • 도커 이미지: docker images로 php 베이스 이미지를 찾고, 새로 받은 뒤 다시 빌드·배포했는지
  • 스테이징·개발 서버, 오래된 관리자 페이지 전용 서버
  • 설치형 솔루션에 묶여 들어온 PHP (NAS 관리 화면, 사내 그룹웨어 등)
  • Windows에서 직접 받은 PHP(IIS·XAMPP 등) — php.net 윈도우 빌드로 교체
  • 공유 호스팅 — 호스팅사 공지와 적용 일정 확인

PART 06당장 업데이트가 안 된다면: 임시 완화책

PHP 공식 공지는 분명히 적었다. 업데이트만이 완전한 해결책이고, 아래 설정은 설치를 안전하게 만들지 않는다. 그래도 패치까지 몇 시간이라도 벌어야 한다면 다음 설정을 쓴다. 반드시 요청 해석 전에 적용되는 위치(php.ini, FPM 풀 설정, 웹서버 설정)에 넣어야 한다.

; php.ini — 요청 해석 전에 적용되는 위치에 넣는다
memory_limit = -1
post_max_size = 8M          ; 파일 업로드가 필요하면 32M
upload_max_filesize = 2M    ; 항상 post_max_size보다 작게
session.upload_progress.enabled = 0
fatal_error_backtraces = 0  ; PHP 8.5만 해당
; FPM 풀 설정(/etc/php/8.5/fpm/pool.d/www.conf 등) — 앱이 덮어쓰지 못하게 admin 값으로
php_admin_value[memory_limit] = -1
php_admin_value[session.upload_progress.enabled] = 0

적용한 뒤에는 모든 작업 프로세스를 재시작한다. 몇 가지 함정도 같이 적어 둔다.

PHP 공식 보안 공지의 완화책 항목 기준
함정이유
ini_set()이나 .user.ini로 설정요청 해석이 끝난 뒤에 적용되므로 효과가 없다
memory_limit=-1만 하고 끝메모리 무제한은 서버 전체가 버티지 못할 수 있다. 컨테이너·cgroup 메모리 한도로 프로세스 단위 안전장치를 따로 둔다
RLIMIT_AS, RLIMIT_DATA로 메모리 제한PHP 공지가 쓰지 말라고 명시했다
display_errors나 @로 오류 숨기기진단 메시지를 숨겨도 취약 경로는 그대로다
업로드 진행률 기능 사용 중session.upload_progress를 끄면 진행률 표시가 멈춘다. 카페24도 같은 영향을 공지했다

웹방화벽도 시간을 버는 수단이다. Cloudflare는 무료 요금제를 포함한 모든 고객에게 알려진 공격 패턴 차단 규칙을 배포했고, 구글 클라우드는 Cloud Armor 규칙과 함께 검사 한도를 넘는 큰 요청 본문을 막으라고 권했다. 다만 이것도 Cloudflare를 거치는 트래픽만 막는다. 서버 IP로 직접 들어오는 요청은 그대로다.

PART 07이미 당했는지 확인하는 법

Amazon은 최소한 10월 17일부터의 기록을 살펴보라고 권했다. 이번 취약점은 애플리케이션 아래 단계에서 터지기 때문에 앱 로그에는 흔적이 거의 안 남을 수 있다. Wiz가 제시한 신호를 기준으로 웹서버·PHP 로그를 보자.

Wiz·Patchstack·Amazon 권고 정리
볼 것어디서
이상한 multipart 요청 직후 메모리 한도 오류나 HTTP 500 반복nginx·Apache 접근 로그, PHP 오류 로그
비정상적으로 크거나 깨진 PHPSESSID 쿠키접근 로그(쿠키를 남기도록 설정된 경우), WAF 로그
설명되지 않는 PHP 작업 프로세스 재시작FPM 로그(child exited 등), journalctl
웹 루트에 새로 생긴 PHP 파일find /var/www -name "*.php" -newermt "2026-10-17"
# 10월 17일 이후 500 응답이 몰린 IP 상위
awk '$9==500 {print $1}' /var/log/nginx/access.log* | sort | uniq -c | sort -rn | head

# FPM 작업 프로세스 비정상 종료 흔적
journalctl -u php8.5-fpm --since "2026-10-17" | grep -Ei "exited|signal|memory" | head

의심 흔적이 나오면 그 서버는 침해됐다고 보고 움직이는 게 맞다. 서버가 들고 있던 DB 비밀번호, API 키, 세션 비밀키를 바꾸고, 가능하면 깨끗한 이미지에서 다시 올린다. 워드프레스라면 Patchstack이 경고한 대로 UpdraftCentral 연결 키도 지우고 새로 발급하자. 출처가 불분명한 "긴급 보안 패치 플러그인"이나 퍼온 코드 조각은 설치하지 않는다.

영삼
영삼의 생각
PHP 재단은 이번 취약점의 발견자로 Calif, OpenAI, Wiz 등을 꼽았고, Calif와 Wiz는 연구에 AI 모델을 썼다고 밝혔다. 동시에 인터넷에 도는 공격 도구 일부도 AI로 만들어졌다는 보도가 나왔다. 찾는 쪽도 공격하는 쪽도 빨라졌다는 얘기다. 나 같은 1인 운영자가 할 수 있는 현실적인 방어는 결국 자동 보안 업데이트를 켜 두고, 재시작까지 자동으로 되는지 한 번은 직접 확인해 두는 것이다. 오늘 아침 나는 그 덕분에 확인만 하고 끝났다.
정리하면
  1. PHP2Shell은 PHP 엔진 자체 문제다. 앱과 플러그인 업데이트로는 해결되지 않는다.
  2. 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 이상으로 올리고, 모든 PHP 작업 프로세스를 재시작한다.
  3. 배포판 패키지는 버전 숫자 대신 변경 기록의 CVE 번호로 패치 여부를 확인한다.
  4. 8.1 이하는 공식 패치가 없다. 업그레이드 계획을 지금 잡는다.
  5. 10월 17일 이후 로그에서 500 오류 폭증, 이상한 세션 쿠키, 프로세스 재시작을 찾아본다.

자주 묻는 질문

PHP2Shell은 정확히 무엇인가요?

PHP2Shell은 2026년 10월 21일 패치된 PHP 엔진의 원격 코드 실행 취약점 두 건(CVE-2026-109618, CVE-2026-109619)을 부르는 별칭입니다. 인증 없이 보낸 웹 요청만으로 서버에서 코드를 실행할 수 있고, 심각도는 CVSS v4.0 기준 9.2점입니다.

어떤 PHP 버전이 안전한가요?

PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 이상이 공식 패치 버전입니다. 우분투·데비안 같은 배포판 패키지는 버전 숫자가 낮아 보여도 보안 패치가 백포트되어 있을 수 있으니 패키지 변경 기록에서 CVE 번호를 확인하세요. PHP 8.1 이하는 공식 릴리스가 없습니다.

워드프레스 플러그인만 업데이트하면 되나요?

아닙니다. 이번 취약점은 워드프레스가 아니라 그 아래에서 도는 PHP 엔진에 있습니다. 워드프레스, 그누보드, 라이믹스 등 어떤 PHP 프로그램이든 PHP 자체를 패치된 버전으로 올려야 합니다.

PHP를 업데이트한 뒤 따로 해야 할 일이 있나요?

PHP-FPM이나 Apache 같은 PHP 작업 프로세스를 반드시 재시작해야 합니다. 이미 실행 중인 프로세스는 이전 코드를 메모리에 들고 있기 때문입니다. FPM 마스터 프로세스의 시작 시각이 패키지 설치 시각보다 뒤인지 확인하면 됩니다.

session.upload_progress.enabled를 끄면 안전해지나요?

완전히 안전해지지는 않습니다. PHP 공식 공지에 따르면 이 설정은 CVE-2026-109619의 공격 경로 일부를 줄이는 임시 조치일 뿐이며, 업데이트만이 완전한 해결책입니다. 또 이 설정을 끄면 파일 업로드 진행률 표시 기능이 동작하지 않습니다.

공유 호스팅을 쓰는데 제가 할 일이 있나요?

호스팅사가 PHP를 관리하므로 직접 패치할 수는 없습니다. 호스팅사 공지에서 패치 적용 일정을 확인하고, 사이트가 PHP 8.1 이하 버전을 선택해 쓰고 있다면 관리 화면에서 8.2 이상으로 바꾸는 것을 검토하세요.

참고 자료

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록