Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions winPEAS/winPEASexe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
145 changes: 145 additions & 0 deletions winPEAS/winPEASexe/winPEAS/Checks/ServicesInfo.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -34,6 +36,8 @@ public void PrintInfo(bool isDebug)
PrintModifiableServices,
PrintWritableRegServices,
PrintPathDllHijacking,
PrintLegacySignedKernelDrivers,
PrintKernelQuickIndicators,
}.ForEach(action => CheckRunner.Run(action, isDebug));
}

Expand Down Expand Up @@ -206,5 +210,146 @@ void PrintPathDllHijacking()
}
}


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<ServicesInfoHelper.KernelDriverInfo> 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<string> reasons = new List<string>();

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<string, object> 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<string, object> 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<string, object> 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";
}
}
}

106 changes: 106 additions & 0 deletions winPEAS/winPEASexe/winPEAS/Info/ServicesInfo/ServicesInfoHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -276,6 +279,109 @@ public static List<Dictionary<string, string>> GetWriteServiceRegs(Dictionary<st
}


private static readonly DateTime LegacyDriverCutoff = new DateTime(2015, 7, 29);

public static List<KernelDriverInfo> GetKernelDriverInfos()
{
List<KernelDriverInfo> drivers = new List<KernelDriverInfo>();

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 /////////
//////////////////////////////////////
Expand Down
Loading