PHP 긴급 패치, 로그인 없이 서버가 뚫린다? PHP2Shell 원리와 내 서버 확인·패치법

PHP 긴급 패치, 로그인 없이 서버가 뚫린다? PHP2Shell 원리와 내 서버 확인·패치법

지난 10월 21일 밤(한국시간), 전 세계 웹사이트 관리자들이 한꺼번에 업데이트를 시작했습니다. 웹사이트 열 곳 중 일곱 곳 가까이가 쓰는 프로그램, PHP에서 로그인 없이 남의 서버를 조종할 수 있는 구멍이 두 개 발견됐기 때문입니다.

이 글에서는 다음을 차례로 봅니다.

  1. PHP는 무슨 일을 하고, 얼마나 많이 쓰이나
  2. 사건 타임라인
  3. PHP2Shell: 인증 없는 원격 코드 실행
  4. 구멍 1: 메모리 부족과 비상구
  5. 구멍 2: 앞 손님의 흔적(use-after-free)
  6. 어떤 서버가 위험하고, 고친 버전은 무엇인가
  7. 실습: 내 서버 버전 확인하고 패치하기
  8. 지금 할 일 세 가지

숫자 읽는 법. [공식 문서] 는 PHP 프로젝트가 직접 낸 보안 공지·권고, [커뮤니티 보고] 는 언론·통계 사이트가 낸 자료, [직접 측정] 은 저희가 맥의 로컬 Docker에서 직접 돌려 본 결과입니다. 공격 방법은 다루지 않고, 확인하고 막는 쪽만 다룹니다.

1. PHP는 무슨 일을 하나

PHP는 웹사이트 뒤에서 페이지를 만들어 주는 프로그래밍 언어입니다. 쇼핑몰에서 주문 버튼을 누르면, 서버에 있는 PHP가 주문을 받아 처리하고, 결과 화면(HTML)을 만들어 브라우저로 돌려줍니다.

얼마나 많이 쓰일까요. 웹 기술 통계 사이트 W3Techs 기준으로, 서버 언어를 알 수 있는 웹사이트의 69.3%가 PHP를 씁니다 [커뮤니티 보고] (W3Techs, 2026-10-22 확인). 블로그와 회사 홈페이지를 많이 만드는 워드프레스도 PHP로 만들어져 있습니다. 그래서 PHP에 구멍이 나면 인터넷의 큰 부분이 한꺼번에 영향을 받습니다.

단, 69.3%는 PHP를 쓰는 사이트의 비율이지, 취약한 사이트의 비율이 아닙니다. 이미 고친 버전을 쓰는 곳도 있고, 설정에 따라 영향이 다르기도 합니다.

2. 사건 타임라인

  • 10월 17일: 아마존 보안팀이 미끼용 서버(허니팟)에서 이 구멍을 노린 공격 시도를 기록했다고 밝혔습니다. 공개 나흘 전입니다. [커뮤니티 보고] (Help Net Security 보도, 아마존 원문은 확인하지 못했습니다)
  • 10월 20일: PHP 보안팀이 다음 날 치명적 보안 업데이트를 낸다고 미리 알렸습니다. [공식 문서] (PHP 재단 공지)
  • 10월 21일 14:00 UTC(한국시간 23:00): 고친 버전 네 개(8.5.12, 8.4.27, 8.3.36, 8.2.35)가 나왔습니다. [공식 문서] (php.net)

일부에서는 "급하게 내놨다"고 했지만, 실제로는 하루 전에 예고하고 예정대로 배포했습니다.

3. PHP2Shell: 인증 없는 원격 코드 실행

PHP2Shell로 묶인 두 취약점과 위험도 9.2

보안 업계와 언론은 이 두 구멍을 묶어 PHP2Shell이라고 부릅니다(PHP 공식 이름은 아닙니다). 셸(shell) 은 서버에 명령을 내리는 창을 말합니다. PHP를 통해 남의 서버 명령창을 얻는다는 뜻입니다.

  • 공식 번호가 붙은 취약점은 두 개입니다. CVE-2026-109618과 CVE-2026-109619. CVE는 공개된 보안 취약점마다 붙는 고유 번호입니다.
  • 위험도 점수(CVSS v4.0, 취약점 위험도를 0~10점으로 매기는 표준)는 둘 다 9.2점, 등급은 치명적(Critical) 입니다. [공식 문서] (GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp)

php.net 공지에 나온 표현은 "인증 없는 원격 코드 실행(unauthenticated remote code execution)" 입니다. 세 단어로 나눠 보면 이렇습니다.

  • 인증 없이: 아이디도 비밀번호도 없는 사람이
  • 원격으로: 인터넷 너머에서
  • 코드 실행: 내 서버에 원하는 명령을 실행시킬 수 있다

고객 정보를 빼 가거나, 사이트를 바꿔 버리거나, 서버를 다른 공격의 발판으로 쓸 수도 있다는 뜻입니다.

4. 구멍 1: 메모리 부족과 비상구

요청 하나의 메모리 작업대. 노란 칸은 아직 준비되지 않은 메모리

첫 번째 구멍(CVE-2026-109618)은 메모리가 부족할 때 생깁니다. 식당 주방에 비유해 보겠습니다.

  1. PHP는 요청 하나를 처리할 때마다 메모리를 씁니다. 주방의 작업대라고 생각하면 됩니다.
  2. 작업대가 꽉 차면(메모리 부족, OOM), 하던 일을 그 자리에서 멈추고 비상구로 바로 빠져나갑니다.
  3. 급하게 나가면서 작업대 일부가 아직 준비도 안 된 상태로 남습니다.
  4. 그런데 마감 정리 담당은 작업대가 멀쩡하다고 믿고 그대로 읽어 버립니다.

공격자가 이 순간을 정교하게 만들어 내면, 정리 과정이 엉뚱한 일을 하게 만들 수 있습니다. 권고문은 Apache mod_php가 요청 시작에 실패해도 마감 정리 단계를 무조건 부른다고 설명합니다. 패치는 메모리 부족 때 이렇게 "비상구로 바로 뛰쳐나가는" 동작을 없앴습니다. [공식 문서] (GHSA-w8hw-w9fx-j79w)

5. 구멍 2: 앞 손님의 흔적(use-after-free)

요청 A가 치명적 오류로 청소를 건너뛰면, 다음 요청 B가 이미 반납된 메모리를 읽는다

두 번째 구멍(CVE-2026-109619)은 앞 손님의 흔적입니다. 이번에는 호텔에 비유합니다.

  • 서버에서는 일꾼(워커 프로세스) 하나가 요청 여러 개를 차례로 처리합니다. 호텔 직원 한 명이 방 하나에 손님을 차례로 받는 것과 비슷합니다.
  • 원래는 손님이 나가면 방을 싹 치웁니다. 그런데 치명적인 오류(fatal error) 가 나면 이 청소 단계를 건너뛸 때가 있습니다.
  • 그러면 다음 손님이 왔을 때, 이미 반납된 방을 가리키는 열쇠가 그대로 남아 있습니다.

이렇게 이미 돌려준 메모리를 다시 쓰는 실수를 해제 후 사용(use-after-free) 이라고 부릅니다. 권고문은 이것도 원격 코드 실행으로 이어질 수 있다고 밝혔습니다. 오류 표시를 끄거나 @를 붙이는 것으로는 막을 수 없습니다. [공식 문서] (GHSA-6wmf-4rv5-p3rp)

6. 어떤 서버가 위험한가, 고친 버전은

SAPI별 영향과 고친 버전 네 개

PHP를 웹 서버에 붙이는 방식(SAPI)에 따라 권고문의 판단이 다릅니다. [공식 문서]

방식권고문 판단
mod_php (Apache에 PHP를 붙여 쓰는 방식)공격이 실제로 확인됨
PHP-FPM (많이 쓰는 별도 프로세스 방식)설정·경로에 따라 영향, 분석상 취약
FrankenPHP분석상 영향받을 가능성이 높음
LSAPI영향 가능성 있음(검증되지 않음)

고친 버전은 8.2.35, 8.3.36, 8.4.27, 8.5.12입니다. 이번 공식 업데이트는 8.2부터 나왔으니, 그보다 오래된 버전은 지원되는 버전으로 올려야 합니다. php.net 공지는 분명히 말합니다. "완전한 완화책은 없다. 업데이트만이 안전한 선택이다." [공식 문서] (php.net)

7. 실습: 내 서버 버전 확인하고 패치하기

맥의 로컬 Docker에 작은 동네 빵집 주문 사이트를 띄웠습니다. 일부러 패치 전 버전인 PHP 8.4.26(php:8.4.26-apache 이미지)을 쓰게 했습니다. [직접 측정]

밖에서 보이는 버전

응답 머리말에 X-Powered-By: PHP/8.4.26이 그대로 찍힌다
  1. Dockerfile 첫 줄에 FROM php:8.4.26-apache가 적혀 있습니다. 이 서버가 쓰는 PHP 버전입니다.
  2. docker compose로 서버를 켜고, 밖에서 응답 머리말(header)만 받아 봅니다.
curl -sI localhost:8473 | grep -i powered
# X-Powered-By: PHP/8.4.26

버전이 그대로 찍혀 나옵니다. 공격자도 이렇게 버전을 보고 목표를 고를 수 있습니다. 작은 확인 스크립트로 이번 패치 버전 목록과 비교하면 결과는 취약, 8.4.27 이상으로 올리라고 나옵니다.

임시 조치

업데이트 전에 당장 할 수 있는 조치부터 넣었습니다. 보안 권고에 나온 대로 업로드 진행률 기능을 끄고, 버전 번호를 밖으로 알리는 기능도 같이 껐습니다.

session.upload_progress.enabled = 0
expose_php = Off

다만 권고문도 이 설정은 이미 확인된 공격 경로 하나만 막을 뿐, 다른 경로는 막지 못한다고 적고 있습니다. 설정을 바꾼 뒤에는 워커를 모두 재시작해야 합니다. [공식 문서] (GHSA-6wmf-4rv5-p3rp)

진짜 해결: 버전 올리기

다시 확인하면 머리말에 버전이 사라지고, 확인 스크립트는 "패치됨"

Dockerfile의 8.4.26을 8.4.27로 바꾸고 다시 빌드했습니다.

sed -i '' 's/8.4.26/8.4.27/' Dockerfile

같은 확인을 다시 하면 결과가 달라집니다. [직접 측정]

  • 응답 머리말에 PHP 버전이 아예 나오지 않습니다(expose_php = Off).
  • 확인 스크립트는 PHP 8.4.27 → 패치됨이라고 알려 줍니다.
  • 서버 안에서 php -i로 보면 session.upload_progress.enabled => Off입니다.

8. 지금 할 일 세 가지

지금 할 일 세 가지
  1. 버전 확인. 서버에서는 php -v로, 호스팅 서비스를 쓴다면 관리 화면에서 봅니다.
  2. 바로 업데이트하고 재시작. 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12보다 낮다면 업데이트하고, PHP를 돌리는 워커 프로세스까지 재시작합니다.
  3. 배포판 보안 공지 확인. 리눅스 배포판 패키지는 버전 번호는 그대로 두고 고친 내용만 넣는 경우가 있습니다(백포트). 번호만 보고 판단하지 말고 배포판의 보안 공지도 같이 확인하세요.

웹호스팅을 쓴다면 호스팅 업체에 패치 여부를 물어보는 것이 가장 빠릅니다. 공개되기 전부터 공격 시도가 있었다는 보도가 있는 만큼, 오늘 확인할 일을 내일로 미루지 않는 게 중요합니다.

한계

  • 실습은 로컬 Docker의 mod_php(Apache) 이미지 하나로만 했습니다. PHP-FPM, FrankenPHP 환경은 직접 돌려 보지 않았습니다.
  • 공격 재현이나 PoC(개념 증명 코드)는 다루지 않았습니다. 공개 PoC가 있는지, CISA의 "실제 악용된 취약점 목록(KEV)"에 올랐는지는 1차 출처로 확인하지 못해 쓰지 않았습니다.
  • 10월 17일 공격 시도 기록은 보도를 통한 인용이며, 아마존이 낸 원문은 확인하지 못했습니다.
  • 일부에서 나온 "웹의 70~75%", "수백만 건 해킹" 같은 숫자는 1차 출처로 확인되지 않아 뺐습니다.

영상으로 보기

같은 내용을 그림 설명과 실제 터미널 화면으로 영상에 담았습니다. 10월 24일 오후 7시(한국시간)에 공개됐습니다.

출처

Comments0
No comments yet.

Related Posts