
PHP2Shell 노출 헌팅 및 관련 분석을 위한 리포지토리
PHP2Shell(CVE-2026-109618 / CVE-2026-109619)에 대한 Defender XDR 노출 헌팅.
v3.3 · 2026년 10월 22일
목적: PHP2Shell에 노출될 수 있는 PHP를 실행 중인 온보딩된 디바이스를 찾습니다.
범위: Defender XDR 고급 헌팅 · 온보딩된 Windows 및 Linux 엔드포인트 · 기본 30일 조회 기간 · 활성 PHP만 해당. 포함되지 않는 항목: 휴면 상태의 설치 및 관리되지 않는 디바이스. 설치된 소프트웨어(TVM) 테이블은 Defender XDR에서만 쿼리할 수 있으므로 Sentinel에서는 실행할 수 없습니다.
| 헌트 | Windows | Linux | 질문 |
|---|---|---|---|
| 1 | windows/01-any-php.kql | linux/01-any-php.kql | PHP가 있는가? 디바이스별 예/아니오. |
| 2 | windows/02-evidence-breakout.kql | linux/02-evidence-breakout.kql | 버전과 함께 증거 분류. |
| 3 | windows/03-safety-net.kql | linux/03-safety-net.kql | 안전망: 웹 포트에서 서비스 중인 디바이스, 수신 대기 프로세스, PHP 상태. |
모든 이벤트 검사는 각 헌트 상단의 let Lookback = 30d;라는 하나의 조회 기간을 사용합니다. IP 주소는 지난 7일 동안 어댑터별 최신 보고서에서 가져옵니다. 설치된 소프트웨어는 현재 TVM 스냅샷입니다. 온보딩된 엔드포인트만 검사합니다(OnboardingStatus == "Onboarded", DeviceCategory == "Endpoint").
다음 중 하나라도 일치하면 해당 디바이스는 PHP가 확인됨으로 간주됩니다.
이름 매칭 방식:
^…$)가 적용되므로, 파일 이름 전체와 일치해야 하며 일부만 일치해서는 안 됩니다.startswith "php", 그리고 두 OS 모두에서 frankenphp, Linux에서는 lsphp. 그런 다음 남은 항목에 대해서만 정규식이 실행됩니다.php9.dll)는 자동으로 매칭됩니다.patterns.test.js는 각 정규식을 이러한 예시에 대해 실행합니다. 정규식을 변경하면 그곳의 예시도 업데이트하세요.Windows
| 검사 | 테이블 | 매칭 | 중요한 이유 |
|---|---|---|---|
| PHP 실행 파일 시작됨 | DeviceProcessEvents | 정규식 ^(php(-cgi|-win)?|frankenphp)\.exe$, 정확히 네 개의 이름만 허용: php.exe(CLI), php-cgi.exe(FastCGI 워커), php-win.exe(CLI, 콘솔 없음), frankenphp.exe(웹 서버에 내장된 PHP). phpstorm64.exe 및 기타 php* 도구는 매칭되지 않음 | PHP가 실행되었음을 증명합니다. 헌트 2는 바이너리의 버전 정보(ProcessVersionInfoProductVersion)에서 버전을 보여줍니다 |
| PHP 엔진 DLL 로드됨 | DeviceImageLoadEvents | 정규식 ^php\d*(ts|isapi|apache[\w_]*)?\.dll$: php, 임의의 버전 번호, 선택적 ts / isapi / apache… 접미사, 그다음 .dll. 예시는 아래 DLL 표에 있습니다. 확장 DLL(php_curl.dll 및 기타 php_*.dll)은 php 바로 뒤에 밑줄이 허용되지 않으므로 매칭되지 않습니다 | IIS 또는 Apache와 같이 php*.exe가 시작되지 않는 다른 프로세스 내부에서 실행 중인 PHP를 볼 수 있는 유일한 방법입니다. 헌트 2는 DLL과 이를 로드한 프로세스를 보여줍니다 |
| 설치된 소프트웨어 | DeviceTvmSoftwareInventory | 정규식 아님: SoftwareName has "php"(이름에서 php가 단어 전체로 존재) 또는 SoftwareVendor =~ "php"(정확히 일치, 대소문자 구분 없음) | 등록된 설치를 포착합니다. Zip 설치(일반적인 Windows 방식)는 보통 등록되지 않습니다 |
Windows 패턴이 매칭하는 PHP 엔진 DLL 예시
| DLL | 무엇인지 | 일반적인 호스트 프로세스 (hunt 2에 표시됨) |
|---|---|---|
php8.dll, php7.dll | 엔진, 비스레드 안전 빌드 | php-cgi.exe (IIS, nginx 또는 Apache mod_fcgid 아래의 FastCGI), php.exe |
php8ts.dll, php7ts.dll, php5ts.dll | 엔진, 스레드 안전 빌드 | httpd.exe (Apache 모듈), php.exe |
php8apache2_4.dll, php7apache2_4.dll, php5apache2_2.dll | Apache 모듈 로더 | httpd.exe |
php5isapi.dll | 레거시 IIS ISAPI 모듈 (PHP 5.2 이하, 지원되지 않음) | w3wp.exe |
이 표는 일반적인 이름을 나열한 것이지 허용 목록이 아닙니다. 패턴에 맞는 모든 이름이 일치합니다. DLL 이름은 주 버전만 알려줍니다. 정확한 버전은 동일한 장치의 php-cgi.exe 또는 php.exe 프로세스 행이나 설치된 소프트웨어에서 확인할 수 있습니다.
Linux
| 검사 | 테이블 | 일치 항목 | 중요한 이유 |
|---|---|---|---|
| PHP 바이너리 시작됨 | DeviceProcessEvents | 정규식 ^(php[\d.]*|php-(fpm|cgi)[\d.]*|lsphp[\d.]*|frankenphp)$: php, php-fpm, php-cgi 또는 lsphp (LiteSpeed), 각각 숫자와 점으로 구성된 선택적 버전이 붙을 수 있으며, 추가로 frankenphp. 예: php, php8.3, php83, php-fpm8.3, php-cgi8.2, lsphp83. phpunit, phpize, php-config 같은 도구는 기본 이름 뒤에 숫자와 점만 올 수 있으므로 일치하지 않습니다 | PHP가 실행되었음을 증명합니다. Hunt 2는 두 번째 정규식 php-?(?:fpm|cgi)?/?(\d+\.\d+) (예: php-fpm8.3 또는 /etc/php/8.3/는 8.3.x를 제공)을 통해 이름, 경로 또는 명령줄에서 추출한 major.minor 힌트를 표시합니다 |
| 설치된 패키지 | DeviceTvmSoftwareInventory | 정규식이 아님: SoftwareName contains "php" (부분 문자열이므로 php8.3-fpm 및 libapache2-mod-php8.3 같은 버전이 붙은 이름도 일치) 또는 SoftwareVendor =~ "php" | Apache mod_php와 윈도우 이전부터 실행 중인 php-fpm을 확인하는 유일한 검사입니다. Linux에는 여기서 라이브러리 로드 검사가 없으며, 포크된 php-fpm 워커는 프로세스 시작을 생성하지 않습니다 |
| 검사 | 테이블 | 일치 항목 | 중요한 이유 |
|---|---|---|---|
| 활성 웹 서비스 | DeviceNetworkEvents | 고정 포트 목록(80, 443, 8080, 8443)에서의 InboundConnectionAccepted. 루프백은 제외됩니다(RemoteIPType != "Loopback"). 고유 및 공용 소스와 수락 프로세스(via <process>)를 표시합니다 | 웹 서버가 조회 기간 이전에 시작되었더라도 장치가 서비스 중임을 증명합니다. ntoskrnl.exe = HTTP.sys (IIS, ADFS, RD Gateway, Windows Admin Center, SSTP) |
| 웹 서버 시작됨 | DeviceProcessEvents | 정규식이 아님: 대소문자를 구분하지 않는(in~) 정확한 이름의 고정 목록. Windows: w3wp.exe, httpd.exe, nginx.exe, caddy.exe, lighttpd.exe, frankenphp.exe. Linux: httpd, apache2, nginx, lshttpd, litespeed, openlitespeed, caddy, lighttpd, frankenphp | 기간 내에 시작되었고 PHP를 로드하지 않은 웹 서버는 높은 신뢰도로 "Not seen"을 제공합니다. Windows는 또한 정규식 -ap\s+"?([^"\s]+)을 통해 w3wp.exe 명령줄에서 추출한 IIS 애플리케이션 풀 이름을 표시합니다 |
hunt 3의 PHP 열 값
| 값 | 의미 |
|---|---|
PHP seen (see hunt 2) | 하나 이상의 PHP 탐지 검사가 일치했습니다. |
Not seen | PHP 증거가 없으며, 기간 내에 웹 서버가 시작되었거나(높은 신뢰도) 장치가 웹을 서비스하지 않습니다. |
Not seen - no web server start in <N>d (N = Lookback) | 웹 포트에서 서비스 중이지만 검사할 웹 서버 프로세스 시작이 없습니다. 이것이 남은 사각지대입니다. 호스트의 via 프로세스를 확인하세요. |
uncomment for evidence-only rows로 표시된 줄의 주석을 해제하세요.let Lookback = 30d; 줄을 변경하고, 모든 헌트에서 동일한 값을 사용하세요.
npm test는 30d를 초과하는 값과 헌트 간에 혼재된 값을 거부합니다.두 OS 모두:
Windows:
Linux, Linux 양성 대조 테스트가 통과할 때까지 미검증:
Linux 커버리지 격차:
PHP 탐지 블록은 각 OS의 세 헌트 내에서 동일합니다. 세 개를 함께 변경하세요. 서로 어긋나면 npm test가 실패합니다. 탐지 정규식을 변경할 때는 tests/lint/patterns.test.js의 예상 일치 및 비일치 항목을 업데이트하세요. 테스트는 쿼리에서 정규식을 읽으므로, 복사본이 아닌 여러분의 수정 사항을 검사합니다.