1. Trang chủ
  2. » Công Nghệ Thông Tin

16 phat hien loi va lo hong bao mat phan mem phu luc 40 tr

214 70 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 214
Dung lượng 1,86 MB

Nội dung

Trang 1

BAN CƠ YẾU CHÍNH PHỦ

HỌC VIỆN KỸ THUẬT MẬT MÃ

TS ĐẶNG VŨ SƠN ThS VŨ ĐÌNH THU

GIÁO TRÌNH

TÌM VÀ PHÁT HIỆN LỖ HỔNG PHẦN MỀM

Trang 2

BAN CƠ YẾU CHÍNH PHỦ

HỌC VIỆN KỸ THUẬT MẬT MÃ

TS ĐẶNG VŨ SƠN ThS VŨ ĐÌNH THU

GIÁO TRÌNH

TÌM VÀ PHÁT HIỆN LỖ HỔNG PHẦN MỀM

Trang 3

1.2.2 Mô hình phát triển tiến hoá 4

1.2.3 Mô hình xoắn ốc Boehm 5

1.2.4 Các quy trình linh hoạt 5

2.2.5 Cơ chế xác thực, phân quyền thực yếu 48

Câu hỏi ôn tập chương 2: 49

Trang 4

Câu hỏi ôn tập chương 3 58

4.2.3 Khai thác lỗi sai định dạng chuỗi 84

4.2.4 Khai thác lỗ hổng gây ra do lỗi không kiểm soát đầuvào 111

4.3 Khai thác lỗ hổng phần mềm sử dụng phần mềmMetasploit Framework 115

Khai thác lỗ hổng phần mềm sử dụng các module có sẵncủa Metasploit: 119

4.4 Xây dựng mã khai thác lỗ hổng phần mềm 120

4.4.1 Một số kiến thức cần biết 120

4.4.2 Các dạng Shellcode 122

4.4.3 Viết Shellcode khai thác lỗ hổng phần mềm 125

Câu hỏi ôn tập chương 4 131

5.CHƯƠNG 5 PHÁT TRIỂN VÀ SỬ DỤNG PHẦN MỀM AN TOÀN 132

5.1 Phát triển phần mềm an toàn 132

5.1.1 Yêu cầu tiền SDL: đào tạo an ninh 132

5.1.2 Pha 1: Yêu cầu 134

2 Viết Module khai thác lỗ hổng phần mềm dựa trênMetasploit Framework 159

Trang 6

DANH MỤC TỪ VIẾT TẮT

STTTừ viết

2 XSS Cross Site Scripting

4 PVF Potentially ble Function

6 NOP No Operation formed

Per-7 DLL Dynamic Link Library

Trang 7

Hình 2.4 Sơ đồ vị trí các hàm trong Ngăn xếp 15

Hình 2.5 Trạng thái của ngăn xếp sau khi hàm function_A()gọi hàm function_B() 16

Hình 2.9 Ghi đè lên địa chỉ trả về 21

Hình 2.10 Danh sách liên kết trước và sau khi thực hiện thayđổi 25

Hình 2.11 Sự thay đổi Ngăn xếp khi thực thi chương trình bị lỗioff-by-one 33

Hình 2.12 Minh họa bộ nhớ khi thực hiện khai thác lỗi địnhdạng chuỗi 36

Hình 2.13 Thông báo minh họa lỗi XSS 46

Hình 3.1 Mô hình phân tích từ vựng 54

Hình 3.2 Ví dụ đồ thị luồng điều khiển 57

Hình 4.1 Ngăn xếp của chuỗi định dạng 90

Hình 4.2 Bộ nhớ lưu trữ chuỗi giá trị nhập vào 96

Hình 4.3 Kiến trúc Metasploit Framework 116

Hình 4.6 Kết quả sau khi thực thi shellcode thêm người dùng 131

Trang 8

DANH MỤC CÁC BẢNG

Bảng 3.1: Kết quả thu được sau khi phân tích từ vựng 55

Trang 9

LỜI NÓI ĐẦU

Tìm và phát hiện lỗ hổng phần mềm là một lĩnh vực quantrọng trong An toàn thông tin, đây cũng là một lĩnh vực khóđòi hỏi người làm lĩnh vực này phải có một kiến thức tốt về rấtnhiều nội dung liên quan đến phần mềm và an toàn phầnmềm

Giáo trình này là tài liệu dùng để giảng dạy cho sinh viênchuyên ngành an toàn thông tin tại Học viện Kỹ thuật Mật mã.Giáo trình trình bày những nội dung cơ bản về quy trình pháttriển phần mềm, các lỗi phần mềm thường gặp, các phươngpháp phát hiện lỗ hổng phần mềm, cũng như cách thức xâydựng một module khai thác lỗ hổng phần mềm Giáo trình cóthể sử dụng làm tài liệu tham khảo rất hữu ích cho những aiquan tâm đến an toàn thông tin cụ thể là lĩnh vực tìm và pháthiện lỗ hổng phần mềm.

Trong quá trình xây dựng giáo trình, các tác giả đã cốgắng để cập đến các nội dung của lĩnh vực phát hiện lỗ hổngphần mềm, tuy nhiên đây là lĩnh vực khó do vậy khó có thểtránh được những thiếu sót Hy vọng trong những lần chỉnhsửa bổ sung về sau sẽ hoàn thiện giáo trình hơn để phục vụtốt hơn cho chương trình đào tạo kỹ sư An toàn thông tin tạiHọc viện Kỹ thuật Mật mã.

Nhóm tác giả

Trang 10

CHƯƠNG I TỔNG QUAN VỀ PHẦN MỀM VÀ LỖ HỔNG PHẦNMỀM

1.1 Khái niệm phần mềm

Phần mềm máy tính hay gọi tắt là phần mềm là một tậphợp những câu lệnh hoặc chỉ thị được viết bằng một hoặc nhiềungôn ngữ lập trình theo một trật tự xác định, và các dữ liệu haytài liệu liên quan nhằm tự động thực hiện một số nhiệm vụ haycác chức năng hoặc giải quyết một vấn đề cụ thể nào đó.

Phần mềm thực hiện gửi các chỉ thị trực tiếp tới phần cứnghoặc bằng cách cung cấp dữ liệu để phục vụ các chương trìnhhay phần mềm khác Phần mềm khác với phần cứng ở chỗ làphần mềm không thể sờ hay đụng vào, và nó cần phải có phầncứng mới có thể chạy được.

Trước đây, để tạo ra chương trình máy tính người ta phảilàm việc trực tiếp với các con số 0 hoặc 1 (sử dụng hệ số nhịphân), hay còn gọi là ngôn ngữ máy Công việc này vô cùng khókhăn, chiếm nhiều thời gian, công sức và đặc biệt dễ gây ra lỗi.Để khắc phục nhược điểm này, người ta đề xuất ra hợp ngữ,một ngôn ngữ cho phép thay thế dãy 0 hoặc 1 này bởi các từgợi nhớ tiếng Anh Tuy nhiên, cải tiến này vẫn còn chưa thậtthích hợp với đa số người dùng máy tính, những người luônmong muốn các lệnh chính là ý nghĩa của các thao tác mà nómô tả Vì vậy, ngay từ những năm 1950, người ta đã xây dựngngôn ngữ lập trình mà câu lệnh của nó gần với ngôn ngữ tựnhiên như ngôn ngữ lập trình FORTRAN Ngôn ngữ này được gọilà ngôn ngữ lập trình bậc cao.

Chương trình máy tính thường được tạo ra bởi con người,những người này được gọi là lập trình viên, tuy nhiên cũng tồntại những chương trình được sinh ra bởi các chương trình khác.

Phân loại phần mềm:

Trang 11

Phân loại theo cách thức hoạt động:

Phần mềm hệ thống: Dùng để vận hành máy tính và cácphần cứng máy tính, ví dụ như các hệ điều hành máy tính Win-dows, Linux, Unix, các thư viện động (còn gọi là thư viện liên kếtđộng; tiếng Anh: dynamic linked library - DLL) của hệ điều hành,các trình điều khiển (driver), phần sụn (firmware) và BIOS Đâylà các loại phần mềm mà hệ điều hành liên lạc với chúng đểđiều khiển và quản lý các thiết bị phần cứng.

Phần mềm ứng dụng: Để người sử dụng có thể hoàn thànhmột hay nhiều công việc nào đó, ví dụ như các phần mềm vănphòng (Microsoft Office, OpenOffice), phần mềm doanh nghiệp,phần mềm quản lý nguồn nhân lực, phần mềm giáo dục, cơ sởdữ liệu, phần mềm trò chơi, chương trình tiện ích, hay các loạiphần mềm độc hại.

Các phần mềm chuyển đổi mã bao gồm trình biên dịch vàtrình thông dịch: các loại chương trình này sẽ đọc các câu lệnhtừ mã nguồn được viết bởi các lập trình viên theo một ngôn ngữlập trình và dịch nó sang dạng ngôn ngữ máy mà máy tính cóthể hiểu đưọc, hay dịch nó sang một dạng khác như là tập tinđối tượng (object file) và các tập tin thư viện (library file) màcác phần mềm khác như hệ điều hành chẳng hạn có thể hiểu đểvận hành máy tính thực thi các lệnh.

Phân loại theo theo khả năng ứng dụng:

Những phần mềm không phụ thuộc, nó có thể được bán chobất kỳ khách hàng nào trên thị trường tự do Ví dụ: phần mềmvề cơ sở dữ liệu như Oracle, đồ họa như Photoshop, Corel Draw,soạn thảo và xử lý văn bản, bảng tính,

Ưu điểm: Thông thường đây là những phần mềm có khảnăng ứng dụng rộng rãi cho nhiều nhóm người sử dụng

Khuyết điểm: Thiếu tính uyển chuyển, tùy biến.

Trang 12

Những phần mềm được viết theo đơn đặt hàng hay hợpđồng của một khách hàng cụ thể nào đó (một công ty, bệnhviện, trường học, ) Ví dụ: phần mềm điều khiển, phần mềm hỗtrợ bán hàng,

Ưu điểm: Có tính uyển chuyển, tùy biến cao để đáp ứngđược nhu cầu của một nhóm người sử dụng nào đó

Khuyết điểm: Thông thường đây là những phần mềm ứngdụng chuyên ngành hẹp.

1.2 Quy trình phát triển phần mềm

Quy trình phát triển phần mềm là một cấu trúc bao gồm tậphợp các thao tác và các kết quả tương quan sử dụng trong việcphát triển để sản xuất ra một phần mềm Đây được coi là mộtthành phần tập con của vòng đời phát triển hệ thống Có bốnthao tác là nền tảng của hầu hết các quy trình phát triển phầnmềm là:

Đặc tả phần mềm: Định nghĩa các chức năng của phần mềm

và điều kiện để các chức năng này hoạt động.

Phát triển phần mềm: Để phần mềm đạt được như đặc tả thì

phải trải qua quy trình phát triển phần mềm này.

Đánh giá phần mềm: Phần mềm cần phải được đánh giá để

chắc chắn rằng nó có các chức năng và hoạt động đúng nhưkhách hàng mong muốn.

Sự tiến hóa của phần mềm: Phần mềm phải tiến hóa để thỏa

mãn nhu cầu thay đổi của khách hàng.

Sau đây là một số mô hình phát triển phần mềm tiêu biểu:

Trang 13

yếu tố này được tổng hợp lại và thống nhất bởi cả người pháttriển và khách hàng.

Thiết kế phần mềm và hệ thống: Thiết kế hệ thống các quytrình, các thành phần và các yêu cầu về cả phần mềm lẫn phầncứng Thiết kế phần mềm là việc biểu thị các chức năng hệthống phần mềm mà có thể được xây dựng thành một haynhiều chương trình khả thi.

Xây dựng và thử nghiệm các đơn vị: Trong giai đoạn này,phần mềm phải được xây dựng là một tập hợp nhiều chươngtrình hay nhiều đơn vị nhỏ Thử nghiệm các đơn vị để kiểm traxem các đơn vị đáp ứng các yêu cầu đã đặt ra trong thiết kế.

Tổng hợp và thử nghiệm toàn bộ: Các đơn vị hay cácchương trình riêng lẻ được tích hợp lại và thử nghiệm tổng thểxem đã đáp ứng được các yêu cầu đã đặt ra trong thiết kế tổngthể hay chưa Sau khi thử nghiệm và chứng tỏ được phần mềmđã đáp ứng được yêu cầu khách hàng, phần mềm sẽ được cungứng cho khách hàng.

Sản xuất và bảo trì: Thông thường đây là pha lâu nhất củachu kỳ sống sản phẩm Phần mềm được cài đặt và được dùngtrong thực tế Bảo trì bao gồm điều chỉnh các lỗi mà chưa đượcphát hiện trong các giai đoạn trước của chu kì sống Bảo trìcũng bao gồm việc thực hiện nâng cấp hệ thống khi có yêu cầumới.

Chỗ yếu của mô hình này là nó không linh hoạt Các bộphận của dự án chia ra thành những phần riêng khi thực hiệnphát triển phần mềm Hệ thống phân phối đôi khi không dùngđược vì không thỏa mãn được yêu cầu của khách hàng Tuynhiên mô hình này phản ảnh thực tế công nghệ và đây vẫn làmô hình cơ sở cho đa số các hệ thống phát triển phần mềm -phần cứng.

Trang 14

1.2.2 Mô hình phát triển tiến hoá

Hình 1.1 Phát triển phần mềm theo mô hình tiến hoá

Phân tích mô hình: Mô hình phát triển tiến hóa này hiệu quảhơn mô hình thác nước Tuy nhiên, nó vẫn còn các khuyết điểm:

Quy trình thì không nhìn thấy rõ được: Các nhà quản lý cầnphân phối thường xuyên để tính được sự tiến triển.

Phần mềm thường được cấu trúc nghèo nàn: Sự thay đổiliên tục dễ làm đổ vỡ cấu trúc của phần mềm, tạo ra sự khókhăn và tốn phí.

Thường đòi hỏi những kỹ năng đặc biệt: Hầu hết các hệthống phát triển theo cách này được tiến hành bởi các nhómnhỏ có kỹ năng cao cũng như các cá nhân phải năng động.

Mô hình này thích hợp với việc phát triển các loại phần mềmnhỏ và các loại phần mềm có vòng đời ngắn.

1.2.3 Mô hình xoắn ốc Boehm

Đây là mô hình phát triển từ mô hình thác nước cho thấymức độ tổng quát hơn các pha sản xuất của một sản phẩm Môhình được đề xuất bởiBoehmvào năm 1988 Mô hình này có thểchỉ ra các rủi ro có thể hình thành trong mô hình quy trình pháttriển tổng quát.

Mô hình Boehm có dạng xoắn ốc Mỗi vòng lặp đại diện chomột pha của quy trình phần mềm Vòng trong cùng tập trung vềtính khả thi, vòng kế về định nghĩa các yêu cầu, kế đến là thiếtkế,

Trang 15

Không có một pha nào được xem là cố định trong vòngxoắn Mỗi vòng có 4 phần tương ứng với một pha.

Cài đặt đối tượng: Chỉ ra các đối tượng của các giai đoạncủa dự án Những vấn đề khó khăn hay cấp thiết của quy trìnhvà của sản phẩm được xác định và lên kế hoạch chi tiết Xácđịnh các yếu tố rủi ro của dự án Các phương án thay thế tùytheo các rủi ro này có thể được dự trù.

Lượng định và giảm thiểu rủi ro Tiến hành phân tích mỗiyếu tố rủi ro đã xác định Các bước đặt ra để giảm thiểu rủi ro.

Phát triển và đánh giá: Sau khi đánh giá các yếu tố rủi ro,một mô hình phát triển cho hệ thống được lựa chọn.

Lên kế hoạch: Đề án được xem xét và quyết định có nênhay không tiếp tục pha mới trong vòng lặp.

1.2.4 Các quy trình linh hoạt

Là quy trình mà trong đó cấu trúc khởi động sẽ nhỏ nhưnglinh động và lớn dần theo đề án phần mềm nhằm tìm ra các khókhăn trước khi nó trở thành vấn đề có thể dẫn tới những thiệthại cho quý trình phát triển Quy trình này nhấn mạnh sự gọnnhẹ và tập trung hơn là các phương pháp truyền thống Các quytrình linh hoạt dùng các thông tin phản hồi thay vì dùng các kếhoạch, như là một cơ chế diều khiển chính Các thông tin phảnhồi có được từ các thử nghiệm và các phiên bản phát hành củaphần mềm.

Các quy trình linh hoạt thưòng có hiệu quả hơn các phươngpháp cũ, nó dùng ít thời gian lập trình để sản xuất ra nhiều chứcnăng hơn, chất lượng cao hơn, nhưng nó không cung cấp mộtkhả năng lên một kế hoạch lâu dài.

Lập trình cực hạn, gọi tắt làXP, là loại quy trình linh hoạt

được biết đến nhiều nhất Trong XP, các pha được xúc tiến trongcác bước cực nhỏ nếu so với các quy trình kiểu cũ, gọi là các

Trang 16

"toán" xử lý Bước đầu tiên cho đến các bước sau có thể chỉ tốnmột ngày hay một tuần, thay vì phải tốn nhiều tháng như trongphương pháp thác nước Đầu tiên, một người viết các thửnghiệm tự động để cung cấp các mục tiêu cụ thể cho sự pháttriển Kế đến là giai đoạn viết mã (bởi một cặp lập trình viên);giai đoạn này hoàn tất khi mà các mã viết qua được tất cả cácthử nghiệm và không có yêu cầu thêm thử nghiệm cần thiết nàonữa Thiết kế và kiến trúc được điều chỉnh và nâng cao ngaysau giai đoạn viết mã này bởi người đã viết mã trong giai đoạntrước Hệ thống chưa hoàn tất nhưng hoạt động được này đượckhai thác hay được đem ra minh họa cho khách hàng mà trongsố đó có người trong đội phát triển phần mềm Thời điểm nàynhững người thực nghiệm lại bắt đầu viết các thử nghiệm chonhững phần quan trọng kế tiếp của hệ thống.

1.3 Lỗ hổng phần mềm và hiểm họa

Một lỗ hổng phần mềm là một điểm yếu hoặc là một lỗitrong phần mềm có thể bị khai thác bởi một kẻ tấn công để làmthay đổi hoạt động bình thường của phần mềm

Trong hầu hết các trường hợp lỗ hổng phần mềm được côngbố thì các lỗ hổng này được phát hiện khi người dùng sử dụngvà đưa vào dữ liệu sai khác như đưa vào dữ liệu có độ dài vượtquá ngưỡng cho phép và phần mềm sẽ bộc lộ lỗ hổng khi xử lýcác dữ liệu này Chính việc đưa vào các dữ liệu không đúngđược kẻ tấn công sử dụng để tìm lỗ hổng và tìm cách chèn cácmã độc hại vào hệ thống, cho phép kẻ tấn công có thể chạy cácđoạn mã riêng và thực hiện các hành vi khác.

Các lỗ hổng phần mềm thường là những khe hở chính mà kẻtấn công thường tập trung khai thác để xâm nhập vào các hệthống máy tính – từ các máy chủ đến các máy cá nhân củangười dùng cuối

Trang 17

Những hệ thống phần mềm càng phức tạp và lớn thì hiểnnhiên việc kiểm soát sự xuất hiện những lỗ hổng càng khó, bấtkể các kỹ sư thiết kế có trình độ cao đến đâu Và chính nhữngphần mềm này lại thường chiếm vai trò chủ chốt, cũng như tácđộng đến nhiều ngóc ngách của hệ thống Nhờ tận dụng nhữnglỗ hổng của những phần mềm này, kẻ xấu có thể thực hiệnnhững thay đổi nhất định lên hệ thống của người dùng, hay nắmđược quyền điều khiển, truy cập các thông tin nhạy cảm.

Trong thực tế, các lỗ hổng có thể bị khai thác sử dụng chomục đích xấu tồn tại trên bất cứ phần mềm nào Thậm chí cónhững phần thiết kế khó có thể bị cho là lỗi cho đến khi xuấthiện những công nghệ cho phép người ngoài khai thác nó vànhà phát triển phải thiết kế lại cách sản phẩm của mình vậnhành Khi cập nhật phần mềm mới, ngoài việc thêm vào cácchức năng mới cho phần mềm, hay cải thiện hiệu năng hoạtđộng cho sản phẩm, nhà sản xuất còn thực hiện sửa chữa cáclỗi của sản phẩm để đảm bảo cho sản phẩm an toàn hơn Vớicác sản phẩm phổ biến trên thị trường, được phát hành bởi cáccông ty, tổ chức hoạt động một cách chuyên nghiệp, điều này làrất cần thiết.

Tuy vậy, khi có phiên bản phần mềm mới thì sẽ có nhữngngười phát hiện ra lỗi mới của sản phẩm, những người này cóthể không phải là người phát triển phần mềm đó, do vậy cáchãng phần mềm lớn thường tổ chức các cuộc thi khai thác lỗhổng trên phần mềm của họ, sau đó tuyển mộ nhân tài từ cáccuộc thi đó

Trong nhiều trường hợp khi nhà phát triển phần mềm đãphát hiện ra lỗ hổng thì việc khắc phục lỗ hổng có thể mấtnhiều thời gian hơn việc kẻ tấn công viết ra công cụ khai thác lỗhổng, và thực hiện phá hoại, xâm nhập trái phép hệ thống haytrộm cắp dữ liệu bằng công cụ đó Đó cũng chính là lý do màcác bài viết về lỗ hổng bảo mật thường chỉ xuất hiện vài tháng

Trang 18

sau khi lỗ hổng đã được sửa Các lỗ hổng này có thể được báocho nhà sản xuất để sửa chữa

Trong trường hợp kẻ xấu phát hiện ra lỗ hổng trước vàkhông công bố, sau đó phát triển công cụ khai thác lỗ hổng vàâm thầm phát tán Thậm chí giới tội phạm còn đem các lỗ hổngnày ra giao dịch, trao đổi ngầm với nhau, hay bán kèm vớinhững bộ phần mềm được viết ra chuyên để phục vụ việc tìmhiểu, khai thác lỗ hổng Nhà phát triển phần mềm hoàn toànkhông biết đến sự tồn tại của lỗ hổng đó nên không thể nói đếnviệc sửa chữa lỗ hổng Cũng chính vì cuộc tấn công được thựchiện khi nhà phát triển chưa biết về sự tồn tại của lỗ hổng này,lỗ hổng này còn được gọi là lỗ hổng zero-day.

Có rất nhiều dạng lỗ hổng phần mềm khác nhau, trongchương tiếp theo sẽ trình bày về các lỗ hổng phần mềm tiêubiểu thường gặp đối với một phần mềm.

Câu hỏi ôn tập chương 1:

1 Phần mềm là gì? Có những dạng phần mềm gì?

2 Có những quy trình phát triển phần mềm gì, trình bày cácquy trình phát triển phần mềm đó và các ưu, nhược điểmcủa các quy trình đó.

3 Lỗ hổng phần mềm là gì? Những hiểm họa do lỗ hổngphần mềm gây ra.

4 Trình bày những nguyên nhân chính gây ra lỗ hổng phầnmềm? Có thể loại trừ hết mọi lỗ hổng phần mềm đượckhông?

Trang 19

1. CHƯƠNG 2 CÁC DẠNG LỖ HỔNG PHẦN MỀM1.4 Cách thức phân loại

Như đã nói ở chương trước, các lỗ hổng phần mềm trên mộthệ thống là các điểm yếu có thể tạo ra sự ngưng trệ dịch vụ,thêm quyền với người sử dụng hoặc cho phép truy cập bất hợppháp vào hệ thống Các lỗ hổng này tồn tại ngay chính tại hệđiều hành như trong các hệ điều hành Windows, Unix, Linux;hoặc trong các ứng dụng mà người dùng thường xuyên sử dụngnhư Microsoft office, Web Browser, các phần mềm cơ sở dữ liệu…

Phần lớn các lỗ hổng phần mềm là do lỗi lập trình gây ra.Việc sử dụng không đúng cú pháp của ngôn ngữ lập trình,không kiểm soát chặt chẽ dữ liệu đầu vào, cũng như sai sót khitính các giá trị biên chính là các lỗi gây lỗ hỗng phần mềm vàcho phép kẻ tấn công có thể lợi dụng các lỗi này để tấn công hệthống.

Có nhiều tổ chức khác nhau phân loại các lỗ hổng theo cáchkhác nhau Theo cách phân loại của Bộ quốc phòng Mỹ, các loạilỗ hổng trên một hệ thống được phân loại như sau:

Lỗ hổng loại C: Các lỗ hổng này cho phép thực hiện các cuộc

tấn công từ chối dịch vụ (DoS) DoS là hình thức tấn công sửdụng các giao thức ở tầng Internet trong bộ giao thức TCP/IP đểlàm hệ thống ngưng trệ dẫn đến tình trạng từ chối người dùnghợp pháp truy cập hay sử dụng hệ thống Các dịch vụ có chứa lỗhổng cho phép thực hiện các cuộc tấn công DoS có thể đượcnâng cấp hoặc sửa chữa bằng các phiên bản mới hơn của cácnhà cung cấp dịch vụ Hiện nay chưa có giải pháp hoàn thiệnnào để khắc phục các lỗ hổng loại này Chủ yếu các lỗ hổng loạinày thường thấy ở các dịch vụ Web Ví dụ, trình duyệt web củangười dùng bị nhiễm một đoạn mã độc, khi các người dùng kíchhoạt trình duyệt này lập tức đoạn mã độc sẽ thực hiện gửi liêntiếp các gói tin đến máy chủ đích mà kẻ tấn công muốn tấn

Trang 20

công, số lượng gói tin gia tăng làm cho hệ thống quá tải vàngừng dịch vụ

Lỗ hổng loại B: Lỗ hổng loại này có mức độ nguy hiểm trung

bình, cho phép người sử dụng nội bộ có thể leo thang đặc quyềnhoặc truy cập trái phép Những lỗ hổng loại này thường xuấthiện trong các dịch vụ trên hệ thống Người dùng nội bộ làngười dùng được phép truy cập vào hệ thống với những quyềnhạn nhất định Một dạng khác của lỗ hổng loại B xảy ra đối vớicác phần mềm viết bằng ngôn ngữ C và C++ Những chươngtrình viết bằng các ngôn ngữ này thường sử dụng một vùngđệm – là một vùng nhớ dùng để lưu trữ các dữ liệu trước khi xửlý, và chương trình không kiểm soát chặt chẽ các giá trị đầuvào Kẻ tấn công lợi dụng lỗi này để nhập vào các ký tự đặc biệtnhằm làm tràn bộ đệm, từ đó thực hiện các lệnh hay đoạn mãđặc biệt trên hệ thống.

Lỗ hổng loại A: Lỗ hổng loại A có mức độ rất nguy hiểm;

đe dọa đến tính toàn vẹn và bảo mật của hệ thống Các lỗ hổng này cho phép người sử dụng ở ngoài có thể truy nhập vào hệ thống bất hợp pháp Lỗ hổng rất nguy hiểm, có thể làm phá hủy toàn bộ hệ thống Lỗ hổng này xuất hiện ở các hệ thống quản trị yếu kém hoặc không kiểmsoát được cấu hình mạng …

1.5 Các dạng lỗ hổng phần mềm phổ biến

1.5.1 Tràn bộ đệm

Các tiến trình có thể được đưa vào bộ nhớ theo một cáchnào đó mà hệ điều hành lựa chọn, nhưng hầu hết toàn bộ cáchệ thống hiện nay tuân theo một số qui ước chung Thôngthường, 1 tiến trình được tổ chức thành các vùng chính sau đây:

- Mã chương trình: Phần này chứa các chỉ thị thực thi chươngtrình có thể được biên dịch và thực hiện bởi bộ xử lý Mãchương trình bao gồm các mã biên dịch cho việc thực thichương trình và các mã bổ sung nằm trong các thư việnchia sẻ của chương trình Các thư viện chia sẻ thườngkhông nằm cùng mã chương trình chính.

Trang 21

- Dữ liệu chương trình: Phần này được sử dụng để lưu cácbiến của chương trình không bao gồm các thành phần củahàm cục bộ Nó bao gồm cả các biến toàn cục và các biếntĩnh Vùng dữ liệu này cũng thường chứa một vùng nhớđộng, được gọi là “program heap”, để chứa các biến cấpphát động.

- Ngăn xếp chương trình: Được sử dụng như một bộ lưu trữđộng cho các hàm đang thực thi, và nó giữ cho thứ tự gọihàm được thực hiện đúng mong muốn

Vùng đệm là một khu vực bộ nhớ được sử dụng cho việc lưutrữ tạm thời dữ liệu Bộ đệm có thể được xây dựng với số lượngvà kích thước bất kỳ, bao gồm cả các khối cấp phát bộ nhớkhông có kiểu không xác định Bộ đệm được sử dụng như làvùng lưu trữ các giá trị đầu vào của người dùng và lắp ráp cácthông điệp nhận được từ một hệ thống từ xa

Tràn bộ đệm là loại lỗi thông thường, dễ tránh, nhưng lạiphổ biến và nguy hiểm nhất Năm 2009, tổ chức SANS đưa rabáo cáo về 25 lỗi lập trình nguy hiểm nhất trong đó vẫn có lỗitràn bộ đệm.

Tràn bộ đệm là lỗi xảy ra khi dữ liệu xử lý thường là dữ liệuđầu vào dài quá giới hạn của vùng nhớ chứa nó Nếu phía sauvùng nhớ này chứa những dữ liệu quan trọng tới quá trình thựcthi của chương trình thì dữ liệu dư có thể sẽ làm hỏng các dữliệu quan trọng này Tùy thuộc vào cách xử lý của chương trìnhđối với các dữ liệu quan trọng mà việc khai thác lỗi có thể thựchiện đến mức là điều khiển chương trình thực hiện tác vụ mongmuốn Lỗ hổng loại này thường xảy ra trên ngôn ngữ C và C++.

Trang 22

Hình 2.1 Tràn bộ đệm

Trong hình 2.1 mô tả vị trí và quá trình tràn bộ đệm Dữ liệunhập vào tăng dần từ hình 2.1 (A), hình 2.1 (B) đến hình 2.1 (C)và ghi đè lên một phần dữ liệu quan trọng Qua đó, ta có thểnhận thấy ba điểm thiết yếu của việc tận dụng lỗi tràn bộ đệm: Dữ liệu quan trọng phải nằm phía sau dữ liệu bị tràn Như hình

2.1, nếu dữ liệu quan trọng nằm bên trái thì dù dữ liệu nhập vàocó nhiều đến đâu thì cũng không ảnh hưởng đến dữ liệu quantrọng.

 Phần dữ liệu tràn phải tràn tới được dữ liệu quan trọng Đôi khita có thể làm tràn bộ đệm với một số lượng ít dữ liệu, chưa đủdài để có thể làm thay đổi giá trị của dữ liệu quan trọng nằmcách xa đó.

 Cuối cùng, dữ liệu quan trọng bị thay đổi vẫn phải còn ý nghĩavới chương trình Trong nhiều trường hợp, tuy ta có thể thay đổidữ liệu quan trọng, nhưng trong quá trình đó ta cũng thay đổi

Trang 23

các dữ liệu khác và khiến cho chương trình bỏ qua việc sử dụngdữ liệu quan trọng Xem xét ví dụ dưới đây:

Ví dụ 2.1 Mã chương trình bị lỗi tràn bộ đệmFunc (char *ch)

char buffer[100];strcpy(buffer,ch);}

Ta thấy rằng biến buffer chỉ được cấp phát 100 ký tự Tuynhiên, biến ch thì lại không giới hạn số ký tự Do đó, nếu biến chnhập vào có số ký tự lớn hơn số lượng ký tự mà biến buffer có

thể chứa là 100 thì sẽ xảy ra lỗi tràn bộ đệm Khi đó ứng dụngsẽ báo lỗi và không thể trả lời các yêu cầu từ người dùng.

1.5.1.1 Tràn bộ đệm trên Stack

Trong khoa học máy tính, một ngăn xếp (còn gọi là bộ xếp chồng,tiếng Anh: stack) là một cấu trúc dữ liệu trừu tượng hoạt động theonguyên lý "Vào sau ra trước" (Last In First Out-LIFO) Phần tử nào đượcthêm vào sau cùng sẽ là phần tử được lấy ra đầu tiên.

Stack là một phần của bộ nhớ Khi chương trình được nạp vào bộnhớ thì phân đoạn stack nằm ngay sau phân đoạn heap Stack được cấpphát bởi hệ điều hành cho mỗi thread khi thread được tạo Khi thread kếtthúc, stack sẽ được xóa bỏ Kích thước của stack được định nghĩa khiđược tạo và không thể thay đổi Kết hợp với LIFO không đòi hỏi cơ chếquản lý phức tạp nên hoạt động trên stack khá nhanh Tuy nhiên, nó bịgiới hạn trong kích cỡ.

Mọi phần tử trong Stack phải cùng kiểu dữ liệu và có thể là bất kỳkiểu dữ liệu nào Một Stack gồm có phần đáy (bottom) và phần đỉnh (top).Phần tử nằm ở đỉnh Stack được gọi là Top Item Mọi thao tác thêm, xóaphần tử đều diễn ra ở đỉnh Stack.

Trang 24

Hình 2.2 Stack

Stack đơn giản chỉ là một danh sách Do đó, nó có hầu hết các thaotác như trên danh sách như thêm, xóa, tuy nhiên cách cài đặt sẽ khác đimột chút Các thao tác cơ bản nhất của Stack là:

Push : Thêm một phần tử vào Stack

Hình 2.3 Push

Pop : Lấy một phần tử ra khỏi Stack

Hình 2.4 Pop

Trang 25

Stack lưu biến cục bộ, lời gọi hàm và những thông tin khác mà không cầnlưu trữ trong thời gian lớn Mỗi lần gọi hàm, các tham số của hàm được pushvào stack, và các giá trị được lưu vào các thanh ghi (EIP, EBP) Khi hàm kếtthúc, giá trị đã lưu của EIP được lấy ra từ stack và đặt trở lại EIP, từ đó ứngdụng có thể trở lại hoạt động bình thường.

Mỗi tiến trình có một ngăn xếp thực thi hay còn gọi là “ngăn

xếp chương trình”, “ngăn xếp lời gọi” hoặc đơn giản chỉ là”ngăn xếp” Ngăn xếp thực thi cung cấp nền tảng cần thiết chocác hàm được sử dụng trong mọi ngôn ngữ lập trình có cấu trúc.Các hàm có thể được gọi theo một thứ tự tùy ý, và chúng có thểcó tính đệ qui hoặc đệ qui lẫn nhau Ngăn xếp thực thi cung cấpchức năng này với các bản ghi thao tác, mỗi bản ghi là mộtchuỗi các lời gọi từ hàm tới hàm và do đó chúng có thể được lầntheo khi hàm trả về Một bản ghi thao tác cũng có thể bao gồmdữ liệu cần thiết được cấp phát tại mỗi thời điểm một hàm đượcgọi, chẳng hạn như các biến cục bộ, trạng thái lưu trữ, và cáctham số của hàm.

Do mỗi ngăn xếp thực thi là một phần cơ sở của các chươngtrình, chúng được thực thi với sự trợ giúp của CPU thay vì mộtphần mềm quản lí Các bộ xử lý thường có các thanh ghi đặcbiệt trỏ tới đỉnh của ngăn xếp, và có thể được thay đổi bởi cácthao tác mã máy push() hoặc pop() Trên CPU Intel x86, thanhghi này được gọi là thanh ghi ESP (là viết tắt của “extendedstack pointer”)

Trên các hệ thống CPU mới nhất, các ngăn xếp được đánhđịa chỉ giảm dần Điều này có nghĩa là từ một địa chỉ mức caotrên bộ nhớ ảo và giảm dần xuống các địa chỉ thấp hơn Mộtthao tác push trừ một giá trị địa chỉ từ con trỏ ngăn xếp và dođó con trỏ ngăn xếp sẽ trỏ về địa chỉ thấp hơn của bộ nhớ.Tương tự như vậy, thao tác pop sẽ cộng thêm một giá trị địa chỉvào con trỏ ngăn xếp, và chuyển nó đến địa chỉ cao hơn trongbộ nhớ.

Trang 26

Mỗi lần hàm được gọi, chương trình tạo một Ngăn xếp mới,cấu trúc này này đơn giản là một khối bộ nhớ riêng liền nhau vàliền với vị trí bộ nhớ hàm sử dụng để lưu trữ các biến địaphương và các thông tin trạng thái nội tại Khối bộ nhớ này đượcgiành riêng cho hàm cho tới khi nó trả lại, tại thời điểm đó, nóđược giải phóng khỏi ngăn xếp Để hiểu quá trình này qua ví dụdưới đây:

Ví dụ 2.2 Mã chương trình minh họa các hàmint function_B(int a, int b)

int x,y;x=a*a;y=b*b;

return (x+y);}

int function_A(int p,int q){

int c;

c=p*q*function_B(p,q);return c;

Khi function_A()thực thi, một ngăn xếp được cấp phát và

được đặt trên đỉnh của ngăn xếp cũ, như trong hình 2.4

Hình 2.4 Sơđồvị trí

cáchàm trong Ngăn xếp

Địa chỉ thấpdần

Trang 27

Sơ đồ này được giản lược từ ngăn xếp của chương trình, tuyvậy vẫn có thể thấy được cấu trúc bố trí cơ bản trong ngăn xếpkhi hàm main() gọi đến hàm function_A().

Hình 2.5 Trạng thái của ngăn xếp sau khi hàm function_A() gọihàm function_B()

Khi function_B() kết thúc, nó trở về function_A() Ngăn xếpcủa function_B() được lấy ra khỏi đỉnh của ngăn xếp, và ngănxếp lại trở về trạng thái như hình 5.1 Điều này đơn giản cónghĩa là giá trị của ESP trở về giá trị vốn có trước khifunction_B() được gọi.

Sơ đồ ngăn xếp trong hình 2.4 và 2.5 được biểu diễn đơn

giản hóa Trên thực tế, hàm main() không phải là hàm đầu tiêngọi ngăn xếp Thường các hàm được gọi trước hàm main là cáchàm khởi tạo môi trường thực thi của tiến trình Chẳng hạn, cáchệ thống glibc Linux thường bắt đầu bởi hàm _start(), hàm gọi_libc_start_main(), hàm trong đó gọi hàm main().

Mỗi hàm có nhiệm vụ quản lí ngăn xếp của chính nó, ngănxếp này có kích thước dựa trên số lượng và kích thước của biếncục bộ Các biến cục bộ cần được truy nhập trực tiếp khi hàmyêu cầu, do vậy là không hiệu quả nếu sử dụng các thao táclệnh pop và push Hơn nữa, rất nhiều chương trình sử dụng cácthanh ghi khác, được gọi là các con trỏ cấu trúc hay con trỏ cơsở Trên các CPU Intel x86, thanh ghi này được gọi là EBP (viết0xBFFFFC00

Trang 28

tắt của “extended base pointer”) Thanh ghi này trỏ tới vị tríđầu tiên ngăn xếp của hàm Mỗi biến trong ngăn xếp này có thểđược truy cập bằng cách tham chiếu đến một vị trí bộ nhớ đãđược cố định cách con trỏ cơ sở một khoảng cố định Việc sửdụng các con trỏ cơ sở là tùy biến, và đôi khi có thể bỏ qua việcsử dụng các con trỏ này.

Một thành phần quan trọng nữa đó là thông tin trạng tháinội tại được ghi lại trong mỗi ngăn xếp Các thông tin trạng tháiđược lưu trữ trên ngăn xếp khác nhau tùy theo kiến trúc của bộxử lí, nhưng thường nó bao gồm con trỏ trạng thái của hàmtrước và một địa chỉ trả về Giá trị địa chỉ trả về này được lưu lạiđể khi hàm đang thực thi trả về, CPU có thể biết được vị trí cácthao tác tiếp theo cần thực hiện Chắc chắn rằng, con trỏ trạngthái cũng phải được khôi phục lại để các biến cục bộ truy cậpđảm bảo tính ăn khớp sau khi một hàm gọi một hàm con khácđược cấp phát trong chính ngăn xếp của nó

Lỗi tràn Ngăn xếp:

Lỗi tràn ngăn xếp xuất hiện khi bộ đệm lưu trữ dữ liệu trong bộ nhớ khôngkiểm soát việc ghi giá trị trên nó, dẫn đến tràn ngăn xếp và việc tràn Ngăn xếpnày dẫn đến việc ghi đè địa chỉ trả về của hàm

Trên thực tế các biến địa phương thường được cấp phát gầnnhau, Hơn nữa, nếu một chương trình có một lỗ hổng cho phépcác dữ liệu có thể được ghi thêm vào sau các ngăn xếp cục bộ,các dữ liệu sẽ viết đè lên các biến ở lân cận Các biến lân cậnnày có thể bao gồm các biến địa phương khác, thông tin trạngthái chương trình, và ngay cả các tham số hàm Phụ thuộc vàoviệc có bao nhiêu byte được ghi, kẻ tấn công có thể phá hỏngcác giá trị lưu trong các biến và thông tin trạng thái trong ngănxếp trước đó.

Để bắt đầu, xem xét một trường hợp đơn giản của việc ghiđè 1 biến địa phương Sự nguy hiểm của việc ghi đè lên 1 biến

Trang 29

địa phương là có thể thay đổi hoàn toàn giá trị của biến theocách mà ứng dụng không được xây dựng để thực hiện việc đó.Sự chuyển đổi trạng thái thường có thể gây ra các lỗi nguyhiểm

Dưới đây là sơ đồ ngăn xếp được cấp phát cho chương trìnhở ví dụ trên:

func-tion_BLưu EBP

Lưu EIP (trỏ đến hàm A)Function_B tham số 1(int a)

Function_B tham số 2(int b) Ngăn xếp dành chofunction_A

int c Lưu EBP

Lưu EIP (trỏ đến hàm main)Function_A tham số 1(int p)

Function_A tham số 2(int q) Ngăn xếp cho hàmmain

int retLưu EBP

Lưu EIP (trỏ đến in_libc_start_main)int argc

char argv**

char argp** 0xBFFFFE00

_libc_start_main() stuff

Trang 30

Ngăn xếp cơ sở

Hình 2.6 Bố trí ngăn xếp bộ nhớ

Ta xét một chương trình bị lỗi tràn bộ đệm được minh họanhư dưới đây để thấy rõ hơn thay đổi ngăn xếp trước và sau khingăn xếp bị làm tràn:

Ví dụ 2.3 Mã hàm xác thực người dùng

int authenticate(char*username , char* password){

int authenticated;char buffer[1024];

authenticated= verify_password(username, password};if(authenticated==0)

{

sprintf(buffer, “password is incorrect for user %s\n”, name);

log(“*%s”, buffer); }

return authenticated;}

Giả sử rằng biến authenticated được cấp phát tại đỉnh củangăn xếp, vị trí có địa chỉ cao hơn trong bộ nhớ so với biến vùngđệm Ngăn xếp lúc này có cấu trúc như hình 2.7 dưới đây

(Dữ liệu không xác định)

authenticated: 0x00000000Lưu EBP: 0xBFFFCF00

Lưu EIP : 0x00123456Username: 0x080B4444Password: 0x080B8888Gọi hàm

12345

Trang 31

Hình 2.7 Ngăn xếp cho hàm authenticate(), trước khi bị khaithác lỗi tràn bộ nhớ

Xem xét đoạn mã trên có thể thấy rằng hàm cate() gây ra lỗi tràn bộ nhớ Hàm sprintf() không giới hạn sốlượng dữ liệu ghi ra buffer Vì vậy nếu chuỗi username nằmtrong khoảng 1024 byte, dữ liệu được ghi vào đến tận cuối củabiến buffer và vào biến authenticated, (vì authenticated() ở vịtrí đỉnh của ngăn xếp) Hình 2.8 biểu diễn khi xảy ra lỗi tràn bộnhớ

Authenticated: 000\n(0x0000000A)

Lưu EBP: 0xBFFFCF00Lưu EIP : 0x00123456Username: 0x080B4444Password: 0x080B8888Gọi hàm

Hình 2.8 Ngăn xếp cho hàm authenticate(), sau khi bị khai tháclỗi tràn bộ nhớ

Biến authenticated là một biến trạng thái đơn giản, chỉ rarằng người dùng có hoặc không đăng nhập thành công vào hệthống Giá trị 0 chỉ ra rằng việc xác thực thất bại và một giá trịkhác 0 chỉ ra việc xác thực thành công Bằng việc làm tràn biếnbuffer, kẻ tấn công có thể ghi đè thông tin lên biến authenti-cated, do đó có thể làm cho nó có giá trị khác 0 Và chương

AAAAAAAAAAAAAAA…….AAAAAAA12345

Trang 32

trình thực hiện không chính xác và sẽ coi kẻ tấn công đã đượcxác thực thành công.

Việc ghi đè lên vùng lân cận các biến cục bộ là một kỹ thuậtcó hiệu quả, nhưng nó thường không khả dụng Kỹ thuật nàyphụ thuộc vào biến nào có khả năng bị ghi đè, cách thức trìnhbiên dịch sắp xếp các biến trong bộ nhớ, và cách thức chươngtrình xử lý khi xảy ra tràn bộ nhớ Một kỹ thuật phổ biến hơn lànhắm tới các thông tin trạng thái được lưu trữ trong mọi ngănxếp đó là frame pointer được cất giữ và các địa chỉ trả về Vớihai biến này, địa chỉ trả về là hiệu quả nhất cho kẻ tấn công.Nếu một vùng bộ nhớ bị tràn ghi đè lên giá trị địa chỉ trả về,ứng dụng có thể được định hướng trỏ tới các điểm tùy ý, đằngsau địa chỉ trả về của các hàm đang thực thi Quá trình nàyđược biểu diễn trong hình 2.9.

AAAA BufferAAAA

authenticated: AAAA(0x41414141)

Lưu EBP: AAAA(0x41414141)Lưu EIP : 0x0BADC0DE

Username: 0x080B000APassword: 0x080B8888

Hình 2.9 Ghi đè lên địa chỉ trảvề

Dữ liệu đưavào có chứamã thực thi

Trang 33

Về bản chất, kẻ tấn công chọn một địa chỉ trong chươngtrình nơi chứa các đoạn mã đang thực thi và ghi đè địa chỉ mớilên địa chỉ trả về Địa chỉ ghi lên phụ thuộc chủ ý của kẻ tấncông, nhưng thường hướng việc thực thi tới hai dạng sau đây:

- Việc thực thi có thể được chuyển hướng đến vùng mã củachương trình đang chạy hoặc tới một vài đoạn mã trongthư viện chia sẻ có chứa những thành phần hữu dụng nhưhàm system() trong hệ thống UNIX libc nơi có thể chạy cácđoạn lệnh trong shell.

- Việc thực thi có thể chuyển hướng tới một vùng nhớ chứacác dữ liệu mà kẻ tấn công kiểm soát, chẳng hạn như mộtbiến toàn cục, vị trí ngăn xếp, hoặc một vùng nhớ tĩnh.Trong trường hợp này, kẻ tấn công điền thêm vào các vị trítrả về được nhắm tới với một đoạn mã nhỏ độc lập để làmmột việc gì đó theo mục đích, chẳng hạn như kết nối với kẻtấn công và sinh ra một shell trên các soket kết nối Cácđoạn mã thực hiện điều trên thường được gọi là các shell-code.

1.5.1.2 Tràn bộ đệm trên Heap

Heap được sử dụng cho việc cấp phát bộ nhớ động Trong ngôn ngữ lậptrình C thì việc cấp phát và giải phóng được thực hiện qua hai hàm malloc() vàfree() Khi chương trình được nạp trong bộ nhớ thì phân đoạn heap sẽ nằm trướcphân đoạn ngăn xếp

Bởi vì Heap được sử dụng để lưu trữ dữ liệu, không được sử dụng để lưucác giá trị địa chỉ trả về của hàm như là Ngăn xếp 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ênNgăn xếp

Tuy nhiên vẫn có thể khai thác thành công lỗi tràn bộ đệm trên heap bằnghai cách sau:

Sửa dữ liệu: Kẻ tấn công có thể khai thác lỗ hổng bằng cách ghi đè dữ liệu

quan trọng Điều này có thể là hỏng chương trình hoặc làm thay đổi giá trị có thểđược khai thác sau này (như ghi đè lên một ID người dùng để gán thêm quyềntruy cập).

Trang 34

Sửa đối tượng: Trong nhiều ngôn ngữ lập trình như C++ và Objective-C,

các đối tượng được đặt trên Heap bao gồm các bảng con trỏ hàm và dữ liệu Dođó kẻ tấn công có khả năng thay thế dữ liệu khác hay thậm chí thay thể cả cácinstance methods trong lớp đối tượng

Quản lý Heap

Tuy việc cài đặt các bộ nhớ heap khác nhau tương đốinhiều, nhưng một vài tính chất chung được cài đặt trong hầuhết các thuật toán Về cơ bản, khi một lời gọi tới hàm malloc()hoặc một đoạn chương trình cấp phát tương tự được tạo ra, mộtsố ô nhớ sẽ được lấy từ bộ nhớ heap và được trả về cho ngườidùng.

Khi phần bộ nhớ này được giải phóng bởi hàm free(), hệthống phải đánh dấu nó như bộ nhớ trống để nó có thể được sửdụng lại sau này Thông thường, cần lưu lại trạng thái của cácvùng bộ nhớ trả về cho các lời gọi hàm để bộ nhớ được cấp phátvà được thu hồi một cách hiệu quả Trong nhiều trường hợp cácthông tin trạng thái này được lưu trữ trực tiếp Đặc biệt, hầu hếtcác cài đặt trả lại khối bộ nhớ cho người dùng thông qua cácthông tin trong khối bộ nhớ đưa trong header Loại thông tintrong khối header thường bao gồm:

- Kích thước khối hiện tại- Kích thước khối tiếp theo

- Tình trạng sử dụng của khối (đang được sử dụng hoặc không)

- Một vài cờ có chứa các thông tin

Các khối trống thường được móc nối với nhau sử dụng mộtcấu trúc dữ liệu cơ bản, chẳng hạn như danh sách liên kết đơnhoặc danh sách liên kết kép Hầu hết các cài đặt của heap địnhnghĩa kích thước tối thiểu của một khối đủ lớn để chứa các contrỏ tới các phần tử trước và sau nó trong danh sách và sử dụngkhông gian này để chứa các con trỏ khi khối không được sửdụng

Trang 35

Chú ý là hệ điều hành BSD quản lý bộ nhớ heap khác so vớihầu hết các hệ điều hành khác Chúng lưu hầu hết các thông tinkhối bên ngoài danh sách.

Khai thác các lỗi tràn bộ nhớ heap

Khả năng để chỉnh sửa thông tin header và danh sách contrỏ một cách tùy ý (như khi 1 lỗi tràn bộ nhớ xảy ra) cho phépkẻ tấn công có khả năng phá vỡ sự quản lý của các khối heap.Sự phá vỡ này có thể được sử dụng để chỉnh sửa các header củakhối để lấy quyền thực thi tùy ý bằng cách khai thác các thuậttoán duy trì heap, đặc biệt danh sách duy trì của các khối trống.

1 Các khối được đánh dấu là khối trống được giả sử là chứadanh sách con trỏ tới các khối tiếp theo và các khối trướcnó trong danh sách các đoạn dữ liệu.

2 Khi một khối được giải phóng, nó thường được nối lại với các khối liền nó nếu chúng cũng là các khối trống.

3 Do hai khối được ghép với nhau thành 1 khối, thuật toán heap loại bỏ các đoạn tiếp theo mà ban đầu thuộc danh sách trống, điều chỉnh kích thước của các đoạn trống mới với kích thước lớn hơn, và sau đó cộng đoạn mới vào danh sách trống.

4 Một lỗi tràn trên heap được sử dụng để đánh dấu đoạn tiếptheo là khối trống do đó nó sẽ bị loại khỏi danh sách trống sau này.

5 Lỗi tràn bộ nhớ thiết lập danh sách các con trỏ trong các đoạn bị lỗi và tạo ra vị trí hữu dụng cho kẻ tấn công.

6 Khi thao tác tháo bỏ được thực thi, một giá trị cố định kích thước, cung cấp bởi kẻ tấn công được ghi vào vị trí bộ nhớ được kẻ tấn công định trước.

Để hiểu tại sao việc gỡ bỏ một đoạn dữ liệu có thể đến sựghi đè dữ liệu, xét đoạn mã sau đây cho việc loại bỏ mộtphần tử từ danh sách liên kết kép:

Ví dụ 2.4 Hàm gỡ bỏ phần tử khỏi danh sách liên kết

Trang 36

int unlink(ListElement *element){

ListElement *next =element = element->next;ListElement *prev =element = element->prev;next->prev =prev;

prev->next=next;return 0;

Đoạn mã này loại bỏ một ListElement bằng cách cập nhậtcác con trỏ trong các phần tử liền kề của danh sách để loại bỏcác tham chiếu tới phần tử hiện tại, element Nếu có thể xácđịnh cụ thể giá trị phần tử element->next và element->prev, thìsẽ thấy rằng đoạn mã này cập nhật vị trí bộ nhớ tùy ý với giá trịcó thể điều khiển được Quá trình này được biểu diễn như tronghình 2.10 dưới đây tương ứng với trạng thái trước và sau khi gỡbỏ

Hình 2.10 Danh sách liên kết trước và sau khi thực hiện thay đổi

Việc có thể ghi đè một vị trí bộ nhớ với một giá trị có thểđiều khiển được thường là cách mà kẻ tấn công cần để giành sựkiểm soát một tiến trình Rất nhiều giá trị hữu ích có thể bị ghi

Trang 37

đè cho phép kẻ tấn công thỏa hiệp được ứng dụng Một số mụctiêu phổ biến thường được kẻ tấn công sử dụng đó là:

- Bảng offset toàn cục (GOT)/ bảng liên kết tiến trình (PLT) –UNIX ELF nhị phân sử dụng một bộ nạp cấu trúc để phângiải các hàm được gọi từ thư viện vào địa chỉ Các cấu trúcnày cho phép các thư viện chia sẻ có thể được cấp phát ởbất cứ đâu trong bộ nhớ để ứng dụng không cần sử dụngcác địa chỉ tĩnh cho các hàm API tại thời điểm biên dịch.Bằng cách tấn công vào các cấu trúc này, kẻ tấn công cóthể điều hướng việc thực thi sang một vị trí tùy ý khi mộthàm API được gọi (chẳng hạn, free()).

- Exit Handlers–Là một bảng của các con trỏ hàm được gọi khi một tiến trình kết thúc tron hệ điều hành UNIX Bằng cách ghi đè một trong các giá trị này, nó có thể đưa sự thực thi tới vị trí bất kỳ khi tiến trình gọi hàm exi() hoặc trảvề từ hàm main()

- Lock Pointers – Windows sử dụng một tập các con trỏ hàm trong khối tiến trình để ngăn việc thay đổi không đồng bộ của thông tin tiến trình bởi sự tương tranh giữa các luồng Các con trỏ khóa này có thể bị ghi đè và được sử dụng bởi một loại điều kiện ngoại lệ.

- Đoạn xử lý ngoại lệ: Windows PEB chứa một địa chỉ chođoạn chương trình lọc các ngoại lệ không được quản lý.Đoạn chương trình này được gọi khi một ngoại lệ khôngđược xử lý thành công bởi các bộ xử lý ngoại lệ khác Mộtkỹ thuật phổ biến là sử dụng đoạn mã danh sách lưu trữ đểghi đè lên các ngoại lệ không được quản lý khi cập nhậtmột phần của danh sách (chẳng hạn phần tử liền trước) vàsau đó tạo nên sự truy cập bộ nhớ không hợp lệ khi cậpnhật các phần khác của danh sách (phần tử tiếp theo) Kỹthuật này đảm bảo rằng bộ lọc các ngoại lệ không đượcquản lý được gọi tức thời, giả sử các bộ xử lý ngoại lệ kháckhông bắt được kết quả ngoại lệ.

- Con trỏ hàm – Các ứng dụng sử dụng con trỏ hàm chonhiều mục đích khác nhau, chẳng hạn các lời gọi hàm từthư viện liên kết động, cho các hàm ảo trong C++, hoặc

Trang 38

cho các hàm thực thi mức thấp trong cấu trúc mờ Việc ghiđè lên các con trỏ hàm trong ứng dụng cụ thể có thể cungcấp sự khai thác đáng chú ý để tấn công vào ứng dụng1.5.1.3 Lỗi Double Free

Lỗi này xảy ra khi hàm free() được gọi nhiều hơn 1 lần với cùng một địachỉ bộ nhớ (địa chỉ bộ nhớ này được chuyền vào hàm free() như một đối số).Điều này có thể dẫn tới lỗi tràn bộ đệm do cấu trúc quản lý dữ liệu bộ nhớ sẽ bịhỏng Và vì thế chương trình có thể bị hỏng, hoặc trong một số trường hợp, haihàm malloc() được sử dụng sau đó sẽ trả về cùng một giá trị Điều này dẫn tớiviệc kẻ tấn công sẽ kiểm soát dữ liệu được ghi trong gấp đôi phần bộ nhớ đượccấp phát

1.5.1.4 Lỗi tràn số khi sử dụng số nguyên trong ngôn ngữ lập

trình C

Trong ngôn ngữ C, các biến số nguyên có các giá trị cực đạivà cực tiểu được xác định theo sự biểu diễn của chúng trong bộnhớ Vì vậy có thể tìm hiểu những vấn đề có thể xảy ra khi thửnghiệm với các giới hạn về giá trị của số nguyên Các phép toánhọc đơn giản đối với biến như cộng, trừ, và nhân có thể ra kếtquả mà các biến không thể chứa được.

Ví dụ 2.5 Cộng số nguyênUnsigned int a;

Ở đây biến a có thể chứa giá trị 0xE0000020, tuy nhiên khicộng giá trị 0x20000020 vào 0xE00000E0 kết quả là0x10000040 thì a không thể chứa được gía trị đó vì giá trị đócao hơn giá trị tối đa của biến a có thể chứa, trường hợp này gọilà tràn số học (numeric overflow condition).

Ví dụ 2.6 Trừ số nguyên dươngUnsigned int a;

a=0;a=a-1;

Trang 39

Chương trình thực hiện khởi tạo a có giá trị là 0 sau đó lấya trừ đi 1 được kết quả là -1, nhưng a ở đây khai báo là sốnguyên dương và không thể chứa được gía trị -1, và đây là cũnglà dạng tràn số.

Giới hạn đối với số nguyên dương:

Đối với một số nguyên dương sử dụng X bit để lưu trữ, phéptoán học trên số nguyên đó được thực hiện module 2^X, phéptoán trên số nguyên dương 8 bit là thực hiện modulo 2^8 hay256.

Xét lại ví dụ sau:

Ví dụ 2.7 Cộng số nguyên dươngUnsigned int a;

Phép cộng trên thực hiện modulo 2^32 hay modulo4,294,967,296 (0x100000000)

Kết quả của phép cộng là 0x40 là modulo 0x100000000.Phép cộng trên có thể biểu diễn cụ thể qua phép tính ở dạng nhịphân như sau:

1110 0000 0000 0000 0000 0000 0010 0000 + 0010 0000 0000 0000 0000 0000 0010 0000 =1 0000 0000 0000 0000 0000 0000 0100 0000

Kết quả thực tế nhận được là 0x40 có biểu diễn ở dạng nhịphân:

0000 0000 0000 0000 0000 0000 0100 0000Ví dụ 2.8 Tràn số nguyên

U_char *make_table(unsigned int width, unsigned intheight, u_char *init_row)

{

unsigned int n;int i;z

u_char *buf;

Trang 40

buf= (char *)malloc(n);if (!buf)

return (NULL);for (i=0; i<height;i++)

memcpy(&buf[i*width], init_row, width);return buf;

Mục đích của hàm make_table() đó là lấy chiều rộng, chiềucao, khởi tạo giá trị hàng, và tạo một bảng trong bộ nhớ nơi màmỗi hàng được khởi tạo có cùng nội dung như init_row Nếungười dùng đưa vào giá trị cho chiều rộng là 1000000 và chiềucao 3000 thì hàm malloc() sẽ được gọi và yêu cầu cấp là3,000,000,000 bytes Việc xác định và cấp được vùng nhớ choyêu cầu trên khó có thể thực hiện được và có thể gây ra lỗi trànbộ đệm Việc tràn bộ đệm có thể bị kẻ tấn công khai thác vàchiếm được quyền điều khiển ứng dụng theo các mức độ tùythuộc vào cấp độ môi trường chạy tiến trình của ứng dụng

Xem xét một lỗ hổng cụ thể đã được tìm thấy trong phầnmềm OpenSSH server 3.1 sau:

Ví dụ 2.9 Đoạn mã gây ra lỗ hổng thuộc chương trìnhOpenSSH

U_int nresp;

nresp=packet_get_int();if (nrespn>0) {

response=xmalloc(nresp*sizeof(char*));for (i=0;i<nresp;i++)

response[i]=packet_get_string(NULL);}

Biến nguyên dương nresp là biến nhận giá trị người dùnggửi tới Server với số response từ Server mà client muốn nhận.Nó được sử dụng để xác định cho mảng response[] và điền vàodữ liệu mạng Trong qúa trình xác định mảng response[] bằngviệc gọi hàm xmalloc(), nresp được nhân với sizeof(char *) vớigiá trị thường là 4 bytes Nếu người dùng đưa vào một giá trị

Ngày đăng: 02/10/2021, 19:50

TỪ KHÓA LIÊN QUAN

w