
php2shell(CVE-2026-109618 / CVE-2026-109619)에 대한 개념 증명(PoC) 익스플로잇으로, 취약한 PHP 환경에서의 원격 코드 실행을 시연합니다. 보안 연구 및 교육 목적으로만 사용됩니다.
중요 권고 (CVSS v4.0: 9.2 - 심각): 10월 20일, PHP 코어의 인증 전 원격 코드 실행(RCE) 취약점 두 건의 세부 정보가 조율된 공개에 앞서 온라인에 유출되었습니다. 이를 악용하면 웹 서버에서 곧바로 임의 명령을 실행할 수 있습니다.
php2shell은 PHP 코어 기능에 영향을 미치는 두 가지 심각한 취약점(CVE-2026-109618 및 CVE-2026-109619)을 가리킵니다. 주요 시연된 공격 경로는 PHP 코어의 세션 업로드 진행률 메커니즘에서 발생하는 힙 사용 후 해제(UAF)로, 이는 임의 코드 실행(zend_call_function / system())으로 이어집니다.
PHP의 업로드 진행률 핸들러(ext/session/session.c의 php_session_rfc1867_callback)는 두 개의 원시 zval * 버킷 포인터(post_bytes_processed 및 current_file_bytes_processed)를 활성 HashTable 구조체에 직접 저장합니다.
요청 처리 과정에서:
POST 요청이 기본 구성 값(session.upload_progress.enabled = 1)으로 진행률 추적을 활성화합니다.zend_hash_update() 함수는 소멸자 zval_ptr_dtor를 사용하여 이전 데이터 트리를 파괴하고 메모리 블록을 해제합니다.zend_fcall_info 및 zend_internal_function 구조체를 가리키도록 재지정됩니다.zend_call_function()을 호출하여 임의의 시스템 명령 실행이 이루어집니다.php-src 빌드(버전 8.4.4 및 8.2.34 포함)에서 확인되었습니다.zval_ptr_dtor와 zend_call_function 사이의 심볼 오프셋(--syms)을 사용합니다.다음 표는 CVE-2026-109618 및 CVE-2026-109619의 영향을 받는 PHP 버전과 해당 지원 및 패치 상태를 요약한 것입니다:
| PHP 브랜치 | 상태 | 영향받는 버전 | 수정 / 안전 버전 | 비고 |
|---|---|---|---|---|
| PHP 8.5 | 지원됨 (활성) | < 8.5.12 | 8.5.12 | 긴급 보안 릴리스 게시됨 |
| PHP 8.4 | 지원됨 (활성) | < 8.4.27 | 8.4.27 | 긴급 보안 릴리스 게시됨 |
| PHP 8.3 | 지원됨 (활성) | < 8.3.36 | 8.3.36 | 긴급 보안 릴리스 게시됨 |
| PHP 8.2 | 지원됨 (보안 전용) | < 8.2.35 | 8.2.35 | 긴급 보안 릴리스 게시됨 |
| PHP 8.1 | 지원 종료 (EOL) | 모든 8.1.x 버전 | 공식 패치 없음 (EOL) | session.upload_progress.enabled = Off로 설정하거나 ELS/배포판 백포트 사용 |
| PHP 8.0 | 지원 종료 (EOL) | 모든 8.0.x 버전 | 공식 패치 없음 (EOL) | 공식 지원 종료됨; 구성 완화 조치 필수 |
| PHP 7.x | 지원 종료 (EOL) | 모든 7.0 - 7.4 버전 | 공식 패치 없음 (EOL) | 핵심 ext/session 로직이 취약함; 긴급 완화 조치 또는 업그레이드 필요 |
| PHP 5.x | 지원 종료 (EOL) | 5.4.0+ (RFC1867 진행 상황 추적 포함) | 공식 패치 없음 (EOL) | 공식 지원 종료됨; 호스트 격리 또는 업로드 진행 상황 비활성화 |
[!WARNING] PHP 8.1 및 이전 지원 종료(EOL) 버전은 PHP Foundation으로부터 공식 보안 패치를 받지 못합니다. 이러한 환경에서는 즉시
session.upload_progress.enabled = Off를 적용하거나 제공된 C 소스 패치를 사용하여 PHP를 소스에서 다시 빌드하십시오.
php2shell의 악용은 일반적으로 PHP 워커 프로세스(php-fpm, php-cgi, php-cgi.exe, httpd, apache2)에 의해 직접 생성된 비정상적인 자식 프로세스로 나타납니다.
다음을 실행하는 PHP 워커 프로세스를 모니터링하고 경고하십시오:
/bin/sh, /bin/bash, cmd.exe, powershell.exepython, perlcurl, wget, nc, certutil.exe/dev/tcp/, fsockopen, mkfifowhoami, id, uname -a, ipconfig엔드포인트 탐지 에이전트가 없는 Linux 기반 웹 환경의 경우, Florian Roth의 무료 process-watcher와 같은 도구를 관찰 모드로 실행하여 비정상적인 자식 프로세스 생성 여부를 실시간으로 표시할 수 있습니다.
php.exe, php-cgi.exe)./tmp, /var/tmp)를 검사하십시오.CVE-2026-109618을 대상으로 하는 완전 자동화된 원클릭 원격 익스플로잇이 poc_109618.py에 제공됩니다. 이 익스플로잇은 일반 HTTP 요청을 사용하여 ASLR을 원격으로 우회함으로써 신뢰할 수 있는 임의 명령 실행을 달성합니다.
공격 체인은 HTTP를 통한 네 가지 순차적 단계로 구성됩니다:
--huge-mb, 기본값 12MB)를 통해 OOM(out-of-memory) 조건을 유발하여 Set-Cookie: PHPSESSID를 통해 초기화되지 않은 메모리 누출을 트리거하고, Zend MM 2MB 정렬 청크 베이스를 추출합니다.Set-Cookie를 통해 ZVAL_PTR_DTOR 함수 포인터를 누출시키고, libphp.so의 베이스 주소를 계산합니다.zend_string 내부에 포함된 가짜 HashTable 구조체를 위조하며, pDestructor는 libphp.so의 zif_system을 직접 가리킵니다. 조작된 참조는 PS(http_session_vars)를 덮어씁니다. PHP가 세션 데이터를 해제할 때 zif_system이 제공된 명령을 실행합니다.[!NOTE] 명령은 167바이트의 라이브
zend_string캐리어(0x98 헤더 + NUL 바이트 제한) 내부에 직접 포함되므로, 인라인 명령 문자열은 최대 14바이트(MAX_CMD = 14)로 제한됩니다. 더 긴 명령의 경우sh</tmp/c(8바이트) 또는sh</out/c와 같은 짧은 트리거를 통해 연결하십시오.
기본 익스플로잇 프로파일은 다음 설정의 Apache prefork 환경에서 mod_php를 대상으로 합니다:
display_errors = 1memory_limit = 8M (또는 --huge-mb보다 충분히 낮게)max_input_vars = 1000session.use_cookies = 1, session.use_strict_mode = 0session.upload_progress.enabled = 1# Default command execution against target URL
python3 poc_109618.py -u http://127.0.0.1:8088/index.php
# Execute a custom command (max 14 bytes) and verify via local proof file
python3 poc_109618.py -u http://127.0.0.1:8088/index.php -c 'id>/out/p1' --proof-file out/p1
# Execute command writing to webroot and verify via HTTP GET fetch
python3 poc_109618.py -u http://127.0.0.1:8088/index.php -c 'id>p1.txt' --fetch /p1.txt