public void extensionUnloaded() { Utilities.out("Aborting param bruteforce"); Utilities.unloaded.set(true); }
public static byte[] fixContentLength(byte[] request) { if (countMatches(request, helpers.stringToBytes("Content-Length: ")) > 0) { int start = Utilities.getBodyStart(request); int contentLength = request.length - start; return setHeader(request, "Content-Length", Integer.toString(contentLength)); } else { return request; } }
public void run() { HashMap<String, ArrayDeque<WorkTarget>> itemsByHost = splitItemsByHost(); try { to_spider = new PrintWriter("to_spider", "UTF-8"); Utilities.out("File will be created at "+System.getProperty("user.dir")+"/to_spider"); distributeWork(itemsByHost); } catch (FileNotFoundException e) { Utilities.err(e.getMessage()); } catch (UnsupportedEncodingException e) { Utilities.err(e.getMessage()); } finally { to_spider.close(); } completed = true; requests = null; }
static byte[] appendToQuery(byte[] request, String suffix) { String url = getPathFromRequest(request); if(url.contains("?")) { if (url.indexOf("?") == url.length()-1) { // add suffix } else { suffix = "&" + suffix; } } else { suffix = "?" + suffix; } return replaceFirst(request, url.getBytes(), (url+suffix).getBytes()); }
Attack probeAttack(String payload) { byte[] request = insertionPoint.buildRequest(payload.getBytes()); //IParameter cacheBuster = burp.Utilities.helpers.buildParameter(Utilities.generateCanary(), "1", IParameter.PARAM_URL); //request = burp.Utilities.helpers.addParameter(request, cacheBuster); request = burp.Utilities.appendToQuery(request, Utilities.generateCanary()+"=1"); // todo replace with addCanary method IHttpRequestResponse requestResponse = burp.Utilities.attemptRequest(service, request); return new Attack(requestResponse, null, null, ""); }
Utilities.out("Initiating "+Utilities.getNameFromType(type)+" bruteforce on "+ targetURL); state.started = true; Utilities.out("Resuming "+Utilities.getNameFromType(type)+" bruteforce at "+state.seed+" on "+ targetURL); Utilities.out("Completed attack on "+ targetURL); return attacks; state.seed = Utilities.generate(state.seed, bucketSize, newParams); if (!Utilities.similar(localBase, paramGuess)) { Attack confirmParamGuess = injector.probeAttack(submission); if (!Utilities.similar(localBase, confirmParamGuess)) { Utilities.log("Splitting "+ submission); ArrayList<String> left = new ArrayList<>(candidates.subList(0, candidates.size() / 2)); Utilities.log("Got "+String.join("|",left)); ArrayList<String> right = new ArrayList<>(candidates.subList(candidates.size() / 2, candidates.size())); Utilities.log("Got "+String.join("|",right)); paramBuckets.push(left); paramBuckets.push(right); Attack WAFCatcher = new Attack(Utilities.attemptRequest(service, Utilities.addOrReplaceHeader(baseRequestResponse.getRequest(), "junk-header", submission))); WAFCatcher.addAttack(new Attack(Utilities.attemptRequest(service, Utilities.addOrReplaceHeader(baseRequestResponse.getRequest(), "junk-head", submission)))); if (!Utilities.similar(WAFCatcher, confirmParamGuess)){ Probe validParam = new Probe("Found unlinked param: " + submission, 4, submission); validParam.setEscapeStrings(Keysmith.permute(submission), Keysmith.permute(submission, false));
private boolean tryReflectCache(PayloadInjector injector, String param, IHttpRequestResponse base, int attackDedication, int i, String pathSuffix) { IHttpService service = injector.getService(); byte[] setPoisonReq = Utilities.appendToPath(injector.getInsertionPoint().buildRequest(Utilities.helpers.stringToBytes(param)), pathSuffix); IParameter cacheBuster = Utilities.helpers.buildParameter(Utilities.generateCanary(), "1", IParameter.PARAM_URL); setPoisonReq = Utilities.helpers.addParameter(setPoisonReq, cacheBuster); for (int j = attackDedication - i; j < attackDedication; j++) { Utilities.attemptRequest(service, setPoisonReq); } for (int j = attackDedication - i; j < attackDedication; j += 3) { IHttpRequestResponse getPoison = Utilities.attemptRequest(service, Utilities.appendToPath(Utilities.helpers.addParameter(base.getRequest(), cacheBuster), pathSuffix)); if (Utilities.containsBytes(getPoison.getResponse(), "wrtqv".getBytes())) { Utilities.log("Successful cache poisoning check"); String title = "Cache poisoning"; byte[] headerSplitReq = Utilities.appendToPath(injector.getInsertionPoint().buildRequest(Utilities.helpers.stringToBytes(param + "~zxcv\rvcz")), pathSuffix); cacheBuster = Utilities.helpers.buildParameter(Utilities.generateCanary(), "1", IParameter.PARAM_URL); byte[] headerSplitResp = Utilities.attemptRequest(service, Utilities.helpers.addParameter(headerSplitReq, cacheBuster)).getResponse(); if (Utilities.containsBytes(Arrays.copyOfRange(headerSplitResp, 0, Utilities.getBodyStart(headerSplitReq)), "zxcv\rvcz".getBytes())) { title = "Severe cache poisoning"; } title = title + " "+i; Utilities.callbacks.addScanIssue(new CustomScanIssue(getPoison.getHttpService(), Utilities.getURL(getPoison), getPoison, title, "Cache poisoning: '" + param + "'. Disregard the request and look for wrtqv in the response", "High", "Firm", "Investigate")); return true; } } return false; }
validParam.setPrefix(Probe.REPLACE); Attack paramBase = new Attack(); paramBase.addAttack(altInject.probeAttack(Utilities.generateCanary())); paramBase.addAttack(altInject.probeAttack(Utilities.generateCanary())); ArrayList<Attack> confirmed = altInject.fuzz(paramBase, validParam); if (!confirmed.isEmpty()) { Utilities.callbacks.addScanIssue(Utilities.reportReflectionIssue(confirmed.toArray(new Attack[2]), base, "Potentially swappable param")); String pathCacheBuster = Utilities.generateCanary() + ".jpg"; byte[] base404 = Utilities.appendToPath(base.getRequest(), pathCacheBuster); IHttpRequestResponse get404 = Utilities.attemptRequest(injector.getService(), base404); short get404Code = Utilities.helpers.analyzeResponse(get404.getResponse()).getStatusCode(); IParameter testCacheBuster = Utilities.helpers.buildParameter(Utilities.generateCanary(), "1", IParameter.PARAM_URL); testReq = Utilities.helpers.addParameter(testReq, testCacheBuster); IHttpRequestResponse testResp = Utilities.attemptRequest(injector.getService(), testReq); boolean reflectPoisonMightWork = Utilities.containsBytes(testResp.getResponse(), "wrtqv".getBytes()); boolean statusPoisonMightWork = Utilities.helpers.analyzeResponse(baseResponse.getResponse()).getStatusCode() != Utilities.helpers.analyzeResponse(testResp.getResponse()).getStatusCode(); if (reflectPoisonMightWork) { for (String suffix : potentialSuffixes) { testResp = Utilities.attemptRequest(injector.getService(), Utilities.appendToPath(testReq, suffix)); if (Utilities.containsBytes(testResp.getResponse(), "wrtqv".getBytes())) { if (Utilities.helpers.analyzeResponse(testResp.getResponse()).getStatusCode() == 200) { suffixes.add(suffix);
if (!Utilities.isBurpPro()) { Utilities.out("Can't autoscan identified parameter - requires pro edition"); return; PayloadInjector valueInjector = new PayloadInjector(injector.getBase(), valueInsertionPoint); Attack randBase = valueInjector.probeAttack(Utilities.generateCanary()); randBase.addAttack(valueInjector.probeAttack(Utilities.generateCanary())); randBase.addAttack(valueInjector.probeAttack(Utilities.generateCanary())); randBase.addAttack(valueInjector.probeAttack(Utilities.generateCanary())); Attack potentialBase = valueInjector.probeAttack(potentialValue); if(!Utilities.similar(randBase, potentialBase)) { baseValue = potentialValue; break; Utilities.doActiveScan(Utilities.attemptRequest(injector.getService(), valueInsertionPoint.buildRequest(baseValue.getBytes())), valueInsertionPoint.getPayloadOffsets(baseValue.getBytes()));
@Override public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { new Utilities(callbacks); callbacks.setExtensionName(name); Correlator collab = new Correlator(); Monitor collabMonitor = new Monitor(collab); new Thread(collabMonitor).start(); callbacks.registerExtensionStateListener(collabMonitor); callbacks.registerProxyListener(new Injector(collab)); Utilities.out("Loaded " + name + " v" + version); } }
static IHttpRequestResponse attemptRequest(IHttpService service, byte[] req) { if(unloaded.get()) { Utilities.out("Extension unloaded - aborting attack"); throw new RuntimeException("Extension unloaded"); } IHttpRequestResponse result = null; for(int attempt=1; attempt<3; attempt++) { try { result = callbacks.makeHttpRequest(service, req); } catch(RuntimeException e) { Utilities.log(e.toString()); Utilities.log("Critical request error, retrying..."); continue; } if (result.getResponse() == null) { Utilities.log("Request failed, retrying..."); //requestResponse.setResponse(new byte[0]); } else { break; } } if (result.getResponse() == null) { Utilities.log("Request failed multiple times, giving up"); } return result; }
String[] parts = unparsed.split("~", 2); unparsed = parts[0]; paramValue = Utilities.invert(parts[1]); } else { paramValue = calculateValue(unparsed); boolean isArray = Utilities.parseArrayIndex(keys.get(0)) != -1; Object base; if (isArray) { boolean setValue = i + 1 == keys.size(); int index = Utilities.parseArrayIndex(key); if (index != -1) { ArrayList injectionPoint = (ArrayList) next; if (injectionPoint.size() < index + 1) { for (int k = injectionPoint.size(); k < index; k++) { injectionPoint.add(Utilities.generateCanary()); outputStream.write(headers); outputStream.write(Utilities.helpers.stringToBytes(lastBuild)); return Utilities.fixContentLength(outputStream.toByteArray()); } catch (Exception e) { Utilities.out("Error with " + String.join(":", params)); e.printStackTrace(new PrintStream(Utilities.callbacks.getStdout())); return buildRequest(Utilities.helpers.stringToBytes("error_" + String.join(":", params).replace(":", "_")));
private Attack buildAttackFromProbe(Probe probe, String payload) { boolean randomAnchor = probe.getRandomAnchor(); byte prefix = probe.getPrefix(); String anchor = ""; if (randomAnchor) { anchor = Utilities.generateCanary(); } //else { // payload = payload.replace("z", Utilities.generateCanary()); //} String base_payload = payload; if (prefix == Probe.PREPEND) { payload += insertionPoint.getBaseValue(); } else if (prefix == Probe.APPEND) { payload = insertionPoint.getBaseValue() + anchor + payload; } else if (prefix == Probe.REPLACE) { // payload = payload; } else { Utilities.err("Unknown payload position"); } IHttpRequestResponse req = buildRequest(payload, probe.useCacheBuster()); if(randomAnchor) { req = Utilities.highlightRequestResponse(req, anchor, anchor, insertionPoint); } return new Attack(req, probe, base_payload, anchor); }
private static boolean findPersistent(IHttpRequestResponse baseRequestResponse, Attack paramGuess, String attackID, CircularFifoQueue<String> recentParams, ArrayList<String> currentParams, HashSet<String> alreadyReported) { if (currentParams == null) { currentParams = new ArrayList<>(); } byte[] failResp = paramGuess.getFirstRequest().getResponse(); if (failResp == null) { return false; } if (!Utilities.containsBytes(failResp, "wrtqva".getBytes())) { return false; } byte[] req = paramGuess.getFirstRequest().getRequest(); for(Iterator<String> params = recentParams.iterator(); params.hasNext();) { String param = params.next(); if(currentParams.contains(param) || alreadyReported.contains(param)) { continue; } byte[] canary = Utilities.helpers.stringToBytes(Utilities.toCanary(param.split("~", 2)[0]) + attackID); if (Utilities.containsBytes(failResp, canary) && !Utilities.containsBytes(req, canary)){ Utilities.out("Identified persistent parameter on "+Utilities.getURL(baseRequestResponse) + ":" + param); params.remove(); Utilities.callbacks.addScanIssue(new CustomScanIssue(baseRequestResponse.getHttpService(), Utilities.getURL(baseRequestResponse), paramGuess.getFirstRequest(), "Secret parameter", "Found persistent parameter: '"+param+"'. Disregard the request and look for " + Utilities.helpers.bytesToString(canary) + " in the response", "High", "Firm", "Investigate")); alreadyReported.add(param); return true; } } return false; }
PayloadInjector injector = new PayloadInjector(baseRequestResponse, insertionPoint); String targetURL = baseRequestResponse.getHttpService().getHost(); Utilities.out("Initiating parameter name bruteforce on "+ targetURL); Attack base = injector.buildAttack(baseValue+"&"+Utilities.randomString(6)+"=%3c%61%60%27%22%24%7b%7b%5c", false); base.addAttack(injector.buildAttack(baseValue+"&"+Utilities.randomString((i+1)*(i+1))+"=%3c%61%60%27%22%24%7b%7b%5c", false)); String candidate = Utilities.paramNames.get(i); Attack paramGuess = injector.buildAttack(baseValue + "&" + candidate + "=%3c%61%60%27%22%24%7b%7b%5c", false); if (!Utilities.similar(base, paramGuess)) { Attack confirmParamGuess = injector.buildAttack(baseValue + "&" + candidate + "=%3c%61%60%27%22%24%7b%7b%5c", false); base.addAttack(injector.buildAttack(baseValue + "&" + candidate + "z=%3c%61%60%27%22%24%7b%7b%5c", false)); if (!Utilities.similar(base, confirmParamGuess)) { Probe validParam = new Probe("Backend param: " + candidate, 4, "&" + candidate + "=%3c%61%60%27%22%24%7b%7b%5c", "&" + candidate + "=%3c%62%60%27%22%24%7b%7b%5c"); validParam.setEscapeStrings("&" + Utilities.randomString(candidate.length()) + "=%3c%61%60%27%22%24%7b%7b%5c", "&" + candidate + "z=%3c%61%60%27%22%24%7b%7b%5c"); validParam.setRandomAnchor(false); ArrayList<Attack> confirmed = injector.fuzz(base, validParam); if (!confirmed.isEmpty()) { Utilities.out("Identified backend parameter: " + candidate); attacks.addAll(confirmed); Utilities.out("Parameter name bruteforce complete: "+targetURL); Utilities.out("Parameter name bruteforce aborted: "+targetURL);
public void run() { if(this.attack == null) { if (req.getResponse() == null) { Utilities.log("Baserequest has no response - fetching..."); try { req = Utilities.callbacks.makeHttpRequest(req.getHttpService(), req.getRequest()); Utilities.out("Aborting attack due to failed lookup"); return; Utilities.out("Aborting attack due to null response"); return; Utilities.callbacks.addScanIssue(Utilities.reportReflectionIssue(paramGuesses.toArray((new Attack[paramGuesses.size()])), req));
public IScanIssue findTransformationIssues(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { String leftAnchor = Utilities.randomString(5); String rightAnchor = "z" + Utilities.randomString(2); Attack basicAttack = Utilities.buildTransformationAttack(baseRequestResponse, insertionPoint, leftAnchor, "\\\\", rightAnchor); if (Utilities.getMatches(Utilities.filterResponse(basicAttack.getFirstRequest().getResponse()), (leftAnchor + "\\" + rightAnchor).getBytes(), -1).isEmpty()) { return null;
private boolean tryStatusCache(PayloadInjector injector, String param, int attackDedication, short get404Code) { String canary = Utilities.generateCanary()+".jpg"; byte[] setPoison200Req = injector.getInsertionPoint().buildRequest(Utilities.helpers.stringToBytes(addStatusPayload(param))); setPoison200Req = Utilities.appendToPath(setPoison200Req, canary); byte[] getPoison200Req = injector.getInsertionPoint().buildRequest(Utilities.helpers.stringToBytes(addStatusPayload("xyz"+param+"z"))); getPoison200Req = Utilities.appendToPath(getPoison200Req, canary); for(int j=0; j<attackDedication; j++) { Utilities.attemptRequest(injector.getService(), setPoison200Req); } for(int j=0; j<attackDedication; j+=3) { IHttpRequestResponse getPoison200 = Utilities.attemptRequest(injector.getService(), getPoison200Req); short getPoison200Code = Utilities.helpers.analyzeResponse(getPoison200.getResponse()).getStatusCode(); if (getPoison200Code != get404Code) { Utilities.callbacks.addScanIssue(new CustomScanIssue(getPoison200.getHttpService(), Utilities.getURL(getPoison200), getPoison200, "Dubious cache poisoning " + j, "Cache poisoning: '" + param + "'. Diff based cache poisoning. Good luck confirming", "High", "Tentative", "Investigate")); } return true; } return false; }
@Override public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { new Utilities(callbacks); BlockingQueue<Runnable> tasks; if (Utilities.globalSettings.getBoolean("enable auto-mine")) { Utilities.out("Updating active thread pool size to "+value); try { taskEngine.setCorePoolSize(Integer.parseInt(value)); StringUtils.isNumeric("1"); } catch (java.lang.NoClassDefFoundError e) { Utilities.out("Failed to import the Apache Commons Lang library. You can get it from http://commons.apache.org/proper/commons-lang/"); throw new NoClassDefFoundError(); callbacks.getHelpers().analyzeResponseVariations(); } catch (java.lang.NoSuchMethodError e) { Utilities.out("This extension requires Burp Suite Pro 1.7.10 or later"); throw new NoSuchMethodError(); callbacks.registerContextMenuFactory(new OfferParamGuess(callbacks, paramGrabber, taskEngine)); if(Utilities.isBurpPro()) { callbacks.registerScannerCheck(new GrabScan(paramGrabber)); Utilities.out("Loaded " + name + " v" + version); Utilities.out(" CACHE_ONLY "+Utilities.CACHE_ONLY);
public static byte[] setHeader(byte[] request, String header, String value) { int[] offsets = getHeaderOffsets(request, header); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { outputStream.write( Arrays.copyOfRange(request, 0, offsets[1])); outputStream.write(helpers.stringToBytes(value)); outputStream.write(Arrays.copyOfRange(request, offsets[2], request.length)); return outputStream.toByteArray(); } catch (IOException e) { throw new RuntimeException("Request creation unexpectedly failed"); } catch (NullPointerException e) { Utilities.out("header locating fail: "+header); Utilities.out("'"+helpers.bytesToString(request)+"'"); throw new RuntimeException("Can't find the header"); } }