Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
EXPLOIT-CVE-2026-22778 — CVE-2026-22778에 대한 개념 증명 익스플로잇으로, vLLM의 비디오 처리에서 발생하는 인증되지 않은 RCE이며, FFmpeg의 JPEG2000 디코더에서 힙 주소 노출과 힙 버퍼 오버플로우를 시연합니다. 승인된 테스트를 위한 취약한 실습 환경을 포함합니다. | Kitploit
도구/GitHubGitHub/joaovicdev/exploit-cve-2026-22778
Vulnerability AnalysisExploitationWeb Application ExploitationFuzzingPenetration TestingLearning & EducationBinary ExploitationLabs & Practice
GitHub
joaovicdev/exploit-cve-2026-22778

EXPLOIT-CVE-2026-22778

CVE-2026-22778에 대한 개념 증명 익스플로잇으로, vLLM의 비디오 처리에서 발생하는 인증되지 않은 RCE이며, FFmpeg의 JPEG2000 디코더에서 힙 주소 노출과 힙 버퍼 오버플로우를 시연합니다. 승인된 테스트를 위한 취약한 실습 환경을 포함합니다.

저장소 보기
19시간 14분 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-22778 — vLLM 비디오 처리 원격 코드 실행(RCE)

CVE-2026-22778(CVSS 9.8)에 대한 취약 실습 환경 및 개념 증명(PoC)입니다. vLLM의 멀티모달 입력 처리 경로에서 발생하는 인증 없는 원격 코드 실행 체인입니다.

CVECVE-2026-22778
AdvisoryGHSA-4r2x-xpjr-7cvv
영향 범위vLLM >= 0.8.3, < 0.14.1 (비디오 모델을 서빙하는 배포 환경)
수정 버전vLLM 0.14.1
CVSS9.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
근본 원인CVE-2025-9951 — FFmpeg JPEG2000 디코더의 힙 버퍼 오버플로

취약점

두 개의 개별 결함이 연결되어 발생합니다. 기본 vllm serve에는 인증이 없으므로 두 결함 모두 인증 없이 /v1/chat/completions 및 /v1/invocations 엔드포인트에 도달할 수 있습니다.

1단계 — 힙 주소 노출(ASLR 우회)

이미지 파싱에 실패하면 Pillow는 읽고 있던 BytesIO 객체의 repr()이 포함된 메시지와 함께 예외를 발생시킵니다:

root@kitploit:~
cannot identify image file <_io.BytesIO object at 0x7f4a9c2e1d50>

vLLM은 미디어 로딩 실패를 HTTP 400으로 변환하고 exc.detail을 수정 없이 클라이언트에 반환했습니다 (api_server.py):

root@kitploit:~
async def http_exception_handler(_: Request, exc: HTTPException):
    err = ErrorResponse(
        error=ErrorInfo(
            message=exc.detail,          # <-- 주소를 그대로 노출
            ...

이 단일 주소는 힙 ASLR의 엔트로피를 약 32비트에서 대략 3비트로 줄이며, 이는 2단계를 단순한 크래시가 아닌 악용 가능한 상태로 만드는 핵심입니다.

2단계 — JPEG2000 디코더의 힙 버퍼 오버플로

video_url은 서버에 의해 가져와져 OpenCV에 전달됩니다:

root@kitploit:~
MediaConnector.load_from_url()      vllm/multimodal/utils.py
  -> OpenCVVideoBackend.load_bytes()   vllm/multimodal/video.py
    -> cv2.VideoCapture(BytesIO(data), backend, [])
      -> FFmpeg 5.1.x (opencv-python-headless < 4.13에 번들됨)

vLLM은 FFmpeg 5.1.x가 포함된 opencv-python-headless >= 4.11.0을 고정(pin)했습니다. 해당 버전의 JPEG2000 디코더는 파일의 채널 정의(cdef) 박스에서 직접 대상 평면(plane)을 선택합니다 — libavcodec/jpeg2000dec.c, write_frame_8:

root@kitploit:~
if (planar)
    plane = s->cdef[compno] ? s->cdef[compno]-1 : (s->ncomponents-1);
...
int w = tile->comp[compno].coord[0][1] - ...;   /* 컴포넌트에서 가져옴  */
int h = tile->comp[compno].coord[1][1] - ...;   /* 평면에서 가져오지 않음! */

plane은 공격자가 제어할 수 있지만 w/h는 디코딩 중인 컴포넌트에서 가져오며, 한쪽이 다른 쪽에 맞는지 확인하는 검사가 없습니다. cn=0, asoc=2인 cdef 항목은 컴포넌트 0(전체 해상도 휘도 평면)을 평면 1(2×2 서브샘플링된 색차 평면)로 보냅니다.

이 PoC가 사용하는 150×64 프레임의 경우:

크기
Y 컴포넌트(쓰기)150 × 64 = 9,600 바이트
U 평면(대상)75 × 32 = 2,400 바이트
오버플로할당 영역을 7,200 바이트 초과

FFmpeg는 각 평면을 별도의 AVBuffer로 할당하므로 오버플로는 인접한 힙 청크를 통과합니다 — 여기에는 free 함수 포인터를 보유한 AVBuffer 구조체도 포함됩니다. 1단계의 메모리 누출과 결합하여 해당 포인터를 덮어쓰는 것이 메모리 손상을 코드 실행으로 전환하는 방법입니다.

이 PoC는 메모리 손상 단계에서 멈춥니다. 서버 프로세스를 종료하여 경계를 벗어난 쓰기를 증명합니다. 힙 그루밍과 함수 포인터 덮어쓰기는 의도적으로 구현하지 않았습니다.

실습 환경

lab/app.py는 vLLM 0.13.0의 멀티모달 입력 처리 경로를 최소한으로 재구현한 것입니다 — MediaConnector, ImageMediaIO, OpenCVVideoBackend 및 패치 이전의 오류 처리기로, 각각 미러링하는 업스트림 파일에 대한 주석이 포함되어 있습니다. 모델 런타임은 스텁(stub) 처리되어 있습니다: 취약점은 추론 이전에 실행되는 미디어 입력 처리에 전적으로 존재하며 GPU나 모델 가중치가 필요하지 않습니다.

공격 경로의 모든 요소는 실제 구성 요소입니다 — 주소를 누출하는 동일한 Pillow 호출과 패치되지 않은 opencv-python-headless==4.11.0.86(FFmpeg 5.1.x, libavcodec 59.37.100)에 대한 동일한 cv2.VideoCapture 호출입니다.

사용 방법

root@kitploit:~
docker compose up -d --build
python3 exploit.py

옵션:

root@kitploit:~
python3 exploit.py --target http://localhost:8000
python3 exploit.py --serve                  # 페이로드를 HTTP로 전달
python3 exploit.py --write-payload evil.jp2 # 악성 파일만 생성

익스플로잇은 순수 표준 라이브러리만 사용합니다 — 추가 의존성이 없습니다.

예상 출력

root@kitploit:~
[*] Stage 1 -- heap address disclosure via PIL error message
    HTTP 400
    cannot identify image file <_io.BytesIO object at 0xffff8f555300>
[+] Leaked heap address: 0xffff8f555300
    ASLR bypassed: the heap base is now known to ~3 bits of entropy.

[*] Stage 2 -- heap buffer overflow in the JPEG2000 decoder
    Target alive: boot_id=95b62f18-13c0-4d6d-97d3-1b029207dc01 pid=1
    Payload: 203 bytes, 150x64 yuv420p JP2
    cdef maps component 0 -> plane 1: writes 9600 bytes into a 2400-byte plane (7200-byte overflow)
    Request never completed: Remote end closed connection without response
    Probing /health to see what happened to the worker...
[+] Worker was killed and restarted: boot_id 95b62f18-... -> 4494d28c-...
[+] Out-of-bounds write confirmed.

서버 측 로그:

root@kitploit:~
$ docker compose logs vllm
cve-2026-22778-lab  | INFO:     POST /v1/chat/completions HTTP/1.1" 400 Bad Request
cve-2026-22778-lab  | corrupted size vs. prev_size
cve-2026-22778-lab  | INFO:     Started server process [1]

정리:

root@kitploit:~
docker compose down

페이로드

build_payload()에서 처음부터 구축한 203바이트입니다. 4:2:0 서브샘플링으로 세 개의 컴포넌트를 선언하는 최소 JPEG2000 코덱스트림(FFmpeg가 yuv420p 프레임을 할당하도록)을 포함하는 JP2 컨테이너와, 이를 재매핑하는 cdef 박스로 구성됩니다:

root@kitploit:~
cn=0, typ=0, asoc=2   <-- 컴포넌트 0(전체 해상도)을 평면 1(서브샘플링)로
cn=1, typ=0, asoc=2
cn=2, typ=0, asoc=3

계수 데이터는 비어 있습니다. 디코더는 여전히 SIZ 헤더에서 프레임을 할당하고 쓰기 루프를 실행하므로 실제 이미지 데이터가 필요하지 않습니다.

수정 사항

vLLM 0.14.1에서 세 개의 PR을 통해 수정되었습니다:

  • #31987 — sanitize_message()를 추가하여 객체 repr의 at 0x<addr>> 부분을 클라이언트에 도달하기 전에 제거합니다.
  • #32319 — 나머지 오류 경로도 이를 통과하도록 라우팅합니다.
  • #32668 — opencv-python-headless를 >= 4.13.0으로 상향 조정하여 CVE-2025-9951에 대한 FFmpeg 수정을 포함합니다.

업스트림 FFmpeg는 이제 채널의 순열(permutation)이 아닌 cdef 맵을 거부하고, 재매핑된 인덱스에서 픽셀 형식을 파생합니다:

root@kitploit:~
int cdef_used = 0;
for (i = 0; i < s->ncomponents; i++)
    cdef_used |= 1<<s->cdef[i];
if (cdef_used != ((int[]){0,2,3,14,15})[s->ncomponents])
    return AVERROR_INVALIDDATA;

실습 환경의 고정 버전을 opencv-python-headless>=4.13.0으로 변경하면 동일한 페이로드가 error during processing marker segment ff51 오류와 함께 무해하게 실패합니다.

업그레이드할 수 없는 경우: 비디오 모델을 서빙하지 말고, API 앞에 인증을 배치하며, --allowed-media-domains로 미디어 가져오기를 제한하세요.

참고 사항

  • 실습 환경은 각 크래시 후 자동으로 재시작되므로 PoC를 반복 실행할 수 있습니다.
  • Apple Silicon에서는 docker compose가 기본값인 네이티브 arm64 아키텍처로 빌드하도록 하세요. --platform linux/amd64를 강제하면 컨테이너가 에뮬레이션으로 실행되어 중단 프로세스가 종료되지 않고 멈추므로 크래시를 관찰하기 어렵습니다.

참고 자료

  • NVD — CVE-2026-22778
  • vLLM advisory — GHSA-4r2x-xpjr-7cvv
  • FFmpeg advisory — GHSA-39q3-f8jq-v6mg (CVE-2025-9951)

면책 조항

교육 및 승인된 보안 테스트 전용입니다. 이 저장소의 실습 환경 또는 테스트에 대한 명시적 권한이 있는 시스템에 대해서만 실행하세요.

도구 다운로드