Kỹ thuật khai thác lỗ hổng là một quá trình phức tạp, bao gồm nhiều bước liên kết nhau. Để thực hiện kỹ thuật này, hacker phải trước tiên tìm ra các lỗ hổng (như buffer overflow) trong hệ thống, sau đó, họ sử dụng các lỗ hổng đó để tạo các công cụ khai thác và gửi chúng đến hệ thống đích.
Các bước cơ bản trong khai thác lỗ hổng
- Xác định lỗ hổng: Hacker sử dụng các kỹ thuật trong các module trước để xác định các lỗ hổng, bao gồm footprinting và reconnaissance, dò quét mạng, enumeration và phân tích lỗ hổng. Sau khi xác định hệ điều hành của mục tiêu, hacker sử dụng các trang web như Exploit Database (https://www.exploit-db.com) và Packet Storm (https://packetstormsecurity.com) để tìm lỗ hổng nhằm khai thác chúng.
- Xác định các rủi ro liên quan đến lỗ hổng: Sau khi xác định một lỗ hổng, hacker đánh giá các rủi ro liên quan đến lỗ hổng đó, tức là việc khai thác lỗ hổng này có thể gây ảnh hưởng đến các biện pháp bảo mật trên mục tiêu hay không.
- Xác định khả năng khai thác lỗ hổng: Nếu rủi ro là thấp, hacker có thể xác định khả năng khai thác lỗ hổng để truy cập vào mục tiêu.
- Phát triển công cụ khai thác: Lựa chọn phương thức khai thác: Khai thác online thông qua reverse shell hay khai thác local để leo thang đặc quyền hoặc thực thi ứng dụng lên mục tiêu.
- Tạo, gửi payload độc hại: Sử dụng các công cụ như Metasploit, inject shellcode độc hại vào payload, khi được thực thi, sẽ thiết lập một remote shell tới mục tiêu.
- Truy cập từ xa: Bây giờ, hacker có thể kiểm soát hệ thống.
Exploit Sites
Những trang exploit sites này cung cấp thông tin chi tiết về các lỗ hổng và công cụ khai thác mới nhất.
Exploit Database
Exploit Database chứa thông tin về các lỗ hổng mới nhất có thể tồn tại trên nhiều hệ điều hành, thiết bị, ứng dụng,… Hacker có thể tìm và tải xuống các công cụ khai thác và có thể sử dụng các công cụ khai thác như Metasploit để tấn công.
VulDB
VulDB cung cấp thông tin về các lỗ hổng và công cụ khai thác mới nhất, được đánh giá dựa trên xác suất khai thác cao nhất.
Vulners
Vulners.com là một cơ sở dữ liệu chứa các mô tả về một lượng lớn các lỗ hổng phần mềm trong định dạng có thể đọc được. Các liên kết chéo giữa các thông báo và các cơ sở dữ liệu cập nhật liên tục giúp người dùng cập nhật các mối đe dọa bảo mật mới nhất.
MITRE CVE
MITRE CVE mình đã viết rõ trong phần [CEH v12] Module 5 – Phần 1: Lỗ hổng bảo mật là gì?. Các bạn đọc thêm nhé.
Buffer Overflow
Bộ đệm là khu vực của các vị trí bộ nhớ liền kề được cấp phát cho một chương trình hoặc ứng dụng để xử lý dữ liệu runtime. Tràn bộ đệm là một lỗ hổng phổ biến trong đó các ứng dụng hoặc chương trình chấp nhận nhiều dữ liệu hơn bộ đệm được cấp phát. Lỗ hổng này làm dữ liệu ứng dụng vượt quá bộ đệm, ghi dữ liệu vào bộ đệm và ghi đè lên các vị trí bộ nhớ lân cận. Hơn nữa, lỗ hổng này có thể dẫn đến hệ thống không ổn định, gây sự cố hệ thống, lỗi truy cập bộ nhớ,… và nhiều lỗi nghiêm trọng khác. Hacker khai thác lỗ hổng tràn bộ đệm để inject mã độc vào nhằm gây hại, sửa đổi dữ liệu, leo thang quyền truy cập,…
Một số nguyên nhân chính gây ra lỗi tràn bộ đệm:
- Không kiểm tra đầy đủ hoặc thậm chí không kiểm tra kích thước, ranh giới của bộ đệm.
- Sử dụng các phiên bản cũ của các ngôn ngữ lập trình và chúng dính nhiều lỗ hổng.
- Sử dụng các function không an toàn, không tuân thủ các quy tắc lập trình tốt.
- Thực thi code trong phân đoạn ngăn xếp (stack segment), sử dụng con trỏ để truy cập bộ nhớ heap dẫn đến tràn bộ đệm.
- Không cấp phát bộ nhớ đúng cách và không validate giá trị đầu vào.
Stack-Based Buffer Overflow
Trong hầu hết các ứng dụng, ngăn xếp (stack) được sử dụng để cấp phát bộ nhớ tĩnh. Các khối bộ nhớ liền kề được cấp phát cho ngăn xếp để lưu trữ các biến tạm thời được tạo ra bởi một hàm. Ngăn xếp lưu trữ các biến theo thứ tự “Last-in First-out” (LIFO). Khi một hàm được gọi, bộ nhớ cần thiết để lưu trữ các biến được khai báo trên ngăn xếp, và khi hàm trả về thì lúc này bộ nhớ được giải phóng tự động.
Có hai thao tác trên ngăn xếp, đó là PUSH, lưu trữ dữ liệu vào ngăn xếp, và POP, loại bỏ dữ liệu khỏi ngăn xếp. Bộ nhớ của ngăn xếp bao gồm năm loại thanh ghi:
- EBP (Extended Base Pointer): còn được gọi là StackBase, lưu trữ địa chỉ của phần tử dữ liệu đầu tiên được lưu trữ trên ngăn xếp
- ESP (Extended Stack Pointer): lưu trữ địa chỉ của phần tử dữ liệu tiếp theo sẽ được lưu trữ trên ngăn xếp
- EIP (Extended Instruction Pointer): lưu trữ địa chỉ của lệnh tiếp theo sẽ được thực thi
- ESI (Extended Source Index): lưu giá trị source index
- EDI (Extended Destination Index): lưu trữ giá trị source index
Stack-Based Buffer Overflow xảy ra khi một ứng dụng ghi nhiều dữ liệu hơn vào bộ đệm so với những gì được cấp phát cho bộ đệm đó. Để hiểu về tràn bộ đệm dựa trên ngăn xếp, ta phải tập trung vào các thanh ghi EBP, EIP và ESP. EIP là thanh ghi read-only quan trọng nhất, nó lưu trữ địa chỉ của lệnh cần được thực thi tiếp theo.
Khi một hàm bắt đầu thực thi, stack frame lưu trữ thông tin của nó được đẩy vào ngăn xếp và lưu trữ trên thanh ghi ESP. Khi hàm trả về, stack frame được đẩy ra khỏi ngăn xếp và thực thi tiếp tục từ địa chỉ trả về được lưu trữ trên thanh ghi EIP. Do đó, nếu một ứng dụng bị tấn công tràn bộ đệm, hacker có thể kiểm soát thanh ghi EIP để thay thế địa chỉ trả về của hàm bằng mã độc, cho phép chúng truy cập shell vào mục tiêu.
Ta có 1 đoạn code đơn giản như hình bên dưới:
Đoạn code trên chứa lỗ hổng tràn bộ đệm (buffer overflow) do độ dài chuỗi đầu vào không được kiểm soát trong hàm buffer().
Trong hàm buffer()
, một mảng kích thước 12 được khai báo cho biến buff, nhưng đầu vào của hàm là một chuỗi không được giới hạn kích thước. Nếu đầu vào có độ dài vượt quá 12 ký tự, hàm strcpy()
sẽ ghi đè lên vùng nhớ nằm sau mảng buff, gây ra tràn bộ đệm và có thể gây ảnh hưởng đến giá trị của các biến khác trong chương trình.
Để khắc phục lỗ hổng này, ta nên kiểm tra độ dài chuỗi đầu vào trước khi sao chép vào mảng buff. Có thể sử dụng hàm strncpy()
để sao chép tối đa n ký tự của chuỗi vào mảng, trong đó n là kích thước của mảng buff trừ 1 để để lại chỗ cho ký tự kết thúc chuỗi ‘\0’.
Heap-Based Buffer Overflow
Heap được sử dụng để cấp phát bộ nhớ động. Bộ nhớ heap được cấp phát động trong thời gian thực thi (runtime) và lưu trữ dữ liệu của chương trình. Việc truy cập bộ nhớ heap chậm hơn so với truy cập bộ nhớ ngăn xếp. Việc cấp phát và giải phóng bộ nhớ heap không được thực hiện tự động mà người lập trình phải viết code cho việc cấp phát [malloc()]
bộ nhớ heap và sau khi thực thi hoàn tất, cần phải giải phóng bộ nhớ bằng các hàm như free()
.
Heap-Based Buffer Overflow xảy ra khi một khối bộ nhớ được cấp phát cho heap và dữ liệu được ghi mà không có kiểm tra ranh giới (boundry). Lỗ hổng này dẫn đến việc ghi đè các liên kết đến cấp phát bộ nhớ động (con trỏ đối tượng), heap header, heap data, virtual function tables, …
Tương tự ta cũng có ví dụ sau:
Trong hàm main()
, hai con trỏ in và out được cấp phát vùng nhớ động bằng hàm malloc()
. Sau đó, hàm strcpy()
được sử dụng để sao chép chuỗi “Sample Output” vào vùng nhớ được trỏ bởi con trỏ out và chuỗi được truyền vào dòng lệnh khi chạy chương trình được sao chép vào vùng nhớ được trỏ bởi con trỏ in.
Tuy nhiên, không có kiểm tra độ dài chuỗi đầu vào trước khi sao chép vào vùng nhớ được cấp phát bởi hàm malloc()
. Nếu độ dài chuỗi đầu vào vượt quá kích thước của vùng nhớ được cấp phát, hàm strcpy()
sẽ ghi đè lên vùng nhớ nằm sau vùng nhớ được cấp phát, gây ra tràn bộ đệm
Return-Oriented Programming (ROP) Attack
Return-oriented programming (ROP) là một kỹ thuật tấn công thực thi mã độc trong môi trường được bảo vệ bởi các cơ chế bảo mật như code signing và executable space protection. Kỹ thuật này cho phép hacker chiếm quyền điều khiển của chương trình bằng cách truy cập vào ngăn xếp và sử dụng các thư viện có sẵn được gọi là “gadgets” để thực thi các lệnh tùy ý.
Gadgets là một tập hợp các lệnh kết thúc bằng lệnh RET x86. Hacker sẽ lựa chọn một chuỗi các gadgets khác nhau để tạo thành một chương trình mới và thực thi nó với mục đích độc hại. Kỹ thuật ROP cũng cho phép thực hiện các phân nhánh và tìm kiếm các điều kiện trên dữ liệu của chương trình như so sánh bằng, bé hơn hoặc lớn hơn.
Tấn công ROP rất hiệu quả vì sử dụng các thư viện code hợp lệ có sẵn trong chương trình, và không bị phát hiện bởi các cơ chế bảo mật khác.
Exploit Chaining
Exploit chaining, còn được gọi là vulnerability chaining, là tấn công mạng kết hợp nhiều lỗ hổng hoặc cách khai thác khác nhau để xâm nhập và tấn công mục tiêu từ cấp độ gốc. Đây là một cơ chế tấn công phức tạp, trong đó hacker thường bắt đầu bằng các hoạt động thu thập thông tin để tìm kiếm các lỗ hổng chưa được vá hoặc các điểm yếu trong mục tiêu.
Sau khi xác định các lỗ hổng, hacker trước tiên sẽ truy cập vào mạng mục tiêu bằng cách sử dụng bất kỳ công nghệ và công cụ khai thác nào mà họ tin rằng có khả năng thành công cao nhất. Sau đó, họ đi sâu vào mạng bằng cách sử dụng danh sách các lỗ hổng đã xác định. Khi khai thác thành công các lỗ hổng, hacker đạt được quyền truy cập cấp kernel/root/system để tiến hành các cuộc tấn công tiếp theo mà không bị phát hiện bởi các giải pháp bảo mật.
Mặc dù loại tấn công này tốn thời gian và nỗ lực hơn trong các giai đoạn ban đầu, tuy nhiên việc kết hợp các lỗ hổng khai thác với nhau làm cho khó khắc phục hơn, khi chiều dài và độ sâu của chuỗi khai thác tăng lên.
Comments 1