430 lines
17 KiB
C#
430 lines
17 KiB
C#
using System;
|
|
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;
|
|
using winPEAS.Native.Structs;
|
|
|
|
namespace winPEAS.Checks
|
|
{
|
|
internal class UserInfo : ISystemCheck
|
|
{
|
|
/* Colors Code
|
|
* RED:
|
|
* ---- Privileges users and groups names
|
|
* MAGENTA:
|
|
* ---- Current user and domain
|
|
* BLUE:
|
|
* ---- Locked users
|
|
* CYAN:
|
|
* ---- Active users
|
|
* MediumPurple:
|
|
* ---- Disabled users
|
|
*/
|
|
|
|
|
|
static string badgroups = "docker|Remote |DNSAdmins|AD Recycle Bin|Azure Admins|Admins|Server Operators";//The space in Remote is important to not mix with SeShutdownRemotePrivilege
|
|
static readonly string _badPasswd = "NotChange|NotExpi";
|
|
static readonly string _badPrivileges = "SeImpersonatePrivilege|SeAssignPrimaryPrivilege|SeTcbPrivilege|SeBackupPrivilege|SeRestorePrivilege|SeCreateTokenPrivilege|SeLoadDriverPrivilege|SeTakeOwnershipPrivilege|SeDebugPrivilege";
|
|
|
|
public void PrintInfo(bool isDebug)
|
|
{
|
|
Beaprint.GreatPrint("Users Information");
|
|
|
|
new List<Action>
|
|
{
|
|
PrintCU,
|
|
PrintCurrentUserIdleTime,
|
|
PrintCurrentTenantInfo,
|
|
PrintTokenP,
|
|
PrintClipboardText,
|
|
PrintLoggedUsers,
|
|
PrintLocalUsers,
|
|
PrintRdpSessions,
|
|
PrintEverLoggedUsers,
|
|
PrintHomeFolders,
|
|
PrintAutoLogin,
|
|
PrintPasswordPolicies,
|
|
PrintLogonSessions
|
|
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
|
}
|
|
|
|
Dictionary<string, string> ColorsU()
|
|
{
|
|
var usersColors = new Dictionary<string, string>()
|
|
{
|
|
{ Checks.PaintActiveUsersNoAdministrator, Beaprint.ansi_users_active },
|
|
{ Checks.CurrentUserName + "|"+ Checks.CurrentUserDomainName, Beaprint.ansi_current_user },
|
|
{ Checks.PaintAdminUsers+"|"+ badgroups + "|" + _badPasswd + "|" + _badPrivileges + "|" + "DefaultPassword.*", Beaprint.ansi_color_bad },
|
|
{ @"Disabled", Beaprint.ansi_users_disabled },
|
|
};
|
|
|
|
if (Checks.PaintDisabledUsers.Length > 1)
|
|
{
|
|
usersColors[Checks.PaintDisabledUsersNoAdministrator] = Beaprint.ansi_users_disabled;
|
|
}
|
|
return usersColors;
|
|
}
|
|
|
|
void PrintCU()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Users");
|
|
Beaprint.LinkPrint("https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#users-and-groups", "Check if you have some admin equivalent privileges");
|
|
|
|
List<string> usersGrps = User.GetMachineUsers(false, false, false, false, true);
|
|
|
|
Beaprint.AnsiPrint(" Current user: " + Checks.CurrentUserName, ColorsU());
|
|
|
|
List<string> currentGroupsNames = new List<string>();
|
|
foreach (KeyValuePair<string, string> g in Checks.CurrentUserSiDs)
|
|
{
|
|
if (g.Key == WindowsIdentity.GetCurrent().User.ToString())
|
|
{
|
|
continue;
|
|
}
|
|
currentGroupsNames.Add(string.IsNullOrEmpty(g.Value) ? g.Key : g.Value);
|
|
}
|
|
|
|
Beaprint.AnsiPrint(" Current groups: " + string.Join(", ", currentGroupsNames), ColorsU());
|
|
Beaprint.PrintLineSeparator();
|
|
Beaprint.ListPrint(usersGrps, ColorsU());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintTokenP()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Current Token privileges");
|
|
Beaprint.LinkPrint("https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#token-manipulation", "Check if you can escalate privilege using some enabled token");
|
|
Dictionary<string, string> tokenPrivs = Token.GetTokenGroupPrivs();
|
|
Beaprint.DictPrint(tokenPrivs, ColorsU(), false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintClipboardText()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Clipboard text");
|
|
string clipboard = UserInfoHelper.GetClipboardText();
|
|
if (!string.IsNullOrEmpty(clipboard))
|
|
{
|
|
Beaprint.BadPrint(clipboard);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintLoggedUsers()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Logged users");
|
|
List<string> loggedUsers = User.GetLoggedUsers();
|
|
|
|
Beaprint.ListPrint(loggedUsers, ColorsU());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintRdpSessions()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("RDP Sessions");
|
|
List<Dictionary<string, string>> rdp_sessions = Info.UserInfo.UserInfoHelper.GetRDPSessions();
|
|
if (rdp_sessions.Count > 0)
|
|
{
|
|
string format = " {0,-10}{1,-15}{2,-15}{3,-25}{4,-10}{5}";
|
|
string header = string.Format(format, "SessID", "pSessionName", "pUserName", "pDomainName", "State", "SourceIP");
|
|
Beaprint.GrayPrint(header);
|
|
foreach (Dictionary<string, string> rdpSes in rdp_sessions)
|
|
{
|
|
Beaprint.AnsiPrint(string.Format(format, rdpSes["SessionID"], rdpSes["pSessionName"], rdpSes["pUserName"], rdpSes["pDomainName"], rdpSes["State"], rdpSes["SourceIP"]), ColorsU());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Beaprint.NotFoundPrint();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintEverLoggedUsers()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Ever logged users");
|
|
List<string> everLogged = User.GetEverLoggedUsers();
|
|
Beaprint.ListPrint(everLogged, ColorsU());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintHomeFolders()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Home folders found");
|
|
List<string> user_folders = User.GetUsersFolders();
|
|
foreach (string ufold in user_folders)
|
|
{
|
|
string perms = string.Join(", ", PermissionsHelper.GetPermissionsFolder(ufold, Checks.CurrentUserSiDs));
|
|
if (perms.Length > 0)
|
|
{
|
|
Beaprint.BadPrint(" " + ufold + " : " + perms);
|
|
}
|
|
else
|
|
{
|
|
Beaprint.GoodPrint(" " + ufold);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintAutoLogin()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Looking for AutoLogon credentials");
|
|
bool ban = false;
|
|
Dictionary<string, string> autologon = UserInfoHelper.GetAutoLogon();
|
|
if (autologon.Count > 0)
|
|
{
|
|
foreach (KeyValuePair<string, string> entry in autologon)
|
|
{
|
|
if (!string.IsNullOrEmpty(entry.Value))
|
|
{
|
|
if (!ban)
|
|
{
|
|
Beaprint.BadPrint(" Some AutoLogon credentials were found");
|
|
ban = true;
|
|
}
|
|
Beaprint.AnsiPrint(string.Format(" {0,-30}: {1}", entry.Key, entry.Value), ColorsU());
|
|
}
|
|
}
|
|
|
|
if (!ban)
|
|
{
|
|
Beaprint.NotFoundPrint();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Beaprint.NotFoundPrint();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
void PrintPasswordPolicies()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Password Policies");
|
|
Beaprint.LinkPrint("", "Check for a possible brute-force");
|
|
List<Dictionary<string, string>> PPy = Info.UserInfo.UserInfoHelper.GetPasswordPolicy();
|
|
Beaprint.DictPrint(PPy, ColorsU(), false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Beaprint.PrintException(ex.Message);
|
|
}
|
|
}
|
|
|
|
private void PrintLogonSessions()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Print Logon Sessions");
|
|
|
|
var logonSessions = LogonSessions.GetLogonSessions();
|
|
|
|
foreach (var logonSession in logonSessions)
|
|
{
|
|
Beaprint.NoColorPrint ($" Method: {logonSession.Method}\n" +
|
|
$" Logon Server: {logonSession.LogonServer}\n" +
|
|
$" Logon Server Dns Domain: {logonSession.LogonServerDnsDomain}\n" +
|
|
$" Logon Id: {logonSession.LogonId}\n" +
|
|
$" Logon Time: {logonSession.LogonTime}\n" +
|
|
$" Logon Type: {logonSession.LogonType}\n" +
|
|
$" Start Time: {logonSession.StartTime}\n" +
|
|
$" Domain: {logonSession.Domain}\n" +
|
|
$" Authentication Package: {logonSession.AuthenticationPackage}\n" +
|
|
$" Start Time: {logonSession.StartTime}\n" +
|
|
$" User Name: {logonSession.UserName}\n" +
|
|
$" User Principal Name: {logonSession.UserPrincipalName}\n" +
|
|
$" User SID: {logonSession.UserSID}\n"
|
|
);
|
|
|
|
Beaprint.PrintLineSeparator();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void PrintCurrentUserIdleTime()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Current User Idle Time");
|
|
|
|
var lastInputInfo = new LastInputInfo();
|
|
lastInputInfo.Size = (uint)Marshal.SizeOf(lastInputInfo);
|
|
|
|
if (User32.GetLastInputInfo(ref lastInputInfo))
|
|
{
|
|
var currentUser = WindowsIdentity.GetCurrent().Name;
|
|
var idleTimeMiliSeconds = (uint) Environment.TickCount - lastInputInfo.Time;
|
|
var timeSpan = TimeSpan.FromMilliseconds(idleTimeMiliSeconds);
|
|
var idleTimeString = $"{timeSpan.Hours:D2}h:{timeSpan.Minutes:D2}m:{timeSpan.Seconds:D2}s:{timeSpan.Milliseconds:D3}ms";
|
|
|
|
Beaprint.NoColorPrint($" Current User : {currentUser}\n" +
|
|
$" Idle Time : {idleTimeString}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void PrintLocalUsers()
|
|
{
|
|
try
|
|
{
|
|
Beaprint.MainPrint("Display information about local users");
|
|
|
|
var computerName = Environment.GetEnvironmentVariable("COMPUTERNAME");
|
|
|
|
var localUsers = User.GetLocalUsers(computerName);
|
|
|
|
var colors = new Dictionary<string, string>
|
|
{
|
|
{ "Administrator", Beaprint.ansi_color_bad },
|
|
{ "Guest", Beaprint.YELLOW },
|
|
{ "False", Beaprint.ansi_color_good },
|
|
{ "True", Beaprint.ansi_color_bad },
|
|
};
|
|
|
|
foreach (var localUser in localUsers)
|
|
{
|
|
var enabled = ((localUser.flags >> 1) & 1) == 0;
|
|
var pwdLastSet = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
var lastLogon = new DateTime(1970, 1, 1, 0, 0, 0);
|
|
|
|
if (localUser.passwordAge != 0)
|
|
{
|
|
pwdLastSet = DateTime.Now.AddSeconds(-localUser.passwordAge);
|
|
}
|
|
|
|
if (localUser.last_logon != 0)
|
|
{
|
|
lastLogon = lastLogon.AddSeconds(localUser.last_logon).ToLocalTime();
|
|
}
|
|
|
|
Beaprint.AnsiPrint( $" Computer Name : {computerName}\n" +
|
|
$" User Name : {localUser.name}\n" +
|
|
$" User Id : {localUser.user_id}\n" +
|
|
$" Is Enabled : {enabled}\n" +
|
|
$" User Type : {(UserPrivType)localUser.priv}\n" +
|
|
$" Comment : {localUser.comment}\n" +
|
|
$" Last Logon : {lastLogon}\n" +
|
|
$" Logons Count : {localUser.num_logons}\n" +
|
|
$" Password Last Set : {pwdLastSet}\n",
|
|
colors);
|
|
|
|
Beaprint.PrintLineSeparator();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|