TryHackMe| Abusing Windows Internals
Thuật ngữ Windows internals có thể đóng gói bất kỳ thành phần nào được tìm thấy ở back-end của hệ điều hành Windows. Nó có thể bao gồm process, file format, COM (Component Object Model), task cheduling, I/O System, DLL(Dynamic Link Library), PE (Portable Executable) format,...
Process
Các ứng dụng chạy trên hệ điều hành có thể chứa một hoặc nhiều process. Các process sẽ duy trì và trình diễn một chương trình đang được thực thi.

Process injection: Đưa mã độc vào một process thông qua chức năng hoặc thành phần hợp lệ. Dưới đấy là 4 loại phổ biến

Ở cấp độ độ cơ bản nhất, process injection diến ra dưới dạng shellcode injection
Ở cấp độ cáo hơn, shellcode injection có thể được chia thành 4 bước:
Mở một target process với tất cả quyền truy cập
Allocate target process memory cho shellcode
Viết shellcode vào allocated process trong target process
Thực thi shellcode bằng remote thread.

Phân tích một chương trình injector shellcode cơ bản:
Mở target process bằng các tham số đặc biệt
Allocate memory cho cho đủ kích thước byte của shellcode
Sử dụng allocated memory region để viết shellcode độc hại vào.
Thực thi shellcode nằm trong memory sử dụng
CreateRemoteThread;
Process Hollowing
Có thể chia làm 6 bước:
Tạo một target process ở suspended state
Mở một malicious image
Un-map code hợp lệ từ process memory
Allocate memory locations cho mã độc và ghi từng section vào address space
Đặt entry point cho mã độc
Cho target process chạy

Phân tích một process hollowing injector cơ bản:
Tạo một target process ở suspended state sử dụng CreateProcessA
Mở một malicious image để inject. Quá trình này chia thành 3 bước, bắt đầu bằng việc sử dụng
CreateFileAđể lấy handle cho malicious image
Allocate memory cho local process sử dụng VirtualAlloc. GetFileSize cũng được sử dụng đẻ lấy kích thước của malicious image cho dwSize.
Sử dụng ReadFile để ghi mã độc vào local process memory
Process cần phải "hollowed" bằng cách un-mapping memory. Để làm được điều này, cần phải xác định vị trí của process trong memory (có thể tìm thấy trong
EAXregister) và entry point (có thể tìm thấy trongEBXregister). Tìm 2 register này sử dụngGetThreadContext,sau đóReadProcessMemoryđược sử dụng để lấy base address từEBXvới offset (0x8), thu được từ việc kiểm tra PEB.
Sử dụng
ZwUnmapViewOfSectionđược import từ ntdll.dll để giải phóng memory khỏi target process.
Bắt đầu allocate memory vào trong process đã làm rỗng.
Khi đã allocate memory, có thể ghi file mã độc vào memory. Trước tiên phải ghi PE header.
Sau đó là các PE section.
Cũng có thể sử dụng relocation table để ghi file vào target memory
Sử dụng
SetThreadContextđể chuyểnEAXđể trỏ vào entry point.
Đưa process ra khỏi suspended state sử dụng
ResumeThread
Thead hijacking
Ở cấp độ cao, thread (execution) hijacking có thể được chia thành các bước:
Xác định vị trị và mở target process để kiểm soát
Allocate memory region cho mã độc
Viết mã độc vào allocated memory
Xác định thread ID của target thread để hijack
Mở target thread
Suspend target thread
Lấy thread context
Cập nhật con trỏ lệnh tới mã độc
Viết lại target process context
Tiếp tục hijacked thread
Phân tích một thread hijacking script cơ bản:
Bước 1, 2 ,3
Xác định thread ID sử dụng bộ 3 API calls của Windows:
CreateToolhelp32Snapshot(),Thread32First(), vàThread32Next().
Mở target thread sủ dụng
OpenThreadvớiTHREADENTRY32structure pointer.
Suspend target process vừa mở.
Lấy thread context sử dụng
GetThreadContextđể lưu trữ một pointer.
Ghi đè RIP (Instruction Pointer Register) để trỏ đến malicious region của memory. Để overwrite register này có thể update thread context cho RIP
Update vào thread context hiện tại. Sử dụng
SetThreadContextvà pointer cho context.
Đưa target thread ra khỏi supended state
DLL
Ở cấp độ cao, DLL injection có thể chia thành 5 bước:
Xác địn target process để inject
Mở target process
Allocate memory region cho DLL độc hại
Ghi DLL độc hại vào allocated memory
Chạy và thực thi DLL độc hại
Phân tích một DLL injector cơ bản:
Xác định target thread
Mở process
Allocate memory cho DLL độc hại
Ghi DLL độc hại vào allocated memory
Load DLL sử dụng
LoadLibrary; được import từkernel32. Sau khi load,CreateRemoteThreadcó thể được sử dụng để thực thi memory bằng cách sử dụngLoadLibrarynhư hàm bắt đầu.
Memory Execution Alternatives
Tùy vào môi trường mà các thực thi shellcode sẽ khác nhay, đặc biệt khi gặp phải những thách thức như các hook trên một API mà không thể né tránh hay gỡ bỏ, hay EDR đang giám sát các threads. Ở các phần trước, ta chủ yếu xem xét các phương pháp cấp phát và ghi dữ liệu vào các process cục bộ hoặc từ xa (qua CreateThread và hàm tương tự là CreateRemoteThread). Thực thi cũng là một bước quan trọng trong bất kỳ kỹ thuật injection nào, mặc dù không quan trọng bằng khi cố gắng giảm thiểu các dấu vết bộ nhớ và IOCs (Indicators of Compromise). Khác với việc cấp phát và ghi dữ liệu, có nhiều lựa chọn khác nhau để thực hiện quá trình thực thi. Ta sẽ tìm hiểu ba phương pháp thực thi khác có thể được sử dụng tùy theo hoàn cảnh.
Invoking Function Pointers (Gọi con trỏ hàm)
Con trỏ hàm kiểu void là một phương pháp thực thi khối bộ nhớ độc đáo và khác lạ dựa hoàn toàn vào việc ép kiểu. Kỹ thuật này chỉ có thể thực thi với bộ nhớ được cấp phát cục bộ nhưng không phụ thuộc vào bất kỳ lệnh gọi API hoặc chức năng hệ thống nào khác.
Dòng mã một dòng dưới đây là dạng phổ biến nhất của con trỏ hàm void
Con trỏ hàm:
Phân tích các bước mà nó thực hiện.
Tạo một con trỏ hàm
(void(*)())Ép kiểu con trỏ bộ nhớ đã cấp phát hoặc mảng shellcode thành con trỏ hàm
(<function pointer>)addressPointerTriệu hồi con trỏ hàm để thực thi shellcode
();
Kỹ thuật này có trường hợp sử dụng rất cụ thể nhưng có thể rất khó phát hiện và hữu ích khi cần.
Asynchronous Procedure Calls (APC - Lời gọi thủ tục không đồng bộ)
“APC là một hàm được thực thi không đồng bộ trong ngữ cảnh của một luồng cụ thể.”
Một hàm APC được queued vào một luồng thông qua QueueUserAPC. Sau khi queued, hàm APC sẽ tạo ra một ngắt phần mềm (software interrupt) và thực thi hàm vào lần tiếp theo khi luồng được lập lịch.
Để một ứng dụng người dùng có thể queue một hàm APC, luồng phải ở trạng thái “alertable state”. Trạng thái này yêu cầu luồng phải đang chờ đợi một callback như WaitForSingleObject hoặc Sleep.
Sử dụng VirtualAllocEx và WriteProcessMemory để cấp phát và ghi vào bộ nhớ.
Kỹ thuật này là một sự thay thế tuyệt vời cho việc thực thi bằng luồng, nhưng gần đây đã được chú ý nhiều hơn trong kỹ thuật phát hiện, và các biện pháp cụ thể đang được triển khai để chống lại việc lạm dụng APC. Dù vậy, nó vẫn là một lựa chọn tốt tùy thuộc vào các biện pháp phát hiện mà bạn đang đối mặt.
Thao tác Section (Section Manipulation)
Một kỹ thuật phổ biến trong nghiên cứu mã độc là thao tác PE (Portable Executable) và section. Định dạng PE xác định cấu trúc và định dạng của tệp thực thi trong Windows. Đối với mục đích thực thi, chúng ta chủ yếu tập trung vào các section, cụ thể là .data và .text, cũng như các bảng và con trỏ đến các section cũng thường được sử dụng để thực thi dữ liệu.
Để bắt đầu với bất kỳ kỹ thuật thao tác section nào, chúng ta cần lấy một dump PE. Việc lấy dump PE thường được thực hiện bằng một DLL hoặc tệp độc hại khác được đưa vào xxd.
Cốt lõi của mỗi phương pháp là sử dụng toán học để di chuyển qua dữ liệu hex vật lý, sau đó được dịch sang dữ liệu PE.
Một số kỹ thuật nổi tiếng bao gồm RVA entry point parsing, section mapping, và relocation table parsing.
Nghiên cứu về Browser Injection và Hooking
Phân tích TTPs (Tactics, Techniques, và Procedures) của TrickBot
Credit for initial research: SentinelLabs
TrickBot là một malware ngân hàng nổi tiếng, gần đây quay lại trong các cuộc tấn công tài chính với tính năng chính là browser hooking. Nó nhắm đến các trình duyệt bằng cách sử dụng OpenProcess để lấy handle của các trình duyệt phổ biến như Chrome, Firefox, và Edge. Sau khi truy cập được các tiến trình, TrickBot thực hiện reflective injection với các bước:
Mở tiến trình mục tiêu bằng OpenProcess.
Cấp phát bộ nhớ bằng VirtualAllocEx.
Ghi hàm và shellcode vào bộ nhớ bằng WriteProcessMemory.
Flush cache để commit changes bằng FlushInstructionCache.
Tạo luồng từ xa bằng RemoteThread hoặc RtlCreateUserThread.
Tiếp tục luông
ResumeThreadhoặc quay lại để tạo luồng người dùng mớiRtlCreateUserThread
Sau khi injection thành công, TrickBot thực hiện cài đặt hook để can thiệp các API của trình duyệt. Mã giả cho quá trình này bao gồm:
Tính toán relative_offset để thực hiện nhảy tới mã độc.
Sử dụng VirtualProtectEx để thay đổi quyền bảo vệ bộ nhớ.
Ghi hook bằng opcode nhảy và khôi phục quyền bảo vệ gốc.
Mục tiêu chính của quá trình này là giúp TrickBot có thể can thiệp vào các hàm API của trình duyệt để đánh cắp thông tin nhạy cảm như thông tin đăng nhập.
References
Last updated