
PHP2Shell का गहन तकनीकी वॉकथ्रू: आउट-ऑफ-मेमोरी क्रैश और यूज़-आफ्टर-फ्री से लेकर हीप ग्रूमिंग, ASLR लीक और रिमोट कोड एक्ज़िक्यूशन तक दो PHP कोर CVE को चेन करना।

मैंने यह शोध 26 अक्टूबर, 2026 को लिखना शुरू किया, और मुझे पूरी तरह से यकीन नहीं है कि मैं इसे कब पूरा करूँगा।
लेखन के समय, PHP2Shell के बारे में अभी भी बहुत कम जानकारी उपलब्ध है, विशेष रूप से जब कमज़ोरियों और शोषण प्रक्रिया के विस्तृत तकनीकी विश्लेषण की बात आती है।
सच कहूँ तो, मैं ऐसी व्याख्याएँ ढूँढते-ढूँढते थक गया था जो केवल ऊपरी तौर पर बात करती थीं और वास्तव में यह नहीं दिखाती थीं कि अंदर क्या हो रहा है। मैं कुछ अलग करना चाहता था: एक उचित, गहन तकनीकी वॉकथ्रू जो पूरी प्रक्रिया का पता लगाए, हर महत्वपूर्ण विवरण की जाँच करे और न केवल यह समझाए कि क्या होता है, बल्कि यह भी कि क्यों और कैसे होता है।
यह शोध PHP स्रोत कोड की मेरी अपनी समझ, मेरे प्रयोगों, और इन कमज़ोरियों को समझने की कोशिश करते समय मेरे द्वारा किए गए जाँचों पर आधारित है। मैं इन सभी टुकड़ों को एक साथ जोड़ना, अपने निष्कर्ष साझा करना, और उम्मीद है कि दूसरों के लिए अंतर्निहित अवधारणाओं में से कुछ को समझना आसान बनाना चाहता था।
मेरे मुख्य लक्ष्यों में से एक था इसे तकनीकी गहराई का त्याग किए बिना सुलभ बनाना। मैं चाहता हूँ कि बुनियादी C ज्ञान और सामान्य प्रोग्रामिंग अनुभव रखने वाला कोई भी व्यक्ति इसे समझ सके, भले ही उसका लो-लेवल मेमोरी शोषण में कोई पूर्व अनुभव न हो।
मुझे यह भी उम्मीद है कि यह शोध उन बातों में से कुछ को स्पष्ट करने में मदद कर सकता है जो वर्तमान में खराब तरीके से समझाई गई हैं या गलत समझी जाती हैं। हालाँकि, मैं पारदर्शी रहना चाहता हूँ: यह कमज़ोरियों की मेरी अपनी तकनीकी समझ है, कोई आधिकारिक विश्लेषण या अचूक संदर्भ नहीं। मैं अभी भी सीख रहा हूँ, जाँच कर रहा हूँ, और स्वयं बिंदुओं को जोड़ रहा हूँ। रास्ते में गलतियाँ, अशुद्धियाँ, या ऐसी बातें हो सकती हैं जिन्हें मैंने गलत समझा हो।
यदि आपको कुछ गलत लगे, आपकी कोई अलग व्याख्या हो, या आपको लगे कि किसी बात पर और जाँच की जानी चाहिए, तो कृपया मुझसे संपर्क करने में संकोच न करें। मैं ऐसे सुधारों, चर्चाओं और योगदानों की सचमुच सराहना करूँगा जो इस शोध को अधिक सटीक और सभी के लिए अधिक उपयोगी बनाने में मदद कर सकें।
आखिरकार, इसे साझा करने का पूरा उद्देश्य एक साथ सीखना और अधिक लोगों को यह समझने में मदद करना है कि अंदर ही अंदर वास्तव में क्या हो रहा है।
बुनियादी बातों से पहले से परिचित हैं?? सीधे उस भाग पर जाएँ जिसकी आपको परवाह है:
यदि आप हीप एक्सप्लॉइटेशन में नए हैं या पूरा अनुभव चाहते हैं, तो बस स्क्रॉल करते रहें। मैंने इसे शुरू से अंत तक पढ़ने के लिए लिखा है।
शुरू करने से पहले कुछ बातें सभी को ध्यान में रखनी चाहिए। जैसे-जैसे हम इस शोध में आगे बढ़ेंगे, ये विशेष रूप से उपयोगी साबित होंगी। जैसा कि मैंने पहले उल्लेख किया, मैं चाहता हूँ कि यह वॉकथ्रू सभी के लिए सुलभ हो, इसलिए मैं और भी बुनियादी अवधारणाओं को समझाने के लिए समय लूँगा। यदि आप पहले से ही इनसे परिचित हैं, तो बेझिझक आगे बढ़ें!
एक सामान्य प्रोग्राम में, मेमोरी को विभिन्न क्षेत्रों में व्यवस्थित किया जाता है, जिनमें स्टैक और हीप शामिल हैं।
उदाहरण के लिए, C++ में:
int main() {
int a = 30; // Typically stored on the stack
int* b = new int(30); // b is typically on the stack,
// but the integer it points to is on the heap
}
यहाँ, a एक स्थानीय चर है जिसमें मान 30 है। सूचक b भी एक स्थानीय चर है, लेकिन इसमें हीप पर आवंटित एक पूर्णांक का पता है।
PHP मुख्य रूप से C में लिखा गया है, इसलिए हमें यह समझना होगा कि मेमोरी आवंटन कैसे काम करता है।
OS एक प्रक्रिया को उसका अपना वर्चुअल एड्रेस स्पेस प्रदान करता है। फिर प्रक्रिया का मेमोरी आवंटक उसके लिए उपलब्ध मेमोरी के भीतर आवंटन का प्रबंधन करता है।
उदाहरण के लिए, C++ में, हमारे पास मेमोरी आवंटित करने के लिए new, malloc(), और अन्य तरीके हैं।
आवंटक अक्सर हर बार OS से नई मेमोरी का अनुरोध करने के बजाय मुक्त की गई मेमोरी का पुनः उपयोग करने का प्रयास करते हैं।
साथ ही, जब किसी ऑब्जेक्ट का जीवनकाल समाप्त होता है, तो उसकी मेमोरी में संग्रहीत डेटा जरूरी नहीं कि तुरंत मिटा दिया जाए। उस मेमोरी को बस पुनः उपयोग के लिए उपलब्ध के रूप में चिह्नित किया जा सकता है।
इसे बेहतर ढंग से समझने के लिए, आइए निम्नलिखित कोड पर एक संक्षिप्त नज़र डालें:
#include <cstdlib>
#include <iostream>
int main() {
void* a = malloc(64);
free(a);
void* b = malloc(64);
std::cout << a << "\n" << b << std::endl;
free(b);
return 0;
}
यहाँ, जब हम a और b प्रिंट करते हैं, तो हम पा सकते हैं कि उनमें समान संख्यात्मक मेमोरी पता है।
क्यों? क्योंकि free(a) कॉल करने के बाद malloc() पहले a को आवंटित मेमोरी का पुनः उपयोग कर सकता है, जिससे मेमोरी का एक और ब्लॉक प्राप्त करने की आवश्यकता टल जाती है।
यह हर बार होने की गारंटी नहीं है, लेकिन यह एक सामान्य व्यवहार है।