
CVE-2026-32740 Next.js/sharp leak-to-memcpy-GOT RCE 체인에 대한 비공개 Fortbridge PoC
하드코딩된 Next.js/sharp 이미지 스택의 CVE-2026-32740을 선택 주소 쓰기(arbitrary-address write)와 검증된 /usr/bin/id 콜백으로 전환하는 동작하는 개념 증명(proof of concept)입니다.
이 저장소는 Fortbridge의 비공개 연구 저장소입니다. 포함된 랩 또는 명시적으로 테스트 권한을 부여받은 다른 시스템에 대해서만 사용하십시오.
이 익스플로잇은 대상의 HTTP 업로드 및 이미지 최적화 라우트만을 사용합니다:
g_module_open_full을 사용합니다. 이 GModule 루틴은 dlopen을 감싸서 파일 경로로부터 네이티브 공유 라이브러리를 로드합니다. 익스플로잇은 복구된 libvips 베이스에 하드코딩된 프로파일 오프셋 0x3e995e를 더하여 런타임 주소를 계산합니다. 라이브러리를 로드하면 그 생성자가 실행됩니다./usr/bin/id를 실행하는 생성자를 가진 작은 공유 오브젝트를 컴파일합니다. 이 ELF를 이미지 이름 x.jpg, 미디어 타입 image/jpeg로 공개 업로드 라우트를 통해 전송합니다.memcpy@GOT - 16으로 리다이렉트하는 116x33 4타일 AVIF를 생성합니다.uploads/x.jpg를 저장하고 memcpy@GOT를 파생된 GModule 로더로 교체합니다. 다음 행은 이미 RDI에 라이브러리 경로가 있는 상태로 해당 로더를 호출합니다./usr/bin/id 출력을 반환합니다. 시도별 토큰은 오래된 콜백이 성공으로 집계되는 것을 방지하며, 반환된 uid=... 라인이 증거입니다.원래의 libvips 상대 검증 실행은 evidence/libvips-gmodule-rce-10x.json에 기록되어 있습니다. 10개의 새로운 프로세스 모두 10개의 서로 다른 무작위화된 libvips 베이스와 10개의 독립적으로 파생된 로더 주소로 유효한 /usr/bin/id 출력을 반환했습니다.
정확한 Ubuntu 실행 데이터는 evidence/libvips-gmodule-pie-rce-10x.json에 있습니다. 정확한 Debian 13 APT 실행 데이터는 evidence/debian13-apt-libvips-gmodule-rce-10x.json에 있습니다.
우리는 완전한 익스플로잇을 10개의 새로 시작된 Ubuntu Node 프로세스와 10개의 새로 시작된 Debian Node 프로세스에 대해 테스트했습니다. 20회의 실행 모두 명령 실행에 도달하여 대상의 /usr/bin/id 출력을 반환했습니다. 또한 이 익스플로잇은 모든 무작위화된 libvips 베이스에 대해 서로 다른 GModule 로더 주소를 계산했습니다.
최종 페이로드를 생성하기 전에, 익스플로잇은 여러 번의 ASLR 누출 시도가 필요할 수 있습니다. 각 시도는 누출 AVIF를 업로드하고, 최적화 라우트를 통해 전송하며, 반환된 PNG에서 하나의 프로파일과 하나의 libvips 베이스를 식별하는 4개의 포인터를 확인합니다. Ubuntu는 3회에서 23회의 시도가 필요했습니다. Debian은 3회에서 15회가 필요했습니다. 불완전하거나 모호한 증거는 추측된 프로파일 대신 또 다른 시도를 유발합니다.
이 프로젝트에는 96개의 자동화된 회귀 테스트도 있습니다. 이들은 코드 수준 검사이며, 96회의 추가 익스플로잇 실행이 아닙니다. 이들은 프로파일 검증, 반환된 포인터 분류, 힙 캘리브레이션, 주소 계산, 페이로드 구성, 그리고 증거가 지원되는 대상과 일치하지 않을 때의 안전한 실패를 다룹니다.
두 x86-64 대상 모두 Next.js 15.5.23, sharp 0.34.4, 번들된 libvips 8.17.2, 번들된 libheif 1.20.2, ASLR, NX를 사용합니다. 이들의 네이티브 런타임은 다릅니다:
| Profile | Node | glibc | libstdc++ | Selector relation |
|---|---|---|---|---|
| Ubuntu | 25.8.1, PIE ET_DYN | 2.43-2ubuntu2.4 | 6.0.35 | 0x6000 - 0x690 = 0x5970 |
| Debian 13 | Debian APT 20.19.2, PIE ET_DYN | 2.41-12+deb13u4 | 6.0.33 | 0x6000 - 0x3a0 = 0x5c60 |
완전한 빌드 ID와 SHA-256 값은 profiles/native_stack_profiles_pie.json에 있습니다. Debian 패키지, 아티팩트, 라우트 스모크, 5회 수명 레이아웃 측정은 evidence/debian13-profile-derivation.json에 기록되어 있습니다. Debian 대상은 표준 배포 패키지 nodejs=20.19.2+dfsg-1+deb13u3를 사용하며, Node는 소스에서 컴파일되지 않습니다.
이 체인은 무작위화된 Node 베이스를 필요로 하지 않습니다. 제어 대상은 libvips 내부의 g_module_open_full 루틴이며, 그 무작위화된 베이스는 반환된 픽셀에서 복구됩니다. 각 버전별 프로파일은 익스플로잇에 필요한 빌드별 상수를 하드코딩합니다:
memcpy@GOT 오프셋과 g_module_open_full 오프셋 및 그 검증 명령 바이트;무작위화된 libvips 베이스, 결과 런타임 로더 주소, 최종 2바이트 선택자는 하드코딩되지 않습니다. 이들은 각 대상 프로세스에 대해 반환된 픽셀과 선택된 프로파일로부터 파생됩니다.
익스플로잇은 프로파일이 잘못되었거나 반환된 픽셀이 정확히 하나의 지원되는 프로파일/베이스 쌍을 선택하지 않으면 안전하게 실패합니다. 스톡 프로파일은 또한 완전한 반환 힙 레코드를 요구합니다. 프로파일은 정확한 호환성 주장이므로, 운영자는 사용 전에 대상 아티팩트를 오프라인에서 검증해야 합니다.
로더 ABI가 중요합니다. 덮어쓴 호출은 RDI에 라이브러리 경로를, RSI에 이미지 행 포인터를, RDX에 58바이트 복사 길이를 제공합니다. 이 정확한 프로파일링된 GModule 루틴은 ESI의 지원되는 플래그 비트만 사용하며 성공적인 로드 경로에서 RDX를 역참조하지 않습니다. 오프라인 하네스가 측정 실행에 사용되기 전에 해당 진입점과 명령 시그니처를 검증했습니다.
libaom-av1 인코더가 있는 ffmpegcc로 사용 가능한 C 컴파일러유일한 Python 의존성을 설치하십시오:```bash python3 -m venv .venv . .venv/bin/activate python3 -m pip install -r requirements.txt
AV1 인코딩 지원 확인:```bash
ffmpeg -hide_banner -encoders | grep libaom-av1
이 랩은 의도적으로 임의 업로드를 허용하고 선택된 파일을 sharp로 전달합니다. 신뢰할 수 없는 네트워크에 노출하지 마십시오.```bash cd lab npm ci npm run build npm run start
대상은 그런 다음 `http://127.0.0.1:3000`에서 사용할 수 있습니다.
첫 번째 PIE 프로필에서 사용되는 Node 아티팩트를 기반으로 Ubuntu 랩 이미지를 빌드하려면:```bash
./scripts/build_ubuntu2604_container.sh
docker run --rm --network host \
fortbridge/libheif-grid-nextjs-rce:ubuntu2604
다이제스트로 고정된 Ubuntu 26.04 이미지는 프로파일에 기록된 정확한 Node 25.8.1 PIE 아티팩트를 빌드하고, 그 SHA-256을 검증한 다음, 이를 깨끗한 런타임 스테이지로 복사합니다. Node의 공식 Linux 바이너리는 ET_EXEC인 반면, 이 프로파일은 의도적으로 PIE 실행 파일을 테스트하기 때문에 소스 빌드가 필요합니다.
Debian에서 지원하는 APT 패키지로 Debian 타깃을 재현하려면:```bash
./scripts/build_debian13_container.sh
docker run --rm --network host
fortbridge/libheif-grid-nextjs-rce:debian13
이 이미지는 다이제스트로 고정된 Debian 13 slim 베이스에서 빌드됩니다. npm은
빌더 단계에만 존재하며, 최종 타깃은 Debian APT에서 Node를 설치하고
동일한 애플리케이션과 라우트를 실행합니다.
## 익스플로잇 실행