logo
홈블로그소개
4,743

Built with Next.js, Bun, Tailwind CSS and Shadcn/UI

·개인정보처리방침
AIWeb

PHP2Shell: 요청이 끝나도 남는 상태와 AI 시대의 패치 경계

Toma
2026년 10월 22일
약 10분
목차
🛡️ PHP2Shell: 요청이 끝나도 남는 상태와 AI 시대의 패치 경계
🧩 무엇이 잘못됐나: 요청과 worker의 수명
📦 요청이 끝나도 worker는 다음 요청을 받습니다
🔀 두 취약점은 같은 설명으로 뭉개면 안 됩니다
⚙️ 패치는 어떤 경계를 복구하나
⏹️ 메모리 부족에서 안전하게 멈추기
🧹 요청 소유 상태를 다음 요청에 넘기지 않기
🤖 AI가 바꾼 것은 발견만이 아닙니다
🔬 공개 자료에서 확인한 사례
🧪 연구자 실증: WordPress·Drupal·Joomla
🏗️ 운영사 대응: Coolify와 그 안의 앱은 다른 대상입니다
🧰 실무 적용: 무엇을 확인하고 어디까지 바꿀까
🗂️ 먼저 실행 주체와 업데이트 책임을 나눕니다
🛡️ WAF는 시간을 벌지만 런타임을 고치지는 않습니다
🚧 제약과 오해하기 쉬운 지점
🧯 설정 하나로 “해결”했다고 말하지 않습니다
🧭 PHP-FPM을 일괄적으로 안전하거나 위험하다고 단정하지 않습니다
📝 문서 확인과 직접 검증은 다릅니다
🎯 정리
Sources
이전 포스트Voxtral 3: 음성 에이전트의 발화 종료와 도구 실행을 안전하게 연결하기

목차

🛡️ PHP2Shell: 요청이 끝나도 남는 상태와 AI 시대의 패치 경계
🧩 무엇이 잘못됐나: 요청과 worker의 수명
📦 요청이 끝나도 worker는 다음 요청을 받습니다
🔀 두 취약점은 같은 설명으로 뭉개면 안 됩니다
⚙️ 패치는 어떤 경계를 복구하나
⏹️ 메모리 부족에서 안전하게 멈추기
🧹 요청 소유 상태를 다음 요청에 넘기지 않기
🤖 AI가 바꾼 것은 발견만이 아닙니다
🔬 공개 자료에서 확인한 사례
🧪 연구자 실증: WordPress·Drupal·Joomla
🏗️ 운영사 대응: Coolify와 그 안의 앱은 다른 대상입니다
🧰 실무 적용: 무엇을 확인하고 어디까지 바꿀까
🗂️ 먼저 실행 주체와 업데이트 책임을 나눕니다
🛡️ WAF는 시간을 벌지만 런타임을 고치지는 않습니다
🚧 제약과 오해하기 쉬운 지점
🧯 설정 하나로 “해결”했다고 말하지 않습니다
🧭 PHP-FPM을 일괄적으로 안전하거나 위험하다고 단정하지 않습니다
📝 문서 확인과 직접 검증은 다릅니다
🎯 정리
Sources

🛡️ PHP2Shell: 요청이 끝나도 남는 상태와 AI 시대의 패치 경계

2026년 10월 21일, PHP는 두 가지 치명적 취약점을 수정한 8.5.12·8.4.27·8.3.36·8.2.35를 공개했습니다.[19] 조건이 맞으면 인증하지 않은 공격자가 서버에서 코드를 실행할 수 있는 문제입니다.[19]

이번 사건을 이해하는 핵심은 “PHP 코드를 잘 작성했는가”만이 아닙니다. 취약점은 애플리케이션 아래의 런타임에 있으므로 사이트 코드나 플러그인 업데이트만으로는 해결되지 않습니다.[22]

💡 💡 핵심: 요청이 사용하는 메모리의 수명과 worker가 보관하는 상태의 수명이 어긋나면, 요청 종료가 안전한 경계가 되지 못합니다.[21] PHP2Shell은 이 경계와 패치 책임을 함께 배우는 사례입니다.[20][21]

🧩 무엇이 잘못됐나: 요청과 worker의 수명

📦 요청이 끝나도 worker는 다음 요청을 받습니다

PHP 공식 권고는 worker가 유지하는 오류·session·object·extension 상태 중 일부가 한 요청이 소유한 메모리를 가리킨다고 설명합니다.[21] 이 상태는 요청 메모리를 해제하기 전에 초기화돼야 합니다.[21]

문제는 정상 종료만 가정할 수 없다는 점입니다. fatal error로 정리가 중단되거나, 이미 정리한 뒤의 진단 메시지가 상태를 다시 채우면, 메모리는 해제됐는데 worker의 참조는 남을 수 있습니다.[21]

이때 다음 요청의 초기화보다 먼저 실행되는 처리가 오래된 참조를 사용하면 use-after-free가 발생합니다.[21] 공식 권고는 이를 이전 요청이 상태를 남기는 producer와 다음 요청이 그 상태를 사용하는 consumer의 조합으로 설명합니다.[21]

🔀 두 취약점은 같은 설명으로 뭉개면 안 됩니다

  • CVE-2026-109618 — OOM corruption: 메모리 부족 시 longjmp()로 처리를 빠져나오면서, 아직 완전히 초기화하지 않은 메모리를 종료 절차가 정상 상태처럼 사용할 수 있습니다.[20]
  • CVE-2026-109619 — stale global state: 요청 소유 메모리를 해제한 뒤에도 전역 상태가 남고, 같은 worker의 후속 요청이 정상 초기화 전에 이를 사용할 수 있습니다.[21]

두 문제 모두 메모리 관리와 오류 처리처럼 거의 모든 요청이 거치는 부분에 있습니다.[19] PHP Foundation은 호환성·성능·외부 extension에 미치는 영향 때문에 수정도 어려웠다고 설명합니다.[19]

⚙️ 패치는 어떤 경계를 복구하나

⏹️ 메모리 부족에서 안전하게 멈추기

OOM 권고의 패치는 즉시 longjmp()로 탈출하던 처리를 바꿉니다.[20] 다음 VM safe point에서 처리하는 soft OOM과, 더 높은 임계값에 도달했을 때 _exit()로 종료하는 hard OOM을 사용하도록 설명돼 있습니다.[20]

목적은 메모리 제한을 없애는 것이 아니라, 불완전한 내부 상태를 종료 절차가 잘못 사용하지 않게 하는 것입니다.[20] 공식 권고는 정상적인 메모리 제한 능력은 유지된다고 명시합니다.[20]

🧹 요청 소유 상태를 다음 요청에 넘기지 않기

stale-state 문제에서는 특정 session 기능 하나만 막는 것보다 넓은 상태 초기화가 필요합니다.[21] 공식 권고는 애플리케이션·extension·서버 경로가 서로 다른 producer와 consumer를 만들 수 있어, 모든 경우를 덮는 일반적인 설정 완화책은 없다고 설명합니다.[21]

설계 관점의 제안: 다른 런타임이나 장기 실행 worker를 검토할 때도 “성공한 요청의 정리”뿐 아니라 오류·취소·timeout 이후에 남는 참조와 캐시를 별도 테스트 대상으로 잡는 것이 좋습니다. 이는 PHP의 취약점이 다른 언어에도 그대로 존재한다는 뜻이 아니라, 상태 수명을 점검하는 질문을 가져오자는 의미입니다.

🤖 AI가 바꾼 것은 발견만이 아닙니다

Wiz는 이 연구에 Wiz Atlas·Gemini 4 Argon·GPT-5.6 Sol을 사용했다고 밝혔습니다.[11] 특히 서로 다른 PHP 버전·설정·메모리 배치에 맞춰 실패를 분석하고 수정하는 과정에서 LLM과 testing·debugging 도구의 역할을 설명합니다.[11]

따라서 이 사례의 학습 포인트는 “AI가 취약점 이름을 찾아냈다”보다 분석 → 검증 → 실패 원인 확인 → 조정의 반복에 있습니다. 다만 이는 연구팀이 공개한 작업 설명이며, 이 글에서 모델별 기여도나 비용 절감 효과를 독립 측정한 것은 아닙니다.[11]

PHP Foundation의 설명도 함께 봐야 합니다. OOM 문제의 초기 징후는 2024년 감사 후 이미 드러났고, AI 지원 연구로 보고가 늘어도 모든 판단과 패치에는 사람이 관여한다고 밝힙니다.[19]

💡 ⚠️ 편집 의견: 발견 자동화가 빨라져도 수정안의 호환성 판단, 검토자 확보, 배포 조율이 자동으로 해결되지는 않습니다. “버그를 찾는 속도”와 “안전하게 고치는 처리량”을 다른 운영 문제로 관리해야 합니다.[19]

🔬 공개 자료에서 확인한 사례

🧪 연구자 실증: WordPress·Drupal·Joomla

Wiz는 시험 당시의 wordpress:latest·drupal:latest·joomla:latest 컨테이너 배포에서 인증 없는 원격 코드 실행을 실증했다고 보고했습니다.[11]

이는 연구팀의 시험 대상과 조건에 대한 결과입니다.[11] 모든 PHP 서비스가 동일한 요청으로 똑같이 공격된다는 의미가 아니며, 공식 권고도 exploit의 이식성과 신뢰도가 PHP build·extension·frontend 동작·메모리 배치에 달린다고 설명합니다.[20]

🏗️ 운영사 대응: Coolify와 그 안의 앱은 다른 대상입니다

확인 시점의 Coolify 공식 문서는 Coolify Cloud가 패치됐다고 안내하면서, 플랫폼 패치가 사용자의 서버에 배포된 PHP 애플리케이션까지 업데이트하지는 않는다고 명시합니다.[24]

같은 관리 화면에서 운영하더라도 관리 플랫폼의 런타임과 배포된 앱의 런타임은 별도로 확인해야 한다는 사례입니다.[24] 여기서 확인한 것은 운영사의 문서화된 대응이지, 이 글 작성자가 해당 환경을 감사하거나 무침해를 검증한 결과가 아닙니다.

🧰 실무 적용: 무엇을 확인하고 어디까지 바꿀까

🗂️ 먼저 실행 주체와 업데이트 책임을 나눕니다

아래는 공개 권고를 업무 점검표로 옮긴 적용 제안입니다. 실제 서버 조사나 변경을 수행한 기록은 아닙니다.

  1. 서비스·관리 도구별로 어떤 PHP 런타임이 웹 요청을 처리하는지 정리합니다. CLI와 웹서버가 다른 바이너리·설정을 쓸 수 있으므로 php -v 하나만으로 끝내지 않습니다.[28]
  2. 공식 수정 버전과 배포판·hosting provider의 보안 패치를 대조합니다. backport된 패키지는 upstream 버전 숫자만으로 패치 유무를 판정하기 어렵습니다.[19][28]
  3. 업데이트 뒤 worker 재시작과 실제 웹 요청을 처리하는 버전을 확인하는 절차를 둡니다. 패키지 파일을 교체해도 오래된 프로세스가 계속 실행될 수 있습니다.[28]
  4. 플랫폼과 앱 이미지를 별도 항목으로 관리합니다. Coolify를 업데이트한 것과 그 안의 PHP 앱을 업데이트한 것은 같은 완료 조건이 아닙니다.[24]

🛡️ WAF는 시간을 벌지만 런타임을 고치지는 않습니다

Cloudflare는 같은 HTTP transaction의 request와 response 신호를 함께 보는 full transaction detection을 이번 보호에 사용했다고 설명합니다.[22] 응답을 requester에게 보내기 전에 차단하는 방식도 포함합니다.[22]

하지만 Cloudflare도 WAF 보호를 추가 방어층으로 두고 PHP 업데이트를 권고합니다.[22] Coolify 역시 Cloudflare를 통과하지 않고 origin에 직접 닿는 요청은 그 WAF를 우회한다고 경고합니다.[24]

선택 기준 제안: 런타임 패치를 기본 해법으로 두고, 즉시 패치할 수 없다면 영향 범위에 맞는 격리·임시 보호와 서비스 가용성 비용을 비교하세요. 필터가 있다는 이유로 패치 완료 판정을 대신하지 않는 편이 단순하고 추적하기 쉽습니다.

🚧 제약과 오해하기 쉬운 지점

🧯 설정 하나로 “해결”했다고 말하지 않습니다

session upload progress를 끄는 조치는 문서상 해당 session lifecycle 경로를 줄이지만, 다른 상태 경로까지 해결하지는 않습니다.[21] worker당 요청 수를 줄이는 조언도 성능 조건을 고려해야 하며, worker 재활용만으로 취약 조건이 사라지는 것은 아닙니다.[21]

OOM 권고에는 패치 불가 시의 memory_limit=-1 완화책도 있지만, underlying allocation 실패는 여전히 남아 완전한 해결이 아니라고 명시합니다.[20] 일반 학습 글에서 이 설정을 무조건 복사할 운영 처방으로 제시하지 않는 이유입니다.

🧭 PHP-FPM을 일괄적으로 안전하거나 위험하다고 단정하지 않습니다

OOM 권고는 request startup 실패 시 FPM child가 종료돼 해당 상태 소비를 막는다고 설명하며, 그 권고의 FPM 경로에는 완성된 exploit이 실증되지 않았다고 적습니다.[20]

반면 stale-state 권고는 정상 startup 이후 애플리케이션 실행 중 상태를 남기는 다른 경로에서 FPM의 session lifecycle RCE가 검증됐다고 명시합니다. “FPM은 안전하다”가 아니라 어느 취약점의 어떤 경로인가를 구분해야 하는 이유입니다.[21]

📝 문서 확인과 직접 검증은 다릅니다

이 글은 2026년 10월 22일 KST에 확인한 공식 권고와 연구자·운영사 공개 자료를 대조한 해설입니다. 취약점 재현, PHP 설치·패치, WAF 시험, 사내 자산 점검은 수행하지 않았습니다.

운영 점검에 인용한 Equixly 글은 정식 권고 전 작성된 자료입니다.[28] CLI와 웹 런타임 구분 같은 점검 원칙만 참고했고, 수정 버전·공격 조건은 공개 후의 PHP 공식 권고를 기준으로 삼았습니다.[20][21]

공식 권고는 로그에 오류가 없다는 사실도 안전의 증거가 아니라고 경고합니다. 이 글의 확인만으로 특정 서비스의 취약 여부나 침해 여부를 판정할 수는 없습니다.[21]

🎯 정리

  • 개념: 요청 메모리와 worker 상태의 수명이 어긋나면, 종료된 요청의 상태가 다음 요청에 영향을 줄 수 있습니다.[21]
  • 대응: PHP 런타임 패치와 실제 실행 중인 worker 확인을 기본으로 두고, WAF·설정 변경은 범위가 제한된 보조책으로 다룹니다.[20][22][28]
  • AI 시대의 교훈: 발견·검증 도구와 함께 사람의 판단, 수정 검토, 배포 책임도 확장해야 합니다. PHP Foundation도 AI가 검증을 돕지만 사람의 판단과 패치 작업을 대체하지 않는다고 설명합니다.[19]

Sources

[11] https://www.wiz.io/blog/php2shell-php-rce

[19] https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security

[20] https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w

[21] https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp

[22] https://blog.cloudflare.com/php-vulnerabilities-waf-protection

[24] https://coolify.io/docs/knowledge-base/php-security-advisory-2026

[28] https://equixly.com/blog/2026/10/21/cve-2026-109618-and-cve-2026-109619-what-we-know-about-php2shell-and-how-to-prepare