Tải thư viện an toàn để ngăn chặn các cuộc tấn công tải trước DLL

Hỗ trợ dành cho Windows Vista Gói Dịch vụ 1 (SP1) kết thúc vào ngày 12 tháng 7 năm 2011. Để tiếp tục nhận được bản cập nhật bảo mật cho Windows, hãy đảm bảo rằng bạn đang chạy Windows Vista với Gói Dịch vụ 2 (SP2). Để biết thêm thông tin, hãy tham khảo trang web Microsoft này: Hỗ trợ sẽ kết thúc đối với một số phiên bản Windows.

Khi một ứng dụng tự động tải một thư viện liên kết động (DLL) mà không xác định một đường dẫn đầy đủ tiêu chuẩn, Windows cố gắng xác định vị trí DLL bằng cách tìm kiếm một tập hợp các thư mục được xác định rõ. Nếu kẻ tấn công đạt được quyền kiểm soát của một trong các thư mục, họ có thể buộc các ứng dụng để tải một bản sao độc hại của DLL thay vì DLL mà nó đã mong đợi. Những cuộc tấn công được gọi là "DLL preloading tấn công" và là phổ biến cho tất cả các hệ điều hành hỗ trợ tự động tải thư viện DLL chia sẻ. Ảnh hưởng của các cuộc tấn công như vậy có thể là kẻ tấn công có thể thực hiện mã trong ngữ cảnh của người dùng đang chạy ứng dụng. Khi các ứng dụng đang được chạy như quản trị viên, điều này có thể dẫn đến một địa phương nâng đặc quyền. Chúng tôi biết về quan tâm mới trong các cuộc tấn công này. Để hạn chế ảnh hưởng của sự cố này đối với các khách hàng chung của chúng tôi, chúng tôi sẽ phát hành tài liệu này cho cộng đồng nhà phát triển để đảm bảo rằng họ biết về sự cố này và có các công cụ cần thiết để khắc phục sự cố trong các ứng dụng của họ.

Tóm tắt

Mô tả các cuộc tấn công tải trước DLL

Tấn công dựa trên LoadLibrary

Khi một ứng dụng tự động tải một DLL mà không xác định một đường dẫn đầy đủ tiêu chuẩn, Windows cố gắng để xác định vị trí này DLL bằng cách tuyến tính tìm kiếm thông qua một tập hợp cũng được xác định của các thư mục, được gọi là thứ tự tìm kiếm DLL. Nếu Windows xác định vị trí DLL trong Thứ tự Tìm kiếm DLL, Windows sẽ tải DLL đó. Tuy nhiên, nếu Windows không tìm thấy DLL trong bất kỳ thư mục trong lệnh tìm kiếm DLL, nó sẽ trả về một lỗi để hoạt động tải DLL. Sau đây là Thứ tự Tìm kiếm DLL cho các hàm LoadLibraryLoadLibraryEx , được dùng để tải DLL tự động:

  1. Thư mục mà ứng dụng đã tải từ đó
  2. Thư mục hệ thống
  3. Thư mục hệ thống 16 bit
  4. Thư mục Windows
  5. Thư mục làm việc hiện tại (CWD)
  6. Các thư mục được liệt kê trong biến môi trường PATH

                
Hãy cân nhắc các trường hợp sau:

  • Một ứng dụng tải một DLL mà không chỉ định một đường dẫn đầy đủ tiêu chuẩn mà nó hy vọng sẽ tìm thấy trong CWD của ứng dụng.
  • Ứng dụng được chuẩn bị đầy đủ để xử lý các trường hợp khi nó không tìm thấy DLL.
  • Kẻ tấn công biết thông tin này về các ứng dụng và điều khiển CWD.
  • Kẻ tấn công sao chép phiên bản đặc biệt của họ crafted của DLL trong CWD. Điều này giả định rằng kẻ tấn công có quyền làm điều này.
  • Windows sẽ tìm kiếm thông qua các thư mục trong Lệnh Tìm kiếm DLL và tìm DLL trong CWD của ứng dụng.

Trong trường hợp này, DLL đặc biệt crafted chạy trong ứng dụng và đạt được đặc quyền của người dùng hiện tại.

Đề xuất

Để ngăn chặn cuộc tấn công này, các ứng dụng có thể loại bỏ thư mục làm việc hiện tại (CWD) khỏi đường dẫn tìm kiếm DLL bằng cách gọi API SetDllDirectory bằng cách sử dụng chuỗi trống (""). Nếu một ứng dụng phụ thuộc vào việc tải một DLL từ thư mục hiện tại, xin vui lòng có được thư mục làm việc hiện tại và sử dụng đó để vượt qua trong một đường dẫn đầy đủ tiêu chuẩn của LoadLibrary.

Chúng tôi cũng nhận thức được rằng một số nhà phát triển sử dụng LoadLibrary để xác nhận xem một DLL cụ thể có mặt để xác định phiên bản Windows nào đang được người dùng chạy hay không. Bạn nên lưu ý rằng điều này có thể làm cho ứng dụng dễ bị tấn công. Nếu thư viện bị ảnh hưởng thực sự không tồn tại trên bản phát hành Windows mà ứng dụng được thực hiện trên, kẻ tấn công có thể giới thiệu một thư viện với cùng một tên vào CWD. Chúng tôi đặc biệt khuyên bạn không nên sử dụng kỹ thuật này. Thay vào đó, hãy sử dụng các kỹ thuật được đề xuất được mô tả trong bài viết MSDN, "Tải Phiên bản Hệ thống".

Một ứng dụng tải bổ trợ của bên thứ ba và không thể buộc bổ trợ sử dụng đường dẫn đủ điều kiện cho lệnh gọi LoadLibrary của nó nên gọi SetDllDirectory("") để loại bỏ CWD và sau đó gọi SetDllDirectory("plugin install location") để thêm thư mục cài đặt bổ trợ vào đường dẫn tìm kiếm DLL.

Các cuộc tấn công dựa trên SearchPath

Một cuộc tấn công tương tự tồn tại khi một ứng dụng sử dụng API SearchPath để định vị một DLL và tự động tải đường dẫn được trả về bởi SearchPath. Sau đây là thứ tự tìm kiếm mặc định cho API SearchPath:

  • Thư mục mà ứng dụng đã tải từ đó
  • Thư mục làm việc hiện tại (CWD)
  • Thư mục hệ thống
  • Thư mục hệ thống 16 bit
  • Thư mục Windows
  • Các thư mục được liệt kê trong biến môi trường PATH

Chúng tôi không khuyên bạn nên mẫu này vì nó không an toàn. Chúng tôi khuyên bạn không nên sử dụng hàm SearchPath như một phương pháp định vị tệp .dll nếu mục đích sử dụng đầu ra là một cuộc gọi đến hàm LoadLibrary. Điều này có thể dẫn đến việc định vị sai tệp .dll vì thứ tự tìm kiếm của hàm SearchPath khác với thứ tự tìm kiếm mà hàm LoadLibrary sử dụng. Nếu bạn phải định vị và tải tệp .dll, hãy sử dụng hàm LoadLibrary.

ShellExecute và CreateProcess

Các biến thể của những vấn đề này cũng có thể tồn tại khi nhà phát triển gọi các chức năng tương tự như ShellExecuteCreateProcess để tải thực thi bên ngoài. Chúng tôi khuyên các nhà phát triển nên cẩn thận khi họ tải nhị phân và chỉ định đường dẫn đầy đủ tiêu chuẩn. Điều này sẽ đặt ra ít phức tạp hơn khi bạn tải một nhị phân thay vì một thư viện.

Chúng tôi khuyên các nhà phát triển nên làm như sau:

  • Xác thực ứng dụng của họ cho các trường hợp tải thư viện không an toàn (ví dụ của mỗi được đưa ra sau trong bài viết này). Bao gồm những loại sau:

    • Việc sử dụng SearchPath để xác định vị trí của thư viện hoặc cấu phần.
    • Việc sử dụng LoadLibrary để xác định phiên bản của hệ điều hành.
  • Sử dụng đường dẫn đủ điều kiện cho tất cả các cuộc gọi đến LoadLibrary, CreateProcess và ShellExecute nơi bạn có thể thực hiện.

  • Thực hiện lệnh gọi đến SetDllDirectory với chuỗi trống ("") để loại bỏ thư mục đang hoạt động khỏi thứ tự tìm kiếm DLL mặc định, theo đó là bắt buộc. Hãy lưu ý rằng SetDllDirectory ảnh hưởng đến toàn bộ quy trình. Vì vậy, bạn nên làm điều này một thời gian sớm trong quá trình khởi tạo, không phải trước và sau khi gọi đến LoadLibrary. Vì SetDllDirectory ảnh hưởng đến toàn bộ quy trình, nhiều chuỗi hội thoại gọi SetDllDirectory với các giá trị khác nhau có thể gây ra hành vi không xác định. Ngoài ra, nếu quy trình được thiết kế để tải các DLL của bên thứ ba, việc kiểm tra sẽ cần thiết để xác định xem việc tạo cài đặt trên toàn bộ quy trình có gây ra sự không tương thích hay không. Sự cố đã biết là khi một ứng dụng phụ thuộc vào Visual Basic for Applications, một cài đặt trong toàn bộ quy trình có thể gây ra sự không tương thích.

  • Sử dụng hàm SetSearchPathMode để bật chế độ tìm kiếm quy trình an toàn cho quy trình. Thao tác này sẽ di chuyển thư mục làm việc hiện tại đến vị trí cuối cùng trong danh sách tìm kiếm SearchPath trong suốt thời gian của quy trình.

  • Tránh sử dụng SearchPath để kiểm tra sự tồn tại của DLL mà không xác định đường dẫn đầy đủ tiêu chuẩn, ngay cả khi chế độ tìm kiếm an toàn được bật, bởi vì điều này vẫn có thể dẫn đến các cuộc tấn công tải trước DLL.

Hướng dẫn xác định tải thư viện không an toàn

Trong mã nguồn, sau đây là các ví dụ về tải thư viện không an toàn:

  • Trong ví dụ mã sau đây, ứng dụng sẽ tìm kiếm "schannel.dll" bằng cách sử dụng đường dẫn tìm kiếm ít bảo mật nhất. Nếu kẻ tấn công có thể schannel.dll vào CWD, nó sẽ tải ngay cả trước khi ứng dụng tìm kiếm các thư mục Windows cho thư viện thích hợp.

    DWORD retval = SearchPath(NULL, "schannel", ".dll", err, result, NULL); 
    HMODULE handle = LoadLibrary(result);
    
  • Trong ví dụ mã sau đây, các ứng dụng cố gắng để tải thư viện từ các ứng dụng khác nhau và vị trí hệ điều hành được mô tả trong phần đầu của tài liệu này cho các LoadLibrary() gọi. Nếu có bất kỳ rủi ro nào mà tệp không hiện diện, ứng dụng có thể cố gắng tải tệp từ thư mục làm việc hiện tại. Trường hợp này ít nguy hiểm hơn một chút so với ví dụ trước. Tuy nhiên, nó vẫn khiến người dùng ứng dụng gặp rủi ro nếu môi trường không thể dự đoán hoàn toàn.

    HMODULE handle = LoadLibrary("schannel.dll");
    

                
                
Sau đây là các ví dụ về việc tải thư viện tốt hơn, an toàn hơn:

  • Trong ví dụ mã sau đây, thư viện được tải trực tiếp bằng cách sử dụng đường dẫn đầy đủ tiêu chuẩn. Không có nguy cơ kẻ tấn công giới thiệu mã độc hại trừ khi ông đã có quyền ghi vào thư mục mục tiêu của ứng dụng.

    HMODULE handle = LoadLibrary("c:\\windows\\system32\\schannel.dll");
    

    Lưu ý Để biết thông tin về cách xác định thư mục hệ thống, hãy xem các tài nguyên sau:

    GetSystemDirectory
    http://msdn.microsoft.com/en-us/library/ms724373%28VS.85%29.aspx SHGetKnownFolderPath
    http://msdn.microsoft.com/en-us/library/bb762188%28v=VS.85%29.aspx

  • Trong ví dụ mã sau đây, thư mục làm việc hiện tại được loại bỏ khỏi đường dẫn tìm kiếm trước khi gọi LoadLibrary. Điều này làm giảm nguy cơ đáng kể, vì kẻ tấn công sẽ phải kiểm soát thư mục ứng dụng, thư mục Windows hoặc bất kỳ thư mục được chỉ định trong đường dẫn của người dùng để sử dụng một tấn công tải trước DLL.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
  • Trên tất cả các hệ thống đã cài đặt bản cập nhật bảo mật 963027 (được mô tả trong MS09-014), mã sau đây sẽ vĩnh viễn di chuyển CWD đến vị trí cuối cùng trong thứ tự tìm kiếm. Mọi cuộc gọi sau này đến hàm SetSearchPathMode từ bên trong quy trình tìm cách thay đổi chế độ tìm kiếm sẽ không thành công.

    SetDllDirectory ("");
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
  • Trong ví dụ mã sau đây, thư mục làm việc hiện tại được loại bỏ khỏi đường dẫn tìm kiếm trước khi gọi LoadLibrary. Điều này làm giảm nguy cơ đáng kể, như những kẻ tấn công sẽ phải kiểm soát thư mục ứng dụng, thư mục windows, hoặc bất kỳ thư mục được chỉ định trong đường dẫn của người dùng để sử dụng một cuộc tấn công tải trước DLL.

    SetSearchPathMode (BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
    HMODULE handle = LoadLibrary("schannel.dll");
    
    
    

Sử dụng Giám sát Quy trình để tự động phát hiện tải không an toàn

Microsoft xuất bản một công cụ có tên là Trình giám sát Quy trình. Công cụ này cho phép các nhà phát triển và người quản trị theo dõi chặt chẽ hành vi của một quá trình chạy. Giám sát Quy trình có thể được sử dụng để tự động phát hiện xem một trong các ứng dụng của bạn có thể dễ gặp phải loại sự cố này hay không.

  • Để tải xuống Trình giám sát Quy trình, hãy truy cập trang web Microsoft sau:
    http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx

  • Cố gắng khởi động ứng dụng của bạn bằng cách sử dụng CWD đặt thành một thư mục cụ thể. Ví dụ: bấm đúp vào tệp có phần mở rộng có bộ xử lý tệp được gán cho ứng dụng của bạn.

  • Thiết lập Trình theo dõi Quy trình với các bộ lọc sau đây:

    371495f2-14de-f99c-c55a-f75d31fe9ca8

  • Nếu bị tấn công, bạn sẽ thấy một đường dẫn tương tự như sau: 9acdd1ae-29b9-e499-9de9-8bc665b95e76

     Các cuộc gọi để chia sẻ tập tin từ xa để tải một DLL chỉ ra rằng đây là một chương trình dễ bị tổn thương.

Xem thêm thông tin

Để biết thêm thông tin, hãy truy cập vào các trang web sau của Microsoft:

Thứ tự Tìm kiếm Thư viện Liên kết Động

http://msdn.microsoft.com/en-us/library/ms682586(VS.85).aspx Tài liệu MSDN về hàm SearchPath

http://msdn.microsoft.com/en-us/library/aa365527(VS.85).aspx Tài liệu MSDN về hàm LoadLibrary

http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx Tài liệu MSDN về hàm SetDllDirectory

http://msdn.microsoft.com/en-us/library/ms686203(VS.85).aspx Tài liệu MSDN về hàm SetSearchPathMode

http://msdn.microsoft.com/en-us/library/dd266735(VS.85).aspx Bài đăng blog của David Leblanc, Kỹ sư Bảo mật chính của Microsoft Office

http://blogs.msdn.com/b/david_leblanc/archive/2008/02/20/dll-preloading-attacks.aspx Bài đăng blog của Andrew Roths, nhóm Kỹ thuật MSRC về các cuộc tấn công tải trước DLL

http://blogs.technet.com/b/srd/archive/2009/04/14/ms09-014-addressing-the-safari-carpet-bomb-vulnerability.aspx

Các tài nguyên khác