167 lines
6.2 KiB
C#
167 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Seatbelt.Output.TextWriters;
|
|
using Seatbelt.Output.Formatters;
|
|
|
|
|
|
namespace Seatbelt.Commands.Windows
|
|
{
|
|
internal class CredentialFileInfo
|
|
{
|
|
public CredentialFileInfo(string fileName, string description, Guid guidMasterKey, DateTime lastAccessed, DateTime lastModified, long size)
|
|
{
|
|
FileName = fileName;
|
|
Description = description;
|
|
GuidMasterKey = guidMasterKey;
|
|
LastAccessed = lastAccessed;
|
|
LastModified = lastModified;
|
|
Size = size;
|
|
}
|
|
|
|
public string FileName { get; set; }
|
|
|
|
public string Description { get; set; }
|
|
|
|
public Guid GuidMasterKey { get; set; }
|
|
|
|
public DateTime LastAccessed { get; set; }
|
|
|
|
public DateTime LastModified { get; set; }
|
|
|
|
public long Size { get; set; }
|
|
}
|
|
|
|
internal class WindowsCredentialFileCommand : CommandBase
|
|
{
|
|
public override string Command => "WindowsCredentialFiles";
|
|
public override string Description => "Windows credential DPAPI blobs";
|
|
public override CommandGroup[] Group => new[] { CommandGroup.User };
|
|
public override bool SupportRemote => false; // TODO
|
|
|
|
public WindowsCredentialFileCommand(Runtime runtime) : base(runtime)
|
|
{
|
|
}
|
|
|
|
public override IEnumerable<CommandDTOBase?> Execute(string[] args)
|
|
{
|
|
var systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
|
|
var userFolder = $"{Environment.GetEnvironmentVariable("SystemDrive")}\\Users\\";
|
|
|
|
var credentialFolders = new List<string>()
|
|
{
|
|
$"{systemRoot}\\System32\\config\\systemprofile\\AppData\\Local\\Microsoft\\Credentials",
|
|
$"{systemRoot}\\System32\\config\\systemprofile\\AppData\\Roaming\\Microsoft\\Credentials",
|
|
$"{systemRoot}\\ServiceProfiles\\LocalService\\AppData\\Local\\Microsoft\\Credentials",
|
|
$"{systemRoot}\\ServiceProfiles\\LocalService\\AppData\\Roaming\\Microsoft\\Credentials",
|
|
$"{systemRoot}\\ServiceProfiles\\NetworkService\\AppData\\Local\\Microsoft\\Credentials",
|
|
$"{systemRoot}\\ServiceProfiles\\NetworkService\\AppData\\Roaming\\Microsoft\\Credentials"
|
|
};
|
|
|
|
foreach (var dir in Directory.GetDirectories(userFolder))
|
|
{
|
|
if (dir.EndsWith("Public") || dir.EndsWith("Default") || dir.EndsWith("Default User") ||
|
|
dir.EndsWith("All Users"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
credentialFolders.Add($"{dir}\\AppData\\Local\\Microsoft\\Credentials\\");
|
|
credentialFolders.Add($"{dir}\\AppData\\Roaming\\Microsoft\\Credentials\\");
|
|
};
|
|
|
|
foreach (var credPath in credentialFolders)
|
|
{
|
|
foreach (var commandDtoBase in GetCredentialsFromDirectory(credPath))
|
|
yield return commandDtoBase;
|
|
}
|
|
}
|
|
|
|
private IEnumerable<CommandDTOBase> GetCredentialsFromDirectory(string credPath)
|
|
{
|
|
if (!Directory.Exists(credPath))
|
|
yield break;
|
|
|
|
var userFiles = Directory.GetFiles(credPath);
|
|
if (userFiles.Length == 0)
|
|
yield break;
|
|
|
|
var userCredentials = userFiles.Select(CredentialFile).ToList();
|
|
|
|
yield return new WindowsCredentialFileDTO(credPath, userCredentials);
|
|
}
|
|
|
|
private CredentialFileInfo CredentialFile(string file)
|
|
{
|
|
var size = new FileInfo(file).Length;
|
|
|
|
// jankily parse the bytes to extract the credential type and master key GUID
|
|
// reference- https://github.com/gentilkiwi/mimikatz/blob/3d8be22fff9f7222f9590aa007629e18300cf643/modules/kull_m_dpapi.h#L24-L54
|
|
var credentialArray = File.ReadAllBytes(file);
|
|
var guidMasterKeyArray = new byte[16];
|
|
Array.Copy(credentialArray, 36, guidMasterKeyArray, 0, 16);
|
|
var guidMasterKey = new Guid(guidMasterKeyArray);
|
|
|
|
var stringLenArray = new byte[16];
|
|
Array.Copy(credentialArray, 56, stringLenArray, 0, 4);
|
|
var descLen = BitConverter.ToInt32(stringLenArray, 0);
|
|
|
|
var descBytes = new byte[descLen - 4];
|
|
Array.Copy(credentialArray, 60, descBytes, 0, descBytes.Length);
|
|
|
|
var desc = Encoding.Unicode.GetString(descBytes);
|
|
|
|
var cred = new CredentialFileInfo(
|
|
Path.GetFileName(file),
|
|
desc,
|
|
guidMasterKey,
|
|
File.GetLastAccessTime(file),
|
|
File.GetLastAccessTime(file),
|
|
size
|
|
);
|
|
|
|
return cred;
|
|
}
|
|
}
|
|
|
|
internal class WindowsCredentialFileDTO : CommandDTOBase
|
|
{
|
|
public WindowsCredentialFileDTO(string folder, List<CredentialFileInfo> credentials)
|
|
{
|
|
Folder = folder;
|
|
CredentialInfo = credentials;
|
|
}
|
|
public string Folder { get; set; }
|
|
public List<CredentialFileInfo> CredentialInfo { get; }
|
|
}
|
|
|
|
[CommandOutputType(typeof(WindowsCredentialFileDTO))]
|
|
internal class WindowsCredentialFileFormatter : TextFormatterBase
|
|
{
|
|
public WindowsCredentialFileFormatter(ITextWriter writer) : base(writer)
|
|
{
|
|
}
|
|
|
|
public override void FormatResult(CommandBase? command, CommandDTOBase result, bool filterResults)
|
|
{
|
|
var dto = (WindowsCredentialFileDTO)result;
|
|
|
|
WriteLine(" Folder : {0}\n", dto.Folder);
|
|
|
|
foreach (var credentialFile in dto.CredentialInfo)
|
|
{
|
|
WriteLine(" FileName : {0}", credentialFile.FileName);
|
|
WriteLine(" Description : {0}", credentialFile.Description);
|
|
WriteLine(" MasterKey : {0}", credentialFile.GuidMasterKey);
|
|
WriteLine(" Accessed : {0}", credentialFile.LastAccessed);
|
|
WriteLine(" Modified : {0}", credentialFile.LastModified);
|
|
WriteLine(" Size : {0}\n", credentialFile.Size);
|
|
}
|
|
|
|
WriteLine();
|
|
}
|
|
}
|
|
}
|