Skip to content

Commit

Permalink
Merge pull request #47 from LuemmelSec/main
Browse files Browse the repository at this point in the history
Added option to do Session Enumeration as local Admin User
  • Loading branch information
JonasBK authored Oct 30, 2023
2 parents 4ddf1b2 + 26a5f56 commit 395bffc
Show file tree
Hide file tree
Showing 2 changed files with 258 additions and 8 deletions.
199 changes: 199 additions & 0 deletions src/CommonLib/Impersonate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
//credit to Phillip Allan-Harding (Twitter @phillipharding) for this library.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Xml.Linq;

namespace Impersonate
{
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
};

public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};

public enum ImpersonationLevel
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}

class Win32NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int LogonUser(string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
}

/// <summary>
/// Allows code to be executed under the security context of a specified user account.
/// </summary>
/// <remarks>
///
/// Implements IDispose, so can be used via a using-directive or method calls;
/// ...
///
/// var imp = new Impersonator( "myUsername", "myDomainname", "myPassword" );
/// imp.UndoImpersonation();
///
/// ...
///
/// var imp = new Impersonator();
/// imp.Impersonate("myUsername", "myDomainname", "myPassword");
/// imp.UndoImpersonation();
///
/// ...
///
/// using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
/// {
/// ...
/// 1
/// ...
/// }
///
/// ...
/// </remarks>
public class Impersonator : IDisposable
{
private WindowsImpersonationContext _wic;

/// <summary>
/// Begins impersonation with the given credentials, Logon type and Logon provider.
/// </summary>
///<param name = "userName" > Name of the user.</param>
///<param name = "domainName" > Name of the domain.</param>
///<param name = "password" > The password. <see cref = "System.String" /></ param >
///< param name="logonType">Type of the logon.</param>
///<param name = "logonProvider" > The logon provider. <see cref = "Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider" /></ param >
public Impersonator(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
Impersonate(userName, domainName, password, logonType, logonProvider);
}

/// <summary>
/// Begins impersonation with the given credentials.
/// </summary>
///<param name = "userName" > Name of the user.</param>
///<param name = "domainName" > Name of the domain.</param>
///<param name = "password" > The password. <see cref = "System.String" /></ param >
public Impersonator(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}

/// <summary>
/// Initializes a new instance of the <see cref="Impersonator"/> class.
/// </summary>
public Impersonator()
{ }

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
UndoImpersonation();
}

/// <summary>
/// Impersonates the specified user account.
/// </summary>
///<param name = "userName" > Name of the user.</param>
///<param name = "domainName" > Name of the domain.</param>
///<param name = "password" > The password. <see cref = "System.String" /></ param >
public void Impersonate(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}

/// <summary>
/// Impersonates the specified user account.
/// </summary>
///<param name = "userName" > Name of the user.</param>
///<param name = "domainName" > Name of the domain.</param>
///<param name = "password" > The password. <see cref = "System.String" /></ param >
///< param name="logonType">Type of the logon.</param>
///<param name = "logonProvider" > The logon provider. <see cref = "Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider" /></ param >
public void Impersonate(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
UndoImpersonation();

IntPtr logonToken = IntPtr.Zero;
IntPtr logonTokenDuplicate = IntPtr.Zero;
try
{
// revert to the application pool identity, saving the identity of the current requestor
_wic = WindowsIdentity.Impersonate(IntPtr.Zero);

// do logon & impersonate
if (Win32NativeMethods.LogonUser(userName,
domainName,
password,
(int)logonType,
(int)logonProvider,
ref logonToken) != 0)
{
if (Win32NativeMethods.DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, ref logonTokenDuplicate) != 0)
{
var wi = new WindowsIdentity(logonTokenDuplicate);
wi.Impersonate(); // discard the returned identity context (which is the context of the application pool)
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
if (logonToken != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonToken);

if (logonTokenDuplicate != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonTokenDuplicate);
}
}

/// <summary>
/// Stops impersonation.
/// </summary>
private void UndoImpersonation()
{
// restore saved requestor identity
if (_wic != null)
_wic.Undo();
_wic = null;
}
}
}
67 changes: 59 additions & 8 deletions src/CommonLib/Processors/ComputerSessionProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Contexts;
using System.Security.Principal;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Impersonate;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using SharpHoundCommonLib.OutputTypes;


namespace SharpHoundCommonLib.Processors
{

public class ComputerSessionProcessor
{
private static readonly Regex SidRegex = new(@"S-1-5-21-[0-9]+-[0-9]+-[0-9]+-[0-9]+$", RegexOptions.Compiled);
private readonly string _currentUserName;
private readonly ILogger _log;
private readonly NativeMethods _nativeMethods;
private readonly ILDAPUtils _utils;
private readonly bool _doLocalAdminSessionEnum;
private readonly string _localAdminUsername;
private readonly string _localAdminPassword;

public ComputerSessionProcessor(ILDAPUtils utils, string currentUserName = null,
NativeMethods nativeMethods = null, ILogger log = null)
public ComputerSessionProcessor(ILDAPUtils utils, string currentUserName = null, NativeMethods nativeMethods = null, ILogger log = null, bool doLocalAdminSessionEnum = false, string localAdminUsername = null, string localAdminPassword = null)
{
_utils = utils;
_nativeMethods = nativeMethods ?? new NativeMethods();
_currentUserName = currentUserName ?? WindowsIdentity.GetCurrent().Name.Split('\\')[1];
_log = log ?? Logging.LogProvider.CreateLogger("CompSessions");
_doLocalAdminSessionEnum = doLocalAdminSessionEnum;
_localAdminUsername = localAdminUsername;
_localAdminPassword = localAdminPassword;
}

/// <summary>
Expand All @@ -43,7 +55,27 @@ public async Task<SessionAPIResult> ReadUserSessions(string computerName, string

try
{
apiResult = _nativeMethods.CallNetSessionEnum(computerName).ToArray();
// If we are authenticating using a local admin, we need to impersonate for this
if (_doLocalAdminSessionEnum)
{
try
{
Impersonator Impersonate;
using (Impersonate = new Impersonator(_localAdminUsername, ".", _localAdminPassword, LogonType.LOGON32_LOGON_NEW_CREDENTIALS, LogonProvider.LOGON32_PROVIDER_WINNT50))
{
apiResult = _nativeMethods.CallNetSessionEnum(computerName).ToArray();
}
}
catch
{
// Fall back to default User
apiResult = _nativeMethods.CallNetSessionEnum(computerName).ToArray();
}
}
else
{
apiResult = _nativeMethods.CallNetSessionEnum(computerName).ToArray();
}
}
catch (APIException e)
{
Expand Down Expand Up @@ -139,7 +171,27 @@ public SessionAPIResult ReadUserSessionsPrivileged(string computerName,

try
{
apiResult = _nativeMethods.CallNetWkstaUserEnum(computerName).ToArray();
// If we are authenticating using a local admin, we need to impersonate for this
if (_doLocalAdminSessionEnum)
{
try
{
Impersonator Impersonate;
using (Impersonate = new Impersonator(_localAdminUsername, ".", _localAdminPassword, LogonType.LOGON32_LOGON_NEW_CREDENTIALS, LogonProvider.LOGON32_PROVIDER_WINNT50))
{
apiResult = _nativeMethods.CallNetWkstaUserEnum(computerName).ToArray();
}
}
catch
{
// Fall back to default User
apiResult = _nativeMethods.CallNetWkstaUserEnum(computerName).ToArray();
}
}
else
{
apiResult = _nativeMethods.CallNetWkstaUserEnum(computerName).ToArray();
}
}
catch (APIException e)
{
Expand Down Expand Up @@ -209,7 +261,6 @@ public SessionAPIResult ReadUserSessionsRegistry(string computerName, string com
string computerSid)
{
var ret = new SessionAPIResult();

RegistryKey key = null;

try
Expand All @@ -235,6 +286,6 @@ public SessionAPIResult ReadUserSessionsRegistry(string computerName, string com
{
key?.Dispose();
}
}
}
}
}
}
}

0 comments on commit 395bffc

Please sign in to comment.