diff --git a/winPEAS/winPEASexe/winPEAS/Checks/Checks.cs b/winPEAS/winPEASexe/winPEAS/Checks/Checks.cs index 992878f..2f8f3b4 100644 --- a/winPEAS/winPEASexe/winPEAS/Checks/Checks.cs +++ b/winPEAS/winPEASexe/winPEAS/Checks/Checks.cs @@ -35,7 +35,7 @@ namespace winPEAS.Checks public static string PaintAdminUsers = ""; private static List _systemChecks; - private static HashSet _systemCheckSelectedKeysHashSet = new HashSet(); + private static readonly HashSet _systemCheckSelectedKeysHashSet = new HashSet(); // github url for Linpeas.sh public static string LinpeasUrl = "https://raw.githubusercontent.com/carlospolop/privilege-escalation-awesome-scripts-suite/master/linPEAS/linpeas.sh"; diff --git a/winPEAS/winPEASexe/winPEAS/Checks/FilesInfo.cs b/winPEAS/winPEASexe/winPEAS/Checks/FilesInfo.cs index 184a0a6..dbab372 100644 --- a/winPEAS/winPEASexe/winPEAS/Checks/FilesInfo.cs +++ b/winPEAS/winPEASexe/winPEAS/Checks/FilesInfo.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using winPEAS.Helpers; using winPEAS.Helpers.Registry; using winPEAS.Helpers.Search; using winPEAS.Info.FilesInfo.Certificates; using winPEAS.Info.FilesInfo.McAfee; +using winPEAS.Info.FilesInfo.Office; using winPEAS.Info.FilesInfo.WSL; using winPEAS.Info.UserInfo; using winPEAS.InterestingFiles; @@ -122,6 +121,7 @@ namespace winPEAS.Checks { Putty.PrintInfo, SuperPutty.PrintInfo, + PrintOffice365EndpointsSyncedByOneDrive, PrintCloudCreds, PrintUnattendFiles, PrintSAMBackups, @@ -135,6 +135,7 @@ namespace winPEAS.Checks PrintMachineAndUserCertificateFiles, PrintUsersInterestingFiles, PrintUsersDocsKeys, + PrintOfficeMostRecentFiles, PrintRecentFiles, PrintRecycleBin, PrintHiddenFilesAndFolders, @@ -865,5 +866,115 @@ namespace winPEAS.Checks { } } + + private static void PrintOfficeMostRecentFiles() + { + int limit = 50; + + Beaprint.MainPrint($"Office Most Recent Files -- limit {limit}\n"); + + try + { + var infos = Office.GetOfficeRecentFileInfos(limit); + + Beaprint.ColorPrint($" {"Last Access Date",-25} {"User",-45} {"Application",-20} {"Document"}", Beaprint.LBLUE); + + foreach (var info in infos) + { + Beaprint.NoColorPrint($" {info.LastAccessDate.ToString("yyyy-MM-dd HH:mm"),-25} {info.User,-45} {info.Application,-20} {info.Target}"); + } + } + catch (Exception ex) + { + } + } + + private static void PrintOffice365EndpointsSyncedByOneDrive() + { + void PrintItem(KeyValuePair mpSub) + { + string formattedDateString = string.Empty; + + if (mpSub.Key == "LastModifiedTime") + { + DateTime.TryParse(mpSub.Value, out var parsedDate); + string formattedDate = parsedDate.ToString("ddd dd MMM yyyy HH:mm:ss"); + formattedDateString = $"({formattedDate})"; + } + + Beaprint.NoColorPrint($" {mpSub.Key,-40} {mpSub.Value,-50} {formattedDateString}"); + } + + Beaprint.MainPrint("Enumerating Office 365 endpoints synced by OneDrive.\n"); + + try + { + var infos = Office.GetCloudSyncProviderInfos(); + + foreach (var info in infos) + { + Beaprint.NoColorPrint($" SID: {info.Sid}"); + + var odspInfo = info.OneDriveSyncProviderInfo; + + foreach (var item in odspInfo.OneDriveList) + { + if (item.Value.Count > 0) + { + + string accName = item.Key; + Beaprint.NoColorPrint($" Name: {accName}"); + + foreach (var subItem in item.Value) + { + Beaprint.NoColorPrint($" {subItem.Key,-40} {subItem.Value}"); + } + + // mount points + foreach (string mp in odspInfo.AccountToMountpointDict[accName]) + { + Beaprint.NoColorPrint(""); + + if (odspInfo.MpList.ContainsKey(mp)) + { + foreach (var mpSub in odspInfo.MpList[mp]) + { + PrintItem(mpSub); + } + } + } + } + } + + // iterate Orphaned accounts + var allScopeIds = new List(odspInfo.MpList.Keys); + var orphanedScopeIds = new HashSet(); + + foreach (var scopeId in allScopeIds.Where(scopeId => !odspInfo.UsedScopeIDs.Contains(scopeId))) + { + orphanedScopeIds.Add(scopeId); + } + + if (orphanedScopeIds.Count > 0) + { + Beaprint.ColorPrint("\n Orphaned items", Beaprint.LBLUE); + + foreach (string scopeId in orphanedScopeIds) + { + foreach (var mpSub in odspInfo.MpList[scopeId]) + { + PrintItem(mpSub); + } + Beaprint.NoColorPrint(""); + } + } + + Beaprint.PrintLineSeparator(); + } + } + catch (Exception ex) + { + } + } } } diff --git a/winPEAS/winPEASexe/winPEAS/Checks/UserInfo.cs b/winPEAS/winPEASexe/winPEAS/Checks/UserInfo.cs index c6179e2..63201a9 100644 --- a/winPEAS/winPEASexe/winPEAS/Checks/UserInfo.cs +++ b/winPEAS/winPEASexe/winPEAS/Checks/UserInfo.cs @@ -2,10 +2,13 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; +using System.Security.Cryptography; using System.Security.Principal; using winPEAS.Helpers; +using winPEAS.Helpers.Extensions; using winPEAS.Info.UserInfo; using winPEAS.Info.UserInfo.LogonSessions; +using winPEAS.Info.UserInfo.Tenant; using winPEAS.Info.UserInfo.Token; using winPEAS.Native; using winPEAS.Native.Enums; @@ -41,6 +44,7 @@ namespace winPEAS.Checks { PrintCU, PrintCurrentUserIdleTime, + PrintCurrentTenantInfo, PrintTokenP, PrintClipboardText, PrintLoggedUsers, @@ -391,5 +395,48 @@ namespace winPEAS.Checks { } } + + private static void PrintCurrentTenantInfo() + { + try + { + Beaprint.MainPrint("Display Tenant information (DsRegCmd.exe /status)"); + + var info = Tenant.GetTenantInfo(); + + if (info != null) + { + + Beaprint.NoColorPrint($" Tenant Display Name : {info.TenantDisplayName}\n" + + $" Tenant Id : {info.TenantId}\n" + + $" Idp Domain : {info.IdpDomain}\n" + + $" Mdm Enrollment Url : {info.MdmEnrollmentUrl}\n" + + $" Mdm TermsOfUse Url : {info.MdmTermsOfUseUrl}\n" + + $" Mdm Compliance Url : {info.MdmComplianceUrl}\n" + + $" User Setting Sync Url : {info.UserSettingSyncUrl}\n" + + $" Device Id : {info.DeviceId}\n" + + $" Join Type : {info.JType.GetDescription()}\n" + + $" Join User Email : {info.JoinUserEmail}\n" + + $" User Key Id : {info.UserKeyId}\n" + + $" User Email : {info.UserEmail}\n" + + $" User Keyname : {info.UserKeyname}\n"); + + foreach (var cert in info.CertInfo) + { + Beaprint.NoColorPrint($" Thumbprint : {cert.Thumbprint}\n" + + $" Subject : {cert.Subject}\n" + + $" Issuer : {cert.Issuer}\n" + + $" Expiration : {cert.GetExpirationDateString()}"); + } + } + else + { + Beaprint.NoColorPrint(" Tenant is NOT Azure AD Joined."); + } + } + catch (Exception ex) + { + } + } } } diff --git a/winPEAS/winPEASexe/winPEAS/Helpers/Registry/RegistryHelper.cs b/winPEAS/winPEASexe/winPEAS/Helpers/Registry/RegistryHelper.cs index fada162..9ab52aa 100644 --- a/winPEAS/winPEASexe/winPEAS/Helpers/Registry/RegistryHelper.cs +++ b/winPEAS/winPEASexe/winPEAS/Helpers/Registry/RegistryHelper.cs @@ -150,6 +150,11 @@ namespace winPEAS.Helpers.Registry { return new string[0]; } - } + } + + public static string[] GetUserSIDs() + { + return Microsoft.Win32.Registry.Users.GetSubKeyNames() ?? new string[] { }; + } } } diff --git a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/Office.cs b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/Office.cs new file mode 100644 index 0000000..dfda127 --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/Office.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.Win32; +using winPEAS.Helpers; +using winPEAS.Helpers.Registry; +using winPEAS.Info.FilesInfo.Office.OneDrive; +using winPEAS.Native; + +namespace winPEAS.Info.FilesInfo.Office +{ + internal class Office + { + public static IEnumerable GetOfficeRecentFileInfos(int limit) + { + var orderedRecentFiles = GetRecentOfficeFiles().OrderByDescending(e => e.LastAccessDate).Take(limit); + + foreach (var file in orderedRecentFiles) + { + yield return file; + } + } + + public static IEnumerable GetCloudSyncProviderInfos() + { + var keys = new List { "DisplayName", "Business", "ServiceEndpointUri", "SPOResourceId", "UserEmail", "UserFolder", "UserName", "WebServiceUrl" }; + + // Get all of the user SIDs (so will cover all users if run as an admin or has access to other user's reg keys) + var SIDs = RegistryHelper.GetUserSIDs(); + var account = new Dictionary(); + + foreach (var sid in SIDs) + { + if (!sid.StartsWith("S-1-5") || sid.EndsWith("_Classes")) // Disregard anything that isn't a user + continue; + + var oneDriveSyncProviderInfo = new OneDriveSyncProviderInfo(); + + // Now get each of the IDs (they aren't GUIDs but are an identity value for the specific library to sync) + var subKeys = RegistryHelper.GetRegSubkeys("HKU", $"{sid}\\Software\\SyncEngines\\Providers\\OneDrive"); + if (subKeys == null) + { + continue; + } + + // Now go through each of them, get the metadata and stick it in the 'provider' dict. It'll get cross referenced later. + foreach (string rname in subKeys) + { + var provider = new Dictionary(); + foreach (string x in new List { "LibraryType", "LastModifiedTime", "MountPoint", "UrlNamespace" }) + { + var result = RegistryHelper.GetRegValue("HKU", $"{sid}\\Software\\SyncEngines\\Providers\\OneDrive\\{rname}", x); + if (!string.IsNullOrEmpty(result)) + { + provider[x] = result; + } + } + oneDriveSyncProviderInfo.MpList[rname] = provider; + } + + var odAccounts = RegistryHelper.GetRegSubkeys("HKU", $"{sid}\\Software\\Microsoft\\OneDrive\\Accounts"); + if (odAccounts == null) + { + continue; + } + + foreach (string acc in odAccounts) + { + var business = false; + foreach (string x in keys) + { + var result = RegistryHelper.GetRegValue("HKU", $"{sid}\\Software\\Microsoft\\OneDrive\\Accounts\\{acc}", x); + if (!string.IsNullOrEmpty(result)) + { + account[x] = result; + } + + if (x == "Business") + { + business = (String.Compare(result, "1") == 0) ? true : false; + } + } + var odMountPoints = RegistryHelper.GetRegValues("HKU", $"{sid}\\Software\\Microsoft\\OneDrive\\Accounts\\{acc}\\ScopeIdToMountPointPathCache"); + var scopeIds = new List(); + + if (business) + { + scopeIds.AddRange(odMountPoints.Select(mp => mp.Key)); + } + else + { + scopeIds.Add(acc); // If its a personal account, OneDrive adds it as 'Personal' or the name of the account, not by the ScopeId itself. You can only have one personal account. + } + + oneDriveSyncProviderInfo.AccountToMountpointDict[acc] = scopeIds; + oneDriveSyncProviderInfo.OneDriveList[acc] = account; + oneDriveSyncProviderInfo.UsedScopeIDs.AddRange(scopeIds); + } + + yield return new CloudSyncProviderInfo(sid, oneDriveSyncProviderInfo); + } + } + + private static IEnumerable GetRecentOfficeFiles() + { + foreach (var sid in Registry.Users.GetSubKeyNames()) + { + if (!sid.StartsWith("S-1") || sid.EndsWith("_Classes")) + { + continue; + } + + string userName = null; + try + { + userName = Advapi32.TranslateSid(sid); + } + catch + { + userName = sid; + } + + var officeVersion = RegistryHelper.GetRegSubkeys("HKU", $"{sid}\\Software\\Microsoft\\Office") + ?.Where(k => float.TryParse(k, NumberStyles.AllowDecimalPoint, new CultureInfo("en-GB"), out _)); + + if (officeVersion is null) + { + continue; + } + + foreach (var version in officeVersion) + { + foreach (OfficeRecentFileInfo mru in GetMRUsFromVersionKey($"{sid}\\Software\\Microsoft\\Office\\{version}")) + { + //if (mru.LastAccessDate <= DateTime.Now.AddDays(-lastDays)) continue; + + mru.User = userName; + yield return mru; + } + } + } + } + + private static IEnumerable GetMRUsFromVersionKey(string officeVersionSubkeyPath) + { + var officeApplications = RegistryHelper.GetRegSubkeys("HKU", officeVersionSubkeyPath); + if (officeApplications == null) + { + yield break; + } + + foreach (var app in officeApplications) + { + // 1) HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\\File MRU + foreach (var mru in GetMRUsValues($"{officeVersionSubkeyPath}\\{app}\\File MRU")) + { + yield return mru; + } + + // 2) HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word\User MRU\ADAL_B7C22499E768F03875FA6C268E771D1493149B23934326A96F6CDFEEEE7F68DA72\File MRU + // or HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Word\User MRU\LiveId_CC4B824314B318B42E93BE93C46A61575D25608BBACDEEEA1D2919BCC2CF51FF\File MRU + + var logonAapps = RegistryHelper.GetRegSubkeys("HKU", $"{officeVersionSubkeyPath}\\{app}\\User MRU"); + if (logonAapps == null) + { + continue; + } + + foreach (var logonApp in logonAapps) + { + foreach (var mru in GetMRUsValues($"{officeVersionSubkeyPath}\\{app}\\User MRU\\{logonApp}\\File MRU")) + { + ((OfficeRecentFileInfo)mru).Application = app; + yield return mru; + } + } + } + } + + private static IEnumerable GetMRUsValues(string keyPath) + { + var values = RegistryHelper.GetRegValues("HKU", keyPath); + if (values == null) + { + yield break; + } + + foreach (var mruString in values.Values.Cast().Select(ParseMruString).Where(mruString => mruString != null)) + { + yield return mruString; + } + } + + private static OfficeRecentFileInfo ParseMruString(string mru) + { + var matches = Regex.Matches(mru, "\\[[a-zA-Z0-9]+?\\]\\[T([a-zA-Z0-9]+?)\\](\\[[a-zA-Z0-9]+?\\])?\\*(.+)"); + if (matches.Count == 0) + { + return null; + } + + long timestamp = 0; + var dateHexString = matches[0].Groups[1].Value; + var filename = matches[0].Groups[matches[0].Groups.Count - 1].Value; + + try + { + timestamp = long.Parse(dateHexString, NumberStyles.HexNumber); + } + catch + { + Beaprint.PrintException($"Could not parse MRU timestamp. Parsed timestamp: {dateHexString} MRU value: {mru}"); + } + + return new OfficeRecentFileInfo + { + Application = "Office", + User = null, + Target = filename, + LastAccessDate = DateTime.FromFileTimeUtc(timestamp), + }; + } + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OfficeRecentFileInfo.cs b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OfficeRecentFileInfo.cs new file mode 100644 index 0000000..3e631db --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OfficeRecentFileInfo.cs @@ -0,0 +1,12 @@ +using System; + +namespace winPEAS.Info.FilesInfo.Office +{ + internal class OfficeRecentFileInfo + { + public string Application { get; set; } + public string User { get; set; } + public string Target { get; set; } + public DateTime LastAccessDate { get; set; } + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/CloudSyncProviderInfo.cs b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/CloudSyncProviderInfo.cs new file mode 100644 index 0000000..daa93e7 --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/CloudSyncProviderInfo.cs @@ -0,0 +1,13 @@ +namespace winPEAS.Info.FilesInfo.Office.OneDrive +{ + internal class CloudSyncProviderInfo + { + public CloudSyncProviderInfo(string sid, OneDriveSyncProviderInfo oneDriveSyncProviderInfo) + { + Sid = sid; + OneDriveSyncProviderInfo = oneDriveSyncProviderInfo; + } + public string Sid { get; } + public OneDriveSyncProviderInfo OneDriveSyncProviderInfo { get; } + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/OneDriveSyncProviderInfo.cs b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/OneDriveSyncProviderInfo.cs new file mode 100644 index 0000000..1b14104 --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/Office/OneDrive/OneDriveSyncProviderInfo.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace winPEAS.Info.FilesInfo.Office.OneDrive +{ + internal class OneDriveSyncProviderInfo + { + // Stores the mapping between a sync ID and mount point + public Dictionary> MpList { get; set; } = new Dictionary>(); + // Stores the list of OneDrive accounts configured in the registry + public Dictionary> OneDriveList { get; set; } = new Dictionary>(); + // Stores the mapping between the account and the mountpoint IDs + public Dictionary> AccountToMountpointDict { get; set; } = new Dictionary>(); + // Stores the 'used' scopeIDs (to identify orphans) + public List UsedScopeIDs { get; set; } = new List(); + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/WSL/WSL.cs b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/WSL/WSL.cs index 749d60b..e9fd072 100644 --- a/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/WSL/WSL.cs +++ b/winPEAS/winPEASexe/winPEAS/Info/FilesInfo/WSL/WSL.cs @@ -13,14 +13,14 @@ namespace winPEAS.Info.FilesInfo.WSL $@"bash -c ""{linpeasCmd}""" : Environment.GetEnvironmentVariable("WinDir") + $"\\SysNative\\bash.exe -c \"{linpeasCmd}\""; - ExecuteCommandLine(command); + ExecuteCommand(command); } - private static void ExecuteCommandLine(string fullCommandLine, + private static void ExecuteCommand(string command, string workingFolder = null, string verb = "OPEN") { - string executable = fullCommandLine; + string executable = command; string args = null; if (executable.StartsWith("\"")) @@ -64,14 +64,12 @@ namespace winPEAS.Info.FilesInfo.WSL { while (!process.StandardOutput.EndOfStream) { - string line = process.StandardOutput.ReadLine(); - Console.WriteLine(line); + Console.WriteLine(process.StandardOutput.ReadLine()); } while (!process.StandardError.EndOfStream) { - string line = process.StandardError.ReadLine(); - Console.WriteLine(line); + Console.WriteLine(process.StandardError.ReadLine()); } } } diff --git a/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/JoinType.cs b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/JoinType.cs new file mode 100644 index 0000000..32e6311 --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/JoinType.cs @@ -0,0 +1,19 @@ +using System.ComponentModel; + +namespace winPEAS.Info.UserInfo.Tenant +{ + public enum JoinType + { + [Description("Unknown Join")] + DSREG_UNKNOWN_JOIN, + + [Description("Device Join")] + DSREG_DEVICE_JOIN, + + [Description("Workplace Join")] + DSREG_WORKPLACE_JOIN, + + [Description("No Join")] + DSREG_NO_JOIN + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/Tenant.cs b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/Tenant.cs new file mode 100644 index 0000000..9ba26ab --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/Tenant.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using winPEAS.Helpers; +using winPEAS.Native; +using winPEAS.Native.Structs; + +namespace winPEAS.Info.UserInfo.Tenant +{ + internal class Tenant + { + public static TenantInfo GetTenantInfo() + { + //original code from https://github.com/ThomasKur/WPNinjas.Dsregcmd/blob/2cff7b273ad4d3fc705744f76c4bd0701b2c36f0/WPNinjas.Dsregcmd/DsRegCmd.cs + + string tenantId = null; + var retValue = Netapi32.NetGetAadJoinInformation(tenantId, out var ptrJoinInfo); + if (retValue == 0) + { + var joinInfo = (DSREG_JOIN_INFO)Marshal.PtrToStructure(ptrJoinInfo, typeof(DSREG_JOIN_INFO)); + var jType = (JoinType)joinInfo.joinType; + var did = new Guid(joinInfo.DeviceId); + var tid = new Guid(joinInfo.TenantId); + + var data = Convert.FromBase64String(joinInfo.UserSettingSyncUrl); + var userSettingSyncUrl = Encoding.ASCII.GetString(data); + var ptrUserInfo = joinInfo.pUserInfo; + + DSREG_USER_INFO? userInfo = null; + var certificateResult = new List(); + Guid? uid = null; + + if (ptrUserInfo != IntPtr.Zero) + { + userInfo = (DSREG_USER_INFO)Marshal.PtrToStructure(ptrUserInfo, typeof(DSREG_USER_INFO)); + uid = new Guid(userInfo?.UserKeyId); + var store = new X509Store(StoreName.My, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadOnly); + + foreach (var certificate in store.Certificates) + { + if (certificate.Subject.Equals($"CN={did}")) + { + certificateResult.Add(certificate); + } + } + + Marshal.Release(ptrUserInfo); + } + + Marshal.Release(ptrJoinInfo); + Netapi32.NetFreeAadJoinInformation(ptrJoinInfo); + + return new TenantInfo( + jType, + did, + joinInfo.IdpDomain, + tid, + joinInfo.JoinUserEmail, + joinInfo.TenantDisplayName, + joinInfo.MdmEnrollmentUrl, + joinInfo.MdmTermsOfUseUrl, + joinInfo.MdmComplianceUrl, + userSettingSyncUrl, + certificateResult, + userInfo?.UserEmail, + uid, + userInfo?.UserKeyName + ); + } + + return null; + } + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/TenantInfo.cs b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/TenantInfo.cs new file mode 100644 index 0000000..045530f --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Info/UserInfo/Tenant/TenantInfo.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; + +namespace winPEAS.Info.UserInfo.Tenant +{ + internal class TenantInfo + { + public JoinType JType { get; } + public Guid DeviceId { get; } + public string IdpDomain { get; } + public Guid TenantId { get; } + public string JoinUserEmail { get; } + public string TenantDisplayName { get; } + public string MdmEnrollmentUrl { get; } + public string MdmTermsOfUseUrl { get; } + public string MdmComplianceUrl { get; } + public string UserSettingSyncUrl { get; } + public List CertInfo { get; } + public string UserEmail { get; } + public Guid? UserKeyId { get; } + public string UserKeyname { get; } + + public TenantInfo(JoinType jType, Guid deviceId, string idpDomain, Guid tenantId, string joinUserEmail, string tenantDisplayName, + string mdmEnrollmentUrl, string mdmTermsOfUseUrl, string mdmComplianceUrl, string userSettingSyncUrl, + List certInfo, string userEmail, Guid? userKeyId, string userKeyname) + { + JType = jType; + DeviceId = deviceId; + IdpDomain = idpDomain; + TenantId = tenantId; + JoinUserEmail = joinUserEmail; + TenantDisplayName = tenantDisplayName; + MdmEnrollmentUrl = mdmEnrollmentUrl; + MdmTermsOfUseUrl = mdmTermsOfUseUrl; + MdmComplianceUrl = mdmComplianceUrl; + UserSettingSyncUrl = userSettingSyncUrl; + CertInfo = certInfo; + UserEmail = userEmail; + UserKeyId = userKeyId; + UserKeyname = userKeyname; + } + } +} diff --git a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Putty.cs b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Putty.cs index 4849239..8f02d40 100644 --- a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Putty.cs +++ b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Putty.cs @@ -113,6 +113,7 @@ namespace winPEAS.KnownFileCreds "PublicKeyFile", "PortForwardings", "ConnectionSharing", + "AgentFwd", "ProxyPassword", "ProxyUsername", }; @@ -151,6 +152,7 @@ namespace winPEAS.KnownFileCreds "PublicKeyFile", "PortForwardings", "ConnectionSharing", + "AgentFwd", "ProxyPassword", "ProxyUsername", }; diff --git a/winPEAS/winPEASexe/winPEAS/Native/Advapi32.cs b/winPEAS/winPEASexe/winPEAS/Native/Advapi32.cs index 1aa8f05..3cde34e 100644 --- a/winPEAS/winPEASexe/winPEAS/Native/Advapi32.cs +++ b/winPEAS/winPEASexe/winPEAS/Native/Advapi32.cs @@ -2,8 +2,10 @@ using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.AccessControl; +using System.Security.Principal; using System.Text; using winPEAS.Helpers.CredentialManager; +using winPEAS.Info.NetworkInfo; using winPEAS.Native.Classes; using winPEAS.Native.Enums; using winPEAS.Native.Structs; @@ -209,5 +211,48 @@ namespace winPEAS.Native [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetThreadToken(IntPtr ThreadHandle, SafeTokenHandle TokenHandle); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern bool LookupAccountSid( + string? lpSystemName, + [MarshalAs(UnmanagedType.LPArray)] byte[] Sid, + StringBuilder lpName, + ref uint cchName, + StringBuilder ReferencedDomainName, + ref uint cchReferencedDomainName, + out SID_NAME_USE peUse); + + public static string TranslateSid(string sid) + { + // adapted from http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid + var accountSid = new SecurityIdentifier(sid); + var accountSidByes = new byte[accountSid.BinaryLength]; + accountSid.GetBinaryForm(accountSidByes, 0); + + var name = new StringBuilder(); + var cchName = (uint)name.Capacity; + var referencedDomainName = new StringBuilder(); + var cchReferencedDomainName = (uint)referencedDomainName.Capacity; + + var err = 0; + if (!LookupAccountSid(null, accountSidByes, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out var sidUse)) + { + err = Marshal.GetLastWin32Error(); + + if (err == Win32Error.InsufficientBuffer) + { + name.EnsureCapacity((int)cchName); + referencedDomainName.EnsureCapacity((int)cchReferencedDomainName); + err = 0; + if (!LookupAccountSid(null, accountSidByes, name, ref cchName, referencedDomainName, + ref cchReferencedDomainName, out sidUse)) + { + err = Marshal.GetLastWin32Error(); + } + } + } + + return err == 0 ? $"{referencedDomainName}\\{name}" : ""; + } } } diff --git a/winPEAS/winPEASexe/winPEAS/Native/Enums/SID_NAME_USE.cs b/winPEAS/winPEASexe/winPEAS/Native/Enums/SID_NAME_USE.cs new file mode 100644 index 0000000..88b7399 --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Native/Enums/SID_NAME_USE.cs @@ -0,0 +1,15 @@ +namespace winPEAS.Native.Enums +{ + public enum SID_NAME_USE + { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown, + SidTypeComputer + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Native/Netapi32.cs b/winPEAS/winPEASexe/winPEAS/Native/Netapi32.cs index 57224db..f265154 100644 --- a/winPEAS/winPEASexe/winPEAS/Native/Netapi32.cs +++ b/winPEAS/winPEASexe/winPEAS/Native/Netapi32.cs @@ -42,5 +42,11 @@ namespace winPEAS.Native out uint entriesRead, out uint totalEntries, out IntPtr resumeHandle); + + [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern void NetFreeAadJoinInformation(IntPtr pJoinInfo); + + [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern int NetGetAadJoinInformation(string pcszTenantId, out IntPtr ppJoinInfo); } } diff --git a/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_JOIN_INFO.cs b/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_JOIN_INFO.cs new file mode 100644 index 0000000..c182ccb --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_JOIN_INFO.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; + +namespace winPEAS.Native.Structs +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct DSREG_JOIN_INFO + { + public int joinType; + public IntPtr pJoinCertificate; + [MarshalAs(UnmanagedType.LPWStr)] public string DeviceId; + [MarshalAs(UnmanagedType.LPWStr)] public string IdpDomain; + [MarshalAs(UnmanagedType.LPWStr)] public string TenantId; + [MarshalAs(UnmanagedType.LPWStr)] public string JoinUserEmail; + [MarshalAs(UnmanagedType.LPWStr)] public string TenantDisplayName; + [MarshalAs(UnmanagedType.LPWStr)] public string MdmEnrollmentUrl; + [MarshalAs(UnmanagedType.LPWStr)] public string MdmTermsOfUseUrl; + [MarshalAs(UnmanagedType.LPWStr)] public string MdmComplianceUrl; + [MarshalAs(UnmanagedType.LPWStr)] public string UserSettingSyncUrl; + public IntPtr pUserInfo; + } +} diff --git a/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_USER_INFO.cs b/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_USER_INFO.cs new file mode 100644 index 0000000..4c6689c --- /dev/null +++ b/winPEAS/winPEASexe/winPEAS/Native/Structs/DSREG_USER_INFO.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace winPEAS.Native.Structs +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct DSREG_USER_INFO + { + [MarshalAs(UnmanagedType.LPWStr)] public string UserEmail; + [MarshalAs(UnmanagedType.LPWStr)] public string UserKeyId; + [MarshalAs(UnmanagedType.LPWStr)] public string UserKeyName; + } +} diff --git a/winPEAS/winPEASexe/winPEAS/winPEAS.csproj b/winPEAS/winPEASexe/winPEAS/winPEAS.csproj index 1eb61c0..e5c1b3f 100755 --- a/winPEAS/winPEASexe/winPEAS/winPEAS.csproj +++ b/winPEAS/winPEASexe/winPEAS/winPEAS.csproj @@ -417,6 +417,10 @@ + + + + @@ -460,6 +464,9 @@ + + + @@ -523,6 +530,7 @@ + @@ -535,6 +543,8 @@ + +