1. 개요
- PHP 엔진 자체에서 인증되지 않은 공격자가 원격으로 코드를 실행할 수 있는 2가지 취약점 PHP2Shell (CVE-2026-109618, CVE-2026-109619) 발견
- 두 결함은 서버의 메모리 처리 과정에서 발생하며, 인증되지 않은 공격자가 해당 서버에서 코드를 실행하거나, 메모리에서 다른 요청 또는 서버 자체의 암호, 인증 토큰, API 등 민감 데이터 탈취, 웹 사이트 변조가 가능
- PHP 개발팀은 10월 21일 보안 업데이트를 공개하였고, 전체 웹사이트의 70% 이상이 PHP를 활용하고 있어 신속한 업데이트 또는 보안 조치 적용 필요
2. 취약점
- 공개된 취약점은 요청 처리 중 발생하는 메모리 부족 오류를 PHP가 처리하는 방식에서 비롯됨 [1]~[12]
- PHP의 Zend는 PHP 소스 코드를 바이트코드로 컴파일 및 실행하며, 변수·배열·객체·메모리 할당 등을 관리
> PHP에서 치명적 오류가 발생하면, zend_bailout()이 LONGJMP()를 수행해 현재 C 함수 호출 스택에서 벗어남
> 이때, 오류 발생 전 변경된 상태가 복귀되거나 초기화되지 않아 일부 메모리가 유효한 상태로 남게됨
// Zend/zend.c [13]
ZEND_API ZEND_COLD ZEND_NORETURN void _zend_bailout(const char *filename, uint32_t lineno)
{
...
CG(unclean_shutdown) = 1;
...
LONGJMP(*EG(bailout), FAILURE);
}
2.1 CVE-2026-109618

- PHP가 메모리 부족(OOM, Out Of Memory)으로 요청 처리를 중단하는 과정에서 내부 요청 데이터가 부분적으로만 초기화되어, 후속 요청이 이를 유효한 데이터로 처리하여 메모리 손상 및 원격 코드 실행으로 이어지는 취약점 (CVSS: 9.2) [14][15]
영향받는 버전
- 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가 요청 데이터를 배열 항목에 추가할 때, 항목 수를 먼저 증가시킨 뒤, 키를 저장할 메모리 할당
> 이때, 메모리 할당이 memory_limit을 초과하면 치명적 오류가 발생하고, zend_bailout()을 통해 실행 흐름이 중단
> 그 결과, 배열은 항목이 추가되었다고 기록되며, 해당 항목의 값에는 메모리 값이 남게됨
// Zend/zend_hash.c [16]
add_to_hash:
idx = ht->nNumUsed++;
ht->nNumOfElements++;
p = ht->arData + idx;
p->key = key = zend_string_init(str, len, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
관련 버그 ① 업로드 진행률 역직렬화기의 Use-After-Free
- PHP Session 모듈은 업로드 진행률을 처리하는 동안 세션 데이터를 디코딩하고, 요청의 관리 정보를 BG(unserialize)에 저장
> 메모리 할당 실패로 처리가 중단되면 요청 힙이 해제된 후에도 역직렬화기의 전역 상태가 남을 수 있음
> 이후 동일한 워커의 후속 요청이 해당 상태를 유효한 관리 정보로 취급하면, 이미 해제된 메모리에 접근하는 Use-After-Free 발생
관련 버그 ② 원격 프로세스 메모리 정보 노출
- PHP는 정상 모듈 초기화가 완료되기 전 RFC 1867 Multipart 요청을 파싱하고, 업로드 진행률 처리는 이 단계에서 Session 상태를 초기화하고 Session ID를 PS(id)에 저장할 수 있음
> 메모리 부족 오류로 정리 작업이 중단되어 힙이 해제되어도 PS(id)가 해제된 메모리를 가리키는 상태로 남을 수 있음
> 동일한 워커의 후속 Multipart 요청이 Session 초기화 전 업로드 진행률 정리 단계가 먼저 실행되면, PHP는 오래된 포인터와 길이를 유효한 zend_string으로 신뢰
> 재사용된 힙 내용을 URL 인코딩하여 PHPSESSID 응답 쿠키에 담으면서 메모리가 유출
2.2 CVE-2026-109619

- PHP가 치명적 오류로 실행을 중단한 뒤 요청 메모리를 해제하더라도 전역 상태가 이전 메모리 주소를 계속 참조해, 이후 요청에서 해제된 메모리를 재사용하는 Use-After-Free가 발생하고 원격 코드 실행으로 이어지는 취약점 (CVSS: 9.2) [17][18]
영향받는 버전
- PHP 8.2 < 8.2.35
- PHP 8.3 < 8.3.36
- PHP 8.4 < 8.4.27
- PHP 8.5 < 8.5.12
관련 버그 ① 치명적 오류 백트레이스의 Use-After-Free
- PHP는 가장 최근에 발생한 치명적 오류의 백트레이스를 EG(last_fatal_error_backtrace)에 보관
> 치명적인 메모리 부족 오류가 요청 힙이 파괴되는 동안 이 값이 적절히 초기화되지 않으면, 워커는 이전 요청의 메모리를 가리키는 포인터를 보유한 채 계속 실행됨
> 동일한 워커가 다음 요청 초기에 진단 메시지를 출력하면, 실행기가 해당 상태를 재초기화하기 전에 오래된 포인터에 접근할 수 있음
> 이때 PHP가 백트레이스를 파괴하거나 갱신하는 과정에서 공격자가 재사용한 메모리를 따라가면 요청 간 Use-After-Free가 발생하고, 제어 가능한 메모리 손상으로 발전할 수 있음
관련 버그 ② OPcache 타입 혼동
- OPcache는 컴파일된 PHP 구조체를 공유 메모리에 보관하며, 워커별 런타임 포인터 맵을 통해 해당 구조체에 접근
> zend_accel_script_persist()는 프로세스 로컬의 CG(map_ptr_last) 경계값을 먼저 증가시키고, 영속화가 완료된 뒤 공유 경계값을 갱신함
> 두 작업 사이에 메모리 할당 실패가 발생하면 부분적으로 영속화된 객체는 공유 상태에서 여전히 사용 가능한 것으로 인식
> 이후 다른 워커가 해당 슬롯을 다른 런타임 객체에 재사용하면, 오래된 공유 메타데이터가 잘못된 타입의 포인터를 가리키며 워커 간 타입 혼동과 공유 OPcache 상태 손상을 일으킴
3. 대응방안
- 벤더사 제공 보안 업데이트 적용 [19][20][21]
> 점검 스크립트 또는 무료 점검 도구 활용 [22][23]
| 취약점 | 제품명 | 영향받는 버전 | 해결 버전 |
| CVE-2026-109618 CVE-2026-109619 |
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 이상 |
- WAF 탐지룰 설정
> 요청 본문에 PHP_SESSION_UPLOAD_PROGRESS 문자열이 들어 있는 요청
※ 서버에서 session.upload_progress.name을 변경한 경우 변경한 이름으로 적용
> 대괄호가 깊게 중첩된 필드 이름(a[b][c][d]...)
> filename=""인 빈 업로드 파트가 대량으로 들어 있는 multipart 요청
- 임시 완화 방안 [23]
> session.auto_start = On인 서버는 session.upload_progress.enabled를 꺼도 취약한 것으로 파악
| 실행 방식 | Calif 권고 | 추가 권고 |
| mod_php (apache2handler) | memory_limit = -1 | session.auto_start = 0 |
| PHP-FPM (fpm-fcgi) CGI/FastCGI (cgi-fcgi) |
session.upload_progress.enabled = 0 + memory_limit = -1 |
| SAPI | 적용 위치 | 반영 시점 |
| apache2handler (mod_php) | Apache 설정(vhost 등)에 php_admin_value memory_limit -1, php_admin_flag session.auto_start off | Apache 재시작 |
| fpm-fcgi (PHP-FPM) | 풀 설정에 php_admin_value[memory_limit] = -1, php_admin_flag[session.upload_progress.enabled] = off, php_admin_flag[session.auto_start] = off | PHP-FPM 재시작 |
| cgi-fcgi (CGI/FastCGI) | php.ini 또는 웹 루트의 .user.ini | .user.ini는 최대 5분 |
| 컨테이너 | 이미지의 conf.d에 ini 파일 추가 | 재빌드 후 재배포 |
> 웹 서버 설정
| 서버 | 설명 |
| Apache | LimitRequestBody로 요청 본문 크기를 웹 서비스에 필요한 만큼만 허용 |
| Nginx + PHP-FPM | - client_max_body_size는 웹 서비스에 필요한 최소값으로 두고, 큰 업로드가 필요한 경로만 location 단위로 증가 - fastcgi_request_buffering은 기본값(on) 유지 |
- 침해 여부 확인
| 구분 | 설명 |
| 로그 점검 | ① 비정상 메모리 초과 로그 - in Unknown on line 0 로그가 있을 경우 공격일 가능성이 높음 > 주로 mod_php 공격에서 나타남 > 확인 명령 grep -cE 'Allowed memory size of [0-9]+ bytes exhausted.in Unknown on line 0' \ /var/log/php_errors.log /var/log/apache2/error.log /var/log/httpd/error_log \ /var/log/php-fpm.log 2>/dev/null ② 크래시와 워커 비정상 종료 로그 > 확인 명령 grep -E "Segmentation fault|signal 11|SIGSEGV" \ /var/log/apache2/error.log /var/log/httpd/error_log /var/log/php*-fpm.log 2>/dev/null dmesg | grep -i segfault | grep -E "php|httpd|apache2" |
| 요청·응답 이상 징후 | - 비정상적인 multipart 요청 직후에 메모리 초과 에러나 HTTP 500이 반복되는 경우 - 응답의 PHPSESSID 쿠키가 비정상적으로 길거나 깨진 값인 경우 (메모리 노출 공격의 흔적. WAF나 프록시 로그에서 확인) - 원인을 알 수 없는 PHP 워커 재시작이 급증한 경우 |
| 비정상적으로 큰 세션 파일 | find <세션 저장 경로> -name 'sess_*' -size +1M -exec ls -lh {} \; |
| 침해 흔적 확인 | # 웹서버 계정이 실행 중인 프로세스 (계정명은 환경에 맞게: www-data, apache, nginx 등) ps -u www-data -o pid,ppid,lstart,cmd # 최근 3일 안에 바뀐 PHP 파일 (웹쉘, 변조 확인) find /var/www -name '*.php' -mtime -3 -ls # 웹서버·PHP 프로세스의 외부 연결 ss -tnp | grep -E "php|httpd|apache2|nginx” ※ 흔적 확인 시 해당 서버 격리 및 로그 보존, 메모리 노출 가능성이 있으므로 DB 비밀번호, API 키, 세션·암호화 키 등 비밀정보 교체 |
4. 참고
[1] https://www.php2shell.com/
[2] https://www.wiz.io/blog/php2shell-php-rce
[3] https://openai.com/ko-KR/index/coordinated-disclosure-of-critical-vulnerabilities/
[4] https://calif.io/php2shell/
[5] https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/
[6] https://www.akamai.com/blog/security-research/critical-remote-code-execution-vulnerabilities-php-core
[7] https://www.imperva.com/blog/php2shell-vulnerability-updates/
[8] https://blog.cloudflare.com/php-vulnerabilities-waf-protection/
[9] https://corelight.com/blog/php2shell-detection-before-disclosure
[10] https://www.crowdstrike.com/en-us/blog/crowdstrike-protects-customers-from-php-rce-zero-days/
[11] https://unit42.paloaltonetworks.com/cve-2026-109618-cve-2026-109619/
[12] https://blog.talosintelligence.com/two-critical-rces-in-php-core/
[13] https://github.com/php/php-src/blob/php-8.5.11/Zend/zend.c#L1256
[14] https://nvd.nist.gov/vuln/detail/cve-2026-109618
[15] https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
[16] https://github.com/php/php-src/blob/php-8.5.11/Zend/zend_hash.c#L881
[17] https://nvd.nist.gov/vuln/detail/cve-2026-109619
[18] https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp
[19] https://www.php.net/archive/2026.php#2026-10-21-5
[20] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=72227
[21] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=72230
[22] https://stealien.com/php2shell
[23] https://xint.io/ko/blog/php2shell-vulnerability-emergency-response
[24] https://www.boannews.com/news/articleView.html?idxno=146621
[25] https://www.boannews.com/news/articleView.html?idxno=146628
[26] https://www.boannews.com/news/articleView.html?idxno=146633
[27] https://www.boannews.com/news/articleView.html?idxno=146632
[28] https://www.boannews.com/news/articleView.html?idxno=146653
[29] https://www.boannews.com/news/articleView.html?idxno=146664
[30] https://www.dailysecu.com/news/articleView.html?idxno=208978
[31] https://www.dailysecu.com/news/articleView.html?idxno=208979
[32] https://www.dailysecu.com/news/articleView.html?idxno=208985
[33] https://www.dailysecu.com/news/articleView.html?idxno=208986
[34] https://www.dailysecu.com/news/articleView.html?idxno=208998
[35] https://news.hada.io/topic?id=35761
'취약점 > RCE' 카테고리의 다른 글
| Citrix NetScaler 사전 인증 원격 코드 실행 및 메모리 오버플로 취약점 (CVE-2026-88771, CVE-2026-88772) (0) | 2026.10.19 |
|---|---|
| JetBrains TeamCity On-Premises 신뢰할 수 없는 데이터의 역직렬화 취약점 (CVE-2026-63077) (0) | 2026.10.06 |
| Gitea diffpatch 엔드포인트를 통한 RCE 취약점 (CVE-2026-60004) (0) | 2026.09.17 |
| WordPress 미인증 RCE 체인 (wp2shell: CVE-2026-63030, CVE-2026-60137) (1) | 2026.07.24 |
| GitHub 원격 코드 실행 취약점 (CVE-2026-3854) (0) | 2026.05.05 |












