From 9123910f9da88caa8fd899ea56498c19ade4fb65 Mon Sep 17 00:00:00 2001 From: HackTricks News Bot Date: Wed, 10 Dec 2025 19:18:07 +0000 Subject: [PATCH] Add winpeas privilege escalation checks from: Cracking ValleyRAT: From Builder Secrets to Kernel Rootkits --- winPEAS/winPEASexe/README.md | 1 + .../winPEASexe/winPEAS/Checks/ServicesInfo.cs | 145 ++++++++++++++++++ .../Info/ServicesInfo/ServicesInfoHelper.cs | 106 +++++++++++++ 3 files changed, 252 insertions(+) diff --git a/winPEAS/winPEASexe/README.md b/winPEAS/winPEASexe/README.md index 8dd211c..f1c806d 100755 --- a/winPEAS/winPEASexe/README.md +++ b/winPEAS/winPEASexe/README.md @@ -76,6 +76,7 @@ The goal of this project is to search for possible **Privilege Escalation Paths* New in this version: - Detect potential GPO abuse by flagging writable SYSVOL paths for GPOs applied to the current host and by highlighting membership in the "Group Policy Creator Owners" group. +- Flag legacy/expired-signed kernel drivers (e.g., ValleyRAT's kernelquick) and their registry-controlled stealth configuration so you can spot kernel-level persistence. It should take only a **few seconds** to execute almost all the checks and **some seconds/minutes during the lasts checks searching for known filenames** that could contain passwords (the time depened on the number of files in your home folder). By default only **some** filenames that could contain credentials are searched, you can use the **searchall** parameter to search all the list (this could will add some minutes). diff --git a/winPEAS/winPEASexe/winPEAS/Checks/ServicesInfo.cs b/winPEAS/winPEASexe/winPEAS/Checks/ServicesInfo.cs index 739be63..1905d6b 100644 --- a/winPEAS/winPEASexe/winPEAS/Checks/ServicesInfo.cs +++ b/winPEAS/winPEASexe/winPEAS/Checks/ServicesInfo.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using winPEAS.Helpers; +using winPEAS.Helpers.Registry; using winPEAS.Info.ServicesInfo; namespace winPEAS.Checks @@ -34,6 +36,8 @@ namespace winPEAS.Checks PrintModifiableServices, PrintWritableRegServices, PrintPathDllHijacking, + PrintLegacySignedKernelDrivers, + PrintKernelQuickIndicators, }.ForEach(action => CheckRunner.Run(action, isDebug)); } @@ -206,5 +210,146 @@ namespace winPEAS.Checks } } + + void PrintLegacySignedKernelDrivers() + { + try + { + Beaprint.MainPrint("Kernel drivers with weak/legacy signatures"); + Beaprint.LinkPrint("https://research.checkpoint.com/2025/cracking-valleyrat-from-builder-secrets-to-kernel-rootkits/", + "Legacy cross-signed drivers (pre-July-2015) can still grant kernel execution on modern Windows"); + + List drivers = ServicesInfoHelper.GetKernelDriverInfos(); + if (drivers.Count == 0) + { + Beaprint.InfoPrint(" Unable to enumerate kernel services"); + return; + } + + var suspiciousDrivers = drivers.Where(d => d.Signature != null && (!d.Signature.IsSigned || d.Signature.IsLegacyExpired)) + .OrderBy(d => d.Name) + .ToList(); + + if (suspiciousDrivers.Count == 0) + { + Beaprint.InfoPrint(" No unsigned or legacy-signed kernel drivers detected"); + return; + } + + foreach (var driver in suspiciousDrivers) + { + var signature = driver.Signature ?? new ServicesInfoHelper.KernelDriverSignatureInfo(); + List reasons = new List(); + + if (!signature.IsSigned) + { + reasons.Add("unsigned or signature missing"); + } + else if (signature.IsLegacyExpired) + { + reasons.Add("signed with certificate that expired before 29-Jul-2015 (legacy exception)"); + } + + if (!string.IsNullOrEmpty(driver.StartMode) && + (driver.StartMode.Equals("System", StringComparison.OrdinalIgnoreCase) || + driver.StartMode.Equals("Boot", StringComparison.OrdinalIgnoreCase))) + { + reasons.Add($"loads at early boot (Start={driver.StartMode})"); + } + + if (string.Equals(driver.Name, "kernelquick", StringComparison.OrdinalIgnoreCase)) + { + reasons.Add("service name matches ValleyRAT rootkit loader"); + } + + string reason = reasons.Count > 0 ? string.Join("; ", reasons) : "Potentially risky driver"; + string signatureLine = signature.IsSigned + ? $"Subject: {signature.Subject}; Issuer: {signature.Issuer}; Valid: {FormatDate(signature.NotBefore)} - {FormatDate(signature.NotAfter)}" + : $"Signature issue: {signature.Error ?? "Unsigned"}"; + + Beaprint.BadPrint($" {driver.Name} ({driver.DisplayName})"); + Beaprint.NoColorPrint($" Path : {driver.PathName}"); + Beaprint.NoColorPrint($" Start/State: {driver.StartMode}/{driver.State}"); + Beaprint.NoColorPrint($" Reason : {reason}"); + Beaprint.NoColorPrint($" Signature : {signatureLine}"); + } + } + catch (Exception ex) + { + Beaprint.PrintException(ex.Message); + } + } + + void PrintKernelQuickIndicators() + { + try + { + Beaprint.MainPrint("KernelQuick / ValleyRAT rootkit indicators"); + + bool found = false; + + Dictionary serviceValues = RegistryHelper.GetRegValues("HKLM", @"SYSTEM\\CurrentControlSet\\Services\\kernelquick"); + if (serviceValues != null) + { + found = true; + string imagePath = serviceValues.ContainsKey("ImagePath") ? serviceValues["ImagePath"].ToString() : "Unknown"; + string start = serviceValues.ContainsKey("Start") ? serviceValues["Start"].ToString() : "Unknown"; + Beaprint.BadPrint(" Service HKLM\\SYSTEM\\CurrentControlSet\\Services\\kernelquick present"); + Beaprint.NoColorPrint($" ImagePath : {imagePath}"); + Beaprint.NoColorPrint($" Start : {start}"); + } + + foreach (var path in new[] { @"SOFTWARE\\KernelQuick", @"SOFTWARE\\WOW6432Node\\KernelQuick", @"SYSTEM\\CurrentControlSet\\Services\\kernelquick" }) + { + Dictionary values = RegistryHelper.GetRegValues("HKLM", path); + if (values == null) + continue; + + var kernelQuickValues = values.Where(k => k.Key.StartsWith("KernelQuick_", StringComparison.OrdinalIgnoreCase)).ToList(); + if (kernelQuickValues.Count == 0) + continue; + + found = true; + Beaprint.BadPrint($" Registry values under HKLM\\{path}"); + foreach (var kv in kernelQuickValues) + { + string displayValue = kv.Value is byte[] bytes ? $"(binary) {bytes.Length} bytes" : string.Format("{0}", kv.Value); + Beaprint.NoColorPrint($" {kv.Key} = {displayValue}"); + } + } + + Dictionary ipdatesValues = RegistryHelper.GetRegValues("HKLM", @"SOFTWARE\\IpDates"); + if (ipdatesValues != null) + { + found = true; + Beaprint.BadPrint(" Possible kernel shellcode staging key HKLM\\SOFTWARE\\IpDates"); + foreach (var kv in ipdatesValues) + { + string displayValue = kv.Value is byte[] bytes ? $"(binary) {bytes.Length} bytes" : string.Format("{0}", kv.Value); + Beaprint.NoColorPrint($" {kv.Key} = {displayValue}"); + } + } + + if (!found) + { + Beaprint.InfoPrint(" No KernelQuick-specific registry indicators were found"); + } + else + { + Beaprint.LinkPrint("https://research.checkpoint.com/2025/cracking-valleyrat-from-builder-secrets-to-kernel-rootkits/", + "KernelQuick_* values and HKLM\\SOFTWARE\\IpDates are used by the ValleyRAT rootkit to hide files and stage APC payloads"); + } + } + catch (Exception ex) + { + Beaprint.PrintException(ex.Message); + } + } + + private string FormatDate(DateTime? dateTime) + { + return dateTime.HasValue ? dateTime.Value.ToString("yyyy-MM-dd HH:mm") : "n/a"; + } } } + diff --git a/winPEAS/winPEASexe/winPEAS/Info/ServicesInfo/ServicesInfoHelper.cs b/winPEAS/winPEASexe/winPEAS/Info/ServicesInfo/ServicesInfoHelper.cs index 324ecfc..3277084 100644 --- a/winPEAS/winPEASexe/winPEAS/Info/ServicesInfo/ServicesInfoHelper.cs +++ b/winPEAS/winPEASexe/winPEAS/Info/ServicesInfo/ServicesInfoHelper.cs @@ -2,11 +2,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Management; using System.Reflection; using System.Runtime.InteropServices; using System.Security.AccessControl; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; using System.ServiceProcess; using System.Text.RegularExpressions; using winPEAS.Helpers; @@ -276,6 +279,109 @@ namespace winPEAS.Info.ServicesInfo } + private static readonly DateTime LegacyDriverCutoff = new DateTime(2015, 7, 29); + + public static List GetKernelDriverInfos() + { + List drivers = new List(); + + try + { + using (ManagementObjectSearcher wmiData = new ManagementObjectSearcher(@"root\cimv2", "SELECT Name,DisplayName,PathName,StartMode,State,ServiceType FROM win32_service")) + { + using (ManagementObjectCollection data = wmiData.Get()) + { + foreach (ManagementObject result in data) + { + string serviceType = GetStringOrEmpty(result["ServiceType"]); + if (string.IsNullOrEmpty(serviceType) || !serviceType.ToLowerInvariant().Contains("kernel driver")) + continue; + + string binaryPath = MyUtils.ReconstructExecPath(GetStringOrEmpty(result["PathName"])); + + drivers.Add(new KernelDriverInfo + { + Name = GetStringOrEmpty(result["Name"]), + DisplayName = GetStringOrEmpty(result["DisplayName"]), + StartMode = GetStringOrEmpty(result["StartMode"]), + State = GetStringOrEmpty(result["State"]), + PathName = binaryPath, + Signature = GetDriverSignatureInfo(binaryPath) + }); + } + } + } + } + catch (Exception ex) + { + Beaprint.PrintException(ex.Message); + } + + return drivers; + } + + private static KernelDriverSignatureInfo GetDriverSignatureInfo(string binaryPath) + { + KernelDriverSignatureInfo info = new KernelDriverSignatureInfo + { + FilePath = binaryPath, + IsSigned = false + }; + + if (string.IsNullOrEmpty(binaryPath) || !File.Exists(binaryPath)) + { + info.Error = "Binary not found"; + return info; + } + + try + { + using (var baseCertificate = X509Certificate.CreateFromSignedFile(binaryPath)) + using (var certificate = new X509Certificate2(baseCertificate)) + { + info.IsSigned = true; + info.Subject = certificate.Subject; + info.Issuer = certificate.Issuer; + info.NotBefore = certificate.NotBefore; + info.NotAfter = certificate.NotAfter; + info.IsLegacyExpired = certificate.NotAfter < LegacyDriverCutoff; + } + } + catch (CryptographicException cryptoEx) + { + info.Error = cryptoEx.Message; + } + catch (Exception ex) + { + info.Error = ex.Message; + } + + return info; + } + + internal class KernelDriverInfo + { + public string Name { get; set; } + public string DisplayName { get; set; } + public string PathName { get; set; } + public string StartMode { get; set; } + public string State { get; set; } + public KernelDriverSignatureInfo Signature { get; set; } + } + + internal class KernelDriverSignatureInfo + { + public string FilePath { get; set; } + public bool IsSigned { get; set; } + public string Subject { get; set; } + public string Issuer { get; set; } + public DateTime? NotBefore { get; set; } + public DateTime? NotAfter { get; set; } + public bool IsLegacyExpired { get; set; } + public string Error { get; set; } + } + + ////////////////////////////////////// //////// PATH DLL Hijacking ///////// //////////////////////////////////////