Rate this post

Buffer Overflow được đặc trưng bởi việc ghi đè lên các đoạn bộ nhớ của quá trình mà lẽ ra không bao giờ được sửa đổi một cách cố ý hoặc vô ý. Việc ghi đè các giá trị của IP (Instruction Pointer), BP (Base Pointer) và các register khác gây ra các ngoại lệ, lỗi phân đoạn và các lỗi khác xảy ra. Thông thường những lỗi này kết thúc việc thực thi ứng dụng theo cách không mong muốn. Buffer Overflow xảy ra khi chúng ta thao tác trên bộ đệm kiểu char.

Buffer Overflow có thể bao gồm làm tràn ngăn xếp [Tràn ngăn xếp] hoặc tràn đống [Tràn đống]. Chúng tôi không phân biệt giữa hai điều này trong bài viết này để tránh nhầm lẫn.

Các ví dụ dưới đây được viết bằng ngôn ngữ C trong hệ thống GNU / Linux trên kiến ​​trúc x86.

ví dụ 1

#include <stdio.h>
int main(int argc, char **argv)
{
char buf[8]; // buffer for eight characters
gets(buf); // read from stdio (sensitive function!)
printf("%s\n", buf); // print out data stored in buf
return 0; // 0 as return value
}

Ứng dụng rất đơn giản này đọc từ đầu vào chuẩn một mảng các ký tự và sao chép nó vào bộ đệm kiểu char. Kích thước của bộ đệm này là tám ký tự. Sau đó, nội dung của bộ đệm được hiển thị và ứng dụng sẽ thoát.

Biên dịch chương trình:

user@spin ~/ $ gcc bo-simple.c -o bo-simple
/tmp/ccECXQAX.o: In function `main':
bo-simple.c:(.text+0x17): warning: the `gets' function is dangerous and
should not be used.

Ở giai đoạn này, ngay cả trình biên dịch cũng gợi ý rằng hàm get () không an toàn.

Ví dụ sử dụng:

user@spin ~/ $ ./bo-simple // program start
1234 // we eneter "1234" string from the keyboard
1234 // program prints out the conent of the buffer
user@spin ~/ $ ./bo-simple // start
123456789012 // we eneter "123456789012"
123456789012 // content of the buffer "buf" ?!?!
Segmentation fault // information about memory segmenatation fault

Chúng tôi quản lý (không) may mắn để thực hiện hoạt động bị lỗi bởi chương trình và khiến nó thoát ra bất thường.

Phân tích vấn đề:

Chương trình gọi một hàm, hoạt động trên bộ đệm kiểu char và không kiểm tra việc làm tràn kích thước được gán cho bộ đệm này. Do đó, có thể cố ý hoặc vô ý lưu trữ nhiều dữ liệu hơn trong bộ đệm, điều này sẽ gây ra lỗi. Câu hỏi sau được đặt ra: Bộ đệm chỉ lưu trữ tám ký tự, vậy tại sao hàm printf () lại hiển thị mười hai ?. Câu trả lời đến từ tổ chức bộ nhớ tiến trình. Bốn ký tự làm Buffer Overflow cũng ghi đè giá trị được lưu trữ trong một trong các thanh ghi, điều này cần thiết cho việc trả về hàm đúng. Tính liên tục của bộ nhớ dẫn đến việc in ra dữ liệu được lưu trữ trong vùng bộ nhớ này.

Ví dụ 2

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

void doit(void)
{
        char buf[8];

        gets(buf);
          printf("%s\n", buf);
}

int main(void)
{
        printf("So... The End...\n");
        doit();
        printf("or... maybe not?\n");

        return 0;
}

Ví dụ này tương tự như ví dụ đầu tiên. Ngoài ra, trước và sau hàm doit (), chúng ta có hai lệnh gọi hàm printf ().

Tổng hợp:

Compilation:

user@dojo-labs ~/buffer_overflow $ gcc example02.c -o example02
-ggdb
/tmp/cccbMjcN.o: In function `doit':
/home/user/owasp/buffer_overflow/example02.c:8: warning: the `gets'
function is dangerous and should not be used.

Usage example:
user@dojo-labs ~/buffer_overflow $ ./example02
So... The End...
TEST                   // user data on input
TEST                  // print out stored user data
or... maybe not?

Chương trình giữa hai lệnh gọi printf () được xác định hiển thị nội dung của bộ đệm, được lấp đầy bởi dữ liệu do người dùng nhập vào.

user@dojo-labs ~/buffer_overflow $ ./example02
So... The End...
TEST123456789
TEST123456789
Segmentation fault

Vì kích thước của bộ đệm đã được xác định (char buf [8]) và nó được lấp đầy bằng mười ba ký tự kiểu char, bộ đệm đã bị tràn.

Nếu ứng dụng nhị phân của chúng tôi ở định dạng ELF, thì chúng tôi có thể sử dụng chương trình objdump để phân tích nó và tìm thông tin cần thiết để khai thác Buffer Overflow.

Dưới đây là kết quả được tạo ra bởi objdump. Từ đầu ra đó, chúng ta có thể tìm địa chỉ, nơi printf () được gọi là (0x80483d6 và 0x80483e7).

user@dojo-labs ~/owasp/buffer_overflow $ objdump -d ./example02

 080483be <main>:
 80483be:       8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c2:       83 e4 f0                and    $0xfffffff0,%esp
 80483c5:       ff 71 fc                pushl  0xfffffffc(%ecx)
 80483c8:       55                      push   %ebp
 80483c9:       89 e5                   mov    %esp,%ebp
 80483cb:       51                      push   %ecx
 80483cc:       83 ec 04                sub    $0x4,%esp
 80483cf:       c7 04 24 bc 84 04 08    movl   $0x80484bc,(%esp)
 80483d6:       e8 f5 fe ff ff          call   80482d0 <puts@plt>
 80483db:       e8 c0 ff ff ff          call   80483a0 <doit>
 80483e0:       c7 04 24 cd 84 04 08    movl   $0x80484cd,(%esp)
 80483e7:       e8 e4 fe ff ff          call   80482d0 <puts@plt>
 80483ec:       b8 00 00 00 00          mov    $0x0,%eax
 80483f1:       83 c4 04                add    $0x4,%esp
 80483f4:       59                      pop    %ecx
 80483f5:       5d                      pop    %ebp
 80483f6:       8d 61 fc                lea    0xfffffffc(%ecx),%esp
 80483f9:       c3                      ret
 80483fa:       90                      nop
 80483fb:       90                      nop

Nếu lệnh gọi thứ hai tới printf () thông báo cho quản trị viên về việc đăng xuất của người dùng (ví dụ: phiên đã đóng), thì chúng ta có thể cố gắng bỏ qua bước này và kết thúc mà không cần gọi tới printf ().

user@dojo-labs ~/buffer_overflow $ perl -e 'print "A"x12
  ."\xf9\x83\x04\x08"' | ./example02
  So... The End...
  AAAAAAAAAAAAu*.
  Segmentation fault

Ứng dụng đã kết thúc quá trình thực thi với lỗi phân đoạn, nhưng lệnh gọi thứ hai tới printf () không có chỗ đứng.

Một vài lời giải thích:

perl -e ‘print“ A ”x12.” \ xf9 \ x83 \ x04 \ x08 ”’ – sẽ in ra mười hai ký tự “A” và sau đó là bốn ký tự, thực tế là địa chỉ của lệnh chúng ta muốn thực thi. Tại sao lại là mười hai?

   8 // size of buf (char buf[8])
+  4 // four additional bytes for overwriting stack frame pointer
----
  12

Phân tích vấn đề:

Vấn đề giống như trong ví dụ đầu tiên. Không có quyền kiểm soát kích thước của bộ đệm được sao chép vào bộ đệm được khai báo trước đó. Trong ví dụ này, chúng tôi ghi đè lên thanh ghi EIP với địa chỉ 0x080483f9, thực tế là một lệnh gọi để ret vào giai đoạn cuối của quá trình thực thi chương trình.

Làm thế nào để sử dụng Buffer Overflow theo một cách khác?

Nói chung, việc khai thác các lỗi này có thể dẫn đến:

  • DoS
  • sắp xếp lại việc thực hiện các chức năng
  • thực thi mã (nếu chúng tôi có thể đưa mã shellcode, được mô tả trong tài liệu riêng)

Xem thêm overflow trong css

Buffer Overflow được thực hiện như thế nào?

Những loại lỗi này rất dễ mắc phải. Trong nhiều năm, chúng là cơn ác mộng của lập trình viên. Vấn đề nằm ở các hàm C gốc, không quan tâm đến việc kiểm tra độ dài bộ đệm thích hợp. Dưới đây là danh sách các chức năng như vậy và nếu chúng tồn tại, các chức năng tương đương an toàn của chúng:

  • get () – \> fgets () – đọc ký tự
  • strcpy () – \> strncpy () – sao chép nội dung của bộ đệm
  • strcat () – \> strncat () – nối bộ đệm
  • sprintf () – \> snprintf () – điền vào bộ đệm với dữ liệu thuộc các loại khác nhau
  • (f) scanf () – đọc từ STDIN
  • getwd () – trả về thư mục làm việc
  • realpath () – trả về đường dẫn tuyệt đối (đầy đủ)

Sử dụng các hàm tương đương an toàn để kiểm tra độ dài bộ đệm bất cứ khi nào có thể. Cụ thể:

  • gets () – \> fgets ()
  • strcpy () – \> strncpy ()
  • strcat () – \> strncat ()
  • sprintf () – \> snprintf ()

Những chức năng không có giá trị tương đương an toàn nên được viết lại với các bước kiểm tra an toàn được triển khai. Thời gian dành cho việc đó sẽ có lợi trong tương lai. Hãy nhớ rằng bạn chỉ phải làm điều đó một lần.

Sử dụng các trình biên dịch có khả năng xác định các chức năng không an toàn, lỗi logic và kiểm tra xem bộ nhớ có bị ghi đè khi nào và ở đâu không.

Cách thức tấn công Buffer Overflow

Buffer Overflow là một loại tấn công mà kẻ tấn công cố gắng ghi đè nội dung vào một vùng nhớ đệm (buffer) nằm ngoài giới hạn cho phép. Điều này có thể xảy ra khi dữ liệu được ghi vào một buffer mà không có kiểm tra kích thước hoặc không có sự kiểm soát đúng đắn về việc ghi dữ liệu vào buffer đó. Sau đó, kẻ tấn công sử dụng việc ghi đè này để thực thi mã độc hoặc gây ra lỗi hệ thống.

Cách thức tấn công Buffer Overflow thường gồm các bước sau:

  1. Xác định vùng nhớ đệm (buffer): Kẻ tấn công tìm các vị trí trong ứng dụng mà dữ liệu được ghi vào một buffer không được kiểm tra kích thước.
  2. Tạo dữ liệu đầu vào đặc biệt: Kẻ tấn công tạo dữ liệu đầu vào có kích thước lớn hơn kích thước cho phép của buffer hoặc chứa các dãy ký tự đặc biệt như ký tự NULL, ký tự quay về dòng mới (newline), hoặc các ký tự điều khiển.
  3. Ghi đè vùng nhớ đệm: Kẻ tấn công ghi đè dữ liệu đầu vào đặc biệt vào vùng nhớ đệm, vượt quá giới hạn kích thước của buffer.
  4. Kiểm soát luồng thực thi: Kẻ tấn công sử dụng việc ghi đè vùng nhớ đệm để thay đổi dữ liệu quan trọng như địa chỉ trả về (return address) hoặc các biến cục bộ, từ đó kiểm soát luồng thực thi của chương trình.
  5. Thực thi mã độc: Kẻ tấn công chèn mã độc vào dữ liệu đầu vào và sử dụng việc kiểm soát luồng thực thi để thực thi mã độc đó.

Để phòng ngừa tấn công Buffer Overflow, một số biện pháp phòng ngừa sau có thể được áp dụng:

  • Kiểm tra và xác minh đầu vào: Đảm bảo rằng tất cả đầu vào từ người dùng được kiểm tra và xác minh trước khi sử dụng. Hạn chế hoặc loại bỏ các dữ liệu không hợp lệ hoặc độ dài quá lớn.
  • Sử dụng các ngôn ngữ và công cụ an toàn: Sử dụng ngôn ngữ lập trình có tính bảo mật cao như Rust, Ada, hoặc Java để giảm khả năng xảy ra Buffer Overflow. Sử dụng các công cụ kiểm tra tĩnh (static analysis tools) để phát hiện các lỗi Buffer Overflow trong mã nguồn.
  • Áp dụng kỹ thuật bảo vệ đa lớp: Sử dụng các kỹ thuật bảo vệ đa lớp như canary values, ASLR (Address Space Layout Randomization), DEP (Data Execution Prevention) để làm khó khăn cho kẻ tấn công khi thực hiện Buffer Overflow.
  • Regular patching và cập nhật phần mềm: Luôn cập nhật phiên bản phần mềm và thư viện sử dụng để đảm bảo rằng các lỗ hổng bảo mật đã biết được vá đầy đủ.
  • Thực hiện kiểm thử bảo mật: Thực hiện kiểm thử bảo mật và kiểm tra Buffer Overflow để phát hiện lỗi và khắc phục chúng trước khi triển khai ứng dụng vào môi trường thực tế.

Lưu ý rằng điều này chỉ là một số biện pháp phòng ngừa chung và phụ thuộc vào ngôn ngữ và nền tảng cụ thể mà bạn đang sử dụng, có thể có các biện pháp phòng ngừa khác phù hợp trong mỗi trường hợp cụ thể.

Xem thêm Buffer trong Node.js

Hậu quả của Buffer Overflow Attack

Hậu quả của Buffer Overflow Attack có thể rất nghiêm trọng và tiềm ẩn nhiều rủi ro bảo mật. Dưới đây là một số hậu quả phổ biến của tấn công Buffer Overflow:

  1. Thực thi mã độc: Kẻ tấn công có thể sử dụng Buffer Overflow để thực thi mã độc hoặc chèn mã độc vào vùng nhớ đệm. Điều này có thể dẫn đến việc thực hiện các hành động độc hại, như truy cập, thay đổi hoặc xóa dữ liệu quan trọng, cài đặt phần mềm độc hại, hoặc kiểm soát từ xa máy chủ.
  2. Mất ổn định hệ thống: Khi Buffer Overflow xảy ra, có thể làm mất ổn định hệ thống và gây ra sự cố, crash chương trình hoặc treo máy tính. Điều này có thể dẫn đến mất dữ liệu, gián đoạn dịch vụ, và làm ảnh hưởng đến hoạt động kinh doanh và trải nghiệm người dùng.
  3. Bypass các biện pháp bảo mật: Kẻ tấn công có thể sử dụng Buffer Overflow để vượt qua các biện pháp bảo mật như kiểm tra và xác thực đầu vào, kiểm soát luồng thực thi, và cơ chế bảo vệ khác. Điều này có thể cho phép kẻ tấn công truy cập vào các tài nguyên không được ủy quyền hoặc thực hiện các hành động không mong muốn trong hệ thống.
  4. Rò rỉ thông tin nhạy cảm: Trong một số trường hợp, Buffer Overflow có thể làm rò rỉ thông tin nhạy cảm từ vùng nhớ, bao gồm thông tin đăng nhập, khóa bí mật, hoặc dữ liệu cá nhân. Kẻ tấn công có thể khai thác thông tin này để tiến hành các cuộc tấn công khác hoặc lợi dụng thông tin đó với mục đích xấu.
  5. Tổn hại danh tiếng: Khi một ứng dụng hoặc hệ thống bị tấn công Buffer Overflow, điều này có thể gây ra thiệt hại đáng kể đến danh tiếng của tổ chức hoặc cá nhân liên quan. Không chỉ ảnh hưởng đến niềm tin của người dùng, mà còn có thể làm mất lòng tin của đối tác kinh doanh và gây thiệt hại đến hình ảnh tổ chức.

Để giảm thiểu hậu quả của Buffer Overflow Attack, các biện pháp bảo mật như kiểm tra đầu vào, xác minh đầu vào, và sử dụng kỹ thuật bảo vệ đa lớp có thể được triển khai. Đồng thời, việc áp dụng các quy trình phát hiện và ứng phó sự cố, cùng với việc duy trì các bản vá và cập nhật hệ thống là quan trọng để giảm thiểu rủi ro của Buffer Overflow Attack.

Biện pháp phòng ngừa Buffer Overflow Attack

Để phòng ngừa Buffer Overflow Attack, dưới đây là một số biện pháp mà bạn có thể áp dụng:

  1. Kiểm tra và xác minh đầu vào: Đảm bảo rằng tất cả đầu vào từ người dùng được kiểm tra và xác minh trước khi sử dụng. Điều này bao gồm kiểm tra độ dài và loại dữ liệu đầu vào, đảm bảo rằng nó nằm trong giới hạn cho phép và không chứa ký tự đặc biệt có thể gây ra Buffer Overflow.
  2. Sử dụng hàm an toàn trong ngôn ngữ lập trình: Sử dụng các hàm an toàn như strcpy_s, strncpy_s, sprintf_s (trong C/C++) hoặc StringBuilder (trong Java) thay vì các hàm không an toàn như strcpy, strncpy, sprintf. Các hàm an toàn này có thể giới hạn độ dài và đảm bảo không xảy ra tràn bộ đệm.
  3. Sử dụng kiểm tra và xử lý lỗi: Thực hiện kiểm tra lỗi và xử lý lỗi một cách cẩn thận. Khi xảy ra lỗi, hãy đảm bảo rằng các biến không bị tràn bộ đệm và các vùng nhớ được quản lý chính xác.
  4. Sử dụng kỹ thuật bảo vệ đa lớp: Áp dụng các kỹ thuật bảo vệ đa lớp như canary values, ASLR (Address Space Layout Randomization), DEP (Data Execution Prevention) để làm khó khăn cho kẻ tấn công khi thực hiện Buffer Overflow.
  5. Thực hiện kiểm thử bảo mật: Thực hiện kiểm thử bảo mật và kiểm tra Buffer Overflow để phát hiện lỗi và khắc phục chúng trước khi triển khai ứng dụng vào môi trường thực tế. Kiểm thử bao gồm việc nhập các đầu vào đặc biệt và kiểm tra xem chương trình có chống lại Buffer Overflow không.
  6. Cập nhật và vá lỗi: Luôn cập nhật phiên bản phần mềm và thư viện sử dụng để đảm bảo rằng các lỗ hổng bảo mật đã biết được vá đầy đủ. Theo dõi các bản vá bảo mật và áp dụng chúng một cách đúng đắn.
  7. Đảm bảo an ninh mã nguồn: Áp dụng các phương pháp phân tích mã nguồn tĩnh (static code analysis) để phát hiện và khắc phục các lỗi Buffer Overflow trong mã nguồn.
  8. Giáo dục và đào tạo: Đảm bảo rằng nhân viên lập trình và nhân viên quản lý hệ thống được đào tạo về vấn đề bảo mật và hiểu rõ về các nguy cơ liên quan đến Buffer Overflow Attack.

Nhớ rằng không có biện pháp phòng ngừa tuyệt đối và mỗi ứng dụng cần được xem xét riêng để áp dụng các biện pháp bảo mật phù hợp.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Contact Me on Zalo
Call now