Skip to content
44 changes: 1 addition & 43 deletions src/CommonLib/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
using System.Text.RegularExpressions;
using SharpHoundCommonLib.Enums;
using Microsoft.Extensions.Logging;
using System.IO;
using System.Security;
using SharpHoundCommonLib.Processors;
using Microsoft.Win32;
using System.Threading.Tasks;

namespace SharpHoundCommonLib {
Expand Down Expand Up @@ -151,7 +147,7 @@ public static string DistinguishedNameToDomain(string distinguishedName) {
}

/// <summary>
/// Converts a domain name to a distinguished name using simple string substitution
/// Converts a domain name to a distinguished name using simple string substitution
/// </summary>
/// <param name="domainName"></param>
/// <returns></returns>
Expand Down Expand Up @@ -258,44 +254,6 @@ public static bool IsSidFiltered(string sid) {
return false;
}

public static RegistryResult GetRegistryKeyData(string target, string subkey, string subvalue, ILogger log) {
var data = new RegistryResult();

try {
var baseKey = OpenRemoteRegistry(target);
var value = baseKey.GetValue(subkey, subvalue);
data.Value = value;

data.Collected = true;
}
catch (IOException e) {
log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "Target machine was not found or not connectable";
}
catch (SecurityException e) {
log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "User does not have the proper permissions to perform this operation";
}
catch (UnauthorizedAccessException e) {
log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "User does not have the necessary registry rights";
}
catch (Exception e) {
log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = e.Message;
}

return data;
}

public static IRegistryKey OpenRemoteRegistry(string target) {
return SHRegistryKey.Connect(RegistryHive.LocalMachine, target).GetAwaiter().GetResult();
}

public static string[] AuthenticationOIDs = new string[] {
CommonOids.ClientAuthentication,
CommonOids.PKINITClientAuthentication,
Expand Down
82 changes: 82 additions & 0 deletions src/CommonLib/IRegistryAccessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Security;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using SharpHoundCommonLib.Processors;

namespace SharpHoundCommonLib {
public interface IRegistryAccessor {
public RegistryResult GetRegistryKeyData(string target, string subkey, string subvalue);
public IRegistryKey OpenRemoteRegistry(string target);
public Task<IRegistryKey> Connect(RegistryHive hive, string machineName);
}

public class RegistryAccessor : IRegistryAccessor {
private readonly ILogger _log;
private readonly AdaptiveTimeout _adaptiveTimeout;

public RegistryAccessor(ILogger log = null) {
_log = log ?? Logging.LogProvider.CreateLogger(nameof(RegistryAccessor));
_adaptiveTimeout = new AdaptiveTimeout(maxTimeout: TimeSpan.FromSeconds(10), _log);
}

public RegistryResult GetRegistryKeyData(string target, string subkey, string subvalue) {
var data = new RegistryResult();

try {
using (var baseKey = OpenRemoteRegistry(target)) {
var value = baseKey.GetValue(subkey, subvalue);
data.Value = value;
data.Collected = true;
}
}
catch (IOException e) {
_log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "Target machine was not found or not connectable";
}
catch (SecurityException e) {
_log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "User does not have the proper permissions to perform this operation";
}
catch (UnauthorizedAccessException e) {
_log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = "User does not have the necessary registry rights";
}
catch (Exception e) {
_log.LogDebug(e, "Error getting data from registry for {Target}: {RegSubKey}:{RegValue}",
target, subkey, subvalue);
data.FailureReason = e.Message;
}

return data;
}

public IRegistryKey OpenRemoteRegistry(string target) {
return Connect(RegistryHive.LocalMachine, target).GetAwaiter().GetResult();
}

/// <summary>
/// Gets a handle to a remote registry.
/// </summary>
/// <param name="hive"></param>
/// <param name="machineName"></param>
/// <returns></returns>
/// <exception cref="TimeoutException"></exception>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="System.IO.IOException"></exception>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="System.Security.SecurityException"></exception>
/// <exception cref="UnauthorizedAccessException"></exception>
public async Task<IRegistryKey> Connect(RegistryHive hive, string machineName) {
var remoteKey = await _adaptiveTimeout.ExecuteWithTimeout((_) => RegistryKey.OpenRemoteBaseKey(hive, machineName));
if (remoteKey.IsSuccess)
return new SHRegistryKey(remoteKey.Value);
throw new TimeoutException($"Failed to connect to registry on {machineName}: {remoteKey.Error}");
}
}
}
40 changes: 4 additions & 36 deletions src/CommonLib/IRegistryKey.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using System;
using System.Threading.Tasks;
using Microsoft.Win32;

namespace SharpHoundCommonLib {
public interface IRegistryKey {
public interface IRegistryKey: IDisposable {
public object GetValue(string subkey, string name);
public string[] GetSubKeyNames();
}

public class SHRegistryKey : IRegistryKey, IDisposable {
public class SHRegistryKey : IRegistryKey {
private readonly RegistryKey _currentKey;
private static readonly AdaptiveTimeout _adaptiveTimeout = new AdaptiveTimeout(maxTimeout: TimeSpan.FromSeconds(10), Logging.LogProvider.CreateLogger(nameof(SHRegistryKey)));

private SHRegistryKey(RegistryKey registryKey) {

public SHRegistryKey(RegistryKey registryKey) {
_currentKey = registryKey;
}

Expand All @@ -23,38 +21,8 @@ public object GetValue(string subkey, string name) {

public string[] GetSubKeyNames() => _currentKey.GetSubKeyNames();

/// <summary>
/// Gets a handle to a remote registry.
/// </summary>
/// <param name="hive"></param>
/// <param name="machineName"></param>
/// <returns></returns>
/// <exception cref="TimeoutException"></exception>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="System.IO.IOException"></exception>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="System.Security.SecurityException"></exception>
/// <exception cref="UnauthorizedAccessException"></exception>
public static async Task<SHRegistryKey> Connect(RegistryHive hive, string machineName) {
var remoteKey = await _adaptiveTimeout.ExecuteWithTimeout((_) => RegistryKey.OpenRemoteBaseKey(hive, machineName));
if (remoteKey.IsSuccess)
return new SHRegistryKey(remoteKey.Value);
throw new TimeoutException($"Failed to connect to registry on {machineName}: {remoteKey.Error}");
}

public void Dispose() {
_currentKey.Dispose();
}
}

public class MockRegistryKey : IRegistryKey {
public virtual object GetValue(string subkey, string name) {
//Unimplemented
return default;
}

public virtual string[] GetSubKeyNames() {
throw new NotImplementedException();
}
}
}
Loading
Loading