diff --git a/BappDescription.html b/BappDescription.html
index 8e58698..08b8c2f 100644
--- a/BappDescription.html
+++ b/BappDescription.html
@@ -8,5 +8,6 @@
Configure the parameters used for the scan and customize them in any way you want
Edit the base request performed (you can add headers, cookies, edit the User Agent, etc)
Save the scan output to a file
+ Create an Intruder Payload Set for guessing complete names from shortnames retrieved from scan results (by using wordlists)
The source code is available here
\ No newline at end of file
diff --git a/README.md b/README.md
index 9b6e67d..b244ef0 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ In the Burp UI tab you can:
* Configure the parameters used for the scan and customize them in any way you want
* Edit the base request performed (you can add headers, cookies, edit the User Agent, etc)
* Save the scan output to a file
+* Create an Intruder Payload Set for guessing complete names from shortnames retrieved from scan results (by using wordlists)
## Screenshots
@@ -21,3 +22,13 @@ In the Burp UI tab you can:
### Configuration tab (1366x768)
![config_tab](https://user-images.githubusercontent.com/35109470/146651516-fa33595c-0904-497b-9e28-7591428d5449.png)
+
+## Changelog
+
+* v1.1
+
+ Added an Intruder Payload Set Generator for guessing complete names from shortnames retrieved from scan results (by using wordlists)
+
+* v1.0
+
+ First release
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 86f4dba..cdb0bca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
apply plugin: 'java'
-version '1.0'
+version '1.1'
repositories {
mavenCentral()
diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java
index 22605e6..45ec05a 100644
--- a/src/burp/BurpExtender.java
+++ b/src/burp/BurpExtender.java
@@ -5,12 +5,17 @@
import java.io.UnsupportedEncodingException;
import java.io.FileOutputStream;
import java.io.File;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.LinkedHashSet;
+import java.util.Collections;
import java.net.URL;
import java.net.URLEncoder;
import java.awt.Font;
@@ -39,13 +44,13 @@
import javax.swing.border.CompoundBorder;
import javax.swing.JFileChooser;
-public class BurpExtender implements IBurpExtender, ITab, IScannerCheck
+public class BurpExtender implements IBurpExtender, ITab, IScannerCheck, IIntruderPayloadGeneratorFactory
{
private IBurpExtenderCallbacks callbacks;
private IExtensionHelpers helpers;
private final String NAME = "IIS Tilde Enumeration Scanner";
- private final String VERSION = "1.0";
+ private final String VERSION = "1.1";
private final String AUTHOR = "Michele 'cyberaz0r' Di Bonaventura";
private JTabbedPane mainUI;
@@ -53,6 +58,7 @@ public class BurpExtender implements IBurpExtender, ITab, IScannerCheck
private KillableThread tildeEnumScanner = new KillableThread();
+ private List intruderPayloads = new ArrayList();
// extension tab name
@Override
@@ -84,6 +90,9 @@ public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks)
// register scanner checks
callbacks.registerScannerCheck(this);
+
+ // register intruder payload generator (for filename guessing from scan results)
+ callbacks.registerIntruderPayloadGeneratorFactory(this);
SwingUtilities.invokeLater(new Runnable()
{
@@ -110,9 +119,12 @@ public void actionPerformed(ActionEvent e)
t.setRepeats(false);
// setting up config panel in configuration tab
+ JPanel rightPanel = new JPanel();
+ rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
+ JScrollPane rightScrollPanel = new JScrollPane(rightPanel);
+ rightScrollPanel.setBorder(new EmptyBorder(20, 20, 20, 20));
+
JPanel confPanel = new JPanel(new GridLayout(27, 1));
- JScrollPane confScrollPanel = new JScrollPane(confPanel);
- confScrollPanel.setBorder(new EmptyBorder(20, 20, 20, 20));
JLabel confTitle = new JLabel("Configuration");
confTitle.setForeground(new Color(249, 130, 11));
@@ -135,6 +147,7 @@ public void actionPerformed(ActionEvent e)
// setting up elements in request panel in configuration tab
JTextPane requestEditor = new JTextPane();
JScrollPane requestScrollEditor = new JScrollPane(requestEditor);
+ requestEditor.setFont(new Font("Courier", 0, 14));
requestEditor.setBorder(BorderFactory.createLineBorder(Color.BLACK));
requestEditor.setText
(
@@ -201,7 +214,30 @@ public void actionPerformed(ActionEvent e)
confPanel.add(new JLabel("In-Scope characters:"));
confFields.put("inScopeCharacters", new JTextField("ETAONRISHDLFCMUGYPWBVKJXQZ0123456789_-$~()&!#%'@^`{}", 50));
confPanel.add(confFields.get("inScopeCharacters"));
+
+ JPanel filenameGuessingPanel = new JPanel(new GridLayout(6, 1));
+
+ JLabel filenameGuessingTitle = new JLabel("Complete filename guessing");
+ filenameGuessingTitle.setForeground(new Color(249, 130, 11));
+ filenameGuessingTitle.setFont(new Font("Nimbus", Font.BOLD, 16));
+ filenameGuessingTitle.setAlignmentX(Component.LEFT_ALIGNMENT);
+ filenameGuessingTitle.setBorder(new CompoundBorder(confTitle.getBorder(), new EmptyBorder(10, 10, 10, 10)));
+ filenameGuessingPanel.add(filenameGuessingTitle);
+
+ JCheckBox completeFileGuessCheckbox = new JCheckBox("Create an Intruder Payload Set with possible filenames (using wordlists)", false);
+ filenameGuessingPanel.add(completeFileGuessCheckbox);
+
+ filenameGuessingPanel.add(new JLabel("Complete file name wordlist:"));
+ confFields.put("fileNameWordlist", new JTextField("", 50));
+ filenameGuessingPanel.add(confFields.get("fileNameWordlist"));
+
+ filenameGuessingPanel.add(new JLabel("Complete file extension wordlist:"));
+ confFields.put("fileExtWordlist", new JTextField("", 50));
+ filenameGuessingPanel.add(confFields.get("fileExtWordlist"));
+ rightPanel.add(confPanel);
+ rightPanel.add(filenameGuessingPanel);
+
// setting up scanner tab
JSplitPane scannerTab = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
scannerTab.setBorder(new EmptyBorder(20, 20, 20, 20));
@@ -215,6 +251,7 @@ public void actionPerformed(ActionEvent e)
// setting up elements in scanner tab
JTextPane textPane = new JTextPane();
JScrollPane textScrollPane = new JScrollPane(textPane);
+ textPane.setFont(new Font("Courier", 0, 12));
textPane.setText("IIS Tilde Enumeration Scanner Burp Extension is ready\nThe scan output will be displayed here");
textPane.setEditable(false);
@@ -256,6 +293,7 @@ public void actionPerformed(ActionEvent e)
confFields,
nThreadsField,
exploitModeCheckbox,
+ completeFileGuessCheckbox,
requestEditor,
statusLabel
)
@@ -282,7 +320,7 @@ public void actionPerformed(ActionEvent a)
scannerTab.setBottomComponent(scannerBottomPanel);
configTab.setTopComponent(requestPanel);
- configTab.setBottomComponent(confScrollPanel);
+ configTab.setBottomComponent(rightScrollPanel);
t.start(); // triggering listener for splitting config tab 50:50
@@ -450,6 +488,18 @@ public List doPassiveScan(IHttpRequestResponse baseRequestResponse)
{
return null;
}
+
+ @Override
+ public String getGeneratorName()
+ {
+ return "Filename guessing from Tilde Enumeration scan results";
+ }
+
+ @Override
+ public IIntruderPayloadGenerator createNewInstance(IIntruderAttack attack)
+ {
+ return new IntruderPayloadGenerator(intruderPayloads);
+ }
// strip response data in order to get more granular results
public String stripResponse(String response, String basePath, String queryString)
@@ -510,8 +560,11 @@ class CustomConfig
private int deltaResponseLength;
private int nThreads;
private boolean exploitMode;
+ private boolean completeFileGuess;
+ private File fileNameWordlist;
+ private File fileExtWordlist;
- public CustomConfig(HashMap confFields, JTextPane requestEditor, JTextField nThreadsField, JCheckBox exploitModeCheckbox)
+ public CustomConfig(HashMap confFields, JTextPane requestEditor, JTextField nThreadsField, JCheckBox exploitModeCheckbox, JCheckBox completeFileGuessCheckbox)
{
this.magicFinalPartList = Arrays.asList(confFields.get("magicFinalPartList").getText().split(","));
this.questionMarkSymbol = confFields.get("questionMarkSymbol").getText();
@@ -529,6 +582,9 @@ public CustomConfig(HashMap confFields, JTextPane requestEdi
this.requestString = requestEditor.getText();
this.nThreads = Integer.parseInt(nThreadsField.getText());
this.exploitMode = exploitModeCheckbox.isSelected();
+ this.completeFileGuess = completeFileGuessCheckbox.isSelected();
+ this.fileNameWordlist = new File(confFields.get("fileNameWordlist").getText());
+ this.fileExtWordlist = new File(confFields.get("fileExtWordlist").getText());
}
public List getMagicFinalPartList()
@@ -610,6 +666,21 @@ public boolean getExploitMode()
{
return this.exploitMode;
}
+
+ public boolean getCompleteFileGuess()
+ {
+ return this.completeFileGuess;
+ }
+
+ public File getFileNameWordlist()
+ {
+ return this.fileNameWordlist;
+ }
+
+ public File getFileExtWordlist()
+ {
+ return this.fileExtWordlist;
+ }
public void setQuestionMarkSymbol(String questionMarkSymbol)
{
@@ -671,10 +742,11 @@ class StartScanButton implements ActionListener
private HashMap confFields;
private JTextField nThreadsField;
private JCheckBox exploitModeCheckbox;
+ private JCheckBox completeFileGuessCheckbox;
private JTextPane requestEditor;
private JLabel statusLabel;
- public StartScanButton(JTextField targetUrlField, JTextPane textPane, HashMap confFields, JTextField nThreadsField, JCheckBox exploitModeCheckbox, JTextPane requestEditor, JLabel statusLabel)
+ public StartScanButton(JTextField targetUrlField, JTextPane textPane, HashMap confFields, JTextField nThreadsField, JCheckBox exploitModeCheckbox, JCheckBox completeFileGuessCheckbox, JTextPane requestEditor, JLabel statusLabel)
{
super();
this.targetUrlField = targetUrlField;
@@ -682,6 +754,7 @@ public StartScanButton(JTextField targetUrlField, JTextPane textPane, HashMap insertionPoints = new ArrayList() {{ add(new int[] {offset, offset}); }};
+
+ // send base request to intruder
+ callbacks.sendToIntruder
+ (
+ requester.getHttpService().getHost(),
+ requester.getHttpService().getPort(),
+ requester.getHttpService().getProtocol().equals("https"),
+ config.getRequestString()
+ .replace("§METHOD§", "GET")
+ .replace("§HOST§", requester.getHttpService().getHost())
+ .replace("§PATH§", requester.getBasePath() + "/")
+ .replace("\n", "\r\n")
+ .getBytes(),
+ insertionPoints
+ );
+
+ output.print("[+] Generated " + intruderPayloads.size() + " possible complete filenames, switch to Intruder to launch a guessing attack using the generated filenames");
+ }
-
+ output.status("Scan completed");
toggleScanButton(false);
}
catch (RuntimeException e)
@@ -2044,6 +2167,116 @@ private boolean isFolder(String strInput)
return false;
}
}
+
+ class MatchList
+ {
+ private List matches;
+ private List elementsFound;
+ private List possibleFileNames;
+ private List possibleFileExts;
+
+ public MatchList(List dirsFound, List filesFound, File fileNameWordlist, File fileExtWordlist)
+ {
+ this.elementsFound = buildElementList(dirsFound, filesFound);
+ this.possibleFileNames = Utils.readFile(fileNameWordlist);
+ this.possibleFileExts = Utils.readFile(fileExtWordlist);
+ this.matches = buildMatchList();
+ }
+
+ private List buildElementList(List dirsFound, List filesFound)
+ {
+ List elements = new ArrayList();
+ List parsedElements = new ArrayList();
+
+ elements.addAll(dirsFound);
+ elements.addAll(filesFound);
+ Collections.sort(elements);
+
+ for (int i = 0; i < elements.size(); i++)
+ {
+ if (i < elements.size() - 1)
+ {
+ if (elements.get(i+1).startsWith(elements.get(i)))
+ {
+ continue;
+ }
+ }
+
+ parsedElements.add(elements.get(i).replace("\\?", ""));
+ }
+
+ return parsedElements;
+ }
+
+ private List buildMatchList()
+ {
+ List matchesFound = new ArrayList();
+
+ for (String name : possibleFileNames)
+ {
+ for (String elem : elementsFound)
+ {
+ String elemName = elem.split("~")[0];
+
+ if (elemName.length() < 6)
+ {
+ continue;
+ }
+
+ if (name.toUpperCase().startsWith(elemName))
+ {
+ if (elem.indexOf(".") > 0)
+ {
+ List elemExts = buildExtensionList(elem.substring(elem.lastIndexOf('.') + 1));
+ for (String ext : elemExts)
+ {
+ matchesFound.add(name.toUpperCase() + "." + ext);
+ }
+ }
+ else
+ {
+ matchesFound.add(name.toUpperCase());
+ }
+ }
+
+ }
+ }
+
+ Collections.sort(matchesFound);
+ return matchesFound;
+ }
+
+ private List buildExtensionList(String elemExt)
+ {
+ List fileExts = new ArrayList();
+
+ for (String ext : possibleFileExts)
+ {
+ if (ext.startsWith("."))
+ {
+ ext = ext.substring(1, ext.length());
+ }
+
+ if (ext.toUpperCase().startsWith(elemExt))
+ {
+ fileExts.add(ext.toUpperCase());
+ }
+ }
+
+ if (fileExts.isEmpty())
+ {
+ fileExts.add(elemExt);
+ }
+
+ // remove duplicates before return
+ return new ArrayList(new LinkedHashSet<>(fileExts));
+ }
+
+ public List getMatches()
+ {
+ return this.matches;
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2211,6 +2444,38 @@ public void run()
}
}
+// class to handle Intruder payload generator for filename guessing from scan results
+class IntruderPayloadGenerator implements IIntruderPayloadGenerator
+{
+ private List payloads;
+ int payloadIndex;
+
+ public IntruderPayloadGenerator(List payloads)
+ {
+ this.payloads = payloads;
+ }
+
+ @Override
+ public boolean hasMorePayloads()
+ {
+ return payloadIndex < payloads.size();
+ }
+
+ @Override
+ public byte[] getNextPayload(byte[] baseValue)
+ {
+ byte[] payload = payloads.get(payloadIndex).getBytes();
+ payloadIndex++;
+ return payload;
+ }
+
+ @Override
+ public void reset()
+ {
+ payloadIndex = 0;
+ }
+}
+
// custom issue class
class CustomScanIssue implements IScanIssue
{
@@ -2349,4 +2614,30 @@ public static String tree(String str, int level)
String dentSpace = new String(new char[level]).replace("\0", " ");
return dentSpace + "|_ " + str;
}
+
+ public static List readFile(File file)
+ {
+ List fileContent = new ArrayList();
+
+ try (BufferedReader br = new BufferedReader(new FileReader(file)))
+ {
+ String line;
+ while ((line = br.readLine()) != null)
+ {
+ fileContent.add(line);
+ }
+ }
+
+ catch (FileNotFoundException e)
+ {
+ return null;
+ }
+
+ catch (IOException e)
+ {
+ return null;
+ }
+
+ return fileContent;
+ }
}