Saturday, November 27, 2010

Buffer Overflow คืออะไร

ก่อนเริ่ม ผมขอบอกก่อนว่า ในที่นี้จะกล่าวถึงเฉพาะ Linux ใครที่สนใจ Windows คงต้องคอยอีกนาน (จนกว่าผมจะหมดวิธีเขียน exploit ต่างๆ บน Linux) โดยตัวอย่าง(น่าจะ)ทั้งหมด ผมจะใช้ Ubuntu 10.04 (32 bit) ดังนั้นถ้าใครสนใจ ก็เตรียม VMWare หรือ VirtualBox หรือ ...(แล้วแต่ถนัด) ไว้ได้เลย
ถึงแม้ว่าคุณจะใช้ Ubuntu 10.04 เป็น OS หลักอยู่แล้ว ผมก็แนะนำให้ลงในพวก Virtual Machine เพราะจะต้องมีการใส่ code ที่มีช่องโหว่ (Vulnerable code) และปิด security feature บางอย่างด้วย

เรามาเริ่มกันเลยดีกว่า...

ในทางโปรแกรมมิ่ง buffer หมา่ยถึง memory ที่จองไว้ สำหรับทำงานต่างๆ เช่น รับข้อมูลจากผู้ใช้ ใส่ข้อมูลเก็บชั่วคราว
็Buffer Overflow ก็คือ การใส่ข้อมูลใน buffer เกินที่จองไว้ เช่นเราได้กำหนดขนาด buffer ไว้ 8 bytes แต่เราใส่ข้อมูลไป 12 bytes

Buffer Overflow เป็นปัญหาหนึ่งในเรื่อง security โดยในเริ่มต้น จะยกตัวอย่างที่ง่ายๆ

ตัวอย่างที่ 1 (ex_01_1.c)

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

int main(int argc, char **argv)
{
  int magic = 0;
  char buf[8];

  printf("Before strcpy: magic is 0x%08x\n", magic);
  strcpy(buf, argv[1]);
  printf("After strcpy: magic is 0x%08x\n", magic);
  if (magic == 0x55555555)
    printf("Hahaha, you WIN\n");

  return 0;
}

build code ตัวอย่างที่ 1 ด้วยคำสั่งข้างล่างไม่ต้องพิมพ์ $ นะครับ (option ของ gcc จะมีการกล่าวถึงในหัวข้อถัดๆ ไป)

$ gcc -mpreferred-stack-boundary=2 -fno-stack-protector -o ex_01_1 ex_01_1.c

ใครที่มีความรู้เรื่องนี้มาบ้าง ก็คงจะรู้แล้วว่าผมจะให้ทำอะไร จากตัวอย่างนี้ ให้รันโปรแกรม แล้วให้โปรแกรมพิมพ์คำว่า "Hahaha, you WIN" ให้ได้

มาดูเฉลยกันเลยดีกว่า

จะเห็นว่ามีการจอง buffer ไว้ 8 bytes ครั้งแรกขอลองใส่ 8 ตัว

$ ./ex_01_1 55555555
Before strcpy: magic is 0x00000000
After strcpy: magic is 0x00000000
คราวนี้ลองใส่ 9 ตัว
$ ./ex_01_1 555555555
Before strcpy: magic is 0x00000000
After strcpy: magic is 0x00000035
จะเห็นว่ามีเลข 35 ออกมาตัวหนึ่ง คราวนี้ลองใส่ 12 ตัว
$ ./ex_01_1 555555555555
Before strcpy: magic is 0x00000000
After strcpy: magic is 0x35353535
จะเห็นว่าคราวนี้ magic เป็น 35 หมดเลย ถ้าเราเป็น ASCII table ดู จะเห็นว่าเลข 35 ในฐาน 16 คือตัวอักษร "5" (หลังจากนี้ ผมจะเขียนเลขฐาน 16 เป็น 0x35 หรือ 35h) แต่ที่เราต้องการคือ 55h เมื่อดูที่ ASCII table 55h คือตัวอักษร "U" คราวนี้เราลองใส่เป็น U 12 ตัว
$ ./ex_01_1 UUUUUUUUUUUU
Before strcpy: magic is 0x00000000
After strcpy: magic is 0x55555555
Hahaha, you WIN
:O ทำได้แล้ว จะเห็นว่าเราทำการ copy ข้อมูลที่รับมาจาก argv[1] ลงที่ buf แต่ค่า magic กับถูกเปลี่ยนไปด้วย ที่เป็นแบบนี้ เพราะว่า magic ได้ถูกจองไว้หลัง buf ซึ่งเมื่อมีการเขียนข้อมูลลง buf เกินไว้ที่จอง ข้อมูลที่เกินก็จะถูกเขียนไปที่ magic
คราวนี้ เรามาลองเพิ่มเติม โดยการใส่ตัว U ไป 16 ตัว
$ ./ex_01_1 UUUUUUUUUUUUUUUU
Before strcpy: magic is 0x00000000
After strcpy: magic is 0x55555555
Hahaha, you WIN
Segmentation fault
o.O Segmentation fault คืออะไร ค่านี้เราไม่มีการสั่งให้โปรแกรมแสดงออกมา
Segmentation fault เกิดเมื่อโปรแกรมมีการ access memory ที่ OS ไม่อนุญาต และที่เกิดขึ้นเพราะว่า เราได้เขียนทับข้อมูลส่วนที่ใช้สำหรับควบคุมการทำงานของโปรแกรม ซึ่งทำให้โปรแกรมทำงานผิดพลาด ซึ่งในกรณีนี้เราจะกลับมาดูอีกครั้ง ว่าเราสามารถทำอะไรได้บ้าง >=)

น่าสนใจไหมครับ... แต่ก่อนที่จะถึงส่วนที่สนุก ผมต้องอธิบายเกี่ยวกับความรู้พื้นฐานสำหรับการเขียน exploit ก่อน เช่น memory layout, assembly, ELF, ... ซึ่งเรื่องพวกนี้ ผมคิดว่าน่าเบื่อ แต่จำเป็นต้องรู้

สุดท้าย tutorial การเขียน exploit ชุดนี้ สำหรับคนที่รู้ภาษา C และ Linux command พอสมควร ถ้าใครอ่านตอนนี้ไม่รู้เรื่อง แล้วสนใจ คงต้องไปหาความรู้เพิ่มเติมนะครับ

6 comments:

  1. Int ในที่นี้ 4 Byte ปะคับ

    ReplyDelete
  2. ใช่ครับ ผมจะพูดถึงเฉพาะ 32 bit ดังนั้น int มีขนาด 4 byte ตลอด

    ReplyDelete
  3. กระจ่างเลย เข้าใจง่ายดีครับ ^^

    ReplyDelete
  4. มือใหม่ครับ กำลังศึกษาดูอยู่

    แต่ก็มีงงบ้างเล็ก แต่ยังทำไม่ได้เลย พยายาม T^T

    ReplyDelete
  5. ชอบมากๆเลยครับ แนวนี้
    กระตุ้นต่อมความรู้ของผมเป็นอย่างมากๆ
    เขียนต่อเยอะๆนะครับ
    จะติดตามเป็นแฟนพันธุ์แท้กันไปเลย

    ReplyDelete
  6. สุดยอดมากเลยครับ เข้าใจความหมาย แต่เพิ่งมาเห็นภาพก็วันนี้แหละ

    ReplyDelete