[Flare-On7] Chal9-crackinstaller write-up
Firstly: Credit to my brother (cre4milk) for his technical review and keep me up when writing this write-up!!!!
1. Analysis
1.1. Phân tích crackstaller.exe
1.1.1. Dump credHelper.dll
Load file vào IDA, sau khi phân tích xong IDA sẽ đi tới hàm main (0x0140002124)
của chương trình. Ngay tại đầu hàm, chương trình thực hiện giải mã ra một PE file ( credHelper.dll
):
Hàm giải mã đơn giản thực hiện cấp phát vùng nhớ có kích thước 0x1A600
bytes để lưu dữ liệu sau giải mã. Sử dụng vòng lặp xor để giải mã dữ liệu tại offset 0x17480
với key giải mã là [0x8, 0x67, 0x53, 0x9]
:
Sau đó, chương trình cấu thành đường dẫn để lưu file tại C:\Users\<account>\AppData\Local\Microsoft\Credentials\credHelper.dll
. Sử dụng các hàm CreateFileW
, WriteFile
để tạo và ghi nội dung đã giải mã vào file:
Cuối cùng, sử dụng LoadLibraryW
để load file credHelper.dll
, sau đó gọi tới hàm DllRegisterServer()
trong module credHelper.dll
.
Kết thúc phần phân tích trên, tạm thời thu được file credHelper.dll
. credHelper.dll
chính là một COM DLL.
1.1.2. Phân tích hàm init_proc
Nếu chỉ dừng lại ở trên thì có vẻ không hợp lý lắm vì thấy còn nhiều khác trong chương trình. Sử dụng xrefs để tìm hàm gọi tới main cũng như kết hợp code coverage thông qua Lighthouse plugin, biết được chương trình thực hiện trick để hijack hàm runtime _initterm().
Đi tới _init_proc() tại 0x0140002530
, đầu hàm này chương trình gọi hàm f_retrieve_service_apis_funcs (0x0140001CD8)
để lấy địa chỉ các APIs thuộc hai thư viện advapi32.dll
; kernel32.dll
. Tên hàm cần lấy được giải mã thông qua hàm decrypt_string
đã mô tả ở trên. Danh sách các hàm cần lấy địa chỉ bao gồm:
Tiếp theo, tiến hành giải mã vào bộ nhớ hai driver là Capcom.sys
và Driver.sys
.
Hàm giải mã thực hiện:
- Tính SHA256 của chuỗi “
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
” được giá trị hash “e173d43de98094098259467ff632b4fc61496af96f3a354a006360d246e8166f
” - Thông qua hàm
f_Salsa20_key_setup (0x0140001010)
để transform giá trị hash ở trên thành key giải mã. - Gọi hàm
f_Salsa20_decrypt (0x01400014EC)
để giải mã PE file vào vùng nhớ đã cấp phát.
Tới đây, dump được 02 driver để phục vụ phân tích sau. Sau khi giải mã thành công hai driver trên, chương trình thực hiện tiếp:
- Tạo file
cfs.dll
tại thư mụcC:\Windows\System32
. - Mapping nội dung đã giải mã của driver
Capcom.sys
ở trên vào filecfs.dll
. - Gọi hàm
f_start_service (0x0140001FB4)
, sử dụng các APIs liên quan đến service đã lấy được địa chỉ ở trên để khởi chạy một service dưới tên làcfs
và lấy handle của device có đường dẫn là\\.\Htsysm72FB
.
- Nếu khởi chạy được service, chương trình gọi tới hàm
f_interact_with_driver (0x0140002C44)
để thực hiện tương tác vớiDriver.sys
. Nếu thành công sẽ dừng và xóa servicecfs
.
Đi sâu vào f_interact_with_driver
, hàm này thực hiện nhiệm vụ:
- Gọi hàm
f_decrypt_string
để giải mã ra chuỗi “DriverBootstrap
”. - Parse
Driver.sys
trên bộ nhớ để lấy địa chỉ RVA của hàmDriverBootstrap
. Từ đó lấy được địa chỉ offset của hàmDriverBootstrap
tại0x3170
. - Gọi hàm
VirtualAlloc
để cấp phát vùng nhớ có kích thước45 bytes (0x2D)
để chứa nội dung của một shellcode. - Tạo một context với nội dung gồm: địa chỉ base của
Driver.sys
; kích thước củaDriver.sys (0x5800)
; địa chỉ offset của hàmDriverBootstrap (0x3170)
thuộc driver này; địa chỉ củasub_140002A10
thuộccrackstaller.exe
. - Cuối cùng gửi một IO Control Code có giá trị
0xAA013044
tớiCapcom.sys
(lúc này đã được mapping và chạy dưới service name làcfs
) thông qua hàmDeviceIoControl
để inject shellcode đã được cài đặt ở trên tớiCapcom.sys
(Refs: Capcom Rootkit Proof-Of-Concept; Capcom Driver Analysis)
1.1.3. Phân tích sub_140002A10
Như phân tích ở trên, nội dung của shellcode có tham chiếu tới sub_140002A10
. Đoạn mã tại địa chỉ này thực hiện nhiệm vụ cơ bản như sau:
- Gọi hàm
f_find_ntoskrnl_module (0x0140002768)
để tìm modulentoskrnl.exe
thông qua giá trị hash được tính toán trước là0xC036346A
. - Gọi hàm
f_resolve_ntoskrnl_apis (0x0140002964)
với tham số truyền vào là các giá trị hash cho trước để lấy địa chỉ của các hàm APIs thuộcntoskrnl.exe
. Thuật toán maching hash cơ bản như sau:
- Cấp phát vùng nhớ (pool memory) với độ lớn bằng kích thước của
Driver.sys (0x5800)
và gắn pool tag cho nó là “FLAR
”. - Sao chép nội dung của
Driver.sys
vào vùng nhớ đã cấp phát. - Tìm kiếm giá trị “
0xDC16F3C3B57323
” và thay thế bằng giá trị “0x41424143414242
”. - Xây dựng context và gọi hàm
PsCreateSystemThread
với entry point của thread được tạo chính là địa chỉ của hàmDriverBootstrap
thuộcDriver.sys
.
1.2. Phân tích driver.sys
1.2.1. Hàm DriverBootstrap
Theo phân tích tại sub_140002A10
, sub này sẽ gọi PsCreateSystemThread
để tạo một system thread nhằm thưc thi hàm DriverBootstrap
trong driver.sys
. Load driver.sys
vào IDA, code tại hàm DriverBootstrap
thực hiện nhiệm vụ sau:
- Parse header của
driver.sys
để lấy địa chỉ củaDriverEntry
. - Gọi hàm
IoCreateDriver
để thưc thi code tạiDriverEntry
.
1.2.2. Hàm main của driver.sys
Code tại DriverEntry
thực hiện đăng kí một callback function (f_callback_function
) tại địa chỉ 0x0140004570
.
Bằng việc đăng kí hàm callback như trên thì Driver.sys
chính là một filter driver. Hàm callback này là một RegistryCallback
, sẽ giám sát, chặn hoặc thay đổi hành động tác động vào registry. Code tại hàm f_callback_function
thực hiện nhiệm vụ sau:
- Gọi hàm
decrypt_string
để giải mã ra chuỗi{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}\Config
. Như vậy, hàm callback sẽ chặn bắt những sự kiện thay đổi xảy ra trên registry key này. - Tính SHA256 của data là
0xDC16F3C3B57323
, tuy nhiên giá trị này đã bị thay thế bằng “BBACABA
” như đã phân tích tạisub_140002A10
.
- Dựa vào giá trị hash tính được ở trên, sử dụng thuật toán salsa20 để thiết lập key giải mã. Sau đó thực hiện giải mã dữ liệu ra
RC4_key
. Đây chính là key cần tìm để giải mã ra flag. Key này có độ dài là15
.
1.3. Phân tích CredHelper.dll
1.3.1. Hàm DllRegisterServer
Quay trở lại với file credHelper.dll
đã dump được ở trên, tại hàm main
của crackstaller.exe
sẽ gọi tới hàm DllRegisterServer()
của dll này. Load vào IDA, nhiệm vụ của hàm DllRegisterServer()
đơn giản như sau:
- Gọi
GetModuleFileNameW
để lấy đường dẫn củacredHelper.dll
. Dll này nằm tạiC:\Users\<account>\AppData\Local\Microsoft\Credentials\credHelper.dll
. - Gọi
StringFromGUID2
để tạo GUID string{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}
đồng thời tạo đường dẫn làCLSID\{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}
. Điều này này sẽ signal đoạn code giải mã password trongdriver.sys
mà chúng ta đã đề cập ở trên. - Cuối cùng thiết lập giá trị registry tương ứng tại
HKEY_CLASSES_ROOT
.
- Kết quả có được tương tư như hình dưới đây:
Sau khi đăng ký như một COM DLL Server, credHelper.dll
sẽ expose ra các methods như sau:
1.3.2. Hàm GetPassword
Tại hàm GetPassword()
có địa chỉ 0x018000153
, chương trình thực hiện nhiệm vụ đọc ra giá trị của từ Registry và transform nó thành :
1.3.3. Hàm GetFlag
Tại hàm GetFlag()
có địa chỉ 0x01800016D8
, code tại đây thực hiện giải mã ra chuỗi flag cần tìm với key giải mã có được ở trên và gán chuỗi này vào Registry tương ứng:
Như vậy, sau khi phân tích code của credHelper.dll
có được nội dung của flag đã bị encrypt như trên hình. Nhiệm vụ bây giờ là cần tìm được password để giải mã.
2. Get RC4_key through remote kernel debugging
Kết thúc toàn bộ quá trình phân tích ở trên, có thể hình dung được flow thực hiện của crackstaller.exe
như sau:
crackstaller.exe
bị hijack_initterm()
, nên sẽ thực thi_init_proc()
trước hàmmain
. Tại đây, giải mã ra 02 driver là Capcom.sys và Driver.sys (filter driver). Capcom.sys được mapping vàocfs.dll
và được khởi chạy dưới dạngSERVICE_KERNEL_DRIVER
.- Tạo một shellcode và gọi hàm
DeviceIoControl
để inject shellcode này vào Capcom.sys. - Shellcode khi thưc thi sẽ nhảy tới
sub_0140002A10
củacrackstaller.exe
. Tại đây, thực hiện thay thế data trongDriver.sys
và gọi hàmPsCreateSystemThread
để tạo thread thực thi lệnh bắt đầu từ hàmDriverBootstrap
thuộc Driver.sys. - Code tại
DriverBootstrap
lấy địa chỉ hàmDriverEntry
và gọi hàmIoCreateDriver
để thực thi hàm này. - Code tại
DriverEntry
gọi hàmCmRegisterCallbackEx
để đăng kí mộtcallback_function
.Callback_function
sẽ chờ khicredHelper.dll
được load lên để thực hiện giải mã ra mộtRC4_key
. - Hàm
main
củacrackstaller.exe
giải mã racredHelper.dll
. Lấy địa chỉ của hàmDllRegisterServer()
và gọi hàm này để thực thi. - Hàm
DllRegisterServer()
củacredHelper.dll
khi được load lên có nhiệm vụ tạo ra một COM Object trong Registry là{CEEACC6E-CCB2-4C4F-BCF6-D2176037A9A7}
. Đồng thời, nó sẽ lấy Password trong Registry làmRC4_key
để giải mã ra Flag.
Như vây, dữ liệu mã hóa của Flag đã biết thông qua phân tích credHelper.dll. Để có được key giải mã mà không cần viết lại thuật toán thì cách nhanh nhất là debug vào Driver.sys. Để debug được, sử dụng VirtualKD-Redux (do VirtualKD tương thích không tốt từ VMware15 trở đi) nhằm hỗ trợ Windbg thực hiện remote debugging vào máy ảo được hiệu quả hơn.
Tại máy ảo, thực hiện debug crackstaller.exe
. Đặt bp tại lời gọi tới hàm VirtualAlloc
, sau đó thực thi code để chương trình thiết lập giá trị cho shellcode buffer, tới hàm DeviceIoControl
thì dừng lại. Follow vùng nhớ chứa shellcode và sửa lệnh sti (0xFB)
thành int3 (0xCC)
:
Trace qua lệnh DeviceIoControl
, lúc này Windbg sẽ signal và dừng lại tại lệnh int3
. Sử dụng lệnh eb
để restore lại byte đã patch:
Trace code tại Windbg sẽ nhảy tới hàm 0x0140002A10
. Tại đây sẽ thấy code tại hàm này thực hiện thay đổi dữ liệu như đã phân tích ở trên:
Tiếp tục trace code cho tới khi dừng lại tại lời gọi hàm PsCreateSystemThread
. Lúc này, thanh ghi rax
đang trỏ tới hàm địa chỉ hàm DriverBootstrap
của Driver.sys.
Gõ lệnh bp rax
để đặt một bp tại hàm này:
Thực thi chương trình sẽ dừng lại tại đầu hàm DriverBootstrap
. Tiếp tục trace code và đặt bp tại lời gọi tới hàm IoCreateDriver
, lúc này thanh ghi rdx
sẽ trỏ tới địa chỉ của hàm DriverEntry
. Gõ lệnh bp rdx
để đặt bp:
Tiếp tục thực thi chương trình, trace code tới lời gọi hàm CmRegisterCallbackEx
. Lúc này, thanh ghi rcx
sẽ trỏ tới địa chỉ của hàm callback. Gõ lệnh bp rcx
để đặt bp tại hàm callback này:
Cho thực thi chương trình sẽ dừng lại tại đầu hàm callback. Lúc này, nó sẽ chờ cho tới khi credHelper.dll
được load lên và chạy. Do đó, xóa bp đã đặt ở đầu hàm, tìm và đặt bp tại chỗ gọi hàm giải mã ra RC4_key
, sau đó cho thực thi. Để có thể trigger được bp đã đặt, tại máy ảo thực hiện lệnh sau để chạy credHelper.dll
:
Quạy lại Windbg, bp đã hit. Trace qua hàm giải mã và thực hiện dump giá trị tại rsp+0D8h
sẽ có được RC4_key
là “H@n $h0t FiRst!
”:
3. Decrypt flag
Với RC4_key ở trên, sử dụng CyberChef để thực hiện giải mã ra flag để submit là S0_m@ny_cl@sse$_in_th3_Reg1stry@flare-on.com
:
End.
m4n0w4r