diff --git a/pom.xml b/pom.xml index b67f97f..e506451 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.codemagi burp-suite-utils - 1.2.4 + 1.2.5 jar Burp Suite Utils The Burp Suite Utils project provides developers with APIs for building Burp Suite Extensions. diff --git a/src/main/java/com/codemagi/burp/Offsets.java b/src/main/java/com/codemagi/burp/Offsets.java new file mode 100644 index 0000000..ee4a5c5 --- /dev/null +++ b/src/main/java/com/codemagi/burp/Offsets.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021 augustd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.codemagi.burp; + +/** + * + * @author August Detlefsen [augustd at codemagi dot com] + */ +public class Offsets { + private Integer start; + private Integer end; + + public Offsets(Integer start, Integer end) { + this.start = start; + this.end = end; + } + + public Integer getStart() { + return start; + } + + public void setStart(Integer start) { + this.start = start; + } + + public Integer getEnd() { + return end; + } + + public void setEnd(Integer end) { + this.end = end; + } + + /** + * Return true if this set of Offsets overlaps the other set passed in. + * + * @param other Another Offsets instance to compare against + * @return true if this set of Offsets overlaps the other set passed in. + */ + public boolean overlaps(Offsets other) { + if (other == null) return false; + + return (this.start <= other.getEnd() && other.getStart() <= this.end); + } + + /** + * Combine two sets of Offsets into one overlapping set. + * + * @param other Another Offsets instance to combine with + * @return An Offsets instance which combines the start/stop points of both instances + */ + public Offsets combine(Offsets other) { + if (other == null) return this; + + return new Offsets(Math.min(start, other.getStart()), Math.max(end, other.getEnd())); + } + + /** + * Retrieve the start/stop points as an int[] array. + * + * @return An array of int suitable for passing into a Burp IScanIssue + */ + public int[] toArray() { + int[] output = {start, end}; + return output; + } +} diff --git a/src/main/java/com/codemagi/burp/PassiveScan.java b/src/main/java/com/codemagi/burp/PassiveScan.java index 66e50d4..69c3043 100644 --- a/src/main/java/com/codemagi/burp/PassiveScan.java +++ b/src/main/java/com/codemagi/burp/PassiveScan.java @@ -7,6 +7,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; @@ -157,15 +158,28 @@ protected List processIssues(List matches, IHttpReques if (!matches.isEmpty()) { Collections.sort(matches); //matches must be in order //get the offsets of scanner matches - List startStop = new ArrayList<>(1); + LinkedList offsets = new LinkedList<>(); for (ScannerMatch match : matches) { callbacks.printOutput("Processing match: " + match); callbacks.printOutput(" start: " + match.getStart() + " end: " + match.getEnd() + " full match: " + match.getFullMatch() + " group: " + match.getMatchGroup()); //add a marker for code highlighting - startStop.add(new int[]{match.getStart(), match.getEnd()}); + //startStop.add(new int[]{match.getStart(), match.getEnd()}); + Offsets matchOffsets = match.getOffsets(); + if (!matchOffsets.overlaps(offsets.peekLast())) { + offsets.add(match.getOffsets()); + } else { + //if the new offsets overlap, combine them into one and add them to the list + Offsets combinedOffsets = matchOffsets.combine(offsets.pop()); + offsets.add(combinedOffsets); + } } + List startStop = new ArrayList<>(1); + for (Offsets os : offsets) { + startStop.add(os.toArray()); + } issues.add(getScanIssue(baseRequestResponse, matches, startStop)); callbacks.printOutput("issues: " + issues.size()); + callbacks.printOutput("offsets: " + offsets.size()); } return issues; diff --git a/src/main/java/com/codemagi/burp/ScanIssue.java b/src/main/java/com/codemagi/burp/ScanIssue.java index e01cd2a..a826bd2 100644 --- a/src/main/java/com/codemagi/burp/ScanIssue.java +++ b/src/main/java/com/codemagi/burp/ScanIssue.java @@ -59,7 +59,7 @@ public ScanIssue( this.severity = severity; this.confidence = confidence; } - + public ScanIssue(IScanIssue existing) { this.httpService = existing.getHttpService(); this.url = existing.getUrl(); diff --git a/src/main/java/com/codemagi/burp/ScannerMatch.java b/src/main/java/com/codemagi/burp/ScannerMatch.java index b2d92dd..c739707 100644 --- a/src/main/java/com/codemagi/burp/ScannerMatch.java +++ b/src/main/java/com/codemagi/burp/ScannerMatch.java @@ -8,33 +8,29 @@ */ public class ScannerMatch implements Comparable { - private Integer start; - private int end; private String fullMatch; private String matchGroup; private String type; private ScanIssueSeverity severity; private ScanIssueConfidence confidence; private MatchRule rule; + private Offsets offsets; public ScannerMatch(int start, int end, String match, String type) { - this.start = start; - this.end = end; + offsets = new Offsets(start, end); this.matchGroup = match; this.type = type; } public ScannerMatch(Integer start, int end, String match, String type, ScanIssueSeverity severity) { - this.start = start; - this.end = end; + offsets = new Offsets(start, end); this.matchGroup = match; this.type = type; this.severity = severity; } public ScannerMatch(Integer start, int end, String match, MatchRule rule) { - this.start = start; - this.end = end; + offsets = new Offsets(start, end); this.matchGroup = match; this.rule = rule; this.type = rule.getType(); @@ -43,8 +39,7 @@ public ScannerMatch(Integer start, int end, String match, MatchRule rule) { } public ScannerMatch(Integer start, int end, String fullMatch, String matchGroup, MatchRule rule) { - this.start = start; - this.end = end; + offsets = new Offsets(start, end); this.fullMatch = fullMatch; this.matchGroup = matchGroup; this.rule = rule; @@ -53,12 +48,12 @@ public ScannerMatch(Integer start, int end, String fullMatch, String matchGroup, this.confidence = rule.getConfidence(); } - public int getStart() { - return start; + public Integer getStart() { + return offsets.getStart(); } - public int getEnd() { - return end; + public Integer getEnd() { + return offsets.getEnd(); } public String getFullMatch() { @@ -73,9 +68,9 @@ public MatchRule getRule() { return rule; } - public Pattern getPattern() { - return rule.getPattern(); - } + public Pattern getPattern() { + return rule.getPattern(); + } public String getType() { return type; @@ -91,7 +86,11 @@ public ScanIssueConfidence getConfidence() { @Override public int compareTo(ScannerMatch m) { - return start.compareTo(m.getStart()); + return this.getStart().compareTo(m.getStart()); } + public Offsets getOffsets() { + return offsets; + } + } diff --git a/src/test/java/com/codemagi/burp/OffsetsTest.java b/src/test/java/com/codemagi/burp/OffsetsTest.java new file mode 100644 index 0000000..8da8108 --- /dev/null +++ b/src/test/java/com/codemagi/burp/OffsetsTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021 august. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.codemagi.burp; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author august + */ +public class OffsetsTest { + + Offsets a = new Offsets(10, 15); + Offsets b = new Offsets(20, 25); + Offsets c = new Offsets(12, 17); + Offsets d = new Offsets(8, 13); + Offsets e = new Offsets(5, 20); + + public OffsetsTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void testOverlap() { + assertFalse(a.overlaps(b)); + assertFalse(b.overlaps(a)); + + assertTrue(a.overlaps(c)); + assertTrue(c.overlaps(a)); + + assertTrue(a.overlaps(d)); + assertTrue(d.overlaps(a)); + + assertTrue(a.overlaps(e)); + assertTrue(e.overlaps(a)); + + assertTrue(b.overlaps(e)); + assertTrue(e.overlaps(b)); + } + + @Test + public void testCombine() { + Offsets product = a.combine(c); + assertEquals(new Integer(10), product.getStart()); + assertEquals(new Integer(17), product.getEnd()); + } +}