killchain-compendium/post exploitation/Seatbelt/Seatbelt/Commands/Windows/WindowsCredentialFileComman...

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();
}
}
}