From c1c36a09048608f88def25a72a8a6c5be0607dcc Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Mon, 6 Jul 2026 11:05:20 +0200 Subject: [PATCH] Fix PR winPEAS host-checker mock --- .github/workflows/PR-tests.yml | 78 +++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/.github/workflows/PR-tests.yml b/.github/workflows/PR-tests.yml index 740b1c1..cef23eb 100644 --- a/.github/workflows/PR-tests.yml +++ b/.github/workflows/PR-tests.yml @@ -111,6 +111,7 @@ jobs: from http.server import BaseHTTPRequestHandler, HTTPServer import json import sys + import threading body_path = sys.argv[1] count_path = sys.argv[2] @@ -121,8 +122,13 @@ jobs: body = self.rfile.read(length).decode("utf-8", "replace") with open(body_path, "w", encoding="utf-8") as f: f.write(body) + try: + with open(count_path, "r", encoding="utf-8") as f: + count = int((f.read() or "0").strip()) + except FileNotFoundError: + count = 0 with open(count_path, "w", encoding="utf-8") as f: - f.write("1") + f.write(str(count + 1)) vulns = [] for i in range(1, 56): severity = "low" @@ -154,26 +160,57 @@ jobs: self.send_header("Content-Length", str(len(data))) self.end_headers() self.wfile.write(data) + threading.Thread(target=self.server.shutdown, daemon=True).start() + + def do_GET(self): + if self.path == "/ready": + data = b"ready" + self.send_response(200) + self.send_header("Content-Type", "text/plain") + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + return + + self.send_response(404) + self.end_headers() def log_message(self, fmt, *args): pass - HTTPServer(("127.0.0.1", 18768), Handler).handle_request() + HTTPServer(("127.0.0.1", 18768), Handler).serve_forever() "@ | Set-Content -Path $serverPath -Encoding utf8 $pythonCandidates = @( - @{ FilePath = "py"; Arguments = @("-3", $serverPath, $bodyPath, $countPath) }, - @{ FilePath = "python"; Arguments = @($serverPath, $bodyPath, $countPath) }, - @{ FilePath = "python3"; Arguments = @($serverPath, $bodyPath, $countPath) } + @{ FilePath = "python"; VersionArgs = @("--version"); ServerArgs = @($serverPath, $bodyPath, $countPath) }, + @{ FilePath = "python3"; VersionArgs = @("--version"); ServerArgs = @($serverPath, $bodyPath, $countPath) }, + @{ FilePath = "py"; VersionArgs = @("-3", "--version"); ServerArgs = @("-3", $serverPath, $bodyPath, $countPath) } ) - $pythonCommand = $pythonCandidates | - Where-Object { Get-Command $_.FilePath -ErrorAction SilentlyContinue } | - Select-Object -First 1 + $pythonCommand = $null + foreach ($candidate in $pythonCandidates) { + if (!(Get-Command $candidate.FilePath -ErrorAction SilentlyContinue)) { + continue + } + + & $candidate.FilePath @($candidate.VersionArgs) | Out-Null + if ($LASTEXITCODE -eq 0) { + $pythonCommand = $candidate + break + } + } if (!$pythonCommand) { Write-Error "No Python interpreter found to launch the mock host-checker server." } - $server = Start-Process -FilePath $pythonCommand.FilePath -ArgumentList $pythonCommand.Arguments -PassThru -NoNewWindow + $startInfo = [System.Diagnostics.ProcessStartInfo]::new() + $startInfo.FileName = $pythonCommand.FilePath + $startInfo.UseShellExecute = $false + $startInfo.RedirectStandardOutput = $true + $startInfo.RedirectStandardError = $true + foreach ($arg in $pythonCommand.ServerArgs) { + [void]$startInfo.ArgumentList.Add($arg) + } + $server = [System.Diagnostics.Process]::Start($startInfo) try { $serverReady = $false $deadline = (Get-Date).AddSeconds(15) @@ -182,26 +219,26 @@ jobs: break } - $client = $null try { - $client = [System.Net.Sockets.TcpClient]::new() - $connectTask = $client.ConnectAsync("127.0.0.1", 18768) - if ($connectTask.Wait(500) -and $client.Connected) { + $readyResponse = Invoke-WebRequest -UseBasicParsing -TimeoutSec 1 -Uri "http://127.0.0.1:18768/ready" + if ($readyResponse.StatusCode -eq 200) { $serverReady = $true break } } catch { - } finally { - if ($client) { - $client.Dispose() - } } Start-Sleep -Milliseconds 250 } if (!$serverReady) { - Write-Error "Mock host-checker server did not become ready before winPEAS execution." + if (!$server.HasExited) { + $server.Kill() + [void]$server.WaitForExit(5000) + } + $stdout = $server.StandardOutput.ReadToEnd() + $stderr = $server.StandardError.ReadToEnd() + Write-Error "Mock host-checker server did not become ready before winPEAS execution. ExitCode=$($server.ExitCode)`nSTDOUT:`n$stdout`nSTDERR:`n$stderr" } $env:HACKTRICKS_HOST_CHECKER_URL = "http://127.0.0.1:18768/api/host-checker" @@ -242,8 +279,9 @@ jobs: Write-Error "The host-checker payload did not include installed packages." } } finally { - if (!$server.HasExited) { - Stop-Process -Id $server.Id -Force + if ($server -and !$server.HasExited) { + $server.Kill() + [void]$server.WaitForExit(5000) } }