
Firefox के RTCEncodedFrameBase में Use-After-Free भेद्यता का प्रदर्शन करने वाला प्रूफ-ऑफ-कॉन्सेप्ट, जो WebRTC Encoded Transforms के माध्यम से हीप भ्रष्टाचार और संभावित RCE को सक्षम बनाता है।
Firefox के RTCEncodedFrameBase घटक में Use-After-Free (UAF) भेद्यता के लिए PoC, जो WebRTC Encoded Transforms API के माध्यम से शोषणीय है।
CVE-2025-14321: RTCEncodedFrameBase का डिस्ट्रक्टर फ्रेम की मूल मेमोरी को मुक्त करते समय DetachArrayBuffer() को कॉल नहीं करता। परिणामस्वरूप, JavaScript के ArrayBuffers पहले से मुक्त मेमोरी (डैंगलिंग पॉइंटर्स) की ओर इशारा करते रहते हैं, जिससे Firefox के कंटेंट प्रोसेस के हीप पर मनमाना पढ़ना और लिखना संभव होता है।
इस PoC का परीक्षण Mozilla Firefox 145.0.1 और Windows 10 पर किया गया है।
Firefox NewArrayBufferWithUserOwnedContents() के माध्यम से एन्कोडेड वीडियो/ऑडियो फ्रेम्स को JavaScript ArrayBuffers के रूप में उजागर करता है। जब मूल (C++) फ्रेम नष्ट होता है, तो ArrayBuffer की बैकिंग मेमोरी मुक्त हो जाती है, लेकिन JavaScript में ArrayBuffer अलग (detach) नहीं होता। यह स्वामित्व अपरिवर्तनीयता का उल्लंघन करता है और एक डैंगलिंग पॉइंटर उत्पन्न करता है।
कमजोर कोड (dom/media/webrtc/jsapi/RTCEncodedFrameBase.cpp):
// ❌ डिस्ट्रक्टर ArrayBuffer को अलग नहीं करता
RTCEncodedFrameBase::~RTCEncodedFrameBase() = default;
पैच किया गया कोड:
// ✅ मूल मेमोरी मुक्त करने से पहले ArrayBuffer को अलग करता है
RTCEncodedFrameBase::~RTCEncodedFrameBase() {
DetachData();
}
new Uint8Array(buf) हीप पर अन्य ऑब्जेक्ट्स को पुनः आवंटित मेमोरी से डेटा पढ़ता हैnew Uint8Array(buf).fill(0x41) हीप पर आसन्न ऑब्जेक्ट्स (vtables, DOM संरचनाएं, आदि) को दूषित करता हैये प्रिमिटिव्स भेद्यता प्रदर्शित करने के लिए पर्याप्त हैं। अतिरिक्त हीप शेपिंग के साथ, ये रिमोट कोड निष्पादन (RCE) तक बढ़ सकते हैं।
media.peerconnection.scripttransform.enabled = true
media.peerconnection.ice.loopback = true
media.peerconnection.ice.no_host = false
media.peerconnection.ice.relay_only = false
media.peerconnection.ice.proxy_only = false
⚠ प्राथमिकताएँ बदलने के बाद Firefox को पुनः प्रारंभ करें।
PoC getUserMedia() के माध्यम से कैमरा एक्सेस का अनुरोध करने का प्रयास करता है। यह अनिवार्य नहीं है यदि ICE प्राथमिकताएँ सही ढंग से सेट की गई हों। इसका कार्य Firefox को RFC IP हैंडलिंग मोड 1 में बढ़ावा देना है, जो उन परिदृश्यों में ICE होस्ट उम्मीदवारों की उत्पत्ति सुनिश्चित करता है जहाँ अकेले प्राथमिकताएँ पर्याप्त नहीं हैं।
व्यवहार में:
getUserMedia() बिना प्रॉम्प्ट दिखाए चुपचाप विफल हो जाता है (NotFoundError)। ICE फिर भी media.peerconnection.ice.loopback = true के कारण कनेक्ट होता है।वेब वर्कर file:// से काम नहीं करते। HTTP के माध्यम से सर्व करें:
python3 -m http.server 8080
कमजोर Firefox में खोलें: http://localhost:8080/poc-cve-2025-14321.html
PoC कैमरा एक्सेस का अनुरोध करने का प्रयास करता है। यदि कैमरा उपलब्ध है और उपयोगकर्ता स्वीकार करता है, तो Firefox सत्र को RFC IP हैंडलिंग मोड 1 में बढ़ावा देता है। यदि getUserMedia() विफल होता है (बिना कैमरे वाली VM, अनुमति अस्वीकृत), तो PoC फ्रेम स्रोत के रूप में एक कैनवास के साथ जारी रहता है — यदि media.peerconnection.ice.loopback = true सक्रिय है तो ICE वैसे भी कनेक्ट होता है।
एक 320×240 का <canvas> 30fps पर एनिमेशन के साथ captureStream(30) के माध्यम से बनाया जाता है। यह पूर्वानुमेय रूप से एन्कोडेड वीडियो फ्रेम उत्पन्न करता है। एक बार ICE कनेक्ट हो जाने और कैमरा उपयोग हो जाने के बाद, PoC replaceTrack() के माध्यम से कैमरा ट्रैक को कैनवास ट्रैक से बदल देता है और कैमरा मुक्त कर देता है।
मानक SDP नेगोशिएशन और ट्रिकल ICE के साथ दो स्थानीय RTCPeerConnection (pc1 ↔ pc2) बनाए जाते हैं। उम्मीदवार सीधे पीयर्स के बीच आदान-प्रदान किए जाते हैं।
SDP नेगोशिएशन से पहले pc1 के सेंडर को एक RTCRtpScriptTransform असाइन किया जाता है। वर्कर सेंडिंग पाइपलाइन से प्रत्येक एन्कोडेड फ्रेम को इंटरसेप्ट करता है।
पहले 200 फ्रेम में से प्रत्येक के लिए, वर्कर:
frame.data (ArrayBuffer जो मूल मेमोरी की ओर इशारा करता है) निकालता हैleaks[]) में सहेजता हैnew Uint8Array(buf).fill(0x41)आगे न भेजने पर, GC C++ रैपर को नष्ट कर देता है और मूल मेमोरी मुक्त कर देता है। लेकिन JavaScript का ArrayBuffer पॉइंटर बनाए रखता है — डैंगलिंग पॉइंटर बन गया।
फ्रेम 201 से शुरू करते हुए, हर 3 फ्रेम पर वर्कर:
0x41 से भिन्न है, तो आवंटकर्ता ने उस मेमोरी का पुन: उपयोग किया → UAF की पुष्टि0x41 को फिर से लिखता है (दूसरे के हीप पर राइट प्रिमिटिव)मुक्त मेमोरी पर पढ़ने/लिखने का यह चक्र हीप की प्रगतिशील क्षति का कारण बनता है जब तक कि Firefox टैब क्रैश न हो जाए (सलाह में रिपोर्ट किए गए SIGSEGV के समतुल्य)।
[0.4s] ✓ प्रारंभिक ट्रैक: कैनवास (फ़ॉलबैक)
[0.4s] ✓ ICE कनेक्शन स्थापित!
[0.5s] ▶▶▶ पहला एन्कोडेड फ्रेम प्राप्त! ◀◀◀
[0.5s] लीक #0: 1219B → 41414141414141414141414141414141
[2.7s] लीक #49: 1497B → 41414141414141414141414141414141
[9.8s] लीक #199: 1870B → 41414141414141414141414141414141
[9.9s] 200 ArrayBuffers बनाए रखा → मूल मेमोरी पहले ही मुक्त
[9.9s] → डैंगलिंग पॉइंटर्स सक्रिय, पुन: उपयोग की प्रतीक्षा…
[ टैब क्रैश — हीप क्षति ]
नोट: यदि कैमरा उपलब्ध है और अनुमति दी गई है, तो लॉग दिखाएगा
✓ getUserMedia स्वीकृत — ICE मोड 1 सक्रियऔर फिर✓ ट्रैक बदला गया: कैमरा → कैनवासICE कनेक्शन के बाद। बिना कैमरे वाली VM में, PoC बिना प्रॉम्प्ट के सीधे कैनवास का उपयोग करता है।
टैब का क्रैश हीप क्षति की पुष्टि करता है: अन्य ऑब्जेक्ट्स (vtables, DOM नोड्स) को पुनः आवंटित मेमोरी पर 0x41 लिखने से कंटेंट प्रोसेस में अमान्य मेमोरी एक्सेस होता है।
✓ बफर[0] सही ढंग से अलग — फिक्स सक्रिय
ArrayBuffer अलग — पैच किया गया संस्करण ✓
डिस्ट्रक्टर में DetachData() मूल मेमोरी मुक्त करने से पहले ArrayBuffer को अमान्य कर देता है, डैंगलिंग पॉइंटर को समाप्त कर देता है।
├── poc-cve-2025-14321.html # कार्यात्मक PoC (सुपाठ्य स्रोत कोड)
└── README.md # यह फ़ाइल
Mozilla ने Firefox 146 में सभी डिस्ट्रक्टर्स और RTCEncodedFrameBase के टियरडाउन पथों में DetachData() जोड़कर भेद्यता को ठीक किया।
कमिट: https://hg-edge.mozilla.org/mozilla-central/rev/1051067f6e83
⚠ केवल शैक्षिक और अनुसंधान उद्देश्यों के लिए
यह PoC भेद्यता के अस्तित्व को हीप क्षति (क्रैश) के बिंदु तक प्रदर्शित करता है। यह कोड निष्पादन के लिए आवश्यक हीप शेपिंग, ASLR बाइपास या हाईजैक तकनीकों को लागू नहीं करता। इसका उद्देश्य विशेष रूप से नियंत्रित वातावरण में CVE के सत्यापन और समझ के लिए है।