PHÂN TÍCH MẪU RANSOMWARE PETYA
Ransomware Petya
Trỗi dậy từ đống tro tàn của Wannacry, một hiểm họa mới bắt đầu: Petya. Trong hai năm 2016 và 2017, ransomware Petya và những biến thể của nó đã ảnh hưởng đến hàng nghìn máy tính trên toàn thế giới. Ngay sau khi ransomware Wannacry vừa có dấu hiệu lắng xuống, Petya nỗi lên như một sự thay thế hoàn hảo.
Điểm đặc biệt của loại malware này là nó không mã hóa các tập tin dữ liệu của người dùng mà thay đổi Master Boot Record(MBR) và mã hóa Master File Table (MFT) khiến cho người dùng thậm chí còn không boot được vào hệ điều hành.

Theo các nguồn thông tin, cuộc tấn công của ransomware Petya bắt nguồn từ công ty M.E.Doc, một công ty kiểm toán có trụ sở tại Ukrainian, thông qua phần mềm của M.E.Doc có chứa Petya trong một bản cập nhật. Ngoài ra, Petya còn được chèn trong các file văn bản được gửi có chủ đích tới các cơ quan tổ chức khi người dùng mở lên thì ransomware sẽ lừa người dùng kích hoạt marco có sẵn trong các phiên bản của Office.
Stage 1: High level
Trên không gian mạng hiện nay có rất nhiều biến thể của ransomware Petya nhưng trong bài viết này ta sẽ tập trung phân tích mẫu:
SHA-256:26b4699a7b9eeb16e76305d843d4ab05e94d43f3201436927e13b3ebafa90739
Ta dễ dàng nhận ra mẫu ransomware cần phải được unpack trước khi thực thi các lệnh thực. Trong quá trình debug ransomware có gọi đến các hàm như VirtualProtect và VirtualAlloc để phân bổ và thay đổi quyền của một vùng nhớ mới. Phỏng đoán ràng đây sẽ là vùng nhớ chứa mã thực của ransomware sau khi unpack. Vậy nên ta chỉ cần đặt breakpoint ở điểm đầu của vùng nhớ mới được tạo ra và đây là kết quả:

Như ta thấy trong hình trên, trong cửa sổ hexdump là header của một pe file. Dump toàn bộ section này ra ta thu được một file Setup.dll với đầy đủ import table rất dễ đọc.

Đi qua lần lượt các hàm được thực hiện trong file Setup.dll khi được khởi chạy. Đầu tiên, ransomware Petya lấy thông tin ổ cứng của nạn nhân bằng hàm DeviceIoControl để láy vị trí vật lý của một volume trên ổ cứng, thông tin về chủng loại, kích thước, tích chất của phân vùng ổ cứng(bằng IOCTL_DISK_GET_PARTITION_INFO_EX, PARTITION_INFORMATION_EX, ). Dưới đây là pseudocode hàm lấy vị trí vật lý của một volumn trên một hoặc nhiều ổ cứng:
v1 = this; BytesReturned = 0; v2 = GetSystemDirectoryA(0, 0); v3 = v2; if ( !v2 ) return 0; v5 = (CHAR *)sub_239090(v2); if ( !GetSystemDirectoryA(v5, v3) ) return 0; *(_DWORD *)FileName = 1546542172; v9 = *v5; v10 = 58; sub_239070(v5); v6 = CreateFileA(FileName, 0, 3u, 0, 3u, 0, 0); if ( v6 == (HANDLE)-1 ) { CloseHandle((HANDLE)0xFFFFFFFF); return 0; } DeviceIoControl(v6, 0x560000u, 0, 0, &OutBuffer, 0x20u, &BytesReturned, 0); // Trong do 0x560000 là IoControlCode duoc thay lan luot la 0x70048, 0x70000 trong cac ham con lai de lay thong tin o dia CloseHandle(v6); qmemcpy(v1, "\\\\.\\PhysicalDrive", 17); v1[17] = v12 + 48; v1[18] = 0; return 1;
Sau đó, ransomware tạo một buffer chứa link trả tiền chuộc “hxxp://petya5koahtsf7sv[.]onion/[Random]”, “hxxp://petya37h5tbhyvki[.]onion/[Random]” Ransom Note. Và gọi đến hàm CryptGenRandom để tạo ra khóa cá nhân của nạn nhân.
v4 = (_DWORD *)phProv; *(_DWORD *)phProv = 0; if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) ) return -60; if ( !CryptGenRandom(phProv, dwLen, pbBuffer) ) return -60; CryptReleaseContext(phProv, 0); *v4 = dwLen; return 0;
Kết thúc payload, ransomware dùng NtRaiseHardError để ép máy khởi động lại
v0 = GetCurrentProcess(); if ( !OpenProcessToken(v0, 0x28u, &TokenHandle) ) return 0; LookupPrivilegeValueA(0, "SeShutdownPrivilege", (PLUID)NewState.Privileges); NewState.PrivilegeCount = 1; NewState.Privileges[0].Attributes = 2; AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0, 0, 0); if ( GetLastError() ) return 0; v2 = GetModuleHandleA("NTDLL.DLL"); v3 = GetProcAddress(v2, "NtRaiseHardError"); ((void (__cdecl *)(signed int, _DWORD, _DWORD, _DWORD, signed int, char *))v3)(-1073740976, 0, 0, 0, 6, &v5); return 1;
Stage 2: Low level
Giờ ta phân tích mã độc được chèn vào MBR của ổ đĩa:

Từ kết quả dump ra từ \.\PhysicalDrive0 ta có:
- Sector 0: Điểm được bootloader độc đầu tiên
- Sector 1-33: Toàn bộ là 0x37
- Sector 34-49: Đoạn kernel của ransomware
- Sector 50-53: Trống
- Sector 54: Nonce, CNC và Personal Key
- Sector 55-56: Data được mã hóa
Khi máy khởi động đoạn mã của ransomware sẽ được thực thi:

Để đọc sector tử ổ đĩa nó sử dụng interrupt 13

Tiếp đến, Ransomware sẽ check xem MBR đã bị mã hóa chưa?

Nếu chưa mã hóa, Petya sử dụng thuật toán Salsa20 để khóa MFT.
MFT (Master File Table) là thành phần quan trọng nhất trong hệ thống NTFS. MFT chứa thông tin về tất cả các tập tin và thư mục trong ổ đĩa logic.
Sau khi mã hóa xong màn hình chính sẽ được hiển thị

Khi người dùng nhập key Petya sẽ kiểm tra định dạng của key:
- Có độ dài 16 byte
- Chỉ chấp nhận các ký tự sau 123456789abcdefghijkmnopqrstuvwxABCDEFGHJKLMNPQRSTUVWX

Mặc dù, ta hoàn toàn có thể bypass check_key bằng cách đổi địa chỉ của một số hàm jump nhưng như vậy cũng không giải mã được MFT. Tuy nhiên, do giới hạn về kích thước của các sector nên ransomware Petya không triển khai đầy đủ thuật toán Salsa 20 nên ta có thể brute force được key giải mã.
Trong quá trình giải mã của Petya ta thấy:
- Petya load lên bộ nhớ 512 byte của sector thứ 55(đây là dữ liệu cần được giải mã)
- Petya load lên bộ nhớ 8 byte ở offset 0x6c21 ngay trước CNC trong sector thứ 54(đây là nonce)

Ta có được bản mã và nonce. Ta hoàn toàn có thể đọc thuật toán của salsa và tự viết script brute force hoặc sử dụng script được viết bằng golang của một anh bạn rất tốt bụng leo-stone.

Tổng kết
Việc tạo ra một ransomware được khởi chạy ở boot sector, mã hóa MBR và MFT là một hướng đi rất thú vị. Tuy nhiên, việc triển khai ransomware dưới tầng kernel đã tạo ra một vài lỗ hổng trong lúc triển khai thuật toán mã hóa giúp cho chúng ta có thể giải mã mà không cần key. Điều này đã khiến cho Petya phiên bản đầu thể không lây nhiễm rộng rãi. Mặc dù vậy, những mã độc có hướng đi như Petya, ví dụ như Goldeneye, đã tạo cảm hứng cho hacker phát triển những ransomware tấn công vào tầng kernel, đặt ra thách thức cho các nhà bảo mật.