Chương này trình bày các vấn đề lý thuyết sau:
· Trình bày về các vấn đề liên quan đến kiểm thử mở như : Khái niệm, lịch sử ra đời, các giai đoạn của kiểm thử mờ v.v…
· Các lỗ hổng của ứng dụng
· Phân loại kiểm thử mờ
Fuzzing hay kiểm thử mờ (fuzz testing) là một kỹ thuật kiểm thử hộp đen (black box), tự động hoặc bán tự động liên quan đến việc cung cấp đầu vào không hợp lệ, bất ngờ hoặc ngẫu nhiên vào một chương trình máy tính. Sau đó, chương trình sẽ được giám sát các trường hợp ngoại lệ như treo máy, lỗi mã không được thực thi, tài nguyên bộ nhớ thất thoát nhằm để xác định các hành vi bất thường, phát hiện các lỗ hổng bảo mật tiềm ẩn của chương trình. Fuzzing thường được sử dụng để kiểm tra ninh tra chính cho việc phát hiện các lỗ hổng bảo mật nghiêm trọng ở các phần mềm lớn hoặc hệ thống máy tính [16].
Hình 1.1. Mô hình kiểm thử mờ phát hiện các lỗ hổng bảo mật cho phần mềm
Fuzzing về cơ bản cũng giống như kỹ thuật kiểm thử phần mềm, nhưng nó được sử dụng để phát hiện ra một loạt các vấn đề, trong đó có: lỗi mã hóa, lỗ hổng bảo mật giống như Cross Site Scripting (XSS), tràn bộ đệm (Buffer Overflow), từ chối dịch vụ (DoS), chèn câu truy vấn (SQL Injection) như mô tả ở 1.1 v.v…
Fuzzing có nguồn gốc từ năm 1988 bởi giáo sư Barton Miller tại Đại học Wisconsin [6]. Ông cùng đồng nghiệp của mình, thực hiện khám phá lỗ hổng qua các công cụ dòng lệnh và chương trình GUI chạy trên hệ thống UNIX, WindowSystem,Macbằng cách “tấn công” vào hệ thống với dữ liệu đầu vào không hợp lệ, bất ngờ, và ngẫu nhiên hoặc vào hệ thống ở các cấp độ khác nhau, nhằm nỗ lực để khám phá các hành vi bất ngờ hoặc và thất bại của hệ thống; bao gồm treo hệ thống, không khẳng định mã, và rò rỉ bộ nhớ v.v…
Có rất nhiều sự kiện quan trọng đánh dấu lịch sử của fuzzing, có thể mô tả qua sơ đồ hình 1.2 [21].
Hình 1.2 Lịch sử của Fuzzing
Tùy thuộc vào các nhân tố khác nhau, việc lựa chọn cách tiếp cận Fuzzing có thể khác nhau. Tuy nhiên, về cơ bản Fuzzing có các giai đoạn như sau :
Tùy theo mục đích, tác động, nguy cơ và người dùng mà ở giai đoạn này các mục tiêu khác nhau có thể được lựa chọn. Hiện nay, các mục tiêu được đánh giá có nguy cơ rủi ro cao:
-Các ứng dụng như nhận dữ liệu qua mạng - có khả năng bị tổn hại từ xa, tạo điều kiện thực thi mã từ xa, để tạo ra các chương trình độc hại (virus, worm ,,,).
- Các ứng dụng chạy ở mức ưu đãi cao hơn so với một người sử dụng - những điều đó có tiềm năng để cho phép kẻ tấn công thực thi mã ở mức độ đặc quyền cao hơn của chính họ, được gọi là leo thang đặc quyền.
- Các ứng dụng xử lý thông tin có giá trị - một kẻ tấn công có thể phá vỡ các điều khiển và vi phạm sự toàn vẹn, tin cậy hoặc sẵn sàng có của dữ liệu có giá trị.
- Các ứng dụng xử lý thông tin cá nhân – một kẻ tấn công có thể phá vỡ các điều khiển và vi phạm sự toàn vẹn, tin cậy hoặc sẵn sang có của dữ liệu cá nhân có giá trị(Windows Explorer, Window Registry, Media files, Office Documents, Configuration files)
Hình 1.3. Các giai đoạn của Fuzzing
Đầu vào ứng dụng có thể có nhiều hình thức, hoặc từ xa (mạng traffic), hoặc cục bộ (các file, các khóa registry, các biến môi trường, đối số dòng lệnh, tên đối tượng …). Một số fuzzer đã tiến hóa để phục vụ cho nhiều loại đầu vào. Các lớp đầu vào ứng với fuzzers phổ biến như sau [21]:
1. Command line arguments
2. Environment variables (ShareFuzz)
3. Web applications (WebFuzz)
4. File formats (FileFuzz)
5. Network protocols (SPIKE)
6. Memory
7. COM objects (COMRaider)
8. Inter Process Communication
Giai đoạn này được xem là quan trọng nhất với fuzzing. Ngày nay, nó được nghiên cứu và phát triển đáng kể bởi các nhà khoa học. Mục đích của một fuzzer là để kiểm tra sự tồn tại của lỗ hổng bảo mật có thể truy cập thông qua đầu vào trong các ứng dụng phần mềm. Do đó, fuzzer phải tạo ra dữ liệu thử nghiệm mà ở các mức độ, mà sau đó nó có thể được thông qua vào mục tiêu ứng dụng đầu vào. Dữ liệu được tạo ra có thể dạng file nhị phân (Binary files), file văn bản (Text files) được tạo ra lặp đi lặp lại vào thời điểm bắt đầu của mỗi lần test.
Toàn bộ phạm vi của dữ liệu thử nghiệm tạo ra cho fuzzing ứng với một mục tiêu nhất định (gọi là test data) bao gồm nhiều trường cá nhân riêng biệt (gọi là test case). Các cách tiếp cận chung để kiểm tra mờ là để lặp đi lặp lại cung cấp các trường hợp thử nghiệm để các mục tiêu và theo dõi các phản ứng. Trong suốt quá trình kiểm thử, một test case được tìm thấy để gây ra một sự thất bại ứng dụng, sự kết hợp của một trường hợp thử nghiệm cụ thể và thông tin về bản chất của sự thất bại đó gây ra, đại diện cho một báo cáo lỗi. Báo cáo lỗi có thể được coi như là đầu ra của fuzzing và có thể được thông qua, tạo điều kiện thuận lợi cho các nhà phát triển trong quá trình giải quyết thất bại.
Các dữ liệu kiểm thử được tạo ra là một tập hợp các quy tắc hoặc các luật, thông thường là được xác định bởi người sử dụng hoặc do chuyên gia đề xuất. Điều này được thể hiện trong hình vẽ 1.4.
Hình 1.4: Mô hình cơ bản của fuzzer bao gồm các luật định nghĩa bởi user
cho phát sinh dữ liệu
Có vô số các phương pháp tiếp cận khác nhau để tạo ra dữ liệu kiểm thử, nhưng tất cả chúng đều thuộc ở một trong 2 loại: kiểm thử zero knowledge (bao gồm random, brute force và ‘blind’ mutation fuzzing) hoặc analysis-based (gọi termed protocol hoặc protocol implementation testing).
Ở giai đoạn này, thông thường các fuzzers thực hiện phần lớn các chức năng của các cách tiếp cận nêu trên nhưng bằng cách giải pháp đặt biệt để tự động hóa quá trình xử lý kiểm thử.
Giai đoạn này không đơn thuần, các fuzzers phát hiện các lỗ hổng qua fuzzing, mà phải định nghĩa các lỗi được phát hiện. Điều này có ý nghĩa hết sức quan trọng trong việc phân tích và báo cáo lỗi. Để báo cáo lỗi đòi hỏi sự hiểu biết rõ về hoạt động xử lý, và có thể được tích hợp vào sự kiện phân loại lỗi tự động như phương pháp phát hiện lỗi do Microsoft đề xuất thông qua bảng xếp hạng fuzzing.
Dưới đây là bảng do Howard và Lipner chỉ ra phương pháp của Microsoft sử dụng để phát hiện lỗi xếp hạng qua fuzzing [10]. Phân tích đầu ra fuzzer được thực hiện ở mức assembly.
Bảng 1.1: Các lỗi được khám phá qua sử dụng kiểm thử mờ [10].
Bảng 1.1 cho thấy phương pháp của Microsoft để xếp hạng các lỗi phát hiện qua fuzzing. Rõ ràng là từ bảng này là phần lớn các lỗi được phát hiện thông qua fuzzing được đọc hoặc viết vi phạm truy cập.
Bảng 1.2 cho thấy lỗi bảo mật cho các ứng dụng Web do OWASP công bố năm 2013.
Sau khi một hoặc một số lỗi phần mềm đã được xác định, các fuzzers gửi một danh sách các khiếm khuyết này để một đội ngũ phát triển, để họ có thể sửa chữa chúng. Tất nhiên, việc này đòi hỏi một cuộc kiểm tra cho dù khiếm khuyết có hay không có khả năng khai thác nhằm tìm hiểu các tác động gì sẽ ảnh hưởng đến người dùng.
Lỗ hổng của chương phần mềm được tạo ra trong giai đoạn khác nhau: đặc tả, sản xuất, và phát triển của chu trình SDLC (hình 1.5). Chính vì điều đó nên sản phẩm cuối cùng không tránh khỏi các vấn đề về an toàn. Fuzzing thường có thể phát hiện các
Hình 1.5 Các giai đoạn trong SDLC mà lỗ hổng được giới thiệu
khuyết tật được bỏ qua khi phần mềm được viết và sửa lỗi. Thực tế cho thấy hơn 70% số lỗ hổng bảo mật hiện đại do lập trình sai sót, chỉ có ít hơn 10% là vấn đề cấu hình và khoảng 20% là vấn đề thiết kế. Trên 80% triển khai phần mềm truyền thông ngày nay rất dễ bị lỗ hổng bảo mật. Ví dụ, 25 trong số 30 sản phẩm triển khai Bluetooth bị “sụp” khi họ đã được thử nghiệm với các công cụ Bluetooth fuzzing [3].
Ngoài ra, kết quả từ các dự án nghiên cứu PROTOS chỉ ra rằng hơn 80% của tất cả các sản phẩm thử nghiệm không thành công khi kiểm thử mờ với các tính năng WAP, VoIP, LDAP, và SNMP [3].
Fuzzing làm việc tốt nhất đối với các vấn đề mà gây ra lỗi của một chương trình như là: tràn bộ nhớ (buffer overflow), Cross-Site scripting(XSS), Denial of Service (DoS), lỗi chuỗi định dạng (Format String Errors), chèn câu truy vấn (SQL Injection)v.v… [9]. Vì thế với fuzzing người ta có thể kiểm tra sự an toàn của bất kỳ quá trình, các dịch vụ, thiết bị, hệ thống, hoặc mạng máy tính v.v…
Đối với kiểm thử bảo mật, một kỹ thuật phổ biến là kiểm thử dựa trên tập fuzz vector cụ thể nào đó, bao gồm các kiểm thử để kích hoạt các loại của lỗ hổng cụ thể:
+Cross Site Scripting (XSS)
+Buffer Overflows và Format String Errors
+Integer Overflows
+SQL Injection
+Active/Passive SQL Injection
+LDAP Injection
+XML/XPATH Injection v.v…
Fuzzing cũng có thể được sử dụng bởi tin tặc tìm cách có được thông tin về các hệ thống và đáp ứng hệ thống để sử dụng trong việc xây dựng các cuộc tấn công. Vì vậy điều quan trọng là xác định, đánh giá rủi ro và nguy cơ sử dụng được sử dụng trong việc tấn công các ứng dụng của bạn.
Fuzz testingmột mình không thể cung cấp một bức tranh hoàn chỉnh của bảo mật tổng thể, chất lượng, hiệu quả của một chương trình trong một tình huống hoặc ứng dụng cụ thể. Các chương trình kiểm thử mờ (Fuzzers) có hiệu quả nhất khi được sử dụng kết hợp với mở rộng kiểm thử hộp đen, kiểm thử beta và các phương pháp gỡ lỗi đã được chứng minh khác [25].
Mục tiêu fuzzing đối với một ứng dụng, bao gồm các file được định dạng, giao thức mạng, tham số dòng lệnh, biến môi trường, ứng dụng Web và nhiều thứ khác. File định dạng và các giao thứcmạng là mục tiêu phổ biến nhất củafuzzing, nhưng bất kỳ loại chương trình đầu vào có thể được mờ hóa (fuzzed).
Việc phân loại fuzzing có thể tùy thuộc vào attack vectors, mục tiêu fuzzing, phương pháp fuzzing, v v… Tuy nhiên, có hai phương pháp phân loại phổ biến ở đây :
-Kiểm thử mờ dựa trên đột biến(Mutation Based Fuzzing): Hay còn gọi là kiểm thử mờ câm (Dumb Fuzzing), đó là phương pháp biến đổi mẫu dữ liệu hiện có để tạo dữ liệu kiểm thử. Đối với cách tiếp cận này thì :
+ Người thực hiện ít hoặc không có kiến thức về cấu trúc của các yếu tố đầu vào được giả định.
+Tính dị thường được thêm vào đầu vào hợp lệ hiện có có thể hoàn toàn ngẫu nhiên hoặc theo một số chẩn đoán về mặt kinh nghiệm.
+ Phụ thuộc vào các yếu tố đầu vào được sửa đổi.
+Yêu cầu ít hoặc việc thiết lập thời gian đơn giản hoặc không cần thiết v.v…
Hình 1.6.Kỹ thuật Bit Flipping
Công cụ để thực hiện cho phương pháp này : Taof, GPF, ProxyFuzz, Peach Fuzzer v.v…Ví dụ Bit Flipping là một trong những kỹ thuật được sử dụng trong kiểm thử đột biến, trong đó các bit được xáo trộn theo thứ tự hoặc ngẫu nhiên và có thể thêm một số chuỗi mới vào cuối đầu vào đang tồn tại (Hình 1.6).
-Kiểm thử mờ dựa trên thế hệ (Generation Based Fuzzing) hay còn gọi là kiểm thử mờ thông minh (Smart Fuzzing): Xác định dữ liệu kiểm thử mới dựa trên mô hình đầu vào.
Đối với cách tiếp cận này thì :
+ Trường hợp thử nghiệm được tạo ra từ một số mô tả về các định dạng: RFC, các định dạng tài liệu v.v…
+ Tính dị thường được thêm vào mỗi điểm có thể có trong các đầu vào.
+ Hỗ trợ kiến thức về giao thức nên cho kết quả tốt hơn so với fuzzing ngẫu nhiên.
+ Có thể mất thời gian đáng kể để thiết lập.
Công cụ để thực hiện : SPIKE, Sulley, Mu-4000 v.v…
Bảng 1.3. Bảng so sánh Mutation Based với Generation Based
TheoOWASP(Open Web Application Security Project) là một tổ chức phi lợi nhuận phát triển các dự án liên quan tới bảo mật ứng dụng Web hàng đầu thế giới, đưa ra 2 cách phân loại khác về Fuzzing hỗ trợ cho kiểm thử mờ các ứng dụng Web (protocol fuzzing).
-Recursive Fuzzing: Là một tiến trình của fuzzing, nó được hiểu như là một phần của một request bằng cách duyệt qua tất cả các kết hợp có thể của một bộ chữ cái Alphabet.
Giả sử ta gởi một request là 1 chuỗi có dạng :
http://www.google.com/8302fa3b
Nếu chọn "8302fa3b" như một phần của request này là một tập các chuỗi của bảng chữ cái Alphabet hệ thập lục phân (tức là {0,1,2,3,4,5,6,7,8,9, a, b, c, d, đ , f}) thuộc loại fuzzing đệ quy. Điều này sẽ tạo ra tổng cộng 168 request có dạng như sau:
http://www.google.com/00000000
...
http://www.google.com/11000fff
...
http://www.google.com/ffffffff
- Replacive Fuzzing : Là quá trình fuzzing mà một phần của yêu cầu được thực hiện thông qua việc thay thế nó bằng một tập giá trị mờ. Giá trị này được hiểu như một fuzz vector. Xét trường hợp này:
http://www.example.com/8302fa3b
Để thực hiện kiểm thử để chống lại lỗ hổng Cross Site Scripting (XSS) bằng cách gửi đến các fuzz vector như sau :
http://www.example.com/>"><script>alert("XSS")</script>&
http://www.example.com/'';!--"<XSS>=&{()}
Trên đây là một dạng thức của fuzzing replacive. Trong dạng này, tổng số request phụ thuộc vào số lượng các fuzz vector xác định.
Các chương trình và framework được dùng để tạo ra kỹ thuật fuzzing hoặc thực hiện fuzzing, thường được gọi fuzzer.
Fuzzers có thể được phân loại dựa trên hai tiêu chí khác nhau:
1. Injectionvector hoặc attack vector
2. Kỹ thuật test case
Fuzzers có thể được chia dựa trên các lĩnh vực ứng dụng mà chúng sử dụng, nhưng về cơ bản theo hướng attack vector.
Đối với Fuzzers theo loại Injectionvector nó sẽ thực hiện kiểm thử hộp đen thông qua việc tiêm nhiễm một số “lối vào” như hình (hình 1.8). Các Fuzzers loại này dùng để kiểm thử phía client và một số khác để kiểm thử phía server. Đối với fuzzers kiểm thử phía client với giao thức HTTP hoặc TLS sẽ nhằm mục tiêu vào trình duyệt. Nhưng đối với các fuzzers kiểm thử phía Server sẽ thực hiện kiểm thử trên máy chủ Web Server. Một số fuzzers khác hỗ trợ kiểm thử trên cả hai Server và Client, hoặc thậm chí cả hai (dùng để phân tích proxy hoặc phân tích lưu lượng ).
Hình 1.7: Attackvectors ở các mức độ khác nhau
Fuzzers cũng có thể được phân loại dựa trên testcase phức tạp. Các test case được tạo ra trong fuzzing với mục tiêu tạo ra các lớp khác nhau trong phần mềm, và nhờ đó có thể thâm nhập vào các lớp logic khác nhau trong ứng dụng (hình 1.8). Fuzzers mà thay đổi các giá trị khác nhau trong các giao thức sẽ kiểm tra được lỗ hổng như: tràn số nguyên và các vấn đề khác về số nguyên. Khi cấu trúc thông điệp được biến đổi dị thường (anomalized), các fuzzer sẽ tìm thấy sai sót trong phân tích cú pháp thông điệp (Chẳng hạn trong đặt tả XML và ASN.1).
Hình 1.8: Các loại bất thường và kết quả là chế độ thất bại khác nhau
Một ví dụ phương pháp phân loại dựa trên sự phức tạp của test case trong một fuzzer:
+Staticandrandomtemplate-basedfuzzer:Những fuzzers thường chỉ kiểm tra các giao thức đáp ứng yêu cầu đơn giản, hoặc các định dạng tập tin. Không có chức năng năng động có liên quan nào.
+Block-basedfuzzers:Những fuzzers sẽ thực hiện cấu trúc cơ bản cho một giao thức đáp ứng yêu cầu đơn giản và có thể chứa một số chức năng động thô sơ như tính toán về checksums và chiều dài các giá trị (lengthvalues).
+Dynamicgenerationorevolutionbasedfuzzers:Đó là những fuzzers mà không nhất thiết phải hiểu được giao thức hoặc định dạng tập tin đang được fuzzed, nhưng có thể tìm hiểu nó dựa trên một vòng phản hồi từ hệ thống mục tiêu.
+Model-basedorsimulation-basedfuzzers:Là những fuzzers thực hiện kiểm thử giao diện hoặc thông qua một mô hình hoặc một mô phỏng, hoặc cũng có thể được triển khai đầy đủ của một giao thức. Không chỉ có cấu trúc thông điệp được fuzzed, mà còn thông điệp bất thường trong chuỗi được tạo ra.
Hiệu quả của fuzzing phụ thuộc vào :
+ Độ bao phủ không gian đầu vào (input spacecoverage) : Không gian đầu vào của giao diện kiểm thử càng tốt thì hiệu quả đạt càng cao.
+ Chất lượng của dữ liệu kiểm thử (qualityoftestdata) : Các đầu vào độc hại tiêu biểu (representativemalicious) và dị hình (malformed) sẽ làm sẽ là tăng cường khả năng kiểm thử đối với các yếu tố hoặc cấu trúc trong định nghĩa giao diện.
1.4.2 Triển khai Fuzzer
Như phân tích ở trên, fuzzer là một chương trình tiêm dữ liệu tự động hoặc bán tự động vào một chương trình để phát hiện lỗi. Đối với phần dữ liệu phát sinh thì được thực hiện bằng các máy sinh dữ liệu (generators) và phần xác định sự tổn thương hoặc lổ hổng dựa vào các công cụ debug.
Các máy sinh dữ liệu đơn giản thường sử dụng kết hợp các vector fuzzing tĩnh (được biết trước các giá trị nguy hiểm), hoặc dữ liệu toàn hoàn ngẫu nhiên. Lợi thế quan trọng của kiểm thử ngẫu nhiên là thiết lập đơn giản, thời gian không đáng kể. Tuy nhiên, thử nghiệm ngẫu nhiên là rất khó có thể tiếp xúc với tất cả các hành vi có thể có của một chương trình. Một số kỹ thuật áp dụng cho máy sinh dữ liệu dựa trên giai đoạn phát sinh kiểm thử tự động đã được đề xuất để cải thiện những hạn chế nêu trên như: Kỹ thuật dựa trên ngữ pháp (Grammar-based techniques)[8] hoặc phân tích ngữ pháp kết hợp đột biến về cấu trúc(GrammarAnalysis and Structural Mutation) [18] gần đây đã được giới thiệu để tạo đầu vào phức tạp cho các hệ thống phần mềm.Tuy nhiên, những kỹ thuật này đòi hỏi một ngữ pháp được đưa ra để tạo đầu vào chương trình kiểm thử mà không phải lúc nào cũng khả thi. Fuzzers thế hệ mới sử dụng thuật toán di truyền để liên kết dữ liệu tiêm và quan sát tác động được đánh giá là hiệu quả hơn cả, nhưng các công cụ hỗ trợ chúng thường là chưa công khai.
Các loại tấn công của fuzzing hay kiểm thử mờ có thể bao gồm sự kết hợp của các cuộc tấn công vào các con số (signed, unsigned integers, float...), ký tự (urls, command-line inputs), siêu dữ liệu, các chuỗi nhị phân, định dạng file (.pdf, png, .wav, .mpg…), các giao thức mạng (http, SOAP, SNMP…), cũng có thể bao gồm bất kỳ giao diện I/O/ nào đó, các dòng lệnh tùy chọn, import/export, các form, nội dung hay yêu cầu (request) do người dùng tạo ra v.v…
Cách tiếp cận chung cho fuzzing là sinh tập dữ liệu giá trị nguy hiểm được biết đến (gọi là fuzz vectors) ứng từng loại đầu vào cụ thể hoặc các lỗ hổng hoặc với các định dạng file, mã nguồn, các giao thức hoặc tổ hợp lại với nhau. Từ đó, tiêm vào đầu vào không hợp lệ hoặc ngẫu nhiên để tiết lộ hành vi bất ngờ, xác định lỗi hoặc các lỗ hổng tiềm ẩn của ứng dụng hay hệ thống.
» Tin mới nhất:
» Các tin khác: