package burp;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
public class BurpExtender implements IBurpExtender, ITab, Runnable {
private IBurpExtenderCallbacks callbacks;
private IExtensionHelpers helpers;
private JPanel mainPanel;
private JTable resultTable;
private JTextArea requestTextArea;
private JTextArea responseTextArea;
private DefaultTableModel tableModel;
private List<IHttpRequestResponse> httpMessages = new ArrayList<>();
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) {
this.callbacks = callbacks;
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Dir Index Checker");
SwingUtilities.invokeLater(this);
}
@Override
public void run() {
mainPanel = new JPanel(new BorderLayout());
// Top button panel
JButton scanButton = new JButton("Scan Site Map for Directory Indexing");
scanButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
scanSiteMap();
}
});
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
topPanel.add(scanButton);
mainPanel.add(topPanel, BorderLayout.NORTH);
// Table for results
String[] columnNames = {"URL", "Status", "Indexing", "Time"};
tableModel = new DefaultTableModel(columnNames, 0);
resultTable = new JTable(tableModel);
JScrollPane tableScrollPane = new JScrollPane(resultTable);
mainPanel.add(tableScrollPane, BorderLayout.CENTER);
// Split pane for request/response view
requestTextArea = new JTextArea();
responseTextArea = new JTextArea();
requestTextArea.setEditable(false);
responseTextArea.setEditable(false);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
new JScrollPane(requestTextArea), new JScrollPane(responseTextArea));
splitPane.setDividerLocation(500);
mainPanel.add(splitPane, BorderLayout.SOUTH);
// Event on row selection
resultTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int selectedRow = resultTable.getSelectedRow();
if (selectedRow >= 0 && selectedRow < httpMessages.size()) {
IHttpRequestResponse message = httpMessages.get(selectedRow);
requestTextArea.setText(helpers.bytesToString(message.getRequest()));
responseTextArea.setText(helpers.bytesToString(message.getResponse()));
}
}
});
callbacks.addSuiteTab(this);
}
private void scanSiteMap() {
tableModel.setRowCount(0);
httpMessages.clear();
IHttpRequestResponse[] siteMapItems = callbacks.getSiteMap(null);
Set<String> visited = new HashSet<>();
for (IHttpRequestResponse item : siteMapItems) {
IRequestInfo reqInfo = helpers.analyzeRequest(item);
URL url = reqInfo.getUrl();
String urlString = url.toString();
if (!urlString.endsWith("/")) continue; // only directory paths
if (visited.contains(urlString)) continue;
visited.add(urlString);
byte[] responseBytes = item.getResponse();
if (responseBytes == null) continue;
IResponseInfo resInfo = helpers.analyzeResponse(responseBytes);
int statusCode = resInfo.getStatusCode();
String body = helpers.bytesToString(responseBytes).substring(resInfo.getBodyOffset());
boolean isIndexed = body.contains("Index of")
|| body.matches("(?i).*<title>\s*Index of.*</title>.*")
|| body.matches("(?i).*<a href\s*=\s*"[^"]+".*>.*</a>.*");
String indexingStr = isIndexed ? "YES" : "NO";
String timeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
tableModel.addRow(new Object[]{urlString, statusCode, indexingStr, timeStr});
httpMessages.add(item);
}
if (tableModel.getRowCount() == 0) {
JOptionPane.showMessageDialog(mainPanel,
"No directory-style URLs or valid responses found in Site Map.",
"Notice", JOptionPane.INFORMATION_MESSAGE);
}
}
@Override
public String getTabCaption() {
return "Dir Index Checker";
}
@Override
public Component getUiComponent() {
return mainPanel;
}
}