Trong đó Buffer Overflow hay còn gọi là lỗi tràn bộ đệm là một lỗi lập trình có thể gây ra một ngoại lệ truy cập bộ nhớ máy tính và chương trình bị kết thúc, hoặc khi người dùng có ý phá
Trang 1HỌC VIỆN KỸ THUẬT MẬT MÃ
AN TOÀN THÔNG TIN
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
BÁO CÁO BÀI TẬP LỚN
Đề tài:
TÌM HIỂU VỀ LỖ HỔNG TRÀN BỘ ĐỆM
(BUFFER OVERFLOW)
Sinh viên thực hiện:
Nguyễn Văn Lĩnh AT150631
Lê Gia Long AT150332
Trần Hữu Long AT150434
Giảng viên:
Vũ Thị Vân
Học viện Kỹ Thuật Mật Mã
Hà Nội, tháng 9 năm 2021
Trang 2Nhận xét của giảng viên bộ môn:
Trang 3LỜI MỞ ĐẦU :
Trong tình hình hiện nay, các cuộc tấn công vào môi trường mạng đã và đang phát triển nhanh chóng, kể cả hình thức và quy mô hoạt động, có tính chất xuyên biên giới, gây ảnh hưởng nghiêm trọng đến hòa bình thế giới, sự ổn định về chính trị, kinh tế của các nước, đặc biệt xâm phạm đến quyền và lợi ích của mỗi cá nhân, tổ chức Những vụ tấn công nhằm vào tất cả các máy tính có mặt trên Internet, các máy tính của công ty lớn như AT&T, IBM, các trường đại học, các cơ quan nhà nước, các tổ chức quan sự, nhà băng Một số vụ tấn công có quy mô khổng lồ (có tới 100.000 máy tính bị tấn công )
Với những công cụ tự động tìm lỗi hổng tuy giúp rất nhiều cho những nhà lập trình web nhưng vẫn không thể ngăn chặn toàn bộ vì công nghệ web đang phát triển nhanh chóng (chủ yếu chú trọng đến yếu tố thẩm mĩ, yếu tố tốc độ ) nên dẫn đến nhiều khuyết điểm mới phát sinh Sự tấn công không nằm trong khuổn khổ vài
kĩ thuật đã phát hiện, mà linh động và tăng lên tùy vào những sai sót của nhà quản trị hệ thống cũng như của những người lập trình
Trong đó Buffer Overflow hay còn gọi là lỗi tràn bộ đệm là một lỗi lập trình
có thể gây ra một ngoại lệ truy cập bộ nhớ máy tính và chương trình bị kết thúc, hoặc khi người dùng có ý phá hoại, họ có thể lợi dụng lỗi này để phá vỡ an ninh hệ thống Để có thể hiểu rõ hơn về lỗ hổng tràn bộ đệm (Buffer Overflow) cũng như nguyên nhân dẫn đến lỗi tràn bộ đệm tạo ra lỗ hỏng phần mềm thì sau đây nhóm
em xin trình bày báo cáo về đề tài “ Tìm hiểu về lỗ hổng tràn bộ đệm (Buffer Overflow)” Ở đề tài này nhóm em sẽ chỉ ra các vấn đề như: khái niệm về lỗi tràn
bộ đệm, ví dụ, nguyên nhân và biện pháp phòng chống Cuối cùng thì nhóm em sẽ tiến hành thực nghiệm tấn công lỗ hổng tràn bộ nhớ đệm
LỜI MỞ ĐẦU: 3
Trang 4I GIỚI THIỆU: 5
1 Các khái niệm 5
1.1 Buffer: 5
1.2 Stack: 5
1.3 Thanh ghi: 5
2 Buffer Overflow: 5
2.1 Khái niệm: 5
2.2 Ví dụ: 6
2.3 Nguyên nhân: 6
2.4 Tác hại: 6
II KHAI THÁC BUFFER OVERFLOW: 7
1 Các kiểu lỗi Buffer Overflow thường gặp 7
1.1 Stack overflow: 7
1.2 Format String: 7
2 Các kiểu khai thác Buffer Overflow 7
2.1 Tổ chức bộ nhớ: 7
2.2 Khai thác lỗi tràn bộ đệm trên stack (Stack overflow) 8
2.3 Khai thác lỗi tràn bộ đệm trên heap (Heap Overflow) 9
2.4 Một số cách khai thác khác 11
III Phòng chống Buffer Overflow 11
1 Cách phát hiện Buffer Overflow 11
2 Các cách phòng chống Buffer Overflow 12
2.1 Lựa chọn ngôn ngữ lập trình: 12
2.2 Sử dụng các thư viện an toàn: 12
2.3 Chống tràn bộ đệm trên stack: 13
2.4 Bảo vệ không gian thực thi: 13
2.5 Ngẫu nhiên hóa sơ đồ không gian địa chỉ (Address space layout randomization ASLR): 13
2.6 Kiểm tra sâu đối với gói tin (deep packet inspection - DPI): 13
IV Kết luận chung: 13
Trang 5I GIỚI THIỆU:
1 Các khái niệm
1.1 Buffer:
Buffer hay bộ đệm là một khối dành riêng của bộ nhớ máy tính, cho phép chứa nhiều các phần tử của cùng kiểu dữ liệu Với ngôn ngữ lập trình C, Buffer thường được tổ chức dưới dạng là mảng của các từ nhớ
1.2 Stack:
Stack hay ngăn xếp là một kiểu dữ liệu trừu tượng dùng trong khoa học máy tính Một Stack của các đối tượng (Object) có tính chất: Đối tượng được đưa vào Stack cuối cùng sẽ được lấy ra đầu tiên (LIFO – Last In First Out) Stack hỗ trợ 2 thao tác quan trọng nhất là PUSH và POP để thực hiện việc thêm một đối tượng vào Stack và loại bỏ 1 đối tượng khỏi Stack
1.3 Thanh ghi:
Thanh ghi là các ô nhớ có dung lượng nhỏ nằm trong nhân CPU có tốc độ truy cập cao, được sử dụng để tăng tốc độ xử lý các lệnh của chương trình trên máy tính bằng cách cung cấp các truy cập trực tiếp đến các giá trị cần sử dụng Hầu hết các máy tính hiện đại hoạt động theo nguyên lý là chuyển dữ liệu từ bộ nhớ sang các thanh ghi, sau đó việc tính toán sẽ được thực hiện trên các thanh ghi này rồi kết quả được chuyển lại về bộ nhớ
2 Buffer Overflow:
2.1 Khái niệm:
Buffer Overflow hay lỗi tràn bộ đệm là một điều kiện bất thường khi tiến trình lưu trữ dữ liệu vượt ra ngoài biên của bộ đệm có chiều dài cố định Kết quả là
dữ liệu có thể đè lên các bộ nhớ liền kề Dữ liệu bị ghi đè có thể bao gồm các bộ đệm khác, các biến và dữ liệu điều khiển luồng chảy của cả chương trình (program flow control)
Các lỗi tràn bộ đệm có thể làm cho tiến trình bị đổ vỡ hoặc cho ra kết quả sai Các lỗi này có thể được kích hoạt bởi các dữ liệu vào được thiết kế đặc biệt để thực thi các đoạn mã phá hoạt hoặc làm cho chương trình hoạt động không như mong muốn Bằng cách đó lỗi tràn bộ đệm gây ra nhiều lỗ hổng bảo mật đối với phần mềm và tạo cơ sở cho nhiều thủ thuật khai thác
Trang 62.2 Ví dụ:
Hình 1.1 Ví d v Buffer Overflow ụ ề
Ở ví dụ này hàm func khai báo hai biến buffa và buffb có kích thước lần lượt
là 10 và 5 Chương trình yêu cầu nhập tên và lấy thông tin nhập vào Sau đó thông tin được sao chép từ buffa sang buffb và kết thúc
Nếu người dùng nhập hơn 10 kí tự thì chương trình sẽ bị sập Hàm strcpy sẽ sao chép dữ liệu từ buffa sang buffb Nhưng buffb có kích thước nhỏ hơn buffa nên nếu nhập vào ít hơn 10 kí tự nhưng lớn hơn 5 kí tự thì khi sao chép từ buffa sang buffb sẽ gây ra hiện tượng tràn bộ nhớ đệm
2.3 Nguyên nhân:
Nguyên nhân gây ra lỗi Buffer Overflow của các chương trình, ứng dụng:
- Phương thức kiểm tra biên (boundary) không được thực hiện đầy đủ hoặc là được bỏ qua
- Các ngôn ngữ lập trình như là ngôn ngữ C, bản thân nó đã tiền ẩn các lỗi mà hacker có thể khai thác
- Các phương thức strcat(), strcpy(), sprintf(), bcopy(), gets(), canf() trong ngôn ngữ C có thể được khai thác vì các hàm này không kiểm tra những buffer được cấp phát trên stack có kích thước lớn hơn dữ liệu được copy vào buffer hay không
2.4 Tác hại:
Tác hại của lỗi Buffer Overflow:
- Lỗi tràn bộ đệm xảy ra khi một ứng dụng cố gắng ghi dữ liệu vượt khỏi phạm
vi bộ đệm (giới hạn cuối hoặc cả giới hạn đầu của bộ đệm)
- Lỗi tràn bộ đệm có thể khiến ứng dụng ngừng hoạt động, gây mất dữ liệu hoặc thậm chí giúp kẻ tấn công kiểm soát hệ thống hoặc tạo cơ hội cho kẻ tấn công thực hiện nhiều thủ thuật khai thác khác nhau
Trang 7II KHAI THÁC BUFFER OVERFLOW:
1 Các kiểu lỗi Buffer Overflow thường gặp
1.1 Stack overflow:
Lỗi stack overflow sẽ xuất hiện khi buffer tràn trong stack space và là hình thức tấn công phổ biến nhất của lỗi tràn bộ đệm
Mục đích:
- Ghi đè một biến địa phương nằm gần bộ nhớ đệm trong stack để thay đổi hành vi của chương trình nhằm phục vụ ý đồ của hacker
- Ghi đè địa chỉ trả về trong khung stack Khi hàm trả về thực thi sẽ được tiếp tục tại địa chỉ mà hacker đã chỉ rõ, thường là tại một bộ đệm chứa dữ liệu vào của người dùng
1.2 Format String:
Tràn bộ đệm chuỗi định dạng (thường được gọi là “lỗ hổng định dạng chuỗi”) là lỗi tràn bộ đệm ở mức chuyên môn cao, tác hại tương tự như các cuộc tấn công tràn bộ đệm khác Về cơ bản, lỗ hổng định dạng chuỗi tận dụng lợi thế của các kiểu dữ liệu hỗn hợp và kiểm soát thông tin trong chức năng nhất định, chẳng hạn như C/C++ printf
2 Các kiểu khai thác Buffer Overflow.
Có 2 kiểu khai thác Buffer Overflow chính:
- Stack overflow
- Heap overflow
2.1 Tổ chức bộ nhớ:
Mỗi tiến trình thực thi đều được hệ điều hành cấp phát cho một không gian
bộ nhớ ảo (logic) giống nhau Không gian nhớ này gồm 3 vùng: text, data và stack Trong đó:
- Vùng Text là vùng cố định, chứa các mã lệnh thực thi (instruction) và dữ liệu chỉ đọc (real-only) Vùng này được chia sẻ giữa các tiến trình thực thi cùng một file chương trình và tương ứng với phân đoạn text của file thực thi
Dữ liệu ở vùng này chỉ đọc mọi thao tác nhằm ghi lên vùng nhớ đều gây lỗi segmentation violation
- Vùng Data chứa các dữ liệu đã được khởi tạo hoặc chưa khởi tạo giá trị Các biến toàn cục và biến tĩnh được chứa trong vùng này
Data region = Data + BSS + Heap
Data: chứa các biến toàn cục (Global Variable) và các biến tĩnh đã được khởi tạo (Static Variable) được khai báo bởi người lập trình
Trang 8 BSS: chứa các biến chưa được khởi tạo hoặc khởi tạo không rõ ràng, phản hồi tới khu vực Data-BSS của file thực thi được (Executable file) Dữ liệu trong Data region có thể đọc/ghi (Read-write)
Heap: Địa chỉ bắt đầu ngay sau kết thúc của BSS và có thể phát triển kích thước tăng dần trong quá trình thực thi Việc cấp phát và thu dọn
bộ nhớ trong Heap được thực hiện qua các lời gọi malloc(), realloc() và free() Lời gọi hệ thống brk() và sbrk() được dùng để điều chỉnh kích
cỡ (resize) của Heap Vùng Heap được chia sẻ bởi tất cả các thư viện chia
sẻ và các module nạp động trong tiến trình
- Vùng Stack là vùng nhớ được rành riêng khi thực thi chương trình dùng để chứa giá trị các biến cục bộ của hàm, tham số gọi hàm cũng như giá trị trả
về Thao tác trên bộ nhớ stack được thao tác theo cơ chế “ vào sau ra trước”-LIFO (Last In First Out) với hai lệnh quan trọng nhất là PUSH và POP Stack có một thanh ghi (ESP) gọi là con trỏ Stack (Stack pointer) luôn trỏ tới đỉnh của Stack Đáy của Stack là một địa chỉ cố định Kích cỡ của Stack được điều chỉnh động bởi nhân của hệ điều hành (Kernel) trong thời gian thực thi (Run-time) CPU thực hiện các lệnh PUSH và POP với Stack
Stack gồm các khung, gọi là Stack Frame Các Stack Frame được thêm vào khi gọi một hàm (function) và được loại bỏ ra khỏi Stack khi trở về từ hàm Một Stack Frame gồm: các tham số của hàm, các biến địa phương của hàm đó, và các
dữ liệu cần thiết để khôi phục khung Stack trước để quay về hàm gọi (Previous Stack Frame) – Dữ liệu này gồm: Giá trị của con trỏ lệnh vào thời điểm hàm được gọi (SavedEIP) và địa chỉ đầu tiên của Stack Frame (Frame Pointer) của hàm trước
đó (SavedEBP)
Hình 2.1 Tổ chức bộ nhớ
Trang 92.2 Khai thác lỗi tràn bộ đệm trên stack (Stack overflow)
Định nghĩa:
Vùng bộ nhớ ảo Stack chứa các đối số của hàm, địa chỉ lệnh trả về, địa chỉ stack frame trước đó và các biến được khai báo cục bộ trong hàm
Việc tràn bộ đệm xảy ra khi bộ đệm đặt trên Stack bị tràn, dẫn đến việc thay đổi dữ liệu ở các vùng nhớ có địa chỉ cao hơn, cụ thể là các biến địa phương của hàm hoặc địa chỉ lệnh trả về (SavedEIP), từ đó thay đổi việc thực thi bình thường của chương trình và tạo điều kiện cho kẻ tấn công “thao túng” phần mềm hoặc hệ điều hành
Hình 2.2 Stack
Mục đích:
Hacker thạo kỹ thuật và có ý đồ xấu có thể khai thác các lỗi tràn bộ đệm trên stack để thao túng chương trình theo một trong các cách sau:
- Ghi đè một biến địa phương nằm gần bộ nhớ đệm trong stack để thay đổi hành vi của chương trình nhằm tạo thuận lợi cho kẻ tấn công
- Ghi đè địa chỉ trả về trong một khung stack (stack frame) Khi hàm trả về, thực thi sẽ được tiếp tục tại địa chỉ mà kẻ tấn công đã chỉ rõ, thường là tại một bộ đệm chứa dữ liệu vào người dùng
- Nếu không biết địa chỉ của phần dữ liệu người dùng cung cấp, nhưng biết rằng địa chỉ của nó được lưu trong một thanh ghi, thì có thể ghi đè lên địa chỉ trả về một giá trị địa chỉ của một opcode mà opcode này sẽ có tác dụng làm cho thực thi nhảy đến phần dữ liệu người dùng
Trang 10Hình 2.3 Stack khi bị tấn công bởi Atacker
Ví dụ:
Hình 2.4 Ví dụ về Stack Buffer Overflow
2.3 Khai thác lỗi tràn bộ đệm trên heap (Heap Overflow).
Định nghĩa
Heap là một khu vực của bộ nhớ được sử dụng bởi một ứng dụng và được cấp phát động tại thời gian chạy của các hàm, chẳng hạn như malloc() Một hiện tượng tràn bộ đệm xảy ra trong khu vực dữ liệu heap được gọi là một hiện tượng
Trang 11tràn heap và có thể khai thác được bằng các kỹ thuật khác với các lỗi tràn stack Bộ nhớ heap được cấp phát động bởi các ứng dụng tại thời gian chạy và thường chứa
dữ liệu của chương trình
Bởi vì Heap được sử dụng để lưu trữ dữ liệu, không được sử dụng để lưu các giá trị địa chỉ trả về của hàm như là Stack nên việc khai thác lỗi tràn bộ đệm trên Heap khó khăn hơn nhiều so với việc khai thác lỗi tràn bộ đệm trên Stack
Hình 2.4 Dung lượng heap đơn giản
Mục đích:
- Trong cách tấn công heap overflow, attacker làm tràn bộ nhớ sẽ có thể overwrite các dynamic variables, vì thế có thể dẫn đến các hiệu ứng không mong muốn
- Việc khai thác được thực hiện bằng cách phá dữ liệu này theo các cách đặc biệt để làm cho ứng dụng ghi đè lên các cấu trúc dữ liệu nội bộ chẳng hạn các con trỏ của danh sách liên kết
Hình 2.6 Heap Overflow
Ví dụ:
Trang 12Hình 2.5 Ví dụ về Heap Buffer Overflow
2.4 Một số cách khai thác khác.
- Khai thác dựa vào các lỗ hổng phần mềm thông qua ngôn ngữ lập trình (phần mềm thường được viết bằng ngôn ngữ C)
- Khai thác các trang web có tương tác người dùng nhưng không ràng buộc
dữ liệu nhập như các trường hợp username, password,
III Biện pháp phòng chống Buffer Overflow.
1 Cách phát hiện Buffer Overflow.
Có 2 cách cơ bản để phát hiện các lỗi buffer overflow mà hacker có thể sử dụng :
- Nhìn vào source code: Hacker tìm kiếm các string là các biến cục bộ trong các hàm của chương trình, xem xét chúng có được kiểm tra biên (boundary check) chưa Kiểm tra tiêu chuẩn của các hàm có liên quan đến phần các chuỗi trong phần input, output
- Nhập vào các ứng dụng một dữ liệu rất lớn và xem xét ứng dụng có bất cứ biểu hiện không bình thường nào không
Các bước xác định Buffer Overflow:
Bước 1: Chạy máy chủ web trên máy cục bộ
Bước 2: Phát yêu cầu với mọi thẻ dài thẻ kết thúc với “$$$$$”
Bước 3: Nếu máy chủ web bị treo, tìm kiếm bãi tập kết lõi của “$$$$$” để tìm kiếm vị trí tràn
Bước 4: Sử dụng các công cụ tự động như codeBlocker, eEye Retina, …
Trang 13 Bước 5: Sử dụng bộ phận phân tách và trình gỡ rối
Bước 6: Sử dụng IDA-Proto để xây dựng lại vị trí bị khai thác
2 Các cách phòng chống Buffer Overflow.
Việc xử lý bộ đệm trước khi đọc hay thực thi có thể làm thất bại các cuộc khai thác lỗi tràn bộ đệm nhưng vẫn không ngăn chặn được một cách tuyệt đối Việc xử lý bao gồm:
- Chuyển từ chữ hoa thành chữ thường
- Loại bỏ các ký tự đặc biệt và lọc các xâu không chứa kí tự là chữ số hoặc chữ cái Ngoài ra, vẫn còn có các kỹ thuật để tránh việc lọc và xử lý này: -Alphanumeric code: mã gồm toàn chữ và số
- Polumorphic code: mã đa hình
- Seft-modifying code: mã tự sửa đổi
- Tấn công kiểu return – to – libc
Vì vậy, để tránh các nguy cơ bị khai thác lỗi buffer overflow chúng ta cần sử dụng các biện pháp phòng tránh hiệu quả hơn
2.1 Lựa chọn ngôn ngữ lập trình:
Ngôn ngữ lập trình có một ảnh hưởng lớn đối với sự xuất hiện lỗi tràn bộ đệm
- Ngôn ngữ lập trình C và C++ là hai ngôn ngữ lập trình thông dụng, nhưng hạn chế của nó là không kiểm tra việc truy cập hoặc ghi đè dữ liệu thông qua các con trỏ Cụ thể nó không kiểm tra dữ liệu copy vào một mảng có phù hợp với kích thước của mảng hay không
- Cyclone: một biến thể của C, giúp ngăn chặn các lỗi tràn bộ đệm bằng việc gắn thông tin về kích thước mảng với các mảng
- Ngôn ngữ lập trình sử dụng nhiều kỹ thuật đa dạng để tránh gần hết việc sử dụng con trỏ và kiểm tra biên do người dùng xác định
- Nhiều ngôn ngữ lập trình khác cung cấp việc kiểm tra tại thời gian chạy Việc kiểm tra này cung cấp một ngoại lệ hay một cảnh báo khi C hay C++ ghi đè dữ liệu ví dụ như Pythol, Ada, Lisp,
- Ngoài ra, các môi trường Java hay Net cũng đòi hỏi kiểm tra biên đối với tất
cả các mảng
2.2 Sử dụng các thư viện an toàn:
Sử dụng các thư viện được viết tốt và đã được kiểm thử dành cho các kiểu
dữ liệu trừu tượng mà các thư viện này thực hiện tự động việc quản lý bộ nhớ, trong đó có kiểm tra biên có thể làm giảm sự xuất hiện và ảnh hưởng của các hiện