Skip to content

Commit

Permalink
Add anonymise flag
Browse files Browse the repository at this point in the history
  • Loading branch information
ph1ll committed Feb 2, 2024
1 parent 5e41ea6 commit 26c2fa7
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Options:
-p | --pwdump <file> The path to output hashes in pwdump format.
-u | --users-csv <file> The path to output user details in CSV format.
-c | --computers-csv <file> The path to output computer details in CSV format.
--anonymise Anonymise the pwdump and reversible passwords files.
--history-hashes Include history hashes in the pdwump output.
--dump-reversible <file> The path to output clear text passwords, if reversible encryption is enabled.
--wordlist The path to a wordlist of weak passwords for basic hash cracking. Warning, using this option is slow, the use of a dedicated password cracker, such as 'john', is recommended instead.
Expand Down
3 changes: 2 additions & 1 deletion src/NtdsAudit/NtdsAudit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>default</LangVersion>
<LangVersion>latest</LangVersion>
<DocumentationFile>bin\Debug\NtdsAudit.xml</DocumentationFile>
<RunCodeAnalysis>true</RunCodeAnalysis>
<CodeAnalysisRuleSet>CodeAnalysis.ruleset</CodeAnalysisRuleSet>
Expand All @@ -54,6 +54,7 @@
<CodeAnalysisRuleSet>CodeAnalysis.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
<DocumentationFile>bin\Release\NtdsAudit.xml</DocumentationFile>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>061C8D6E497AF8F1F068CCA3BC25C1A558201466</ManifestCertificateThumbprint>
Expand Down
65 changes: 60 additions & 5 deletions src/NtdsAudit/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Reflection;

Expand Down Expand Up @@ -46,6 +47,7 @@ private static void Main(string[] args)
var pwdumpPath = commandLineApplication.Option("-p | --pwdump <file>", "The path to output hashes in pwdump format.", CommandOptionType.SingleValue);
var usersCsvPath = commandLineApplication.Option("-u | --users-csv <file>", "The path to output user details in CSV format.", CommandOptionType.SingleValue);
var computersCsvPath = commandLineApplication.Option("-c | --computers-csv <file>", "The path to output computer details in CSV format.", CommandOptionType.SingleValue);
var anonymise = commandLineApplication.Option("--anonymise", "Anonymise the pwdump and reversible passwords files.", CommandOptionType.NoValue);
var includeHistoryHashes = commandLineApplication.Option("--history-hashes", "Include history hashes in the pdwump output.", CommandOptionType.NoValue);
var dumpReversiblePath = commandLineApplication.Option("--dump-reversible <file>", "The path to output clear text passwords, if reversible encryption is enabled.", CommandOptionType.SingleValue);
var wordlistPath = commandLineApplication.Option("--wordlist", "The path to a wordlist of weak passwords for basic hash cracking. Warning, using this option is slow, the use of a dedicated password cracker, such as 'john', is recommended instead.", CommandOptionType.SingleValue);
Expand Down Expand Up @@ -139,7 +141,7 @@ private static void Main(string[] args)
if (pwdumpPath.HasValue())
{
WritePwDumpFile(pwdumpPath.Value(), ntdsAudit, baseDateTime, includeHistoryHashes.HasValue(), wordlistPath.HasValue(), dumpReversiblePath.Value(), useRdn.HasValue());
WritePwDumpFile(pwdumpPath.Value(), ntdsAudit, baseDateTime, includeHistoryHashes.HasValue(), wordlistPath.HasValue(), dumpReversiblePath.Value(), useRdn.HasValue(), anonymise.HasValue());
}
if (usersCsvPath.HasValue())
Expand Down Expand Up @@ -236,7 +238,7 @@ private static void WriteComputersCsvFile(string computersCsvPath, NtdsAudit ntd
}
}

private static void WritePwDumpFile(string pwdumpPath, NtdsAudit ntdsAudit, DateTime baseDateTime, bool includeHistoryHashes, bool wordlistInUse, string dumpReversiblePath, bool useRdn)
private static void WritePwDumpFile(string pwdumpPath, NtdsAudit ntdsAudit, DateTime baseDateTime, bool includeHistoryHashes, bool wordlistInUse, string dumpReversiblePath, bool useRdn, bool anonymise)
{
DomainInfo domain = null;

Expand Down Expand Up @@ -286,8 +288,32 @@ private static void WritePwDumpFile(string pwdumpPath, NtdsAudit ntdsAudit, Date
// <username>:<uid>:<LM-hash>:<NTLM-hash>:<comment>:<homedir>:
using (var file = new StreamWriter(pwdumpPath, false))
{
StreamWriter mapFile = null;
if (anonymise)
{
mapFile = new StreamWriter($"{pwdumpPath}.map", false);
}

var r = new Random((int)((DateTimeOffset)baseDateTime).ToUnixTimeSeconds());
for (var i = 0; i < users.Length; i++)
{
string userId;

if (anonymise)
{
var bytes = new byte[16];
r.NextBytes(bytes);
userId = new Guid(bytes).ToString();
}
else if (useRdn)
{
userId = users[i].Name;
}
else
{
userId = users[i].SamAccountName;
}

var comments = $"Disabled={users[i].Disabled}," +
$"Expired={!users[i].Disabled && users[i].Expires.HasValue && users[i].Expires.Value < baseDateTime}," +
$"PasswordNeverExpires={users[i].PasswordNeverExpires}," +
Expand All @@ -298,7 +324,7 @@ private static void WritePwDumpFile(string pwdumpPath, NtdsAudit ntdsAudit, Date
$"IsDomainAdmin={users[i].RecursiveGroupSids.Contains(domain.DomainAdminsSid)}," +
$"IsEnterpriseAdmin={users[i].RecursiveGroupSids.Intersect(ntdsAudit.Domains.Select(x => x.EnterpriseAdminsSid)).Any()}";
var homeDir = string.Empty;
file.Write($"{domain.Fqdn}\\{(useRdn ? users[i].Name : users[i].SamAccountName)}:{users[i].Rid}:{users[i].LmHash}:{users[i].NtHash}:{comments}:{homeDir}:");
file.Write($"{(anonymise ? string.Empty : $"{domain.Fqdn}\\")}{userId}:{(anonymise ? i : users[i].Rid)}:{users[i].LmHash}:{users[i].NtHash}:{comments}:{homeDir}:");

if (includeHistoryHashes && users[i].NtHistory != null && users[i].NtHistory.Length > 0)
{
Expand All @@ -314,26 +340,55 @@ private static void WritePwDumpFile(string pwdumpPath, NtdsAudit ntdsAudit, Date
for (var j = 0; j < users[i].NtHistory.Length; j++)
{
var lmHash = (users[i].LmHistory?.Length > j) ? users[i].LmHistory[j] : NtdsAudit.EMPTY_LM_HASH;
file.Write($"{domain.Fqdn}\\{(useRdn ? users[i].Name : users[i].SamAccountName)}__history_{j}:{users[i].Rid}:{lmHash}:{users[i].NtHistory[j]}:::");
file.Write($"{(anonymise ? string.Empty : $"{domain.Fqdn}\\")}{userId}__history_{j}:{(anonymise ? i : users[i].Rid)}:{lmHash}:{users[i].NtHistory[j]}:::");

if (j < users[i].NtHistory.Length || i < users.Length - 1)
{
file.Write(Environment.NewLine);
}
}
}

if (anonymise)
{
mapFile.Write($"{userId}:{domain.Fqdn}\\{(useRdn ? users[i].Name : users[i].SamAccountName)}");
mapFile.Write(Environment.NewLine);
}
}

if (anonymise)
{
mapFile.Dispose();
}
}

if (users.Any(x => !string.IsNullOrEmpty(x.ClearTextPassword)) && !string.IsNullOrWhiteSpace(dumpReversiblePath))
{
using (var file = new StreamWriter(dumpReversiblePath, false))
{
var r = new Random((int)((DateTimeOffset)baseDateTime).ToUnixTimeSeconds());
for (var i = 0; i < users.Length; i++)
{
string userId;

if (anonymise)
{
var bytes = new byte[16];
r.NextBytes(bytes);
userId = new Guid(bytes).ToString();
}
else if (useRdn)
{
userId = users[i].Name;
}
else
{
userId = users[i].SamAccountName;
}

if (!string.IsNullOrEmpty(users[i].ClearTextPassword))
{
file.Write($"{domain.Fqdn}\\{(useRdn ? users[i].Name : users[i].SamAccountName)}:{users[i].ClearTextPassword}");
file.Write($"{domain.Fqdn}\\{userId}:{users[i].ClearTextPassword}");

if (i < users.Length - 1)
{
Expand Down
4 changes: 2 additions & 2 deletions src/NtdsAudit/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.0.9.0")]
[assembly: AssemblyFileVersion("2.0.9.0")]
[assembly: AssemblyVersion("2.0.10.0")]
[assembly: AssemblyFileVersion("2.0.10.0")]
[assembly: CLSCompliant(true)]

0 comments on commit 26c2fa7

Please sign in to comment.