mirror of
https://github.com/peass-ng/PEASS-ng.git
synced 2026-07-28 14:47:18 -07:00
Add winPEAS online package vulnerability lookup
This commit is contained in:
@@ -94,6 +94,101 @@ jobs:
|
||||
} else {
|
||||
Write-Error "winPEAS.exe not found at $exePath"
|
||||
}
|
||||
|
||||
- name: Execute winPEAS online package vulnerability lookup with mock
|
||||
shell: pwsh
|
||||
run: |
|
||||
$Configuration = "Release"
|
||||
$exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
|
||||
if (!(Test-Path $exePath)) {
|
||||
Write-Error "winPEAS.exe not found at $exePath"
|
||||
}
|
||||
|
||||
$serverPath = Join-Path $env:RUNNER_TEMP "mock_host_checker.py"
|
||||
$bodyPath = Join-Path $env:RUNNER_TEMP "host_checker_body.json"
|
||||
$countPath = Join-Path $env:RUNNER_TEMP "host_checker_count.txt"
|
||||
@"
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
import json
|
||||
import sys
|
||||
|
||||
body_path = sys.argv[1]
|
||||
count_path = sys.argv[2]
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
length = int(self.headers.get("content-length", "0"))
|
||||
body = self.rfile.read(length).decode("utf-8", "replace")
|
||||
with open(body_path, "w", encoding="utf-8") as f:
|
||||
f.write(body)
|
||||
with open(count_path, "w", encoding="utf-8") as f:
|
||||
f.write("1")
|
||||
vulns = []
|
||||
for i in range(1, 56):
|
||||
vulns.append({
|
||||
"name": f"pkg{i}",
|
||||
"version": f"1.{i}.0",
|
||||
"manager": "windows-registry",
|
||||
"vulns": [f"CVE-2026-{10000 + i}"],
|
||||
})
|
||||
response = {
|
||||
"malicious": False,
|
||||
"results": [],
|
||||
"package_vulnerabilities": {
|
||||
"checked": 300,
|
||||
"affected": 55,
|
||||
"vulnerable_packages": vulns,
|
||||
},
|
||||
}
|
||||
data = json.dumps(response).encode("utf-8")
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
pass
|
||||
|
||||
HTTPServer(("127.0.0.1", 18768), Handler).handle_request()
|
||||
"@ | Set-Content -Path $serverPath -Encoding utf8
|
||||
|
||||
$server = Start-Process python -ArgumentList "`"$serverPath`" `"$bodyPath`" `"$countPath`"" -PassThru -NoNewWindow
|
||||
try {
|
||||
Start-Sleep -Seconds 2
|
||||
$env:HACKTRICKS_HOST_CHECKER_URL = "http://127.0.0.1:18768/api/host-checker"
|
||||
$output = & $exePath applicationsinfo -vulnpackages notcolor 2>&1 | Out-String
|
||||
|
||||
if ($output -notmatch "Online package vulnerabilities found: 55 vulnerable package\(s\), checked 300\.") {
|
||||
Write-Error "The package vulnerability summary was not printed as expected.`n$output"
|
||||
}
|
||||
$vulnLines = ([regex]::Matches($output, "(?m)^\s+- pkg\d+ ")).Count
|
||||
if ($vulnLines -ne 50) {
|
||||
Write-Error "Expected 50 vulnerable package lines, got $vulnLines.`n$output"
|
||||
}
|
||||
if ($output -notmatch "\.\.\. 5 more vulnerable package\(s\) not shown\.") {
|
||||
Write-Error "The hidden vulnerable package count was not printed.`n$output"
|
||||
}
|
||||
if ($output -match "package_vulnerabilities") {
|
||||
Write-Error "Raw package_vulnerabilities JSON leaked into the rendered output.`n$output"
|
||||
}
|
||||
|
||||
$requestCount = Get-Content $countPath -Raw
|
||||
if ([int]$requestCount.Trim() -ne 1) {
|
||||
Write-Error "Expected exactly one host-checker request, got $requestCount"
|
||||
}
|
||||
$request = Get-Content $bodyPath -Raw | ConvertFrom-Json
|
||||
if (!$request.hostname) {
|
||||
Write-Error "The host-checker payload did not include hostname."
|
||||
}
|
||||
if (!$request.packages -or $request.packages.Count -lt 1) {
|
||||
Write-Error "The host-checker payload did not include installed packages."
|
||||
}
|
||||
} finally {
|
||||
if (!$server.HasExited) {
|
||||
Stop-Process -Id $server.Id -Force
|
||||
}
|
||||
}
|
||||
|
||||
- name: Execute winPEAS networkinfo
|
||||
shell: pwsh
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace winPEAS.Tests
|
||||
winPEAS.Checks.Checks.IsLinpeas = false;
|
||||
winPEAS.Checks.Checks.IsLolbas = false;
|
||||
winPEAS.Checks.Checks.IsNetworkScan = false;
|
||||
winPEAS.Checks.Checks.CheckOnlineVulnPackages = false;
|
||||
winPEAS.Checks.Checks.SearchProgramFiles = false;
|
||||
winPEAS.Checks.Checks.NetworkScanOptions = string.Empty;
|
||||
winPEAS.Checks.Checks.PortScannerPorts = null;
|
||||
@@ -240,5 +241,37 @@ namespace winPEAS.Tests
|
||||
Assert.AreEqual(500000, winPEAS.Checks.Checks.MaxRegexFileSize,
|
||||
"max-regex-file-size=500000 should set MaxRegexFileSize to 500000.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void VulnPackages_ArgParsed_Correctly()
|
||||
{
|
||||
ParseOnly("-vulnpackages");
|
||||
Assert.IsTrue(winPEAS.Checks.Checks.CheckOnlineVulnPackages,
|
||||
"-vulnpackages should enable the online package vulnerability lookup.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void All_EnablesOnlinePackageLookup()
|
||||
{
|
||||
ParseOnly("all");
|
||||
Assert.IsTrue(winPEAS.Checks.Checks.CheckOnlineVulnPackages,
|
||||
"all should enable the online package vulnerability lookup.");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PackageVulnerabilityFormatter_CapsAtFiftyLines()
|
||||
{
|
||||
var vulnerablePackages = string.Join(",", Enumerable.Range(1, 55).Select(i =>
|
||||
$"{{\"name\":\"pkg{i}\",\"version\":\"1.{i}.0\",\"manager\":\"windows-registry\",\"vulns\":[\"CVE-2026-{10000 + i}\"]}}"));
|
||||
var responseJson = "{\"malicious\":false,\"results\":[],\"package_vulnerabilities\":{\"checked\":300,\"affected\":55,\"vulnerable_packages\":[" + vulnerablePackages + "]}}";
|
||||
|
||||
var summary = winPEAS.Info.NetworkInfo.HackTricksHostChecker.ParsePackageVulnerabilities(responseJson, 50);
|
||||
|
||||
Assert.AreEqual(300, summary.Checked);
|
||||
Assert.AreEqual(55, summary.Affected);
|
||||
Assert.AreEqual(50, summary.Lines.Count);
|
||||
Assert.AreEqual(5, summary.NotShown);
|
||||
Assert.IsTrue(summary.Lines[0].StartsWith("- pkg1 1.1.0 [windows-registry]: CVE-2026-10001"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using winPEAS.Helpers;
|
||||
using winPEAS.Info.ApplicationInfo;
|
||||
using winPEAS.Info.NetworkInfo;
|
||||
|
||||
namespace winPEAS.Checks
|
||||
{
|
||||
@@ -17,12 +18,55 @@ namespace winPEAS.Checks
|
||||
{
|
||||
PrintActiveWindow,
|
||||
PrintInstalledApps,
|
||||
PrintOnlinePackageVulnerabilities,
|
||||
PrintAutoRuns,
|
||||
PrintScheduled,
|
||||
PrintDeviceDrivers,
|
||||
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
||||
}
|
||||
|
||||
void PrintOnlinePackageVulnerabilities()
|
||||
{
|
||||
if (!Checks.CheckOnlineVulnPackages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("Online package vulnerabilities", "T1518");
|
||||
Beaprint.LinkPrint("", "Optional HackTricks online lookup enabled with -vulnpackages or all. Output is capped at 50 vulnerable packages.");
|
||||
|
||||
var summary = HackTricksHostChecker.GetPackageVulnerabilities(50);
|
||||
if (!string.IsNullOrEmpty(summary.Error))
|
||||
{
|
||||
Beaprint.PrintException(" " + summary.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
Beaprint.NoColorPrint($" Online package vulnerabilities found: {summary.Affected} vulnerable package(s), checked {summary.Checked}.");
|
||||
if (summary.Lines.Count == 0)
|
||||
{
|
||||
Beaprint.GoodPrint(" No vulnerable packages found by the online lookup.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var line in summary.Lines)
|
||||
{
|
||||
Beaprint.BadPrint(" " + line);
|
||||
}
|
||||
|
||||
if (summary.NotShown > 0)
|
||||
{
|
||||
Beaprint.NoColorPrint($" ... {summary.NotShown} more vulnerable package(s) not shown.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintActiveWindow()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace winPEAS.Checks
|
||||
public static bool IsLinpeas = false;
|
||||
public static bool IsLolbas = false;
|
||||
public static bool IsNetworkScan = false;
|
||||
public static bool CheckOnlineVulnPackages = false;
|
||||
public static bool SearchProgramFiles = false;
|
||||
|
||||
public static IEnumerable<int> PortScannerPorts = null;
|
||||
@@ -141,6 +142,7 @@ namespace winPEAS.Checks
|
||||
if (string.Equals(arg, "all", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
print_fileanalysis_warn = false;
|
||||
CheckOnlineVulnPackages = true;
|
||||
}
|
||||
|
||||
if (arg.StartsWith("log", StringComparison.CurrentCultureIgnoreCase))
|
||||
@@ -184,6 +186,12 @@ namespace winPEAS.Checks
|
||||
DontCheckHostname = true;
|
||||
}
|
||||
|
||||
if (string.Equals(arg, "-vulnpackages", StringComparison.CurrentCultureIgnoreCase) ||
|
||||
string.Equals(arg, "vulnpackages", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
CheckOnlineVulnPackages = true;
|
||||
}
|
||||
|
||||
if (string.Equals(arg, "quiet", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
Banner = false;
|
||||
@@ -321,6 +329,11 @@ namespace winPEAS.Checks
|
||||
_systemCheckSelectedKeysHashSet.Add("networkscan");
|
||||
}
|
||||
|
||||
if (CheckOnlineVulnPackages && !isAllChecks)
|
||||
{
|
||||
_systemCheckSelectedKeysHashSet.Add("applicationsinfo");
|
||||
}
|
||||
|
||||
if (isAllChecks)
|
||||
{
|
||||
isFileSearchEnabled = true;
|
||||
@@ -346,6 +359,10 @@ namespace winPEAS.Checks
|
||||
|
||||
CheckRunner.Run(() => CreateDynamicLists(isFileSearchEnabled), IsDebug);
|
||||
|
||||
Info.NetworkInfo.HackTricksHostChecker.Start(
|
||||
includeHostname: !DontCheckHostname,
|
||||
includePackages: CheckOnlineVulnPackages);
|
||||
|
||||
RunChecks(isAllChecks, wait);
|
||||
|
||||
SearchHelper.CleanLists();
|
||||
|
||||
@@ -509,7 +509,7 @@ namespace winPEAS.Checks
|
||||
if (!string.IsNullOrEmpty(resolutionInfo.ExternalCheckResult))
|
||||
{
|
||||
Beaprint.GoodPrint($" External Check Result:");
|
||||
Beaprint.NoColorPrint(resolutionInfo.ExternalCheckResult);
|
||||
Beaprint.NoColorPrint(" " + resolutionInfo.ExternalCheckResult.Replace("\n", "\n "));
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(resolutionInfo.Error))
|
||||
{
|
||||
|
||||
@@ -149,6 +149,7 @@ namespace winPEAS.Helpers
|
||||
Console.WriteLine(LCYAN + " wait" + GRAY + " Wait for user input between checks" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " debug" + GRAY + " Display debugging information - memory usage, method execution time" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " dont-check-hostname" + GRAY + " Don't check the hostname externally" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " -vulnpackages" + GRAY + " Send installed application names/versions to HackTricks for an online vulnerability check. Also enabled by 'all'." + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " log[=logfile]" + GRAY + $" Log all output to file defined as logfile, or to \"{Checks.Checks.DefaultLogFile}\" if not specified" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " max-regex-file-size=1000000" + GRAY + $" Max file size (in Bytes) to search regex in. Default: {Checks.Checks.MaxRegexFileSize}B" + NOCOLOR);
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace winPEAS.Info.ApplicationInfo
|
||||
{
|
||||
public static class InstalledPackageInventory
|
||||
{
|
||||
public const int MaxPackages = 300;
|
||||
|
||||
public static List<Dictionary<string, string>> GetInstalledPackages(int maxPackages = MaxPackages)
|
||||
{
|
||||
var packages = new List<Dictionary<string, string>>();
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
AddRegistryPackages(packages, seen, RegistryHive.LocalMachine, RegistryView.Registry64, maxPackages);
|
||||
AddRegistryPackages(packages, seen, RegistryHive.LocalMachine, RegistryView.Registry32, maxPackages);
|
||||
AddRegistryPackages(packages, seen, RegistryHive.CurrentUser, RegistryView.Default, maxPackages);
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
private static void AddRegistryPackages(
|
||||
List<Dictionary<string, string>> packages,
|
||||
HashSet<string> seen,
|
||||
RegistryHive hive,
|
||||
RegistryView view,
|
||||
int maxPackages)
|
||||
{
|
||||
if (packages.Count >= maxPackages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var baseKey = RegistryKey.OpenBaseKey(hive, view))
|
||||
using (var uninstallKey = baseKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"))
|
||||
{
|
||||
if (uninstallKey == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var subkeyName in uninstallKey.GetSubKeyNames())
|
||||
{
|
||||
if (packages.Count >= maxPackages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (var appKey = uninstallKey.OpenSubKey(subkeyName))
|
||||
{
|
||||
if (appKey == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = CleanValue(appKey.GetValue("DisplayName"));
|
||||
var version = CleanValue(appKey.GetValue("DisplayVersion"));
|
||||
if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(version))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = $"{name}\0{version}";
|
||||
if (!seen.Add(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var package = new Dictionary<string, string>
|
||||
{
|
||||
{ "name", name },
|
||||
{ "version", version },
|
||||
{ "manager", "windows-registry" }
|
||||
};
|
||||
|
||||
var publisher = CleanValue(appKey.GetValue("Publisher"));
|
||||
if (!string.IsNullOrWhiteSpace(publisher))
|
||||
{
|
||||
package["publisher"] = publisher;
|
||||
}
|
||||
|
||||
packages.Add(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Registry inventory is best-effort; unreadable views should not break winPEAS.
|
||||
}
|
||||
}
|
||||
|
||||
private static string CleanValue(object value)
|
||||
{
|
||||
return Convert.ToString(value)?.Trim().Replace("\r", " ").Replace("\n", " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using winPEAS.Info.ApplicationInfo;
|
||||
|
||||
namespace winPEAS.Info.NetworkInfo
|
||||
{
|
||||
public sealed class HostCheckerResult
|
||||
{
|
||||
public string Hostname { get; set; }
|
||||
public string RawResponse { get; set; }
|
||||
public string HostOnlyResponse { get; set; }
|
||||
public string Error { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PackageVulnerabilitySummary
|
||||
{
|
||||
public int Checked { get; set; }
|
||||
public int Affected { get; set; }
|
||||
public int NotShown { get; set; }
|
||||
public string Error { get; set; }
|
||||
public List<string> Lines { get; } = new List<string>();
|
||||
}
|
||||
|
||||
public static class HackTricksHostChecker
|
||||
{
|
||||
private const int TimeoutSeconds = 15;
|
||||
private const string DefaultUrl = "https://tools.hacktricks.wiki/api/host-checker";
|
||||
private static readonly object LockObj = new object();
|
||||
private static Task<HostCheckerResult> lookupTask;
|
||||
private static bool startedWithPackages;
|
||||
private static bool startedWithHostname;
|
||||
|
||||
public static void Start(bool includeHostname, bool includePackages)
|
||||
{
|
||||
if (!includeHostname && !includePackages)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
if (lookupTask != null)
|
||||
{
|
||||
if ((includePackages && !startedWithPackages) || (includeHostname && !startedWithHostname))
|
||||
{
|
||||
lookupTask = Task.Run(() => ExecuteLookup(includeHostname || startedWithHostname, includePackages || startedWithPackages));
|
||||
startedWithHostname = includeHostname || startedWithHostname;
|
||||
startedWithPackages = includePackages || startedWithPackages;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
startedWithHostname = includeHostname;
|
||||
startedWithPackages = includePackages;
|
||||
lookupTask = Task.Run(() => ExecuteLookup(includeHostname, includePackages));
|
||||
}
|
||||
}
|
||||
|
||||
public static HostCheckerResult GetResult()
|
||||
{
|
||||
Start(includeHostname: !Checks.Checks.DontCheckHostname, includePackages: Checks.Checks.CheckOnlineVulnPackages);
|
||||
try
|
||||
{
|
||||
return lookupTask.GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new HostCheckerResult { Error = $"Error during online HackTricks check: {ex.Message}" };
|
||||
}
|
||||
}
|
||||
|
||||
public static PackageVulnerabilitySummary GetPackageVulnerabilities(int maxLines)
|
||||
{
|
||||
Start(includeHostname: !Checks.Checks.DontCheckHostname, includePackages: true);
|
||||
var result = GetResult();
|
||||
if (!string.IsNullOrEmpty(result.Error))
|
||||
{
|
||||
return new PackageVulnerabilitySummary { Error = result.Error };
|
||||
}
|
||||
|
||||
return ParsePackageVulnerabilities(result.RawResponse, maxLines);
|
||||
}
|
||||
|
||||
public static PackageVulnerabilitySummary ParsePackageVulnerabilities(string responseJson, int maxLines)
|
||||
{
|
||||
var summary = new PackageVulnerabilitySummary();
|
||||
if (string.IsNullOrWhiteSpace(responseJson))
|
||||
{
|
||||
summary.Error = "No response received from HackTricks online lookup.";
|
||||
return summary;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var doc = JsonDocument.Parse(responseJson))
|
||||
{
|
||||
var root = doc.RootElement;
|
||||
if (!root.TryGetProperty("package_vulnerabilities", out var packageVulns))
|
||||
{
|
||||
return summary;
|
||||
}
|
||||
|
||||
summary.Checked = GetInt(packageVulns, "checked");
|
||||
summary.Affected = GetInt(packageVulns, "affected");
|
||||
|
||||
if (packageVulns.TryGetProperty("error", out var error) && error.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
summary.Error = "Package vulnerability lookup failed: " + error.GetString();
|
||||
return summary;
|
||||
}
|
||||
|
||||
if (!packageVulns.TryGetProperty("vulnerable_packages", out var packages) ||
|
||||
packages.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
return summary;
|
||||
}
|
||||
|
||||
foreach (var package in packages.EnumerateArray())
|
||||
{
|
||||
if (summary.Lines.Count >= maxLines)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var name = GetString(package, "name");
|
||||
var version = GetString(package, "version");
|
||||
var ecosystem = GetString(package, "ecosystem");
|
||||
var manager = GetString(package, "manager");
|
||||
var vulns = GetStringArray(package, "vulns");
|
||||
if (string.IsNullOrWhiteSpace(name) || vulns.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var source = !string.IsNullOrWhiteSpace(ecosystem) ? ecosystem : manager;
|
||||
var sourcePart = !string.IsNullOrWhiteSpace(source) ? $" [{source}]" : string.Empty;
|
||||
summary.Lines.Add($"- {name} {version}{sourcePart}: {string.Join(", ", vulns)}".Trim());
|
||||
}
|
||||
|
||||
summary.NotShown = Math.Max(0, summary.Affected - summary.Lines.Count);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
summary.Error = "Could not parse package vulnerability lookup response: " + ex.Message;
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
private static HostCheckerResult ExecuteLookup(bool includeHostname, bool includePackages)
|
||||
{
|
||||
var result = new HostCheckerResult();
|
||||
try
|
||||
{
|
||||
var hostname = GetHostname();
|
||||
result.Hostname = hostname;
|
||||
|
||||
var payload = new Dictionary<string, object>
|
||||
{
|
||||
{ "source", "winpeas" },
|
||||
{ "os", GetOsInfo() }
|
||||
};
|
||||
|
||||
if (includeHostname && !string.IsNullOrWhiteSpace(hostname))
|
||||
{
|
||||
payload["hostname"] = hostname;
|
||||
}
|
||||
|
||||
if (includePackages)
|
||||
{
|
||||
payload["packages"] = InstalledPackageInventory.GetInstalledPackages();
|
||||
}
|
||||
|
||||
var url = Environment.GetEnvironmentVariable("HACKTRICKS_HOST_CHECKER_URL");
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
url = DefaultUrl;
|
||||
}
|
||||
|
||||
using (var httpClient = new HttpClient())
|
||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(TimeoutSeconds)))
|
||||
{
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(TimeoutSeconds);
|
||||
var body = JsonSerializer.Serialize(payload);
|
||||
var req = new HttpRequestMessage(HttpMethod.Post, url)
|
||||
{
|
||||
Content = new StringContent(body, Encoding.UTF8, "application/json")
|
||||
};
|
||||
req.Headers.UserAgent.ParseAdd("winpeas");
|
||||
req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
var resp = httpClient.SendAsync(req, cts.Token).GetAwaiter().GetResult();
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
result.Error = $"External check failed (HTTP {(int)resp.StatusCode})";
|
||||
return result;
|
||||
}
|
||||
|
||||
result.RawResponse = resp.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
result.HostOnlyResponse = RemovePackageVulnerabilities(result.RawResponse);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Error = $"Error during online HackTricks check: {ex.Message}";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string RemovePackageVulnerabilities(string responseJson)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(responseJson))
|
||||
{
|
||||
return responseJson;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var doc = JsonDocument.Parse(responseJson))
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
foreach (var property in doc.RootElement.EnumerateObject())
|
||||
{
|
||||
if (!string.Equals(property.Name, "package_vulnerabilities", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
property.WriteTo(writer);
|
||||
}
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(stream.ToArray());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return responseJson;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> GetOsInfo()
|
||||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
{ "id", "windows" },
|
||||
{ "name", "Windows" },
|
||||
{ "version_id", Environment.OSVersion.VersionString },
|
||||
{ "kernel", new Dictionary<string, string>
|
||||
{
|
||||
{ "release", Environment.OSVersion.Version.ToString() },
|
||||
{ "arch", Environment.Is64BitOperatingSystem ? "x64" : "x86" }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetHostname()
|
||||
{
|
||||
try
|
||||
{
|
||||
var hostname = Dns.GetHostName();
|
||||
return string.IsNullOrWhiteSpace(hostname) ? Environment.MachineName : hostname;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Environment.MachineName;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetInt(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.TryGetProperty(propertyName, out var property) && property.ValueKind == JsonValueKind.Number && property.TryGetInt32(out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static string GetString(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.TryGetProperty(propertyName, out var property) && property.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return property.GetString();
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static List<string> GetStringArray(JsonElement element, string propertyName)
|
||||
{
|
||||
if (!element.TryGetProperty(propertyName, out var property) || property.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
return property
|
||||
.EnumerateArray()
|
||||
.Where(item => item.ValueKind == JsonValueKind.String)
|
||||
.Select(item => item.GetString())
|
||||
.Where(value => !string.IsNullOrWhiteSpace(value))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace winPEAS.Info.NetworkInfo
|
||||
{
|
||||
public class HostnameResolutionInfo
|
||||
@@ -15,9 +10,6 @@ namespace winPEAS.Info.NetworkInfo
|
||||
|
||||
public static class HostnameResolution
|
||||
{
|
||||
private const int INTERNET_SEARCH_TIMEOUT = 15;
|
||||
private static readonly HttpClient httpClient = new HttpClient();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to resolve the local hostname via the external lambda.
|
||||
/// Always returns a populated <see cref="HostnameResolutionInfo"/> object.
|
||||
@@ -28,36 +20,10 @@ namespace winPEAS.Info.NetworkInfo
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Determine hostname
|
||||
info.Hostname = Dns.GetHostName();
|
||||
if (string.IsNullOrEmpty(info.Hostname))
|
||||
info.Hostname = Environment.MachineName;
|
||||
|
||||
// 2. Prepare JSON body
|
||||
var payload = new StringContent(
|
||||
JsonSerializer.Serialize(new { hostname = info.Hostname }),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
|
||||
// 3. Configure HttpClient (header added once)
|
||||
if (!httpClient.DefaultRequestHeaders.Contains("User-Agent"))
|
||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "winpeas");
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(INTERNET_SEARCH_TIMEOUT);
|
||||
|
||||
// 4. Call external checker
|
||||
var resp = httpClient
|
||||
.PostAsync("https://tools.hacktricks.wiki/api/host-checker", payload)
|
||||
.GetAwaiter().GetResult();
|
||||
|
||||
if (resp.IsSuccessStatusCode)
|
||||
{
|
||||
info.ExternalCheckResult = resp.Content.ReadAsStringAsync()
|
||||
.GetAwaiter().GetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Error = $"External check failed (HTTP {(int)resp.StatusCode})";
|
||||
}
|
||||
var result = HackTricksHostChecker.GetResult();
|
||||
info.Hostname = result.Hostname;
|
||||
info.ExternalCheckResult = result.HostOnlyResponse;
|
||||
info.Error = result.Error;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace winPEAS.Info.NetworkInfo
|
||||
@@ -49,9 +46,6 @@ namespace winPEAS.Info.NetworkInfo
|
||||
private static readonly string[] DNS_ICMP_IPS =
|
||||
{ "1.1.1.1", "8.8.8.8" };
|
||||
|
||||
private const string LAMBDA_URL =
|
||||
"https://tools.hacktricks.wiki/api/host-checker";
|
||||
|
||||
// Shared HttpClient (kept for HTTP & Lambda checks)
|
||||
private static readonly HttpClient http = new HttpClient
|
||||
{
|
||||
@@ -115,32 +109,7 @@ namespace winPEAS.Info.NetworkInfo
|
||||
|
||||
private static bool TryLambdaAccess(out string error)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var cts =
|
||||
new CancellationTokenSource(TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS));
|
||||
|
||||
var payload = new StringContent(
|
||||
JsonSerializer.Serialize(new { hostname = Environment.MachineName }),
|
||||
Encoding.UTF8,
|
||||
"application/json");
|
||||
var req = new HttpRequestMessage(HttpMethod.Post, LAMBDA_URL);
|
||||
req.Content = payload;
|
||||
req.Headers.UserAgent.ParseAdd("winpeas");
|
||||
req.Headers.Accept.Add(
|
||||
new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
var resp = http.SendAsync(req, cts.Token).GetAwaiter().GetResult();
|
||||
|
||||
error = resp.IsSuccessStatusCode ? null :
|
||||
$"HTTP {(int)resp.StatusCode}";
|
||||
return error == null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.Message;
|
||||
return false;
|
||||
}
|
||||
return TryWebRequest("https://example.com", out error);
|
||||
}
|
||||
|
||||
private static bool TryDnsAccess(string ip, out string error)
|
||||
|
||||
@@ -1226,6 +1226,7 @@
|
||||
<Compile Include="Info\ApplicationInfo\ApplicationInfoHelper.cs" />
|
||||
<Compile Include="Info\ApplicationInfo\AutoRuns.cs" />
|
||||
<Compile Include="Info\ApplicationInfo\DeviceDrivers.cs" />
|
||||
<Compile Include="Info\ApplicationInfo\InstalledPackageInventory.cs" />
|
||||
<Compile Include="Info\ApplicationInfo\SoapClientProxyAnalyzer.cs" />
|
||||
<Compile Include="Info\ApplicationInfo\InstalledApps.cs" />
|
||||
<Compile Include="Helpers\Beaprint.cs" />
|
||||
@@ -1264,6 +1265,7 @@
|
||||
<Compile Include="Info\NetworkInfo\Enums\Protocol.cs" />
|
||||
<Compile Include="Info\NetworkInfo\Enums\TcpTableClass.cs" />
|
||||
<Compile Include="Info\NetworkInfo\Enums\UdpTableClass.cs" />
|
||||
<Compile Include="Info\NetworkInfo\HackTricksHostChecker.cs" />
|
||||
<Compile Include="Info\NetworkInfo\HostnameResolution.cs" />
|
||||
<Compile Include="Info\NetworkInfo\InternetConnectivity.cs" />
|
||||
<Compile Include="Info\NetworkInfo\InternetSettings\InternetSettings.cs" />
|
||||
|
||||
Reference in New Issue
Block a user