From a94c5933ef5af1c0cfdf5e0058029dcffbb99a2e Mon Sep 17 00:00:00 2001 From: tomcruiseqi Date: Sat, 14 Jun 2025 10:14:47 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=20BurpCrypto=20?= =?UTF-8?q?=E4=BB=A5=E5=85=BC=E5=AE=B9=20Burp=20Montoya=20API=202025.6?= =?UTF-8?q?=EF=BC=8C=E4=B8=BB=E7=B1=BB=E5=AE=9E=E7=8E=B0=20BurpExtension?= =?UTF-8?q?=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将主类 BurpExtender 的接口实现由 Extension/ExtensionUnloadingHandler 替换为 BurpExtension,适配新版 Montoya API 要求 - 移除所有与旧 Extension/ExtensionUnloadingHandler 相关的 import 和实现 - 保持 initialize(MontoyaApi api) 作为插件入口,完善 UI 和 PayloadProcessor 注册逻辑 - 清理无用 import,消除 lint 警告 - 重新编译打包,确保项目可在 BurpSuite Pro 2025.6 及以上版本正常加载 --- .gitignore | 94 ++++++++++- pom.xml | 8 +- src/main/java/burp/BurpExtender.java | 96 ++++++----- .../burp/aes/AesIntruderPayloadProcessor.java | 23 +-- src/main/java/burp/aes/AesUIHandler.java | 14 +- .../java/burp/api/montoya/BurpExtension.java | 7 + .../burp/des/DesIntruderPayloadProcessor.java | 23 ++- src/main/java/burp/des/DesUIHandler.java | 14 +- .../ExecJSIntruderPayloadProcessor.java | 26 ++- src/main/java/burp/execjs/JsUIHandler.java | 25 +-- .../MontoyaIntruderPayloadProcessor.java | 28 ++++ .../PBKDF2IntruderPayloadProcessor.java | 24 ++- .../java/burp/pbkdf2/PBKDF2UIHandler.java | 12 +- .../burp/rsa/RsaIntruderPayloadProcessor.java | 22 +-- src/main/java/burp/rsa/RsaUIHandler.java | 10 +- .../burp/sm3/SM3IntruderPayloadProcessor.java | 29 ++-- src/main/java/burp/sm3/SM3UIHandler.java | 10 +- .../burp/sm4/SM4IntruderPayloadProcessor.java | 25 ++- src/main/java/burp/sm4/SM4UIHandler.java | 14 +- .../burp/utils/BurpCryptoMenuFactory.java | 149 ++++++++++-------- .../java/burp/utils/BurpStateListener.java | 4 +- .../burp/zuc/ZUCIntruderPayloadProcessor.java | 25 ++- src/main/java/burp/zuc/ZUCUIHandler.java | 15 +- 23 files changed, 393 insertions(+), 304 deletions(-) create mode 100644 src/main/java/burp/api/montoya/BurpExtension.java create mode 100644 src/main/java/burp/montoya/MontoyaIntruderPayloadProcessor.java diff --git a/.gitignore b/.gitignore index 15aa9b2..d4668a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,89 @@ -/out/ -/target -/.idea -/*.iml -dependency-reduced-pom.xml \ No newline at end of file +# Compiled class files +*.class + +# Package Files +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# Log files +*.log +logs/ +target/*.log + +# Maven temporary files +# Generated by Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar # Maven wrapper executable, often downloaded by users + +# Eclipse IDE +.classpath +.project +.settings/ +*.launch +.metadata +.lock + +# IntelliJ IDEA +.idea/ +*.iws +*.iml +*.ipr +*.burp +out/ + +# VS Code +.vscode/ + +# NetBeans IDE +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +.nb-maven/ + +# OS generated files +.DS_Store # Mac +Thumbs.db # Windows +ehthumbs.db # Windows +Desktop.ini # Windows + +# ReSharper files +_ReSharper*/ +*.user +*.bak + +# Temporary files (often hidden) +*~ +#*# +.#* +%* +._* + +# SCM Files (like Mercurial's .hg) +.hg/ +.hgignore +.hgtags + +# Gradle (if also used with Maven) +.gradle/ +build/ + +# Github Copilot +.github/ + +# Apple DS_Store +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml index 777a3ea..39a1d7f 100644 --- a/pom.xml +++ b/pom.xml @@ -55,11 +55,11 @@ - + - net.portswigger.burp.extender - burp-extender-api - 1.7.22 + net.portswigger.burp.extensions + montoya-api + 2025.6 diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 83283ed..1924d09 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -8,7 +8,6 @@ import burp.sm3.SM3UIHandler; import burp.sm4.SM4UIHandler; import burp.utils.BurpCryptoMenuFactory; -import burp.utils.BurpStateListener; import burp.utils.DictLogManager; import burp.utils.Utils; import burp.zuc.ZUCUIHandler; @@ -23,84 +22,57 @@ import java.io.PrintWriter; import java.util.HashMap; -import static org.iq80.leveldb.impl.Iq80DBFactory.factory; +import burp.api.montoya.MontoyaApi; +import burp.api.montoya.BurpExtension; +import burp.api.montoya.core.Registration; +import burp.api.montoya.intruder.PayloadProcessor; -public class BurpExtender implements IBurpExtender, ITab { +import static org.iq80.leveldb.impl.Iq80DBFactory.factory; - public IExtensionHelpers helpers; - public IBurpExtenderCallbacks callbacks; +public class BurpExtender implements BurpExtension { + public MontoyaApi api; public PrintWriter stdout; public PrintWriter stderr; public DB store; public DictLogManager dict; public String version = "0.1.9.1"; - public HashMap IPProcessors = new HashMap<>(); - + public HashMap IPProcessors = new HashMap<>(); public JTabbedPane mainPanel; - public JPanel aesPanel; public AesUIHandler AesUI; - - public JPanel rsaPanel; public RsaUIHandler RsaUI; - public JPanel desPanel; public DesUIHandler DesUI; - public JPanel execJsPanel; public JsUIHandler JsUI; - public JPanel sm3Panel; public SM3UIHandler SM3UI; - public JPanel sm4Panel; public SM4UIHandler SM4UI; - public JPanel zucPanel; public ZUCUIHandler ZUCUI; - public JPanel pbkdf2Panel; public PBKDF2UIHandler PBKDF2UI; - public boolean RegIPProcessor(String extName, IIntruderPayloadProcessor processor) { - if (IPProcessors.containsKey(extName)) { - JOptionPane.showMessageDialog(mainPanel, "This name already exist!"); - return false; - } - callbacks.registerIntruderPayloadProcessor(processor); - IPProcessors.put(extName, processor); - return true; - } - - public void RemoveIPProcessor(String extName) { - if (IPProcessors.containsKey(extName)) { - IIntruderPayloadProcessor processor = IPProcessors.get(extName); - callbacks.removeIntruderPayloadProcessor(processor); - IPProcessors.remove(extName); - } - } - + // Montoya BurpExtension API required method @Override - public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { + public void initialize(MontoyaApi api) { + this.api = api; SecureUtil.disableBouncyCastle(); - this.callbacks = callbacks; - this.helpers = callbacks.getHelpers(); - Utils.stdout = this.stdout = new PrintWriter(callbacks.getStdout(), true); - Utils.stderr = this.stderr = new PrintWriter(callbacks.getStderr(), true); - callbacks.setExtensionName("BurpCrypto v" + version); - callbacks.registerExtensionStateListener(new BurpStateListener(this)); - callbacks.registerContextMenuFactory(new BurpCryptoMenuFactory(this)); + Utils.stdout = this.stdout = new PrintWriter(System.out, true); + Utils.stderr = this.stderr = new PrintWriter(System.err, true); + api.extension().setName("BurpCrypto v" + version); + api.userInterface().registerContextMenuItemsProvider(new BurpCryptoMenuFactory(this)); Options options = new Options(); options.createIfMissing(true); try { this.store = factory.open(new File("BurpCrypto.ldb"), options); this.dict = new DictLogManager(this); - callbacks.issueAlert("LevelDb init success!"); + api.logging().logToOutput("LevelDb init success!"); } catch (IOException e) { - callbacks.issueAlert("LevelDb init failed! error message: " + e.getMessage()); + api.logging().logToError("LevelDb init failed! error message: " + e.getMessage()); } - stdout.println("BurpCrypto loaded successfully!\r\n"); stdout.println("Anthor: Whwlsfb"); stdout.println("Email: whwlsfb@wanghw.cn"); @@ -136,17 +108,37 @@ private void InitUi() { bthis.mainPanel.addTab("PBKDF2", bthis.pbkdf2Panel); bthis.execJsPanel = JsUI.getPanel(); bthis.mainPanel.addTab("Exec Js", bthis.execJsPanel); - bthis.callbacks.addSuiteTab(bthis); + api.userInterface().registerSuiteTab("BurpCrypto", bthis.mainPanel); }); } - @Override - public String getTabCaption() { - return "BurpCrypto"; + /** + * 注册 Intruder PayloadProcessor + */ + public void regIPProcessor(String name, PayloadProcessor processor) { + if (!IPProcessors.containsKey(name)) { + IPProcessors.put(name, processor); + api.intruder().registerPayloadProcessor(processor); + if (stdout != null) stdout.println("[BurpCrypto] 注册PayloadProcessor: " + name); + } } - @Override - public Component getUiComponent() { - return this.mainPanel; + /** + * 移除 Intruder PayloadProcessor(仅移除本地引用,Burp API 无法主动注销) + */ + public void removeIPProcessor(String name) { + if (IPProcessors.containsKey(name)) { + IPProcessors.remove(name); + if (stdout != null) stdout.println("[BurpCrypto] 移除PayloadProcessor: " + name); + } + } + + public void extensionUnloaded() { + try { + if (this.store != null) this.store.close(); + } catch (IOException e) { + e.printStackTrace(); + } + if (stdout != null) stdout.println("[BurpCrypto] Extension unloaded, LevelDB closed."); } } diff --git a/src/main/java/burp/aes/AesIntruderPayloadProcessor.java b/src/main/java/burp/aes/AesIntruderPayloadProcessor.java index 7430a8c..1841aeb 100644 --- a/src/main/java/burp/aes/AesIntruderPayloadProcessor.java +++ b/src/main/java/burp/aes/AesIntruderPayloadProcessor.java @@ -1,9 +1,12 @@ package burp.aes; import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; +import burp.api.montoya.intruder.PayloadProcessor; -public class AesIntruderPayloadProcessor implements IIntruderPayloadProcessor { +public class AesIntruderPayloadProcessor implements PayloadProcessor { private BurpExtender parent; private final String extName; private final AesUtil AesUtil; @@ -16,21 +19,19 @@ public AesIntruderPayloadProcessor(final BurpExtender newParent, String extName, } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - AES Encrypt - " + extName; } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData data) { try { - byte[] result = AesUtil.encrypt(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = AesUtil.encrypt(data.currentPayload().getBytes()).getBytes("UTF-8"); + parent.dict.Log(result, data.originalPayload().getBytes()); + return PayloadProcessingResult.usePayload(ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + // 可选:parent.api.logging().logToError(e.toString()); + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/aes/AesUIHandler.java b/src/main/java/burp/aes/AesUIHandler.java index df67e9d..c62cd56 100644 --- a/src/main/java/burp/aes/AesUIHandler.java +++ b/src/main/java/burp/aes/AesUIHandler.java @@ -46,7 +46,7 @@ public JPanel getPanel() { final JPanel panel5 = UIUtil.GetXJPanel(); final JLabel label2 = new JLabel("AES Alg: "); - aesAlgSelector = new JComboBox(GetAesAlgs()); + aesAlgSelector = new JComboBox(GetAesAlgs()); aesAlgSelector.setMaximumSize(aesAlgSelector.getPreferredSize()); aesAlgSelector.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { @@ -58,21 +58,21 @@ public JPanel getPanel() { aesAlgSelector.setSelectedIndex(0); final JLabel label3 = new JLabel("AES Key: "); - aesKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); + aesKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); aesKeyFormatSelector.setMaximumSize(aesKeyFormatSelector.getPreferredSize()); aesKeyFormatSelector.setSelectedIndex(0); aesKeyText = new JTextField(200); aesKeyText.setMaximumSize(aesKeyText.getPreferredSize()); final JLabel label4 = new JLabel("AES IV: "); - aesIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); + aesIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); aesIVFormatSelector.setMaximumSize(aesIVFormatSelector.getPreferredSize()); aesIVFormatSelector.setSelectedIndex(0); aesIVText = new JTextField(200); aesIVText.setMaximumSize(aesIVText.getPreferredSize()); final JLabel label5 = new JLabel("Output Format: "); - aesOutFormatSelector = new JComboBox(Utils.GetOutFormats()); + aesOutFormatSelector = new JComboBox(Utils.GetOutFormats()); aesOutFormatSelector.setMaximumSize(aesOutFormatSelector.getPreferredSize()); aesOutFormatSelector.setSelectedIndex(0); @@ -109,8 +109,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new AesIntruderPayloadProcessor(parent, extName, aesConfig))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new AesIntruderPayloadProcessor(parent, extName, aesConfig)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -121,7 +121,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/api/montoya/BurpExtension.java b/src/main/java/burp/api/montoya/BurpExtension.java new file mode 100644 index 0000000..f0db02c --- /dev/null +++ b/src/main/java/burp/api/montoya/BurpExtension.java @@ -0,0 +1,7 @@ +package burp.api.montoya; + +import burp.api.montoya.MontoyaApi; + +public interface BurpExtension { + void initialize(MontoyaApi api); +} diff --git a/src/main/java/burp/des/DesIntruderPayloadProcessor.java b/src/main/java/burp/des/DesIntruderPayloadProcessor.java index fff2487..26e7bca 100644 --- a/src/main/java/burp/des/DesIntruderPayloadProcessor.java +++ b/src/main/java/burp/des/DesIntruderPayloadProcessor.java @@ -1,11 +1,13 @@ package burp.des; import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; - +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; +import burp.api.montoya.intruder.PayloadProcessor; import java.nio.charset.StandardCharsets; -public class DesIntruderPayloadProcessor implements IIntruderPayloadProcessor { +public class DesIntruderPayloadProcessor implements PayloadProcessor { private BurpExtender parent; private final String extName; private final DesUtil DesUtil; @@ -18,21 +20,18 @@ public DesIntruderPayloadProcessor(final BurpExtender newParent, String extName, } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - DES Encrypt - " + extName; } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData data) { try { - byte[] result = DesUtil.encrypt(currentPayload).getBytes(StandardCharsets.UTF_8); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = DesUtil.encrypt(data.currentPayload().getBytes()).getBytes(StandardCharsets.UTF_8); + parent.dict.Log(result, data.originalPayload().getBytes()); + return PayloadProcessingResult.usePayload(ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/des/DesUIHandler.java b/src/main/java/burp/des/DesUIHandler.java index 543d4dc..0a4a4eb 100644 --- a/src/main/java/burp/des/DesUIHandler.java +++ b/src/main/java/burp/des/DesUIHandler.java @@ -52,7 +52,7 @@ public JPanel getPanel() { final JPanel panel8 = UIUtil.GetXJPanel(); final JLabel label2 = new JLabel("DES Alg: "); - desAlgSelector = new JComboBox(GetDesAlgs()); + desAlgSelector = new JComboBox(GetDesAlgs()); desAlgSelector.setMaximumSize(desAlgSelector.getPreferredSize()); desAlgSelector.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { @@ -78,14 +78,14 @@ public JPanel getPanel() { desAlgSelector.setSelectedIndex(0); final JLabel label3 = new JLabel("DES Key: "); - desKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); + desKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); desKeyFormatSelector.setMaximumSize(desKeyFormatSelector.getPreferredSize()); desKeyFormatSelector.setSelectedIndex(0); desKeyText = new JTextField(200); desKeyText.setMaximumSize(desKeyText.getPreferredSize()); final JLabel label4 = new JLabel("DES IV: "); - desIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); + desIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); desIVFormatSelector.setMaximumSize(desIVFormatSelector.getPreferredSize()); desIVFormatSelector.setSelectedIndex(0); desIVText = new JTextField(200); @@ -104,7 +104,7 @@ public JPanel getPanel() { desEncKey3Text.setMaximumSize(desEncKey3Text.getPreferredSize()); final JLabel label8 = new JLabel("Output Format: "); - desOutFormatSelector = new JComboBox(Utils.GetOutFormats()); + desOutFormatSelector = new JComboBox(Utils.GetOutFormats()); desOutFormatSelector.setMaximumSize(desOutFormatSelector.getPreferredSize()); desOutFormatSelector.setSelectedIndex(0); @@ -157,8 +157,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new DesIntruderPayloadProcessor(parent, extName, desConfig))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new DesIntruderPayloadProcessor(parent, extName, desConfig)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -169,7 +169,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/execjs/ExecJSIntruderPayloadProcessor.java b/src/main/java/burp/execjs/ExecJSIntruderPayloadProcessor.java index 08d9650..a6c4a8f 100644 --- a/src/main/java/burp/execjs/ExecJSIntruderPayloadProcessor.java +++ b/src/main/java/burp/execjs/ExecJSIntruderPayloadProcessor.java @@ -1,14 +1,17 @@ package burp.execjs; import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; +import burp.api.montoya.intruder.PayloadProcessor; import burp.execjs.engine.HtmlUnitEngine; import burp.execjs.engine.JreBuiltInEngine; import burp.execjs.engine.RhinoEngine; import java.nio.charset.StandardCharsets; -public class ExecJSIntruderPayloadProcessor implements IIntruderPayloadProcessor { +public class ExecJSIntruderPayloadProcessor implements PayloadProcessor { private BurpExtender parent; private final String extName; private final IJsEngine jsEngine; @@ -30,28 +33,23 @@ public ExecJSIntruderPayloadProcessor(final BurpExtender newParent, String extNa try { this.jsEngine.setConfig(config); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); + // 可选:parent.api.logging().logToError(e.toString()); } } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - Exec JS - " + extName; } @Override - public byte[] processPayload(byte[] currentPayload, byte[] originalPayload, byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData data) { try { - byte[] result = jsEngine.eval(new String(currentPayload, StandardCharsets.UTF_8)).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = jsEngine.eval(new String(data.currentPayload().getBytes(), StandardCharsets.UTF_8)).getBytes("UTF-8"); + parent.dict.Log(result, data.originalPayload().getBytes()); + return PayloadProcessingResult.usePayload(ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/execjs/JsUIHandler.java b/src/main/java/burp/execjs/JsUIHandler.java index 76b4b2a..838effd 100644 --- a/src/main/java/burp/execjs/JsUIHandler.java +++ b/src/main/java/burp/execjs/JsUIHandler.java @@ -1,14 +1,8 @@ package burp.execjs; import burp.BurpExtender; -import burp.utils.KeyFormat; import burp.utils.UIUtil; import org.fife.rsta.ac.LanguageSupportFactory; -import org.fife.rsta.ac.js.JavaScriptCompletionProvider; -import org.fife.rsta.ac.js.JavaScriptLanguageSupport; -import org.fife.ui.autocomplete.AutoCompletion; -import org.fife.ui.autocomplete.CompletionProvider; -import org.fife.ui.autocomplete.DefaultCompletionProvider; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.RTextScrollPane; @@ -17,8 +11,6 @@ import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.ItemEvent; -import java.lang.management.ManagementFactory; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -60,7 +52,7 @@ public JPanel getPanel() { methodText.setMaximumSize(methodText.getPreferredSize()); final JLabel label4 = new JLabel("Js Engine: "); - jsEngineSelector = new JComboBox(GetJsEngines()); + jsEngineSelector = new JComboBox(GetJsEngines()); jsEngineSelector.setMaximumSize(jsEngineSelector.getPreferredSize()); jsEngineSelector.setSelectedIndex(0); @@ -98,8 +90,8 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - if (parent.RegIPProcessor(extName, new ExecJSIntruderPayloadProcessor(parent, extName, config))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new ExecJSIntruderPayloadProcessor(parent, extName, config)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -112,7 +104,7 @@ public JPanel getPanel() { return; } } else return; - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); @@ -192,13 +184,8 @@ private void initEditor(boolean useSyntax) { } private boolean canUseCodeEditor() { - try { - String[] version = parent.callbacks.getBurpVersion(); - return (((Double.parseDouble(version[1]) > 2020) || - (Double.parseDouble(version[1]) == 2020 && Double.parseDouble(version[2]) >= 4))); // RSyntaxTextArea code editor only support in BurpSuite 2020.4 or higher. - } catch (Exception ex) { - return false; - } + // 兼容 Montoya API,始终允许使用代码编辑器 + return true; } private String[] GetJsEngines() { diff --git a/src/main/java/burp/montoya/MontoyaIntruderPayloadProcessor.java b/src/main/java/burp/montoya/MontoyaIntruderPayloadProcessor.java new file mode 100644 index 0000000..ddfc6ed --- /dev/null +++ b/src/main/java/burp/montoya/MontoyaIntruderPayloadProcessor.java @@ -0,0 +1,28 @@ +package burp.montoya; + +import burp.api.montoya.intruder.PayloadProcessor; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; + +/** + * Montoya API 2025.6 兼容的 IntruderPayloadProcessor 抽象基类 + */ +public abstract class MontoyaIntruderPayloadProcessor implements PayloadProcessor { + @Override + public String displayName() { + return name(); + } + + @Override + public PayloadProcessingResult processPayload(PayloadData data) { + // Montoya API 2025.6 的 PayloadData 没有 baseValue 字段 + byte[] result = process(data.currentPayload().getBytes(), data.originalPayload().getBytes(), null); + if (result == null) { + return PayloadProcessingResult.skipPayload(); + } + return PayloadProcessingResult.usePayload(burp.api.montoya.core.ByteArray.byteArray(result)); + } + + public abstract String name(); + public abstract byte[] process(byte[] currentPayload, byte[] originalPayload, byte[] baseValue); +} diff --git a/src/main/java/burp/pbkdf2/PBKDF2IntruderPayloadProcessor.java b/src/main/java/burp/pbkdf2/PBKDF2IntruderPayloadProcessor.java index dd7fb1a..6d567cb 100644 --- a/src/main/java/burp/pbkdf2/PBKDF2IntruderPayloadProcessor.java +++ b/src/main/java/burp/pbkdf2/PBKDF2IntruderPayloadProcessor.java @@ -1,19 +1,21 @@ package burp.pbkdf2; import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; +import burp.api.montoya.intruder.PayloadProcessor; import burp.utils.OutFormat; import burp.utils.Utils; import cn.hutool.crypto.digest.SM3; import cn.hutool.crypto.symmetric.PBKDF2; -public class PBKDF2IntruderPayloadProcessor implements IIntruderPayloadProcessor { +public class PBKDF2IntruderPayloadProcessor implements PayloadProcessor { private BurpExtender parent; private final String extName; private final PBKDF2 pbkdf2; private final PBKDF2Config config; - public PBKDF2IntruderPayloadProcessor(final BurpExtender newParent, String extName, PBKDF2Config config) { this.parent = newParent; this.extName = extName; @@ -22,7 +24,7 @@ public PBKDF2IntruderPayloadProcessor(final BurpExtender newParent, String extNa } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - PBKDF2 Encrypt - " + extName; } @@ -32,17 +34,13 @@ private String pbkdf2(byte[] data) { } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData data) { try { - - byte[] result = pbkdf2(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = pbkdf2(data.currentPayload().getBytes()).getBytes("UTF-8"); + parent.dict.Log(result, data.originalPayload().getBytes()); + return PayloadProcessingResult.usePayload(ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/pbkdf2/PBKDF2UIHandler.java b/src/main/java/burp/pbkdf2/PBKDF2UIHandler.java index ee2559b..2aff2d0 100644 --- a/src/main/java/burp/pbkdf2/PBKDF2UIHandler.java +++ b/src/main/java/burp/pbkdf2/PBKDF2UIHandler.java @@ -57,19 +57,19 @@ public JPanel getPanel() { iterationCountText.setText("1000"); final JLabel label2_3 = new JLabel("Mode: "); - algSelector = new JComboBox(GetPBKDF2Modes()); + algSelector = new JComboBox(GetPBKDF2Modes()); algSelector.setMaximumSize(algSelector.getPreferredSize()); algSelector.setSelectedIndex(0); final JLabel label3 = new JLabel("Salt: "); - saltFormatSelector = new JComboBox(Utils.GetKeyFormats()); + saltFormatSelector = new JComboBox(Utils.GetKeyFormats()); saltFormatSelector.setMaximumSize(saltFormatSelector.getPreferredSize()); saltFormatSelector.setSelectedIndex(0); saltText = new JTextField(200); saltText.setMaximumSize(saltText.getPreferredSize()); final JLabel label5 = new JLabel("Output Format: "); - outFormatSelector = new JComboBox(Utils.GetOutFormats()); + outFormatSelector = new JComboBox(Utils.GetOutFormats()); outFormatSelector.setMaximumSize(outFormatSelector.getPreferredSize()); outFormatSelector.setSelectedIndex(0); @@ -114,8 +114,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new PBKDF2IntruderPayloadProcessor(parent, extName, config))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new PBKDF2IntruderPayloadProcessor(parent, extName, config)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -126,7 +126,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/rsa/RsaIntruderPayloadProcessor.java b/src/main/java/burp/rsa/RsaIntruderPayloadProcessor.java index a4f90f4..62aa1af 100644 --- a/src/main/java/burp/rsa/RsaIntruderPayloadProcessor.java +++ b/src/main/java/burp/rsa/RsaIntruderPayloadProcessor.java @@ -1,9 +1,12 @@ package burp.rsa; import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; +import burp.api.montoya.intruder.PayloadProcessor; -public class RsaIntruderPayloadProcessor implements IIntruderPayloadProcessor { +public class RsaIntruderPayloadProcessor implements PayloadProcessor { private BurpExtender parent; private final String extName; private final RsaUtil RsaUtil; @@ -16,21 +19,18 @@ public RsaIntruderPayloadProcessor(final BurpExtender newParent, String extName, } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - RSA Encrypt - " + extName; } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData data) { try { - byte[] result = RsaUtil.encrypt(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = RsaUtil.encrypt(data.currentPayload().getBytes()).getBytes("UTF-8"); + parent.dict.Log(result, data.originalPayload().getBytes()); + return PayloadProcessingResult.usePayload(ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/rsa/RsaUIHandler.java b/src/main/java/burp/rsa/RsaUIHandler.java index 9d1bbab..c20a7ce 100644 --- a/src/main/java/burp/rsa/RsaUIHandler.java +++ b/src/main/java/burp/rsa/RsaUIHandler.java @@ -47,7 +47,7 @@ public JPanel getPanel() { final JPanel panel5 = UIUtil.GetXJPanel(); final JLabel label2 = new JLabel("RSA Public Key Format: "); - rsaPublicKeyFormatSelector = new JComboBox(Utils.GetPublicKeyFormats()); + rsaPublicKeyFormatSelector = new JComboBox(Utils.GetPublicKeyFormats()); rsaPublicKeyFormatSelector.setMaximumSize(rsaPublicKeyFormatSelector.getPreferredSize()); rsaPublicKeyFormatSelector.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { @@ -81,7 +81,7 @@ public JPanel getPanel() { x509Text.setMaximumSize(x509Text.getPreferredSize()); final JLabel label6 = new JLabel("Output Format: "); - outFormatSelector = new JComboBox(Utils.GetOutFormats()); + outFormatSelector = new JComboBox(Utils.GetOutFormats()); outFormatSelector.setMaximumSize(outFormatSelector.getPreferredSize()); outFormatSelector.setSelectedIndex(0); @@ -129,8 +129,8 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - if (parent.RegIPProcessor(extName, new RsaIntruderPayloadProcessor(parent, extName, config))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new RsaIntruderPayloadProcessor(parent, extName, config)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -143,7 +143,7 @@ public JPanel getPanel() { return; } } else return; - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/sm3/SM3IntruderPayloadProcessor.java b/src/main/java/burp/sm3/SM3IntruderPayloadProcessor.java index 837a9f6..e2d5030 100644 --- a/src/main/java/burp/sm3/SM3IntruderPayloadProcessor.java +++ b/src/main/java/burp/sm3/SM3IntruderPayloadProcessor.java @@ -1,29 +1,27 @@ package burp.sm3; -import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; import burp.utils.OutFormat; import burp.utils.Utils; +import burp.api.montoya.intruder.PayloadProcessor; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; import cn.hutool.crypto.digest.SM3; -public class SM3IntruderPayloadProcessor implements IIntruderPayloadProcessor { - private BurpExtender parent; +public class SM3IntruderPayloadProcessor implements PayloadProcessor { private final String extName; private final SM3 sm3Utils; private final SM3Config config; - - public SM3IntruderPayloadProcessor(final BurpExtender newParent, String extName, SM3Config config) { - this.parent = newParent; + public SM3IntruderPayloadProcessor(String extName, SM3Config config) { this.extName = extName; - this.config = (config); + this.config = config; if (config.Salt != null) this.sm3Utils = new SM3(config.Salt); else this.sm3Utils = new SM3(); } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - SM3 Encrypt - " + extName; } @@ -33,17 +31,12 @@ private String SM3Digest(byte[] data) { } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData payloadData) { try { - - byte[] result = SM3Digest(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = SM3Digest(payloadData.currentPayload().getBytes()).getBytes("UTF-8"); + return PayloadProcessingResult.usePayload(burp.api.montoya.core.ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(Utils.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/sm3/SM3UIHandler.java b/src/main/java/burp/sm3/SM3UIHandler.java index ff8b366..55b53a0 100644 --- a/src/main/java/burp/sm3/SM3UIHandler.java +++ b/src/main/java/burp/sm3/SM3UIHandler.java @@ -39,14 +39,14 @@ public JPanel getPanel() { final JPanel panel5 = UIUtil.GetXJPanel(); final JLabel label3 = new JLabel("Salt: "); - saltFormatSelector = new JComboBox(Utils.GetKeyFormats()); + saltFormatSelector = new JComboBox(Utils.GetKeyFormats()); saltFormatSelector.setMaximumSize(saltFormatSelector.getPreferredSize()); saltFormatSelector.setSelectedIndex(0); saltText = new JTextField(200); saltText.setMaximumSize(saltText.getPreferredSize()); final JLabel label5 = new JLabel("Output Format: "); - outFormatSelector = new JComboBox(Utils.GetOutFormats()); + outFormatSelector = new JComboBox(Utils.GetOutFormats()); outFormatSelector.setMaximumSize(outFormatSelector.getPreferredSize()); outFormatSelector.setSelectedIndex(0); @@ -75,8 +75,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new SM3IntruderPayloadProcessor(parent, extName, config))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new SM3IntruderPayloadProcessor(extName, config)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -87,7 +87,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/sm4/SM4IntruderPayloadProcessor.java b/src/main/java/burp/sm4/SM4IntruderPayloadProcessor.java index c74a81c..540409f 100644 --- a/src/main/java/burp/sm4/SM4IntruderPayloadProcessor.java +++ b/src/main/java/burp/sm4/SM4IntruderPayloadProcessor.java @@ -1,36 +1,31 @@ package burp.sm4; -import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.intruder.PayloadProcessor; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; -public class SM4IntruderPayloadProcessor implements IIntruderPayloadProcessor { - private BurpExtender parent; +public class SM4IntruderPayloadProcessor implements PayloadProcessor { private final String extName; private final SM4Util SM4Util; - public SM4IntruderPayloadProcessor(final BurpExtender newParent, String extName, SM4Config config) { - this.parent = newParent; + public SM4IntruderPayloadProcessor(String extName, SM4Config config) { this.extName = extName; SM4Util = new SM4Util(); SM4Util.setConfig(config); } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - SM4 Encrypt - " + extName; } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData payloadData) { try { - byte[] result = SM4Util.encrypt(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = SM4Util.encrypt(payloadData.currentPayload().getBytes()).getBytes("UTF-8"); + return PayloadProcessingResult.usePayload(burp.api.montoya.core.ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/sm4/SM4UIHandler.java b/src/main/java/burp/sm4/SM4UIHandler.java index 4cc9013..c6ade86 100644 --- a/src/main/java/burp/sm4/SM4UIHandler.java +++ b/src/main/java/burp/sm4/SM4UIHandler.java @@ -46,7 +46,7 @@ public JPanel getPanel() { final JPanel panel5 = UIUtil.GetXJPanel(); final JLabel label2 = new JLabel("SM4 Alg: "); - sm4AlgSelector = new JComboBox(GetSM4Algs()); + sm4AlgSelector = new JComboBox(GetSM4Algs()); sm4AlgSelector.setMaximumSize(sm4AlgSelector.getPreferredSize()); sm4AlgSelector.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { @@ -58,21 +58,21 @@ public JPanel getPanel() { sm4AlgSelector.setSelectedIndex(0); final JLabel label3 = new JLabel("SM4 Key: "); - sm4KeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); + sm4KeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); sm4KeyFormatSelector.setMaximumSize(sm4KeyFormatSelector.getPreferredSize()); sm4KeyFormatSelector.setSelectedIndex(0); sm4KeyText = new JTextField(200); sm4KeyText.setMaximumSize(sm4KeyText.getPreferredSize()); final JLabel label4 = new JLabel("SM4 IV: "); - sm4IVFormatSelector = new JComboBox(Utils.GetKeyFormats()); + sm4IVFormatSelector = new JComboBox(Utils.GetKeyFormats()); sm4IVFormatSelector.setMaximumSize(sm4IVFormatSelector.getPreferredSize()); sm4IVFormatSelector.setSelectedIndex(0); sm4IVText = new JTextField(200); sm4IVText.setMaximumSize(sm4IVText.getPreferredSize()); final JLabel label5 = new JLabel("Output Format: "); - sm4OutFormatSelector = new JComboBox(Utils.GetOutFormats()); + sm4OutFormatSelector = new JComboBox(Utils.GetOutFormats()); sm4OutFormatSelector.setMaximumSize(sm4OutFormatSelector.getPreferredSize()); sm4OutFormatSelector.setSelectedIndex(0); @@ -109,8 +109,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new SM4IntruderPayloadProcessor(parent, extName, sm4Config))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new SM4IntruderPayloadProcessor(extName, sm4Config)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -121,7 +121,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); diff --git a/src/main/java/burp/utils/BurpCryptoMenuFactory.java b/src/main/java/burp/utils/BurpCryptoMenuFactory.java index a5f819f..7a6eb1f 100644 --- a/src/main/java/burp/utils/BurpCryptoMenuFactory.java +++ b/src/main/java/burp/utils/BurpCryptoMenuFactory.java @@ -1,17 +1,21 @@ package burp.utils; -import burp.*; +import burp.BurpExtender; +import burp.utils.SelectionInfo; +import burp.utils.SelectionLocation; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.ui.contextmenu.ContextMenuEvent; +import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; import javax.swing.*; import java.awt.*; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Optional; -import static burp.IContextMenuInvocation.*; - -public class BurpCryptoMenuFactory implements IContextMenuFactory { +public class BurpCryptoMenuFactory implements ContextMenuItemsProvider { private BurpExtender parent; @@ -20,19 +24,19 @@ public BurpCryptoMenuFactory(BurpExtender parent) { } @Override - public List createMenuItems(IContextMenuInvocation invocation) { - ArrayList menus = new ArrayList<>(); - //if (invocation.getToolFlag() == parent.callbacks.TOOL_INTRUDER) { + public List provideMenuItems(ContextMenuEvent event) { + ArrayList menus = new ArrayList<>(); JMenuItem menu1 = new JMenuItem("Get PlainText"); menu1.addActionListener(e -> { - IHttpRequestResponse[] resps = invocation.getSelectedMessages(); - if (resps.length > 0) { - IHttpRequestResponse req = resps[0]; - byte[] request = req.getRequest(); - String selectedText = getSelectedText(request, invocation.getSelectionBounds()); - if (selectedText != null && selectedText != "") { + List resps = event.selectedRequestResponses(); + if (resps != null && !resps.isEmpty()) { + HttpRequestResponse req = resps.get(0); + ByteArray request = req.request().toByteArray(); + int[] selectedIndexRange = getSelectionBounds(event); + String selectedText = getSelectedText(request, selectedIndexRange); + if (selectedText != null && !selectedText.isEmpty()) { String plainText = searchKey(selectedText); - if (plainText != null && plainText != "") { + if (plainText != null && !plainText.isEmpty()) { ShowCopiableMessage(plainText, "This message plaintext is: "); } else { JOptionPane.showMessageDialog(menu1, "Not found!"); @@ -41,39 +45,40 @@ public List createMenuItems(IContextMenuInvocation invocation) { } }); menus.add(menu1); - //} JMenu quickCrypto = new JMenu("Quick Crypto"); - for (IIntruderPayloadProcessor entry : parent.IPProcessors.values()) { - JMenuItem _menu = new JMenuItem(entry.getProcessorName()); - _menu.addActionListener(e -> { - IHttpRequestResponse req = invocation.getSelectedMessages()[0]; - SelectionInfo sInfo = getSelectionInfo(invocation); - byte[] data; - if (sInfo.Location == SelectionLocation.Request) { - data = req.getRequest(); - } else { - data = req.getResponse(); - } - int[] selectedIndexRange = invocation.getSelectionBounds(); - byte[] selectedBytes = getSelectedBytes(data, selectedIndexRange); - if (selectedBytes != null && selectedBytes.length > 0) { - byte[] encryptResult = entry.processPayload(selectedBytes, selectedBytes, selectedBytes); - if (encryptResult != null) { - if (!sInfo.ReadOnly) { - if (sInfo.Location == SelectionLocation.Request) { - req.setRequest(Replace(data, selectedIndexRange, encryptResult)); + for (Object obj : parent.IPProcessors.values()) { + try { + Object entry = obj; + JMenuItem _menu = new JMenuItem(entry.getClass().getMethod("getProcessorName").invoke(entry).toString()); + _menu.addActionListener(e -> { + try { + HttpRequestResponse req = event.selectedRequestResponses().get(0); + SelectionInfo sInfo = getSelectionInfo(event); + ByteArray data; + if (sInfo.Location == null || sInfo.Location.name().equals("Request")) { + data = req.request().toByteArray(); + } else { + data = req.response().toByteArray(); + } + int[] selectedIndexRange = getSelectionBounds(event); + byte[] selectedBytes = getSelectedBytes(data, selectedIndexRange); + if (selectedBytes != null && selectedBytes.length > 0) { + byte[] encryptResult = (byte[]) entry.getClass().getMethod("processPayload", byte[].class, byte[].class, byte[].class) + .invoke(entry, selectedBytes, selectedBytes, selectedBytes); + if (encryptResult != null) { + ShowCopiableMessage(new String(encryptResult), "CipherText result: "); } else { - req.setResponse(Replace(data, selectedIndexRange, encryptResult)); + JOptionPane.showMessageDialog(_menu, "has error!"); } - } else { - ShowCopiableMessage(new String(encryptResult), "CipherText result: "); } - } else { - JOptionPane.showMessageDialog(_menu, "has error!"); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + JOptionPane.showMessageDialog(_menu, "Reflection error: " + ex.getMessage()); } - } - }); - quickCrypto.add(_menu); + }); + quickCrypto.add(_menu); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + // 跳过异常的 entry + } } if (quickCrypto.getItemCount() > 0) { menus.add(quickCrypto); @@ -81,21 +86,32 @@ public List createMenuItems(IContextMenuInvocation invocation) { return menus; } - private SelectionInfo getSelectionInfo(IContextMenuInvocation invocation) { + private int[] getSelectionBounds(ContextMenuEvent event) { + // Montoya API: selectionBounds() -> Optional,此处反射兼容,忽略类型警告 + try { + @SuppressWarnings("unchecked") + Optional boundsOpt = (Optional) event.getClass().getMethod("selectionBounds").invoke(event); + return boundsOpt.orElse(null); + } catch (Exception e) { + return null; + } + } + + private SelectionInfo getSelectionInfo(ContextMenuEvent event) { SelectionInfo info = new SelectionInfo(); - switch (invocation.getInvocationContext()) { - case CONTEXT_MESSAGE_EDITOR_RESPONSE: - case CONTEXT_MESSAGE_VIEWER_RESPONSE: + switch (event.invocationType()) { + case MESSAGE_EDITOR_RESPONSE: + case MESSAGE_VIEWER_RESPONSE: info.Location = SelectionLocation.Response; break; default: info.Location = SelectionLocation.Request; break; } - switch (invocation.getInvocationContext()) { - case CONTEXT_MESSAGE_EDITOR_REQUEST: - case CONTEXT_MESSAGE_EDITOR_RESPONSE: - case CONTEXT_INTRUDER_PAYLOAD_POSITIONS: + switch (event.invocationType()) { + case MESSAGE_EDITOR_REQUEST: + case MESSAGE_EDITOR_RESPONSE: + case INTRUDER_PAYLOAD_POSITIONS: info.ReadOnly = false; break; default: @@ -105,29 +121,26 @@ private SelectionInfo getSelectionInfo(IContextMenuInvocation invocation) { } public void ShowCopiableMessage(String message, String title) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - JTextArea ta = new JTextArea(5, 20); - ta.setText(message); - ta.setWrapStyleWord(true); - ta.setLineWrap(true); - ta.setCaretPosition(0); - ta.setEditable(false); - JOptionPane.showMessageDialog(null, new JScrollPane(ta), title, JOptionPane.INFORMATION_MESSAGE); - } + EventQueue.invokeLater(() -> { + JTextArea ta = new JTextArea(5, 20); + ta.setText(message); + ta.setWrapStyleWord(true); + ta.setLineWrap(true); + ta.setCaretPosition(0); + ta.setEditable(false); + JOptionPane.showMessageDialog(null, new JScrollPane(ta), title, JOptionPane.INFORMATION_MESSAGE); }); } private String searchKey(String key) { String value = parent.dict.Search(key); if (value == null) { - value = parent.dict.Search(parent.helpers.urlDecode(key)); + value = parent.dict.Search(parent.api.utilities().urlUtils().decode(key)); } return value; } - private String getSelectedText(byte[] request, int[] selectedIndexRange) { + private String getSelectedText(ByteArray request, int[] selectedIndexRange) { try { return new String(getSelectedBytes(request, selectedIndexRange)); } catch (Exception ex) { @@ -135,10 +148,12 @@ private String getSelectedText(byte[] request, int[] selectedIndexRange) { } } - private byte[] getSelectedBytes(byte[] request, int[] selectedIndexRange) { + private byte[] getSelectedBytes(ByteArray request, int[] selectedIndexRange) { try { + if (selectedIndexRange == null) return null; + byte[] raw = request.getBytes(); byte[] selectedText = new byte[selectedIndexRange[1] - selectedIndexRange[0]]; - System.arraycopy(request, selectedIndexRange[0], selectedText, 0, selectedText.length); + System.arraycopy(raw, selectedIndexRange[0], selectedText, 0, selectedText.length); return selectedText; } catch (Exception ex) { return null; diff --git a/src/main/java/burp/utils/BurpStateListener.java b/src/main/java/burp/utils/BurpStateListener.java index 785211d..158ca51 100644 --- a/src/main/java/burp/utils/BurpStateListener.java +++ b/src/main/java/burp/utils/BurpStateListener.java @@ -1,16 +1,14 @@ package burp.utils; import burp.BurpExtender; -import burp.IExtensionStateListener; import java.io.IOException; -public class BurpStateListener implements IExtensionStateListener { +public class BurpStateListener { private BurpExtender parent; public BurpStateListener(final BurpExtender newParent) { this.parent = newParent; } - @Override public void extensionUnloaded() { try { this.parent.store.close(); // leveldb unload. diff --git a/src/main/java/burp/zuc/ZUCIntruderPayloadProcessor.java b/src/main/java/burp/zuc/ZUCIntruderPayloadProcessor.java index 3da0129..127e4ef 100644 --- a/src/main/java/burp/zuc/ZUCIntruderPayloadProcessor.java +++ b/src/main/java/burp/zuc/ZUCIntruderPayloadProcessor.java @@ -1,36 +1,31 @@ package burp.zuc; -import burp.BurpExtender; -import burp.IIntruderPayloadProcessor; +import burp.api.montoya.intruder.PayloadProcessor; +import burp.api.montoya.intruder.PayloadData; +import burp.api.montoya.intruder.PayloadProcessingResult; -public class ZUCIntruderPayloadProcessor implements IIntruderPayloadProcessor { - private BurpExtender parent; +public class ZUCIntruderPayloadProcessor implements PayloadProcessor { private final String extName; private final ZUCUtil ZUCUtil; - public ZUCIntruderPayloadProcessor(final BurpExtender newParent, String extName, ZUCConfig config) { - this.parent = newParent; + public ZUCIntruderPayloadProcessor(String extName, ZUCConfig config) { this.extName = extName; ZUCUtil = new ZUCUtil(); ZUCUtil.setConfig(config); } @Override - public String getProcessorName() { + public String displayName() { return "BurpCrypto - ZUC Encrypt - " + extName; } @Override - public byte[] processPayload(final byte[] currentPayload, final byte[] originalPayload, final byte[] baseValue) { + public PayloadProcessingResult processPayload(PayloadData payloadData) { try { - byte[] result = ZUCUtil.encrypt(currentPayload).getBytes("UTF-8"); - parent.dict.Log(result, originalPayload); - return result; + byte[] result = ZUCUtil.encrypt(payloadData.currentPayload().getBytes()).getBytes("UTF-8"); + return PayloadProcessingResult.usePayload(burp.api.montoya.core.ByteArray.byteArray(result)); } catch (Exception e) { - this.parent.callbacks.issueAlert(e.toString()); - this.parent.stderr.println(); - e.printStackTrace(this.parent.stderr); - return null; + return PayloadProcessingResult.skipPayload(); } } } diff --git a/src/main/java/burp/zuc/ZUCUIHandler.java b/src/main/java/burp/zuc/ZUCUIHandler.java index 0381fff..8d7c663 100644 --- a/src/main/java/burp/zuc/ZUCUIHandler.java +++ b/src/main/java/burp/zuc/ZUCUIHandler.java @@ -7,7 +7,6 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; -import java.awt.event.ItemEvent; import java.util.ArrayList; public class ZUCUIHandler { @@ -47,26 +46,26 @@ public JPanel getPanel() { final JPanel panel5 = UIUtil.GetXJPanel(); final JLabel label2 = new JLabel("ZUC Alg: "); - zucAlgSelector = new JComboBox(GetZUCAlgs()); + zucAlgSelector = new JComboBox(GetZUCAlgs()); zucAlgSelector.setMaximumSize(zucAlgSelector.getPreferredSize()); zucAlgSelector.setSelectedIndex(0); final JLabel label3 = new JLabel("ZUC Key: "); - zucKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); + zucKeyFormatSelector = new JComboBox(Utils.GetKeyFormats()); zucKeyFormatSelector.setMaximumSize(zucKeyFormatSelector.getPreferredSize()); zucKeyFormatSelector.setSelectedIndex(0); zucKeyText = new JTextField(200); zucKeyText.setMaximumSize(zucKeyText.getPreferredSize()); final JLabel label4 = new JLabel("ZUC IV: "); - zucIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); + zucIVFormatSelector = new JComboBox(Utils.GetKeyFormats()); zucIVFormatSelector.setMaximumSize(zucIVFormatSelector.getPreferredSize()); zucIVFormatSelector.setSelectedIndex(0); zucIVText = new JTextField(200); zucIVText.setMaximumSize(zucIVText.getPreferredSize()); final JLabel label5 = new JLabel("Output Format: "); - zucOutFormatSelector = new JComboBox(Utils.GetOutFormats()); + zucOutFormatSelector = new JComboBox(Utils.GetOutFormats()); zucOutFormatSelector.setMaximumSize(zucOutFormatSelector.getPreferredSize()); zucOutFormatSelector.setSelectedIndex(0); @@ -103,8 +102,8 @@ public JPanel getPanel() { return; } } else return; - if (parent.RegIPProcessor(extName, new ZUCIntruderPayloadProcessor(parent, extName, zucConfig))) - JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); + parent.regIPProcessor(extName, new ZUCIntruderPayloadProcessor(extName, zucConfig)); + JOptionPane.showMessageDialog(mainPanel, "Apply processor success!"); }); deleteBtn = new JButton("Remove processor"); @@ -115,7 +114,7 @@ public JPanel getPanel() { JOptionPane.showMessageDialog(mainPanel, "name empty!"); return; } - parent.RemoveIPProcessor(extName); + parent.removeIPProcessor(extName); JOptionPane.showMessageDialog(mainPanel, "Remove success!"); }); From 1c66d2217a9e03c80dce4654651451f0cd82c6c2 Mon Sep 17 00:00:00 2001 From: tomcruiseqi Date: Sat, 14 Jun 2025 18:17:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E6=97=B6?= =?UTF-8?q?=E5=A6=82=E6=9C=89=E6=97=A7=20BurpCrypto.ldb=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9=E5=88=99=E9=80=92=E5=BD=92=E5=88=A0=E9=99=A4?= =?UTF-8?q?=EF=BC=8C=E5=BD=BB=E5=BA=95=E8=A7=A3=E5=86=B3=20LevelDB=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=94=81=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BurpCrypto.ldb/testfile | 0 src/main/java/burp/BurpExtender.java | 52 ++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 BurpCrypto.ldb/testfile diff --git a/BurpCrypto.ldb/testfile b/BurpCrypto.ldb/testfile new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 1924d09..8ef7c2c 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -20,6 +20,10 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import burp.api.montoya.MontoyaApi; @@ -62,14 +66,36 @@ public void initialize(MontoyaApi api) { SecureUtil.disableBouncyCastle(); Utils.stdout = this.stdout = new PrintWriter(System.out, true); Utils.stderr = this.stderr = new PrintWriter(System.err, true); + File ldbFile = new File("BurpCrypto.ldb"); + // 初始化前如有 ldb 文件夹则递归删除 + if (ldbFile.exists()) { + try { + java.nio.file.Files.walk(ldbFile.toPath()) + .sorted((a, b) -> b.compareTo(a)) + .forEach(p -> { + try { java.nio.file.Files.delete(p); } catch (IOException ignored) {} + }); + if (stdout != null) stdout.println("[BurpCrypto] Old LevelDB folder deleted before init."); + } catch (IOException e) { + if (stdout != null) stdout.println("[BurpCrypto] Failed to delete old LevelDB folder before init: " + e.getMessage()); + } + } + if (this.store != null) { + try { + this.store.close(); + } catch (IOException e) { + api.logging().logToError("LevelDb close failed! error message: " + e.getMessage()); + } + this.store = null; + } api.extension().setName("BurpCrypto v" + version); api.userInterface().registerContextMenuItemsProvider(new BurpCryptoMenuFactory(this)); - Options options = new Options(); + org.iq80.leveldb.Options options = new org.iq80.leveldb.Options(); options.createIfMissing(true); try { - this.store = factory.open(new File("BurpCrypto.ldb"), options); + this.store = org.iq80.leveldb.impl.Iq80DBFactory.factory.open(ldbFile, options); this.dict = new DictLogManager(this); - api.logging().logToOutput("LevelDb init success!"); + api.logging().logToOutput("LevelDb init success! Path: " + ldbFile.getAbsolutePath()); } catch (IOException e) { api.logging().logToError("LevelDb init failed! error message: " + e.getMessage()); } @@ -139,6 +165,26 @@ public void extensionUnloaded() { } catch (IOException e) { e.printStackTrace(); } + // 获取插件 jar 所在目录,递归删除 ldb 文件夹 + String ldbDir = "."; + try { + ldbDir = new File(BurpExtender.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); + } catch (URISyntaxException e) { + if (stdout != null) stdout.println("[BurpCrypto] Failed to get plugin directory: " + e.getMessage()); + } + Path ldbPath = new File(ldbDir, "BurpCrypto.ldb").toPath(); + if (Files.exists(ldbPath)) { + try { + Files.walk(ldbPath) + .sorted((a, b) -> b.compareTo(a)) + .forEach(p -> { + try { Files.delete(p); } catch (IOException ignored) {} + }); + if (stdout != null) stdout.println("[BurpCrypto] LevelDB folder deleted on extension unload."); + } catch (IOException e) { + if (stdout != null) stdout.println("[BurpCrypto] Failed to delete LevelDB folder on extension unload: " + e.getMessage()); + } + } if (stdout != null) stdout.println("[BurpCrypto] Extension unloaded, LevelDB closed."); } } From 80acf23e8ea2d985486d5beffb0e427369dccebc Mon Sep 17 00:00:00 2001 From: tomcruiseqi Date: Sat, 14 Jun 2025 18:38:45 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=E6=AF=8F=E6=AC=A1=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E4=BD=BF=E7=94=A8=E5=94=AF=E4=B8=80=20ldb=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E5=90=8D=EF=BC=8C=E5=BD=BB=E5=BA=95?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=20Windows=20=E4=B8=8B=20LevelDB=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E9=94=81=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/burp/BurpExtender.java | 40 +++++++++++++++------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 8ef7c2c..ba099dc 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -58,6 +58,7 @@ public class BurpExtender implements BurpExtension { public ZUCUIHandler ZUCUI; public JPanel pbkdf2Panel; public PBKDF2UIHandler PBKDF2UI; + public String ldbFolderName; // Montoya BurpExtension API required method @Override @@ -66,7 +67,9 @@ public void initialize(MontoyaApi api) { SecureUtil.disableBouncyCastle(); Utils.stdout = this.stdout = new PrintWriter(System.out, true); Utils.stderr = this.stderr = new PrintWriter(System.err, true); - File ldbFile = new File("BurpCrypto.ldb"); + // 使用唯一 ldb 文件夹名 + ldbFolderName = "BurpCrypto_" + System.currentTimeMillis() + ".ldb"; + File ldbFile = new File(ldbFolderName); // 初始化前如有 ldb 文件夹则递归删除 if (ldbFile.exists()) { try { @@ -165,24 +168,23 @@ public void extensionUnloaded() { } catch (IOException e) { e.printStackTrace(); } - // 获取插件 jar 所在目录,递归删除 ldb 文件夹 - String ldbDir = "."; - try { - ldbDir = new File(BurpExtender.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent(); - } catch (URISyntaxException e) { - if (stdout != null) stdout.println("[BurpCrypto] Failed to get plugin directory: " + e.getMessage()); - } - Path ldbPath = new File(ldbDir, "BurpCrypto.ldb").toPath(); - if (Files.exists(ldbPath)) { - try { - Files.walk(ldbPath) - .sorted((a, b) -> b.compareTo(a)) - .forEach(p -> { - try { Files.delete(p); } catch (IOException ignored) {} - }); - if (stdout != null) stdout.println("[BurpCrypto] LevelDB folder deleted on extension unload."); - } catch (IOException e) { - if (stdout != null) stdout.println("[BurpCrypto] Failed to delete LevelDB folder on extension unload: " + e.getMessage()); + this.store = null; + System.gc(); + try { Thread.sleep(1500); } catch (InterruptedException ignored) {} + // 卸载时删除本次唯一 ldb 文件夹 + if (ldbFolderName != null) { + File ldbFile = new File(ldbFolderName); + if (ldbFile.exists()) { + try { + java.nio.file.Files.walk(ldbFile.toPath()) + .sorted((a, b) -> b.compareTo(a)) + .forEach(p -> { + try { java.nio.file.Files.delete(p); } catch (IOException ignored) {} + }); + if (stdout != null) stdout.println("[BurpCrypto] LevelDB folder deleted on extension unload: " + ldbFolderName); + } catch (IOException e) { + if (stdout != null) stdout.println("[BurpCrypto] Failed to delete LevelDB folder on extension unload: " + e.getMessage()); + } } } if (stdout != null) stdout.println("[BurpCrypto] Extension unloaded, LevelDB closed.");