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.
- Detect SOAPwn-style .NET HTTP client proxies by flagging high-privilege services/processes that embed SoapHttpClientProtocol or ServiceDescriptionImporter indicators.


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
1 change: 1 addition & 0 deletions winPEAS/winPEASexe/winPEAS/Checks/Checks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ internal static void Run(string[] args)
new SystemCheck("userinfo", new UserInfo()),
new SystemCheck("processinfo", new ProcessInfo()),
new SystemCheck("servicesinfo", new ServicesInfo()),
new SystemCheck("soapclientinfo", new SoapClientInfo()),
new SystemCheck("applicationsinfo", new ApplicationsInfo()),
new SystemCheck("networkinfo", new NetworkInfo()),
new SystemCheck("activedirectoryinfo", new ActiveDirectoryInfo()),
Expand Down
88 changes: 88 additions & 0 deletions winPEAS/winPEASexe/winPEAS/Checks/SoapClientInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using winPEAS.Helpers;
using winPEAS.Info.ApplicationInfo;

namespace winPEAS.Checks
{
internal class SoapClientInfo : ISystemCheck
{
public void PrintInfo(bool isDebug)
{
Beaprint.GreatPrint(".NET SOAP Client Proxies (SOAPwn)");

CheckRunner.Run(PrintSoapClientFindings, isDebug);
}

private static void PrintSoapClientFindings()
{
try
{
Beaprint.MainPrint("Potential SOAPwn / HttpWebClientProtocol abuse surfaces");
Beaprint.LinkPrint(
"https://labs.watchtowr.com/soapwn-pwning-net-framework-applications-through-http-client-proxies-and-wsdl/",
"Look for .NET services that let attackers control SoapHttpClientProtocol URLs or WSDL imports to coerce NTLM or drop files.");

List<SoapClientProxyFinding> findings = SoapClientProxyAnalyzer.CollectFindings();
if (findings.Count == 0)
{
Beaprint.NotFoundPrint();
return;
}

foreach (SoapClientProxyFinding finding in findings)
{
string severity = finding.BinaryIndicators.Contains("ServiceDescriptionImporter")
? "Dynamic WSDL import"
: "SOAP proxy usage";

Beaprint.BadPrint($" [{severity}] {finding.BinaryPath}");

foreach (SoapClientProxyInstance instance in finding.Instances)
{
string instanceInfo = $" -> {instance.SourceType}: {instance.Name}";
if (!string.IsNullOrEmpty(instance.Account))
{
instanceInfo += $" ({instance.Account})";
}
if (!string.IsNullOrEmpty(instance.Extra))
{
instanceInfo += $" | {instance.Extra}";
}

Beaprint.GrayPrint(instanceInfo);
}

if (finding.BinaryIndicators.Count > 0)
{
Beaprint.BadPrint(" Binary indicators: " + string.Join(", ", finding.BinaryIndicators));
}

if (finding.ConfigIndicators.Count > 0)
{
string configLabel = string.IsNullOrEmpty(finding.ConfigPath)
? "Config indicators"
: $"Config indicators ({finding.ConfigPath})";
Beaprint.BadPrint(" " + configLabel + ": " + string.Join(", ", finding.ConfigIndicators));
}

if (finding.BinaryScanFailed)
{
Beaprint.GrayPrint(" (Binary scan skipped due to access/size limits)");
}

if (finding.ConfigScanFailed)
{
Beaprint.GrayPrint(" (Unable to read config file)");
}

Beaprint.PrintLineSeparator();
}
}
catch (Exception ex)
{
Beaprint.PrintException(ex.Message);
}
}
}
}
63 changes: 39 additions & 24 deletions winPEAS/winPEASexe/winPEAS/Helpers/MyUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,51 @@ public static string GetCLSIDBinPath(string CLSID)
////////////////////////////////////
/////// MISC - Files & Paths ///////
////////////////////////////////////
public static bool CheckIfDotNet(string path)
public static bool CheckIfDotNet(string path, bool ignoreCompanyName = false)
{
bool isDotNet = false;
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(path);
string companyName = myFileVersionInfo.CompanyName;
if ((string.IsNullOrEmpty(companyName)) ||
(!Regex.IsMatch(companyName, @"^Microsoft.*", RegexOptions.IgnoreCase)))
string companyName = string.Empty;

try
{
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(path);
companyName = myFileVersionInfo.CompanyName;
}
catch
{
// Unable to read version information, continue with assembly inspection
}

bool shouldInspectAssembly = ignoreCompanyName ||
(string.IsNullOrEmpty(companyName)) ||
(!Regex.IsMatch(companyName, @"^Microsoft.*", RegexOptions.IgnoreCase));

if (!shouldInspectAssembly)
{
try
return false;
}

try
{
AssemblyName.GetAssemblyName(path);
isDotNet = true;
}
catch (System.IO.FileNotFoundException)
{
// System.Console.WriteLine("The file cannot be found.");
}
catch (System.BadImageFormatException exception)
{
if (Regex.IsMatch(exception.Message,
".*This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.*",
RegexOptions.IgnoreCase))
{
AssemblyName myAssemblyName = AssemblyName.GetAssemblyName(path);
isDotNet = true;
}
catch (System.IO.FileNotFoundException)
{
// System.Console.WriteLine("The file cannot be found.");
}
catch (System.BadImageFormatException exception)
{
if (Regex.IsMatch(exception.Message,
".*This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.*",
RegexOptions.IgnoreCase))
{
isDotNet = true;
}
}
catch
{
// System.Console.WriteLine("The assembly has already been loaded.");
}
}
catch
{
// System.Console.WriteLine("The assembly has already been loaded.");
}

return isDotNet;
Expand Down
Loading
Loading