Burp Suite User Forum

Create new post

File [Save As] Dialog appearing multiple times when saving a log

Sakura | Last updated: Aug 04, 2023 10:27AM UTC

I am creating a Burp Suite Extension using Java for saving the request/response into a file. The scenario is: 1. Select a log from the [Proxy→HTTP History] 2.Right click, then go to the [Extensions] Menu and select my Extension. 3. [Save as] dialog should appear and the file will be created upon saving. The code worked fine when saving the first log. But when I selected the second log, the [Save as] dialog will appear twice. When I select the third log, it will appear 3 times and so on. I can't figure out if the problem is with the JMenuItem.addActionListener() or in the JFileChooser. Please advise. Thank you very much in advance. Here's my code. -------------------------------------------------------------------------------- public class MyBurpSuiteExtension implements BurpExtension { // Extension name private static final String EXTENSION_NAME = "My Burp Suite Extension"; @Override public void initialize(MontoyaApi api) { // Set Name to be displayed on the Burp Extension List api.extension().setName(EXTENSION_NAME); // Display message to check if extension is loaded successfully api.logging().logToOutput("Extension has been loaded."); // Create Menu in Burp Suite api.userInterface().registerContextMenuItemsProvider(new MyContextMenuItemsProvider(api)); } } -------------------------------------------------------------------------------- public class MyContextMenuItemsProvider implements ContextMenuItemsProvider { private static MontoyaApi api; private final JMenuItem saveReqResData; private final static String SAVE_REQRESDATA = "Save Request & Response Data"; public MyContextMenuItemsProvider(MontoyaApi api) { MyContextMenuItemsProvider.api = api; saveReqResData = new JMenuItem(SAVE_REQRESDATA); api.logging().logToOutput("\nMy Burp Suite Menu Created\n"); } @Override public List<Component> provideMenuItems(ContextMenuEvent event) { List<Component> menuItemList = new ArrayList<>(); try { /************************/ // Get data for request response String reqResData = getRequestResponse(event); //getRequestResponse code not included in snippet /************************/ if (reqResData.length() > 0 || reqResData != null) { saveReqResData.addActionListener(l -> { try { FileUtil.saveToFile((Component)l.getSource(), reqResData); } catch (IOException e) { api.logging().logToOutput(e.getMessage()); } }); } /************************/ // Set menu item list menuItemList.add(saveReqResData); } catch (Exception e) { api.logging().logToOutput(e.getMessage()); } return menuItemList; } } -------------------------------------------------------------------------------- public class FileUtil { public static void saveToFile(Component parent, String str) throws IOException { Preferences pref = Preferences.userRoot(); // Retrieve the selected path or use an empty string if no path has previously been selected String path = pref.get("DEFAULT_PATH", ""); JFileChooser fc = new JFileChooser(); // Set the path that was saved in preferences fc.setCurrentDirectory(new File(path)); if (fc.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); fc.setCurrentDirectory(f); // Save the selected path pref.put("DEFAULT_PATH", f.getAbsolutePath()); JFrame jframe = new JFrame(); if (f.exists() && fc.getDialogType() == JFileChooser.SAVE_DIALOG) { int result = JOptionPane.showConfirmDialog(jframe, "The file exists, overwrite?", "Confirm", JOptionPane.YES_NO_OPTION); // If file is to be overwritten if (result == JOptionPane.YES_OPTION) { // check if file is open. boolean fileIsOpen = f.renameTo(f); if (fileIsOpen) { JOptionPane.showMessageDialog(jframe, "Cannot overwrite. File is opened.", "Error", JOptionPane.ERROR_MESSAGE); return; } } else { return; } } writeToFile(f, str); } } public static void writeToFile(File f, String str) { try (FileOutputStream fos = new FileOutputStream(f)) { fos.write(str.getBytes()); fos.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } }

Hannah, PortSwigger Agent | Last updated: Aug 07, 2023 10:28AM UTC


The reason this is occurring is because every time a right-click occurs, you are adding an additional action listener to your JMenuItem.

Could you move "saveReqResData = new JMenuItem(SAVE_REQRESDATA);" from the constructor to the "provideMenuItems()" function instead?

This should mean that only one action listener is added to a JMenuItem each time. Any leftover JMenuItems will be cleaned up by Java's garbage collector.

Sakura | Last updated: Aug 10, 2023 06:05AM UTC

Hi, Thank you for your assistance with this matter. This solution worked. By the way, my base code for this came from the ContextMenu code from the Burp Extensions Montoya API example.

Hannah, PortSwigger Agent | Last updated: Aug 10, 2023 08:27AM UTC

Glad to hear that worked! We've updated the example to reduce the amount of other people encountering this issue. If there's anything else we can help with, then please let us know.

You must be an existing, logged-in customer to reply to a thread. Please email us for additional support.