All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codemagi.burp.RuleTableComponent Maven / Gradle / Ivy

Go to download

The Burp Suite Utils project provides developers with APIs for building Burp Suite Extensions.

The newest version!
package com.codemagi.burp;

import burp.IBurpExtenderCallbacks;
import burp.IHttpService;
import burp.impl.HttpService;
import com.codemagi.burp.parser.HttpRequest;
import com.codemagi.burp.parser.HttpResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.DefaultCellEditor;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

public class RuleTableComponent extends javax.swing.JPanel {

    IBurpExtenderCallbacks mCallbacks;
    PassiveScan scan;

    private String DEFAULT_URL = "https://raw.githubusercontent.com/augustd/burp-suite-software-version-checks/master/src/burp/match-rules.tab";
    private String backupUrl; 
    public static final String SETTING_URL = "SETTING_URL";
    
    /**
     * Creates new form BurpSuiteTab
     *
     * @param passiveScan The scan to initialize this component for
     * @param callbacks The Burp Extender callbacks object
     * @param defaultUrl The default URL to load match rules from
     */
    public RuleTableComponent(PassiveScan passiveScan, IBurpExtenderCallbacks callbacks, String defaultUrl) {
        this(passiveScan, callbacks, defaultUrl, null);
    }
        
    public RuleTableComponent(PassiveScan passiveScan, IBurpExtenderCallbacks callbacks, String defaultUrl, String backupUrl) {

	mCallbacks = callbacks;
	this.scan = passiveScan;
        this.DEFAULT_URL = defaultUrl;
        this.backupUrl = backupUrl;

	initComponents();

	mCallbacks.customizeUiComponent(rules);
        
        //restore saved settings 
        restoreSettings();
        
	//load match rules from configured URL
        MatchRulesLoader loader = new MatchRulesLoader(urlTextField.getText());
        loader.start();

        //add a listener for changes to the table model
        final DefaultTableModel model = (DefaultTableModel)rules.getModel();
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                if (TableModelEvent.UPDATE == e.getType()) {
                    mCallbacks.printOutput(e.toString());
                    int row = e.getFirstRow();
                    int column = e.getColumn();
                    mCallbacks.printOutput("row: " + row + " column: " + column + " value: " + model.getValueAt(row, column));
                    MatchRule rule = scan.getMatchRule(row);
                    mCallbacks.printOutput("rule 1: " + rule); 
                    if (rule == null) {
                        rule = new MatchRule(Pattern.compile("."), 1, "", ScanIssueSeverity.LOW, ScanIssueConfidence.CERTAIN);
                        scan.addMatchRule(rule);
                    }
                    mCallbacks.printOutput("rule 2: " + rule); 
                    
                    switch (column) { 
                        case 0: 
                            mCallbacks.printOutput("new pattern: " + (String)model.getValueAt(row, column));
                            rule.setPattern(Pattern.compile((String)model.getValueAt(row, column)));
                            break;
                        case 1:
                            rule.setMatchGroup((Integer)model.getValueAt(row, column));
                            break;
                       case 2:
                            rule.setType((String)model.getValueAt(row, column));
                            break;
                        case 3:
                            rule.setSeverity(ScanIssueSeverity.fromName((String)model.getValueAt(row, column)));
                            break;
                        case 4:
                            rule.setConfidence(ScanIssueConfidence.fromName((String)model.getValueAt(row, column)));
                            break;
                    }
                }
            }
        });
    }

    /**
     * Load match rules from a URL
     */
    private boolean loadMatchRules(String rulesUrl) {
        //load match rules from file
        try {
            //check for file URL
            if (rulesUrl != null && rulesUrl.toLowerCase().startsWith("file:")) {
                return loadMatchRulesFromFile(rulesUrl);
            }

            //request match rules from remote URL
            mCallbacks.printOutput("Loading match rules from: " + rulesUrl);
            URL url = new URL(rulesUrl);
            IHttpService service = new HttpService(url);
            HttpRequest request = new HttpRequest(url);
            HttpRequestThread requestThread = new HttpRequestThread(service, request.getBytes(), BaseExtender.getCallbacks());
            byte[] responseBytes = null;
            try {
                TimeLimitedCodeBlock.runWithTimeout(requestThread, 60, TimeUnit.SECONDS);
                responseBytes = requestThread.getResponse();
            } catch (Exception ex) {
                BaseExtender.printStackTrace(ex);
            }

            //parse the response
            if (responseBytes == null) return false; //no response received from server
            HttpResponse response = HttpResponse.parseMessage(responseBytes);

            //read match rules from the response
            Reader is = new StringReader(response.getBody());
            BufferedReader reader = new BufferedReader(is);

            processMatchRules(reader);

            return true;

        } catch (IOException e) {
            scan.printStackTrace(e);
        } catch (Exception e) {
            scan.printStackTrace(e);
        }

        return false;
    }
    
    protected class MatchRulesLoader extends Thread {
        
        private String rulesUrl; 
        
        public MatchRulesLoader(String rulesUrl) {
            this.rulesUrl = rulesUrl;
        }
        
        @Override
        public void run() {
            boolean success = loadMatchRules(rulesUrl);

            if (success) {
                saveSettings();
            } else if (!success && backupUrl != null) {
                mCallbacks.printOutput("WARNING: Failed to load remote match rules");
                success = loadMatchRulesFromJar(backupUrl);
            }
        }
        
    }

    /**
     * Load match rules from within the jar
     */
    private boolean loadMatchRulesFromJar(String rulesUrl) {
	//load match rules from a local file
	try {
	    mCallbacks.printOutput("Loading match rules from local jar: " + rulesUrl);
            InputStream in = getClass().getClassLoader().getResourceAsStream(rulesUrl); 
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            processMatchRules(reader);
            
            return true;

	} catch (IOException e) {
	    scan.printStackTrace(e);
	} catch (NumberFormatException e) {
	    scan.printStackTrace(e);
	}
        
        return false;
    }

    /**
     * Load match rules from a file URL 
     */
    private boolean loadMatchRulesFromFile(String rulesUrl) {
	//load match rules from a local file
	try {
	    mCallbacks.printOutput("Loading match rules from file: " + rulesUrl);
            InputStream in = new URL(rulesUrl).openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));

            processMatchRules(reader);
            
            return true;

	} catch (IOException e) {
	    scan.printStackTrace(e);
	} catch (NumberFormatException e) {
	    scan.printStackTrace(e);
	}
        
        return false;
    }
    
    private void processMatchRules(BufferedReader reader) throws IOException {
        DefaultTableModel model = (DefaultTableModel)rules.getModel();

        String str;
        while ((str = reader.readLine()) != null) {
            mCallbacks.printOutput("str: " + str);
            if (str.trim().length() == 0) {
                continue;
            }

            String[] values = str.split("\\t");
            model.addRow(values);

            try {
                Pattern pattern = Pattern.compile(values[0]);

                scan.addMatchRule(new MatchRule(
                        pattern,
                        new Integer(values[1]),
                        values[2],
                        ScanIssueSeverity.fromName(values[3]),
                        ScanIssueConfidence.fromName(values[4]))
                );
            } catch (PatternSyntaxException pse) {
                //in case the match pattern is invalid
                mCallbacks.printError("Invalid match pattern: " + values[0]);
                
            } catch (NumberFormatException e) {
                //in case the match group is invalid
                mCallbacks.printError("Invalid match group: " + values[1]);
            }
        }
    }
    
    /**
     * Save all configured settings
     */
    public void saveSettings() {
        mCallbacks.printOutput("Saving settings...");
        
        // Clear settings
        mCallbacks.saveExtensionSetting(scan.getSettingsNamespace() + SETTING_URL, null);
        
        // Store settings
        mCallbacks.printOutput("Saving URL: " + urlTextField.getText());
        mCallbacks.saveExtensionSetting(scan.getSettingsNamespace() + SETTING_URL, urlTextField.getText());
    }
    
    /**
     * Restores any found saved settings
     */
    public void restoreSettings() {
        mCallbacks.printOutput("Restoring settings...");
        
        String settingUrl = mCallbacks.loadExtensionSetting(scan.getSettingsNamespace() + SETTING_URL);
        mCallbacks.printOutput("Match rules URL from settings: " + settingUrl);
        if (settingUrl != null) {
            urlTextField.setText(settingUrl);
            //extender.setFormUrl(settingUrl);
        }
    }
    
    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // //GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane2 = new javax.swing.JScrollPane();
        rules = new javax.swing.JTable();
        jLabel2 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        urlTextField = new javax.swing.JTextField();
        loadBtn = new javax.swing.JButton();
        jLabel7 = new javax.swing.JLabel();
        addBtn = new javax.swing.JButton();
        removeBtn = new javax.swing.JButton();
        resetButton = new javax.swing.JButton();

        rules.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Regex", "Group", "Type", "Severity", "Confidence"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        TableColumn severityColumn = rules.getColumnModel().getColumn(3);
        severityColumn.setCellEditor(new DefaultCellEditor(ScanIssueSeverity.getComboBox()));

        TableColumn confidenceColumn = rules.getColumnModel().getColumn(4);
        confidenceColumn.setCellEditor(new DefaultCellEditor(ScanIssueConfidence.getComboBox()));
        jScrollPane2.setViewportView(rules);

        jLabel2.setFont(new java.awt.Font("Tahoma", 1, 13)); // NOI18N
        jLabel2.setForeground(new java.awt.Color(229, 137, 0));
        jLabel2.setText("Match Rules");

        jLabel6.setText("Match rules use regular epressions to flag software version numbers in server responses");

        urlTextField.setText(DEFAULT_URL);
        urlTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                urlTextFieldActionPerformed(evt);
            }
        });

        loadBtn.setText("Load");
        loadBtn.setIgnoreRepaint(true);
        loadBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadBtnActionPerformed(evt);
            }
        });

        jLabel7.setText("Load rules from URL: ");

        addBtn.setText("Add");
        addBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addBtnActionPerformed(evt);
            }
        });

        removeBtn.setText("Remove");
        removeBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeBtnActionPerformed(evt);
            }
        });

        resetButton.setText("Reset");
        resetButton.setToolTipText("Reload default match rules from GitHub");
        resetButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane2)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jLabel6)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(addBtn)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(removeBtn)))
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel7)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(urlTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 406, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(loadBtn)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(resetButton)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel6)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(urlTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel7)
                    .addComponent(loadBtn)
                    .addComponent(resetButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 381, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(addBtn)
                    .addComponent(removeBtn))
                .addContainerGap(12, Short.MAX_VALUE))
        );
    }// //GEN-END:initComponents

    private void loadBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed
	//issue request to URL in GUI
        MatchRulesLoader loader = new MatchRulesLoader(urlTextField.getText());
        loader.start();
    }//GEN-LAST:event_loadBtnActionPerformed

    private void urlTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_urlTextFieldActionPerformed
	// TODO add your handling code here:
    }//GEN-LAST:event_urlTextFieldActionPerformed

    private void addBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addBtnActionPerformed
        DefaultTableModel model = (DefaultTableModel)rules.getModel();
        model.addRow(new Object[]{"", 1, "", "Low", "Certain"});
    }//GEN-LAST:event_addBtnActionPerformed

    private void removeBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeBtnActionPerformed
        DefaultTableModel model = (DefaultTableModel)rules.getModel();
        int[] rows = rules.getSelectedRows();
        for (int i = 0; i < rows.length; i++) {
            model.removeRow(rows[i] - i);
            scan.removeMatchRule(rows[i] - i);
        }
    }//GEN-LAST:event_removeBtnActionPerformed

    private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetButtonActionPerformed
        //clear the existing values from the table    
        DefaultTableModel model = (DefaultTableModel) rules.getModel();
        model.setRowCount(0);
        
        //remove existing match rules from the scan
        scan.clearMatchRules();

        //load the defaults
        urlTextField.setText(DEFAULT_URL);
        
        //issue request to URL
        MatchRulesLoader loader = new MatchRulesLoader(DEFAULT_URL);
        loader.start();
    }//GEN-LAST:event_resetButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addBtn;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JButton loadBtn;
    private javax.swing.JButton removeBtn;
    private javax.swing.JButton resetButton;
    private javax.swing.JTable rules;
    private javax.swing.JTextField urlTextField;
    // End of variables declaration//GEN-END:variables

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy