├── .gitignore
├── BappDescription.html
├── BappManifest.bmf
├── README.md
├── imgs
├── 0.png
├── 1.png
└── 2.png
├── pom.xml
└── src
└── main
└── java
└── burp
└── BurpExtender.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 |
16 | ### Eclipse ###
17 | .apt_generated
18 | .classpath
19 | .factorypath
20 | .project
21 | .settings
22 | .springBeans
23 | .sts4-cache
24 |
25 | ### NetBeans ###
26 | /nbproject/private/
27 | /nbbuild/
28 | /dist/
29 | /nbdist/
30 | /.nb-gradle/
31 | build/
32 | !**/src/main/**/build/
33 | !**/src/test/**/build/
34 |
35 | ### VS Code ###
36 | .vscode/
37 |
38 | ### Mac OS ###
39 | .DS_Store
--------------------------------------------------------------------------------
/BappDescription.html:
--------------------------------------------------------------------------------
1 |
This extension can be used to change the nesting level of extension-generated context menu items.
2 |
3 | Usage
4 | Use the "Menu Level" menu bar option to choose the nesting level for extension-generated context menu items.
5 |
--------------------------------------------------------------------------------
/BappManifest.bmf:
--------------------------------------------------------------------------------
1 | Uuid: e1156b3d48c4469f9f1e234a3119fab1
2 | ExtensionType: 1
3 | Name: Change Menu Level
4 | RepoName: change-menu-level
5 | ScreenVersion: 1.0
6 | SerialVersion: 3
7 | MinPlatformVersion: 0
8 | ProOnly: False
9 | Author: Ovie
10 | ShortDescription: Change the nesting level of extension-generated context menu items.
11 | EntryPoint: target/BurpMenuLevel-1.0-SNAPSHOT.jar
12 | BuildCommand: mvn clean package
13 | SupportedProducts: Pro, Community
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BurpSuite新版本中,插件注册的右键菜单是在第三层,即Extensions -> 插件名 -> 插件菜单,这样点起来有些麻烦。所以写了个小插件,用于修改菜单层级,可以将插件菜单放在第一或第二层。
2 |
3 | 如何实现的:《[Burpsuite 插件开发 - 修改右键菜单层级](https://ovi3.github.io/2023/09/27/burpsuite-extension-menu-level/)》
4 |
5 | A simple BurpSuite extension to change extension context menu level, using in BurpSuite v2021.7 version and newer.
6 |
7 |
8 |
9 | ## 截图
10 |
11 | 默认:
12 |
13 | 
14 |
15 | 设置:
16 |
17 | 
18 |
19 | 效果:
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/imgs/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/0.png
--------------------------------------------------------------------------------
/imgs/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/1.png
--------------------------------------------------------------------------------
/imgs/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/2.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | burp
8 | BurpMenuLevel
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 | UTF-8
15 |
16 |
17 |
18 |
19 |
20 | org.apache.maven.plugins
21 | maven-jar-plugin
22 | 3.3.0
23 |
24 |
25 | false
26 |
27 | Test
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | net.portswigger.burp.extender
38 | burp-extender-api
39 | 1.7.22
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/main/java/burp/BurpExtender.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.HierarchyEvent;
6 | import java.awt.event.HierarchyListener;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class BurpExtender implements IBurpExtender, IExtensionStateListener, IContextMenuFactory {
11 |
12 | private static final String extensionName = "BurpMenuLevel";
13 | private static final String menuLevel = "MENU_LEVEL";
14 |
15 | private IBurpExtenderCallbacks callbacks;
16 | private JMenuBar burpMenuBar;
17 | private JMenu topMenus;
18 |
19 | @Override
20 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
21 | this.callbacks = callbacks;
22 | callbacks.setExtensionName(extensionName);
23 | callbacks.registerContextMenuFactory(this);
24 | callbacks.registerExtensionStateListener(this);
25 |
26 | // 添加顶部栏
27 | burpMenuBar = getBurpFrame().getJMenuBar();
28 | topMenus = new JMenu("Menu Level");
29 |
30 | ButtonGroup group = new ButtonGroup();
31 | JRadioButtonMenuItem level0Menu = new JRadioButtonMenuItem("Name - Scan");
32 | JRadioButtonMenuItem level1Menu = new JRadioButtonMenuItem("Name -> Scan");
33 | JRadioButtonMenuItem level2Menu = new JRadioButtonMenuItem("Extensions -> Name - Scan");
34 | JRadioButtonMenuItem level3Menu = new JRadioButtonMenuItem("Extensions -> Name -> Scan");
35 | group.add(level0Menu);
36 | group.add(level1Menu);
37 | group.add(level2Menu);
38 | group.add(level3Menu);
39 |
40 | int level = getMenuLevel();
41 | switch (level) {
42 | case 0:
43 | level0Menu.setSelected(true);
44 | break;
45 | case 1:
46 | level1Menu.setSelected(true);
47 | break;
48 | case 2:
49 | level2Menu.setSelected(true);
50 | break;
51 | case 3:
52 | level3Menu.setSelected(true);
53 | break;
54 | }
55 |
56 | level0Menu.addActionListener(e -> setMenuLevel("0"));
57 | level1Menu.addActionListener(e -> setMenuLevel("1"));
58 | level2Menu.addActionListener(e -> setMenuLevel("2"));
59 | level3Menu.addActionListener(e -> setMenuLevel("3"));
60 |
61 | topMenus.add(level0Menu);
62 | topMenus.add(level1Menu);
63 | topMenus.add(level2Menu);
64 | topMenus.add(level3Menu);
65 | SwingUtilities.invokeLater(() -> {
66 | burpMenuBar.add(topMenus);
67 | burpMenuBar.revalidate();
68 | burpMenuBar.repaint();
69 | });
70 |
71 |
72 | callbacks.printOutput("Usage: click \"Menu Level\" menu at the top of window to change extension context menu level.");
73 | }
74 |
75 | @Override
76 | public void extensionUnloaded() {
77 | SwingUtilities.invokeLater(() -> {
78 | burpMenuBar.remove(topMenus);
79 | burpMenuBar.revalidate();
80 | burpMenuBar.repaint();
81 | });
82 | }
83 |
84 | private static JFrame getBurpFrame() {
85 | for (Frame f : Frame.getFrames()) {
86 | if (f.isVisible() && f.getTitle().startsWith(("Burp Suite"))) {
87 | return (JFrame) f;
88 | }
89 | }
90 | return null;
91 | }
92 |
93 | private int getMenuLevel() {
94 | String levelStr = callbacks.loadExtensionSetting(menuLevel);
95 | if (levelStr == null || levelStr.length() == 0) {
96 | levelStr = "3";
97 | }
98 |
99 | return Integer.parseInt(levelStr);
100 | }
101 |
102 | private void setMenuLevel(String level) {
103 | callbacks.saveExtensionSetting(menuLevel, level);
104 | }
105 |
106 | @Override
107 | public List createMenuItems(IContextMenuInvocation invocation) {
108 | List menus = new ArrayList<>();
109 | JMenuItem menu = new JMenuItem("flag");
110 | menus.add(menu);
111 |
112 | int level = getMenuLevel();
113 | if (level == 3) {
114 | return null; // 默认不处理; 返回null,不添加自身插件flag菜单
115 | }
116 |
117 | changeContextMenuLevel(menus, level);
118 |
119 | return menus;
120 | }
121 |
122 | /**
123 | *
124 | * @param myMenus
125 | * @param level 可选 0, 1, 2, 3
126 | */
127 | private void changeContextMenuLevel(List myMenus, int level) {
128 | if (myMenus.size() == 0) {
129 | return;
130 | }
131 |
132 | JMenuItem flagMenu = myMenus.get(0);
133 | flagMenu.addHierarchyListener(new HierarchyListener() {
134 | private boolean ran = false;
135 | @Override
136 | public void hierarchyChanged(HierarchyEvent e) {
137 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) {
138 | if (!ran) {
139 | ran = true;
140 | if (flagMenu.getParent() == null || !(flagMenu.getParent() instanceof JPopupMenu)) {
141 | return;
142 | }
143 | JPopupMenu popupMenu = (JPopupMenu) flagMenu.getParent();
144 | Component invoker = popupMenu.getInvoker();
145 |
146 |
147 | if (!(invoker instanceof JMenuItem)) {
148 | return;
149 | }
150 | JMenuItem extensionNameMenuItem = (JMenuItem)invoker;
151 | extensionNameMenuItem.addHierarchyListener(new HierarchyListener() {
152 | private boolean ran2 = false;
153 | @Override
154 | public void hierarchyChanged(HierarchyEvent e) {
155 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) {
156 | if (!ran2) {
157 | ran2 = true;
158 |
159 | if (extensionNameMenuItem.getParent() == null || !(extensionNameMenuItem.getParent() instanceof JPopupMenu)) {
160 | return;
161 | }
162 | JPopupMenu extensionsPopupMenu = (JPopupMenu) extensionNameMenuItem.getParent();
163 |
164 | if (level == 3) { // Extensions -> Name -> Scan
165 | // 默认不做处理
166 | } else {
167 | Component invoker2 = extensionsPopupMenu.getInvoker();
168 |
169 | if (!(invoker2 instanceof JMenuItem) || !((JMenuItem) invoker2).getText().equals("Extensions")) {
170 | return;
171 | }
172 | JMenuItem extensionsMenuItem = (JMenuItem) invoker2;
173 | extensionsMenuItem.addHierarchyListener(new HierarchyListener() {
174 | private boolean ran3 = false;
175 |
176 | @Override
177 | public void hierarchyChanged(HierarchyEvent e) {
178 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) {
179 | if (!ran3) {
180 | ran3 = true;
181 |
182 | if (extensionsMenuItem.getParent() == null || !(extensionsMenuItem.getParent() instanceof JPopupMenu)) {
183 | return;
184 | }
185 | extensionsPopupMenu.remove(extensionNameMenuItem); // 移除自身插件菜单
186 |
187 | JPopupMenu topLevelPopupMenu = (JPopupMenu) extensionsMenuItem.getParent(); // 拿到 topLevelPopupMenu 就能为所欲为
188 |
189 | // 获取
190 | List allMenus = new ArrayList<>();
191 | for (int i = 0; i < extensionsPopupMenu.getComponentCount(); i++ ) {
192 | JMenu m = (JMenu) extensionsPopupMenu.getComponent(i);
193 | allMenus.add(m);
194 | }
195 |
196 | // 移除
197 | extensionsPopupMenu.removeAll();
198 |
199 | // 添加
200 | if (level == 2) { // Extensions -> Name - Scan
201 | for (JMenu menu: allMenus) {
202 | List items = new ArrayList<>();
203 | for (int i = 0; i < menu.getItemCount(); i++) {
204 | JMenuItem item = menu.getItem(i);
205 | item.setText(menu.getText() + " - " + item.getText());
206 | items.add(item);
207 | }
208 | for (JMenuItem item : items) {
209 | extensionsPopupMenu.add(item);
210 | }
211 | }
212 | } else if (level == 1) { // Name -> Scan
213 | int index = topLevelPopupMenu.getComponentIndex(extensionsMenuItem) + 1;
214 | for (int i = 0; i < allMenus.size(); i++) {
215 | JMenu menu = allMenus.get(i);
216 | topLevelPopupMenu.add(menu, index + i);
217 | }
218 |
219 | // 隐藏Extensions菜单
220 | // extensionsMenuItem.setVisible(false);
221 | } else if (level == 0) { // Name - Scan
222 | int index = topLevelPopupMenu.getComponentIndex(extensionsMenuItem) + 1;
223 | int seq = 0;
224 | for (int i = 0; i < allMenus.size(); i++) {
225 | JMenu menu = allMenus.get(i);
226 |
227 | List items = new ArrayList<>();
228 | for (int j = 0; j < menu.getItemCount(); j++) {
229 | JMenuItem item = menu.getItem(j);
230 | item.setText(menu.getText() + " - " + item.getText());
231 | items.add(item);
232 | }
233 | for (JMenuItem item : items) {
234 | topLevelPopupMenu.add(item, index + seq);
235 | seq += 1;
236 | }
237 | }
238 |
239 | }
240 |
241 |
242 | }
243 | }
244 | }
245 | });
246 | }
247 |
248 | }
249 | }
250 | }
251 | });
252 | }
253 | }
254 | }
255 | });
256 |
257 | }
258 | }
--------------------------------------------------------------------------------