Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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