Fuzzing in Binary exploitation: American Fuzzing Lop
Chào những bông hoa nhỏ ham hack ! Hôm nay chúng ta sẽ nói về một kỹ thuật/công cụ khá quan trọng trong việc kiểm thử xâm nhập, tìm kiếm các lỗ hổng bảo mật đó là fuzzing. Fuzzing, còn được gọi là kiểm thử fuzz, là một cách tiếp cận mạnh mẽ được sử dụng trong an ninh mạng để phát hiện lỗ hổng an ninh trong phần mềm, hệ điều hành hoặc mạng bằng cách nhập vào một lượng lớn dữ liệu ngẫu nhiên, được gọi là fuzz, vào hệ thống với mục đích làm cho nó bị lỗi, xảy ra crash, … Blog này sẽ đi sâu vào kỹ thuật fuzzing và fuzzer rất phổ biến đó là AFL. FBI warning: Bài viết có thể gây ngủ gật, quý độc giả vui lòng không đọc khi buồn ngủFuzzing Là Gì?
Fuzzing là một kỹ thuật kiểm thử phần mềm tự động, mục tiêu chính của nó là phát hiện ra những điểm yếu trong một hệ thống, ứng dụng, hoặc mạng bằng cách tạo ra và nhập vào dữ liệu không hợp lệ hoặc ngẫu nhiên. Nếu hệ thống bị lỗi hoặc bị sập, đó có một lỗ hổng an ninh tiềm ẩn có thể bị hacker khai thác. Fuzzing giúp xác định những lỗ hổng này để có thể sửa chữa trước khi bị kẻ tấn công xác định và khai thác chúng.Tại sao lại cần Fuzzing?
Khi xây dựng một chương trình, developers sẽ tự viết các test case để kiểm tra code của mình. Do đó, các test case này sẽ hơi chủ quan vì họ đã biết trước các luồng xử lí.
Vì vậy, developers lại cần đến testers. Testers sẽ đưa ra các test case khách quan nhất, nhưng vẫn chưa đảm bảo được tất cả các nhánh khi chạy chương trình. Trong khi đó, fuzzing sẽ giúp phát hiện ra các lỗi mà khó có thể tìm thấy thông qua việc viết các test case bình thường của tester hay developer. Fuzzing cũng giúp tiết kiệm thời gian và tăng hiệu quả bởi việc kiểm thử được diễn ra tự động, chúng ta có thể tìm ra lỗi ngay cả khi đang ngủ!Fuzzer
Fuzzer là các công cụ (tool) thực hiện việc fuzzing một các tự động. Fuzzer có thể được chia thành 3 loại:- Mutational: fuzzer sẽ ngẫu nhiên hóa dữ liệu đầu vào bằng cách biến đổi hoặc sử dụng các dữ liệu khác nhau
- Grammar: người sử dụng sẽ quyết định các quy luật biến đổi dữ liệu đầu vào
- Feedback-based: đây còn được gọi là smart fuzzer bởi fuzzer sẽ giám sát ảnh hưởng của dữ liệu đầu vào tới chương trình, sau đó đưa ra các quyết định tới việc thay đổi dữ liệu đầu vào sao cho việc fuzzing được tối ưu nhất có thể
American Fuzzing Lop (AFL)
AFL là một fuzzer mã nguồn mở, được phát triển bởi Michal Zalewski vào năm 2013. Thời điểm đó, AFL được coi là một fuzzer rất “hiện đại” và cũng đã phát hiện ra rất nhiều lỗ hổng trong các phần mềm mã nguồn mở như X.Org Server, PHP, OpenSSL, bash, firefox, Qt, SQLite,… Khi thực hiện fuzzing, có 2 tiêu chí rất quan trọng nhằm đánh giá hiệu quả của quá trình fuzzing, đó là độ bao phủ mã nguồn (code coverage) và độ bao phủ các nhánh của chương trình (path coverage). Code coverage được dùng để chỉ lượng mã nguồn được thực thi đối với 1 test case cụ thể. Còn path coverage được dùng để đánh giá về các luồng được thực thi đối với 1 test case cụ thể. Để hiểu rõ về 2 tiêu chí trên, ta hãy cùng xét ví dụ sau:
if (condition 1):
// statements
if (condition 2):
// statements
Trong đoạn mã giả trên, giả sử có 3 test case lần lượt thoả mãn condition 1, condition 2 và cả condition 1 lẫn condition 2. Dẫn tới chương trình có thể có tới 3 nhánh. Giả sử chỉ có test case 1 và test case 2 được kiểm tra, dẫn đến độ bao phủ mã nguồn sẽ là 100%, nhưng 2 test case đó mới kiểm tra được 2 nhánh, do đó độ bao phủ nhánh sẽ là 2/3.
AFL được đánh giá là khá thông minh bởi khi bắt đầu fuzzing, AFL quan sát trạng thái của chương trình khi các test case được xử lí, đồng thời cũng lưu lại các nhánh mã nguồn được kiểm tra. Dựa vào các nhánh đó, AFL sẽ đưa ra các quyết định tới dữ liệu đầu vào nhằm tìm kiếm những nhánh mới, qua đó tăng độ bao phủ nhánh.
Tác giả của AFL cũng đã có một thử nghiệm, khi fuzzing một chương trình mà chương trình ấy chỉ chấp nhận dữ liệu đầu vào là một file ảnh JPEG. Tác giả đã dùng test case ban đầu là 1 file text với nội dung “hello”. Chi tiết về bài viết tại đây.
Workflow sử dụng AFL có thể được mô tả ngắn gọn như sau:
- Biên dịch mã nguồn sang file thực thi bằng trình biên dịch của AFL để AFL có thể dễ dàng quan sát được trạng thái của chương trình.
- Xây dựng (các) test case
- Chạy chương trình đã được biên dịch bằng (các) test case đó
- Phân tích kết quả thu được
Thuật toán của AFL
Có 2 bước chính trong việc xây dựng, biến đổi các dữ liệu đầu vào của AFL:- Mutation: AFL sẽ thực hiện các biến đổi trên cùng 1 test case với các vị trí khác nhau. các biến đổi này bao gồm:
- Đảo bit: thực hiện từ 1 cho tới 32 bits
- Tăng/giảm các số nguyên dạng 8, 16, 32 bits dưới dạng little/big endian
- Sử dụng các số đặc biệt: số 0, số nguyên có dấu/ không dấu lớn nhất/ nhỏ nhất với độ dài khác nhau (cả little/big endian)
- Sử dụng các byte đặc biệt được cung cấp bởi người dùng hoặc tự phát hiện
- Havoc:
- Sử dụng các biến đổi như mutation
- Ghi đè các byte bằng byte bất kì
- Xoá, lặp, gán giá trị cho mỗi byte trong các block nhiều byte
Trải nghiệm sử dụng AFL
Ta cùng thử sử dụng AFL với một chương trình mẫu FuzzGoat. Trước tiên, ta cần phải cài đặt AFL. Việc cài đặt diễn ra khá đơn giản. Cũng như nhiều project khác trên github, ta chỉ cần clone repo về và chạy câu lệnh "make" và sau đó là "make install" (chạy với quyền root).



Tài liệu tham khảo
https://en.wikipedia.org/wiki/American_Fuzzy_Lop_(software) https://github.com/google/AFL https://lcamtuf.coredump.cx/afl/technical_details.txt https://dl.acm.org/doi/10.1145/3551349.3556946 581 lượt xem