mirror of
https://github.com/peass-ng/PEASS-ng.git
synced 2025-12-12 07:40:39 -08:00
Add winpeas privilege escalation checks from: Cracking ValleyRAT: From Builder Secrets to Kernel Rootkits
This commit is contained in:
@@ -76,6 +76,7 @@ The goal of this project is to search for possible **Privilege Escalation Paths*
|
|||||||
|
|
||||||
New in this version:
|
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.
|
- 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).
|
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).
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using winPEAS.Helpers;
|
using winPEAS.Helpers;
|
||||||
|
using winPEAS.Helpers.Registry;
|
||||||
using winPEAS.Info.ServicesInfo;
|
using winPEAS.Info.ServicesInfo;
|
||||||
|
|
||||||
namespace winPEAS.Checks
|
namespace winPEAS.Checks
|
||||||
@@ -34,6 +36,8 @@ namespace winPEAS.Checks
|
|||||||
PrintModifiableServices,
|
PrintModifiableServices,
|
||||||
PrintWritableRegServices,
|
PrintWritableRegServices,
|
||||||
PrintPathDllHijacking,
|
PrintPathDllHijacking,
|
||||||
|
PrintLegacySignedKernelDrivers,
|
||||||
|
PrintKernelQuickIndicators,
|
||||||
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
}.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<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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using winPEAS.Helpers;
|
using winPEAS.Helpers;
|
||||||
@@ -276,6 +279,109 @@ namespace winPEAS.Info.ServicesInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 /////////
|
//////// PATH DLL Hijacking /////////
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|||||||
Reference in New Issue
Block a user