Add kernel file version check to avoid BSOD on Win10 x86

This commit is contained in:
Christophe De La Fuente 2021-02-10 19:30:40 +01:00
parent eaa550fa97
commit ab9dd177b7
No known key found for this signature in database
GPG Key ID: 9E350956EA00352A
8 changed files with 157 additions and 12 deletions

View File

@ -15,6 +15,7 @@ to configure the destination path from Metasploit (see `WRITEABLE_DIR` option
description).
Here is the main workflow:
1. Retrieve the target name (where the PE loader will be dropped).
1. Retrieve the PE loader from the binary and write it on disk.
1. Create a [section object](https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views)
@ -26,6 +27,12 @@ Here is the main workflow:
The source code is based on [Johnny Shaw](https://twitter.com/jxy__s)'s
[PoC](https://github.com/jxy-s/herpaderping).
**This payload won't work on 32-bit Windows 10 versions from 1511 (build
10586) to 1703 (build 15063), including Windows 10 2016 LTSB (build 14393).**
These versions have a bug in the kernel that crashes/BugCheck the OS
when executing this payload. So, to avoid this, the payload won't run if
it detects the OS is one of these versions. More details [here](https://bugs.chromium.org/p/project-zero/issues/detail?id=852).
## Verification Steps
Here are the steps using a Meterpreter payload on a 64-bits target:
@ -141,6 +148,12 @@ Evasion target:
msf6 evasion(windows/process_herpaderping) > run
[+] raU.exe stored at /home/msfuser/.msf4/local/raU.exe
[!] #### WARNING ####
This payload won't work on 32-bit Windows 10 versions from 1511 (build
10586) to 1703 (build 15063), including Windows 10 2016 LTSB (build 14393).
These versions have a bug in the kernel that crashes/BugCheck the OS
when executing this payload. So, to avoid this, the payload won't run if
it detects the OS is one of these versions.
msf6 evasion(windows/process_herpaderping) > cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x86.exe
[*] exec: cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x86.exe

View File

@ -104,7 +104,7 @@
<PrecompiledHeader>Create</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -115,9 +115,9 @@
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -138,7 +138,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -165,7 +165,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -191,10 +191,10 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -317,13 +317,32 @@ HRESULT Herpaderp::ExecuteProcess()
int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR, _In_ int)
{
HRESULT hr = Herpaderp::ExecuteProcess();
HRESULT hr;
#ifndef _WIN64
//
// Only 32-bit version of Windows 10 is affected
// see https://bugs.chromium.org/p/project-zero/issues/detail?id=852
//
hr = Utils::IsBuggyKernel();
if (FAILED(hr))
{
dprintf("Process Herpaderp Failed (%S)", Utils::FormatError(hr).c_str());
return EXIT_FAILURE;
REPORT_AND_RETURN_HR("Checking kernel failed", hr);
}
if (hr == S_OK)
{
hr = E_ABORT;
REPORT_AND_RETURN_HR("Kernel version on this OS is buggy and will BSOD... aborting", hr);
}
dprintf("Kernel is not one of the buggy one");
#endif
hr = Herpaderp::ExecuteProcess();
if (FAILED(hr))
{
REPORT_AND_RETURN_HR("Process Herpaderp failed", hr);
}
dprintf("Process Herpaderp Succeeded");
dprintf("Process Herpaderp succeeded");
return EXIT_SUCCESS;
}

View File

@ -747,3 +747,88 @@ HRESULT Utils::GetFileName(
return S_OK;
}
#ifndef _WIN64
//
// Only needed for 32-bit Windows
//
_Use_decl_annotations_
HRESULT Utils::GetFileVersion(LPCWSTR lptstrFilename, PFILE_VERSION ver)
{
DWORD dwHandle;
DWORD dwLen = GetFileVersionInfoSizeW(lptstrFilename, &dwHandle);
if (dwLen == 0)
{
REPORT_AND_RETURN_WIN32("GetFileVersion: Error getting file version info size", GetLastError());
}
LPVOID lpData = new LPVOID[dwLen];
if (!GetFileVersionInfoW(lptstrFilename, 0, dwLen, lpData))
{
delete[] lpData;
REPORT_AND_RETURN_WIN32("GetFileVersion: Error getting file version info", GetLastError());
}
VS_FIXEDFILEINFO* versionInfo;
UINT uLen;
if (!VerQueryValueW(lpData, L"\\", (LPVOID*)&versionInfo, &uLen))
{
delete[] lpData;
REPORT_AND_RETURN_WIN32("GetFileVersion: Error getting version info", GetLastError());
}
ver->MajorVersion = (versionInfo->dwProductVersionMS >> 16) & 0xFFFF;
ver->MinorVersion = versionInfo->dwProductVersionMS & 0xFFFF;
ver->BuildVersion = (versionInfo->dwProductVersionLS >> 16) & 0xFFFF;
ver->RevisionVersion = versionInfo->dwProductVersionLS & 0xFFFF;
delete[] lpData;
return S_OK;
}
_Use_decl_annotations_
HRESULT Utils::IsBuggyKernel()
{
std::wstring kernelFile;
HRESULT hr = Utils::GetFileName("%SystemRoot%\\System32\\ntoskrnl.exe", kernelFile);
if (FAILED(hr))
{
REPORT_AND_RETURN_HR("Failed to retrieve the target filename", hr);
}
FileHandle kernelHandle(kernelFile);
kernelHandle.get() = CreateFileW(kernelFile.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr);
if (!kernelHandle.valid())
{
REPORT_AND_RETURN_WIN32("BuggyKernel: Failed to open Kernel file", GetLastError());
}
FILE_VERSION ver;
hr = GetFileVersion(kernelFile.c_str(), &ver);
if (FAILED(hr))
{
REPORT_AND_RETURN_HR("BuggyKernel: Failed getting file version", hr);
}
dprintf("Version of %S is %hu.%hu.%hu.%hu",
kernelFile.c_str(),
ver.MajorVersion,
ver.MinorVersion,
ver.BuildVersion,
ver.RevisionVersion
);
if (ver.MajorVersion == 10 &&
ver.MinorVersion == 0 &&
ver.BuildVersion > 10240 &&
ver.BuildVersion < 16299)
{
return S_OK;
}
return S_FALSE;
}
#endif

View File

@ -246,4 +246,22 @@ namespace Utils
_In_ const char* sourceFileName,
_Out_ std::wstring& finalFileName);
#ifndef _WIN64
//
// Only needed for 32-bit Windows
//
typedef struct _FILE_VERSION
{
WORD MajorVersion;
WORD MinorVersion;
WORD BuildVersion;
WORD RevisionVersion;
} FILE_VERSION, * PFILE_VERSION;
_Must_inspect_result_ HRESULT GetFileVersion(
_In_ LPCWSTR lptstrFilename,
_Out_ PFILE_VERSION ver);
_Must_inspect_result_ HRESULT IsBuggyKernel();
#endif
}

View File

@ -180,5 +180,15 @@ class MetasploitModule < Msf::Evasion
patch_binary(pe, 'REPLACEFILENAME', replace_path.b)
file_create(pe)
if arch_suffix == 'x86'
print_warning(
"#### WARNING ####\n"\
"This payload won't work on 32-bit Windows 10 versions from 1511 (build\n"\
"10586) to 1703 (build 15063), including Windows 10 2016 LTSB (build 14393).\n"\
"These versions have a bug in the kernel that crashes/BugCheck the OS\n"\
"when executing this payload. So, to avoid this, the payload won't run if\n"\
"it detects the OS is one of these versions."
)
end
end
end