From 45b375110098baadb334dbfbba30d332b076d153 Mon Sep 17 00:00:00 2001 From: atomiczsec <75549184+atomiczsec@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:26:56 -0500 Subject: [PATCH] Improve initialization diagnostics --- src/main/java/burp/BurpExtender.java | 11 ++++-- src/main/java/burp/RequestSender.java | 50 ++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 4bb6018..02194dc 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -151,11 +151,16 @@ public void run() { updateStatus("Initializing..."); long initStart = System.currentTimeMillis(); - String initialRandomSegment = RequestSender.initialTest(reqRes); - if (initialRandomSegment == null) { - logWarning("Scan aborted: Initial path mapping tests failed"); + RequestSender.InitialTestResult initialTestResult = RequestSender.initialTest(reqRes); + if (initialTestResult == null || !initialTestResult.isSuccess()) { + String reason = initialTestResult != null + ? initialTestResult.getFailureReason() + : "Initial path mapping tests failed"; + logWarning("Scan aborted: " + reason); + updateStatus("Scan aborted: " + reason); return; } + String initialRandomSegment = initialTestResult.getRandomSegment(); logTiming("Initialization", System.currentTimeMillis() - initStart); // Detect CDN/cache layer diff --git a/src/main/java/burp/RequestSender.java b/src/main/java/burp/RequestSender.java index a575b41..02ce921 100644 --- a/src/main/java/burp/RequestSender.java +++ b/src/main/java/burp/RequestSender.java @@ -145,15 +145,15 @@ private static Pattern[] compilePatterns(String... rawPatterns) { * 1. Authenticated and unauthenticated responses are DIFFERENT (confirms auth is required) * 2. Authenticated response with appended segment is SIMILAR to original (confirms backend ignores trailing segments) */ - protected static String initialTest(IHttpRequestResponse message) { + protected static InitialTestResult initialTest(IHttpRequestResponse message) { byte[] orgRequest = buildHttpRequest(message, null, null, true); Map orgDetails = retrieveResponseDetails(message.getHttpService(), orgRequest); if (orgDetails == null) { - return null; + return InitialTestResult.failure("Unable to fetch the original authenticated response"); } int orgStatusCode = (int) orgDetails.get("statusCode"); if (orgStatusCode < 200 || orgStatusCode >= 300) { - return null; // Original request must succeed + return InitialTestResult.failure("Original request returned status " + orgStatusCode); } byte[] originalAuthBody = (byte[]) orgDetails.get("body"); @@ -162,7 +162,7 @@ protected static String initialTest(IHttpRequestResponse message) { byte[] unAuthedRequest = buildHttpRequest(message, null, null, false); Map unauthDetails = retrieveResponseDetails(message.getHttpService(), unAuthedRequest); if (unauthDetails == null) { - return null; + return InitialTestResult.failure("Unable to fetch unauthenticated response"); } int unauthStatusCode = (int) unauthDetails.get("statusCode"); byte[] unauthBody = (byte[]) unauthDetails.get("body"); @@ -175,7 +175,7 @@ protected static String initialTest(IHttpRequestResponse message) { // If unauthenticated response is similar, this endpoint doesn't require auth - skip it if (unauthedIsSimilar) { BurpExtender.logDebug("Initial test failed: Unauthenticated response similar to authenticated"); - return null; + return InitialTestResult.failure("Endpoint looks public (auth vs unauth are similar)"); } // Step 2: Verify that appending a random segment returns SIMILAR content @@ -184,11 +184,11 @@ protected static String initialTest(IHttpRequestResponse message) { byte[] testRequest = buildHttpRequestWithSegment(message, randomSegment, null, true, "/"); Map appendedDetails = retrieveResponseDetails(message.getHttpService(), testRequest); if (appendedDetails == null) { - return null; + return InitialTestResult.failure("Unable to fetch appended path response"); } int appendedStatusCode = (int) appendedDetails.get("statusCode"); if (appendedStatusCode < 200 || appendedStatusCode >= 300) { - return null; // Appended request must also succeed + return InitialTestResult.failure("Appended path returned status " + appendedStatusCode); } byte[] appendedBody = (byte[]) appendedDetails.get("body"); @@ -199,11 +199,11 @@ protected static String initialTest(IHttpRequestResponse message) { if (!appendIsSimilar) { BurpExtender.logDebug("Initial test failed: Appended segment response not similar to original"); - return null; + return InitialTestResult.failure("Backend rejects extra path segments"); } // Both conditions met: auth required AND backend ignores trailing segments - return randomSegment; + return InitialTestResult.success(randomSegment); } /** @@ -1482,4 +1482,36 @@ private byte[] toByteArray(boolean includeCookies) { return BurpExtender.getHelpers().buildHttpMessage(finalHeaders, body); } } + + protected static final class InitialTestResult { + private final boolean success; + private final String randomSegment; + private final String failureReason; + + private InitialTestResult(boolean success, String randomSegment, String failureReason) { + this.success = success; + this.randomSegment = randomSegment; + this.failureReason = failureReason; + } + + protected static InitialTestResult success(String randomSegment) { + return new InitialTestResult(true, randomSegment, null); + } + + protected static InitialTestResult failure(String reason) { + return new InitialTestResult(false, null, reason); + } + + protected boolean isSuccess() { + return success; + } + + protected String getRandomSegment() { + return randomSegment; + } + + protected String getFailureReason() { + return failureReason; + } + } }