├── .gitignore ├── BurpExtender.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | -------------------------------------------------------------------------------- /BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | 4 | import java.io.*; 5 | import java.nio.charset.StandardCharsets; 6 | import java.security.MessageDigest; 7 | import java.awt.Component; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.ItemEvent; 11 | import java.net.URL; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import javax.swing.JScrollPane; 15 | import javax.swing.JSplitPane; 16 | import javax.swing.JTabbedPane; 17 | import javax.swing.JTable; 18 | import javax.swing.SwingUtilities; 19 | import javax.swing.table.AbstractTableModel; 20 | import javax.swing.table.TableModel; 21 | import javax.swing.JLabel; 22 | import javax.swing.JPanel; 23 | import javax.swing.JButton; 24 | import javax.swing.JCheckBox; 25 | import java.awt.*; 26 | import java.awt.event.ItemListener; 27 | import javax.swing.JMenuItem; 28 | import java.util.regex.Matcher; 29 | import java.util.regex.Pattern; 30 | import javax.swing.JTextArea; 31 | import javax.swing.JTextField; 32 | import java.util.Arrays; 33 | 34 | 35 | 36 | 37 | public class BurpExtender extends AbstractTableModel implements IBurpExtender, ITab, IHttpListener, IScannerCheck, IMessageEditorController, IContextMenuFactory 38 | { 39 | private IBurpExtenderCallbacks callbacks; 40 | private IExtensionHelpers helpers; 41 | private JSplitPane splitPane; 42 | private IMessageEditor requestViewer; 43 | private IMessageEditor responseViewer; 44 | private final List log = new ArrayList();//记录原始流量 45 | private final List log2 = new ArrayList();//记录攻击流量 46 | private final List log3 = new ArrayList();//用于展现 47 | private final List log4_md5 = new ArrayList();//用于存放数据包的md5 48 | private IHttpRequestResponse currentlyDisplayedItem; 49 | private JTextField whitelistField; 50 | private List whitelistedParams; 51 | public PrintWriter stdout; 52 | int switchs = 1; //开关 0关 1开 53 | int clicks_Repeater=0;//64是监听 0是关闭 54 | int clicks_Proxy=0;//4是监听 0是关闭 55 | int conut = 0; //记录条数 56 | String data_md5_id; //用于判断目前选中的数据包 57 | public AbstractTableModel model = new MyModel(); 58 | int original_data_len;//记录原始数据包的长度 59 | int is_int = 1; //开关 0关 1开;//纯数据是否进行-1,-0 60 | String temp_data; //用于保存临时内容 61 | int JTextArea_int = 0;//自定义payload开关 0关 1开 62 | String JTextArea_data_1 = "";//文本域的内容 63 | int diy_payload_1 = 1;//自定义payload空格编码开关 0关 1开 64 | int diy_payload_2 = 0;//自定义payload值置空开关 0关 1开 65 | int select_row = 0;//选中表格的行数 66 | Table logTable; //第一个表格框 67 | int is_cookie = -1;//cookie是否要注入,-1关闭 2开启。 68 | String white_URL = ""; 69 | int white_switchs = 0;//白名单开关 70 | 71 | 72 | 73 | 74 | 75 | // 76 | // implement IBurpExtender 77 | // 78 | 79 | @Override 80 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) 81 | { 82 | //输出 83 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 84 | this.stdout.println("hello xia sql!"); 85 | this.stdout.println("你好 欢迎使用 瞎注!(新增参数白名单)"); 86 | this.stdout.println("version:2.9.1"); 87 | this.stdout.println("原版地址:https://github.com/smxiazi/xia_sql"); 88 | 89 | 90 | 91 | // keep a reference to our callbacks object 92 | this.callbacks = callbacks; 93 | 94 | // obtain an extension helpers object 95 | helpers = callbacks.getHelpers(); 96 | 97 | // set our extension name 98 | callbacks.setExtensionName("xia SQL V2.9.1"); 99 | 100 | // create our UI 101 | SwingUtilities.invokeLater(new Runnable() 102 | { 103 | @Override 104 | public void run() 105 | { 106 | 107 | // main split pane 108 | splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 109 | JSplitPane splitPanes = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 110 | JSplitPane splitPanes_2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 111 | 112 | // table of log entries 113 | logTable = new Table(BurpExtender.this); 114 | JScrollPane scrollPane = new JScrollPane(logTable); //给列表添加滚动条 115 | 116 | 117 | 118 | //test 119 | JPanel jp=new JPanel(); 120 | JLabel jl=new JLabel("==>"); //创建一个标签 121 | 122 | Table_log2 table=new Table_log2(model); 123 | JScrollPane pane=new JScrollPane(table);//给列表添加滚动条 124 | 125 | jp.add(scrollPane); //将表格加到面板 126 | jp.add(jl); //将标签添加到面板 127 | jp.add(pane); //将表格加到面板 128 | 129 | //侧边复选框 130 | JPanel jps=new JPanel(); 131 | jps.setLayout(new GridLayout(22, 1)); //六行一列 132 | JLabel jls=new JLabel("插件名:瞎注 author:算命縖子"); //创建一个标签 133 | JLabel jls_1=new JLabel("blog:www.nmd5.com"); //创建一个标签 134 | JLabel jls_2=new JLabel("版本:xia SQL V2.9"); //创建一个标签 135 | JLabel jls_3=new JLabel("感谢名单:Moonlit、阿猫阿狗、Shincehor"); //创建一个标签 136 | JCheckBox chkbox1=new JCheckBox("启动插件", true); //创建指定文本和状态的复选框 137 | JCheckBox chkbox2=new JCheckBox("监控Repeater"); //创建指定文本的复选框 138 | JCheckBox chkbox3=new JCheckBox("监控Proxy"); //创建指定文本的复选框 139 | JCheckBox chkbox4=new JCheckBox("值是数字则进行-1、-0",true); //创建指定文本的复选框 140 | JLabel jls_4=new JLabel("修改payload后记得点击加载"); //创建一个标签 141 | JCheckBox chkbox5=new JCheckBox("自定义payload"); //创建指定文本的复选框 142 | JCheckBox chkbox6=new JCheckBox("自定义payload中空格url编码",true); //创建指定文本的复选框 143 | JCheckBox chkbox7=new JCheckBox("自定义payload中参数值置空"); //创建指定文本的复选框 144 | JCheckBox chkbox8=new JCheckBox("测试Cookie"); //创建指定文本的复选框 145 | JLabel jls_5=new JLabel("如果需要多个域名加白请用,隔开"); //创建一个标签 146 | JTextField textField = new JTextField("填写白名单域名");//白名单文本框 147 | 148 | //chkbox4.setEnabled(false);//设置为不可以选择 149 | 150 | JButton btn1=new JButton("清空列表"); //创建JButton对象 151 | JButton btn2=new JButton("加载/重新加载payload"); //创建JButton对象 152 | JButton btn3=new JButton("启动白名单"); //处理白名单 153 | //JButton btn4=new JButton("启动参数白名单"); //参数白名单 154 | 155 | //自定义payload区 156 | JPanel jps_2=new JPanel(); 157 | jps_2.setLayout(new GridLayout(1, 1)); //六行一列 158 | JTextArea jta=new JTextArea("%df' and sleep(3)%23\n'and '1'='1",18,16); 159 | 160 | //读取ini配置文件 161 | try { 162 | BufferedReader in = new BufferedReader(new FileReader("xia_SQL_diy_payload.ini")); 163 | String str,str_data=""; 164 | while ((str = in.readLine()) != null) { 165 | str_data += str+"\n"; 166 | } 167 | jta.setText(str_data); 168 | } catch (IOException e) { 169 | } 170 | 171 | //jta.setLineWrap(true); //设置文本域中的文本为自动换行 172 | jta.setForeground(Color.BLACK); //设置组件的背景色 173 | jta.setFont(new Font("楷体",Font.BOLD,16)); //修改字体样式 174 | jta.setBackground(Color.LIGHT_GRAY); //设置背景色 175 | jta.setEditable(false);//不可编辑状态 176 | JScrollPane jsp=new JScrollPane(jta); //将文本域放入滚动窗口 177 | jps_2.add(jsp); //将JScrollPane添加到JPanel容器中 178 | 179 | //添加复选框监听事件 180 | chkbox1.addItemListener(new ItemListener() { 181 | @Override 182 | public void itemStateChanged(ItemEvent e) { 183 | if(chkbox1.isSelected()){ 184 | stdout.println("插件xia SQl启动"); 185 | switchs = 1; 186 | }else { 187 | stdout.println("插件xia SQL关闭"); 188 | switchs = 0; 189 | } 190 | 191 | } 192 | }); 193 | chkbox2.addItemListener(new ItemListener() { 194 | @Override 195 | public void itemStateChanged(ItemEvent e) { 196 | if (chkbox2.isSelected()){ 197 | stdout.println("启动 监控Repeater"); 198 | clicks_Repeater = 64; 199 | }else { 200 | stdout.println("关闭 监控Repeater"); 201 | clicks_Repeater = 0; 202 | } 203 | } 204 | }); 205 | chkbox3.addItemListener(new ItemListener() { 206 | @Override 207 | public void itemStateChanged(ItemEvent e) { 208 | if(chkbox3.isSelected()) { 209 | stdout.println("启动 监控Proxy"); 210 | clicks_Proxy = 4; 211 | }else { 212 | stdout.println("关闭 监控Proxy"); 213 | clicks_Proxy = 0; 214 | } 215 | } 216 | }); 217 | chkbox4.addItemListener(new ItemListener() { 218 | @Override 219 | public void itemStateChanged(ItemEvent e) { 220 | if(chkbox4.isSelected()) { 221 | stdout.println("启动 值是数字则进行-1、-0"); 222 | is_int = 1; 223 | }else { 224 | stdout.println("关闭 值是数字则进行-1、-0"); 225 | is_int = 0; 226 | } 227 | } 228 | }); 229 | 230 | chkbox5.addItemListener(new ItemListener() { 231 | @Override 232 | public void itemStateChanged(ItemEvent e) { 233 | if(chkbox5.isSelected()) { 234 | stdout.println("启动 自定义payload"); 235 | jta.setEditable(true); 236 | jta.setBackground(Color.WHITE); //设置背景色 237 | JTextArea_int = 1; 238 | 239 | if (diy_payload_1 == 1){ 240 | String temp_data = jta.getText(); 241 | temp_data = temp_data.replaceAll(" ","%20"); 242 | JTextArea_data_1 = temp_data; 243 | }else { 244 | JTextArea_data_1 = jta.getText(); 245 | } 246 | 247 | }else { 248 | stdout.println("关闭 自定义payload"); 249 | jta.setEditable(false); 250 | jta.setBackground(Color.LIGHT_GRAY); //设置背景色 251 | JTextArea_int = 0; 252 | } 253 | } 254 | }); 255 | 256 | chkbox6.addItemListener(new ItemListener() { 257 | @Override 258 | public void itemStateChanged(ItemEvent e) { 259 | if(chkbox6.isSelected()) { 260 | stdout.println("启动 空格url编码"); 261 | diy_payload_1 = 1; 262 | 263 | //空格url编码 264 | String temp_data = jta.getText(); 265 | temp_data = temp_data.replaceAll(" ","%20"); 266 | JTextArea_data_1 = temp_data; 267 | }else { 268 | stdout.println("关闭 空格url编码"); 269 | diy_payload_1 = 0; 270 | 271 | JTextArea_data_1 = jta.getText(); 272 | } 273 | } 274 | }); 275 | 276 | chkbox7.addItemListener(new ItemListener() { 277 | @Override 278 | public void itemStateChanged(ItemEvent e) { 279 | if(chkbox7.isSelected()) { 280 | stdout.println("启动 自定义payload参数值置空"); 281 | diy_payload_2 = 1; 282 | }else { 283 | stdout.println("关闭 自定义payload参数值置空"); 284 | diy_payload_2 = 0; 285 | } 286 | } 287 | }); 288 | 289 | chkbox8.addItemListener(new ItemListener() { 290 | @Override 291 | public void itemStateChanged(ItemEvent e) { 292 | if(chkbox8.isSelected()) { 293 | stdout.println("启动 测试Cookie"); 294 | is_cookie = 2; 295 | }else { 296 | stdout.println("关闭 测试Cookie"); 297 | is_cookie = -1; 298 | } 299 | } 300 | }); 301 | 302 | btn1.addActionListener(new ActionListener() {//清空列表 303 | @Override 304 | public void actionPerformed(ActionEvent e) { 305 | log.clear();//清除log的内容 306 | log2.clear();//清除log2的内容 307 | log3.clear();//清除log3的内容 308 | log4_md5.clear();//清除log4的内容 309 | conut = 0; 310 | fireTableRowsInserted(log.size(), log.size());//刷新列表中的展示 311 | model.fireTableRowsInserted(log3.size(), log3.size());//刷新列表中的展示 312 | } 313 | }); 314 | 315 | btn2.addActionListener(new ActionListener() {//加载自定义payload 316 | @Override 317 | public void actionPerformed(ActionEvent e) { 318 | if (diy_payload_1 == 1){ 319 | String temp_data = jta.getText(); 320 | temp_data = temp_data.replaceAll(" ","%20"); 321 | JTextArea_data_1 = temp_data; 322 | }else { 323 | JTextArea_data_1 = jta.getText(); 324 | } 325 | //写入ini配置文件 326 | try { 327 | BufferedWriter out = new BufferedWriter(new FileWriter("xia_SQL_diy_payload.ini")); 328 | out.write(JTextArea_data_1); 329 | out.close(); 330 | } catch (IOException exception) { 331 | } 332 | } 333 | }); 334 | btn3.addActionListener(new ActionListener() {//加载自定义payload 335 | @Override 336 | public void actionPerformed(ActionEvent e) { 337 | if(btn3.getText().equals("启动白名单")){ 338 | btn3.setText("关闭白名单"); 339 | white_URL = textField.getText(); 340 | white_switchs = 1; 341 | textField.setEditable(false); 342 | textField.setForeground(Color.GRAY);//设置组件的背景色 343 | }else { 344 | btn3.setText("启动白名单"); 345 | white_switchs = 0; 346 | textField.setEditable(true); 347 | textField.setForeground(Color.BLACK); 348 | } 349 | } 350 | }); 351 | 352 | // 添加白名单输入字段 353 | whitelistField = new JTextField(20); 354 | JButton whitelistButton = new JButton("更新白名单"); 355 | whitelistButton.addActionListener(e -> updateWhitelist()); 356 | 357 | 358 | jps.add(jls); 359 | jps.add(jls_1); 360 | jps.add(jls_2); 361 | jps.add(jls_3); 362 | jps.add(chkbox1); 363 | jps.add(chkbox2); 364 | jps.add(chkbox3); 365 | jps.add(chkbox4); 366 | jps.add(chkbox8); 367 | jps.add(btn1); 368 | jps.add(jls_5); 369 | jps.add(textField); 370 | jps.add(btn3); 371 | jps.add(new JLabel("参数白名单 (用逗号分隔):")); 372 | jps.add(whitelistField); 373 | jps.add(whitelistButton); 374 | jps.add(jls_4); 375 | jps.add(chkbox5); 376 | jps.add(chkbox6); 377 | jps.add(chkbox7); 378 | jps.add(btn2); 379 | 380 | 381 | 382 | 383 | 384 | 385 | // tabs with request/response viewers 386 | JTabbedPane tabs = new JTabbedPane(); 387 | requestViewer = callbacks.createMessageEditor(BurpExtender.this, false); 388 | responseViewer = callbacks.createMessageEditor(BurpExtender.this, false); 389 | tabs.addTab("Request", requestViewer.getComponent()); 390 | tabs.addTab("Response", responseViewer.getComponent()); 391 | 392 | //jp.add(tabs); 393 | 394 | //右边 395 | splitPanes_2.setLeftComponent(jps);//上面 396 | splitPanes_2.setRightComponent(jps_2);//下面 397 | 398 | //左边 399 | splitPanes.setLeftComponent(jp);//上面 400 | splitPanes.setRightComponent(tabs);//下面 401 | 402 | //整体分布 403 | splitPane.setLeftComponent(splitPanes);//添加在左面 404 | splitPane.setRightComponent(splitPanes_2);//添加在右面 405 | splitPane.setDividerLocation(1000);//设置分割的大小 406 | 407 | // customize our UI components 408 | callbacks.customizeUiComponent(splitPane); 409 | callbacks.customizeUiComponent(logTable); 410 | callbacks.customizeUiComponent(scrollPane); 411 | callbacks.customizeUiComponent(pane); 412 | callbacks.customizeUiComponent(jps); 413 | callbacks.customizeUiComponent(jp); 414 | callbacks.customizeUiComponent(tabs); 415 | 416 | // add the custom tab to Burp's UI 417 | callbacks.addSuiteTab(BurpExtender.this); 418 | 419 | // register ourselves as an HTTP listener 420 | callbacks.registerHttpListener(BurpExtender.this); 421 | callbacks.registerScannerCheck(BurpExtender.this); 422 | callbacks.registerContextMenuFactory(BurpExtender.this); 423 | 424 | } 425 | }); 426 | } 427 | // 428 | // implement ITab 429 | // 430 | 431 | @Override 432 | public String getTabCaption() 433 | { 434 | return "xia SQL"; 435 | } 436 | 437 | @Override 438 | public Component getUiComponent() 439 | { 440 | return splitPane; 441 | } 442 | 443 | // 444 | // implement IHttpListener 445 | // 446 | 447 | 448 | 449 | 450 | @Override 451 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) 452 | { 453 | 454 | if(switchs == 1){//插件开关 455 | if(toolFlag == clicks_Repeater || toolFlag == clicks_Proxy){//监听Repeater 456 | // only process responses 457 | if (!messageIsRequest) 458 | { 459 | // create a new log entry with the message details 460 | synchronized(log) 461 | { 462 | //BurpExtender.this.checkVul(messageInfo,toolFlag); 463 | Thread thread = new Thread(new Runnable() { 464 | public void run() { 465 | try { 466 | BurpExtender.this.checkVul(messageInfo,toolFlag); 467 | } catch (Exception ex) { 468 | ex.printStackTrace(); 469 | BurpExtender.this.stdout.println(ex); 470 | } 471 | } 472 | }); 473 | thread.start(); 474 | } 475 | } 476 | } 477 | 478 | } 479 | 480 | } 481 | 482 | @Override 483 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { 484 | return null; 485 | } 486 | 487 | @Override 488 | public List createMenuItems(final IContextMenuInvocation invocation) { 489 | //右键发送按钮功能 490 | 491 | List listMenuItems = new ArrayList(1); 492 | if(invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER || invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_PROXY){ 493 | //父级菜单 494 | IHttpRequestResponse[] responses = invocation.getSelectedMessages(); 495 | JMenuItem jMenu = new JMenuItem("Send to xia SQL"); 496 | 497 | jMenu.addActionListener(new ActionListener() { 498 | @Override 499 | public void actionPerformed(ActionEvent e) { 500 | if(switchs == 1) { 501 | //不应在Swing事件调度线程中发出HTTP请求,所以需要创建一个Runnable并在 run() 方法中完成工作,后调用 new Thread(runnable).start() 来启动线程 502 | Thread thread = new Thread(new Runnable() { 503 | public void run() { 504 | try { 505 | BurpExtender.this.checkVul(responses[0], 1024); 506 | } catch (Exception ex) { 507 | ex.printStackTrace(); 508 | BurpExtender.this.stdout.println(ex); 509 | } 510 | } 511 | }); 512 | thread.start(); 513 | }else { 514 | BurpExtender.this.stdout.println("插件xia SQL关闭状态!"); 515 | } 516 | 517 | } 518 | }); 519 | 520 | listMenuItems.add(jMenu); 521 | 522 | 523 | } 524 | //BurpExtender.this.checkVul(responses,4); 525 | return listMenuItems; 526 | } 527 | 528 | private void updateWhitelist() { 529 | String whitelistText = whitelistField.getText().trim(); 530 | whitelistedParams = Arrays.asList(whitelistText.split("\\s*,\\s*")); 531 | stdout.println("更新白名单: " + whitelistedParams); 532 | } 533 | private void checkVul(IHttpRequestResponse baseRequestResponse, int toolFlag){ 534 | 535 | int is_add; //用于判断是否要添加扫描 536 | String change_sign_1 = ""; //用于显示第一个列表框的状态 变化 部分的内容 537 | 538 | //把当前url和参数进行md5加密,用于判断该url是否已经扫描过 539 | ListparaLists= helpers.analyzeRequest(baseRequestResponse).getParameters(); 540 | temp_data = String.valueOf(helpers.analyzeRequest(baseRequestResponse).getUrl());//url 541 | //stdout.println(temp_data); 542 | String[] temp_data_strarray=temp_data.split("\\?"); 543 | String temp_data =(String) temp_data_strarray[0];//获取问号前面的字符串 544 | 545 | //检测白名单 546 | String[] white_URL_list = white_URL.split(","); 547 | int white_swith = 0; 548 | if(white_switchs == 1){ 549 | white_swith = 0; 550 | for(int i=0;i2){ 598 | is_add = 2; 599 | } 600 | //json中有列表 601 | request_datas = request_data.split("\":\\["); 602 | if(request_datas.length >1){ 603 | is_add = 2; 604 | } 605 | } catch (Exception e) { 606 | stdout.println(e); 607 | } 608 | } 609 | } 610 | } 611 | 612 | 613 | 614 | //url+参数进行编码 615 | temp_data += "+"+helpers.analyzeRequest(baseRequestResponse).getMethod(); 616 | //this.stdout.println(temp_data); 617 | this.stdout.println("\nMD5(\""+temp_data+"\")"); 618 | temp_data = MD5(temp_data); 619 | this.stdout.println(temp_data); 620 | 621 | 622 | 623 | for (Request_md5 i : log4_md5){ 624 | if(i.md5_data.equals(temp_data)){//判断md5值是否一样,且右键发送过来的请求不进行md5验证 625 | if(toolFlag == 1024){ 626 | temp_data = String.valueOf(System.currentTimeMillis()); 627 | this.stdout.println(temp_data); 628 | temp_data = MD5(temp_data); 629 | this.stdout.println(temp_data); 630 | }else { 631 | return; 632 | } 633 | 634 | 635 | } 636 | } 637 | 638 | //用于判断是否要处理这个请求 639 | if (is_add != 0){ 640 | log4_md5.add(new Request_md5(temp_data));//保存对应对md5 641 | stdout.println(is_add); 642 | stdout.println(request_data); 643 | 644 | int row = log.size(); 645 | try{ 646 | original_data_len = callbacks.saveBuffersToTempFiles(baseRequestResponse).getResponse().length;//更新原始数据包的长度 647 | stdout.println(original_data_len); 648 | if(original_data_len <= 0){ 649 | stdout.println("该数据包无响应"); 650 | return; 651 | } 652 | } catch (Exception ex) { 653 | stdout.println("该数据包无响应"); 654 | return; 655 | } 656 | 657 | log.add(new LogEntry(conut,toolFlag, callbacks.saveBuffersToTempFiles(baseRequestResponse),helpers.analyzeRequest(baseRequestResponse).getUrl(),"","","",temp_data,0,"run……",999)); 658 | conut += 1; 659 | fireTableRowsInserted(row, row); 660 | } 661 | 662 | //处理参数 663 | ListparaList= helpers.analyzeRequest(baseRequestResponse).getParameters(); 664 | byte[] new_Request = baseRequestResponse.getRequest(); 665 | int json_count = -1;//记录json嵌套次数 666 | 667 | 668 | //**************************************** 669 | // 循环获取参数 670 | //**************************************** 671 | String para_name = "";//用来记录上一次循环的参数名 672 | for (IParameter para : paraList){// 循环获取参数 673 | int switch_para = 0;//用来判断该参数是否要处理 0 要处理 1 跳过 674 | 675 | if(para.getType() == 6){ 676 | json_count += 1; 677 | } 678 | 679 | //payload 680 | ArrayList payloads = new ArrayList<>(); 681 | payloads.add("'"); 682 | payloads.add("''"); 683 | 684 | 685 | 686 | if (para.getType() == 0 || para.getType() == 1 || para.getType() == 6 || para.getType() == is_cookie){ //getTpe()就是来判断参数是在那个位置的 687 | String key = para.getName();//获取参数的名称 688 | String value = para.getValue();//获取参数的值 689 | 690 | // 检查参数是否在白名单中 691 | if (whitelistedParams != null && whitelistedParams.contains(key)) { 692 | stdout.println("跳过白名单参数: " + key); 693 | continue; 694 | } 695 | stdout.println("\n\n原始数据:"+key+":"+value);//输出原始的键值数据 696 | 697 | if(is_int == 1){//开关,用于判断是否要开启-1、-0的操作 698 | if (value.matches("[0-9]+")) {//用于判读参数的值是否为纯数字 699 | payloads.add("-1"); 700 | payloads.add("-0"); 701 | } 702 | } 703 | 704 | //自定义payload 705 | if(JTextArea_int == 1){ 706 | String[] JTextArea_data = JTextArea_data_1.split("\n"); 707 | for(String a:JTextArea_data){ 708 | //stdout.println(a); 709 | //stdout.println("------"); 710 | payloads.add(a); 711 | } 712 | } 713 | 714 | int change = 0; //用于判断返回包长度是否一致、保存第一次请求响应的长度 715 | 716 | //**************************************** 717 | // 循环payload 718 | //**************************************** 719 | for (String payload : payloads) { 720 | int time_1 = 0,time_2 = 0; 721 | 722 | if(JTextArea_int == 1){ 723 | //自定义payload //参数值为空 724 | if(diy_payload_2 == 1){ 725 | if(payload != "'" && payload !="''" && payload != "-1" && payload != "-0"){ 726 | value = ""; 727 | } 728 | } 729 | } 730 | 731 | //stdout.println(key+":"+value+payload);//输出添加payload的键和值 732 | IHttpService iHttpService = baseRequestResponse.getHttpService(); 733 | 734 | //新的请求包 735 | IHttpRequestResponse requestResponse = null; //用于过if内的变量 736 | 737 | if(para.getType() == 6){ 738 | List headers = helpers.analyzeRequest(baseRequestResponse).getHeaders(); 739 | if(is_add ==1) { 740 | //json格式 741 | stdout.println("json"); 742 | String newBody = "{"; //json body的内容 743 | 744 | for (IParameter paras : paraList) {//循环所有参数,用来自定义json格式body做准备 745 | if (paras.getType() == 6) {//只要json格式的数据 746 | if (key == paras.getName() && value == paras.getValue()) {//判断现在的键和值是否是需要添加payload的键和值 747 | newBody += "\"" + paras.getName() + "\":" + "\"" + paras.getValue() + payload + "\",";//构造json的body 748 | } else { 749 | newBody += "\"" + paras.getName() + "\":" + "\"" + paras.getValue() + "\",";//构造json的body 750 | } 751 | } 752 | } 753 | 754 | newBody = newBody.substring(0, newBody.length() - 1); //去除最后一个, 755 | newBody += "}";//json body的内容 756 | 757 | byte[] bodyByte = newBody.getBytes(); 758 | byte[] new_Requests = helpers.buildHttpMessage(headers, bodyByte); //关键方法 759 | 760 | time_1 = (int) System.currentTimeMillis(); 761 | requestResponse = callbacks.makeHttpRequest(iHttpService, new_Requests);//发送请求 762 | time_2 = (int) System.currentTimeMillis(); 763 | }else if (is_add ==2){ 764 | //json嵌套 765 | //stdout.println("json嵌套"); 766 | 767 | request_data = request_data.replaceAll("\r","");//burp2.x json自动格式美化处理 768 | request_data = request_data.replaceAll("\n","");//burp2.x json自动格式美化处理 769 | 770 | String[] request_data_temp = request_data.split(",\"");//用于临时保存切割的post体内容 771 | String request_data_body = "";//连接字符串 772 | String request_data_body_temp = "";//修改后的body和需要临时编辑的字符串 773 | 774 | 775 | for(int i=0;i < request_data_temp.length;i++){ 776 | if(i==json_count){//判断现在修改的参数 777 | request_data_body_temp = request_data_temp[i]; 778 | 779 | stdout.println("准备修改的值:"+request_data_body_temp); 780 | while (true){ 781 | //空列表如:"test":[]跳过处理 782 | if(request_data_body_temp.contains(":[]")) { 783 | stdout.println(request_data_body_temp+"跳过"); 784 | request_data_body += "\""+request_data_temp[i]+",";//把跳过的字符串连接上 785 | json_count += 1; 786 | i += 1; 787 | request_data_body_temp = request_data_temp[i]; 788 | }else { 789 | break; 790 | } 791 | } 792 | 793 | 794 | //null、true、false等跳过处理 795 | if(request_data_body_temp.toLowerCase().contains(":null") || request_data_body_temp.toLowerCase().contains(":true") || request_data_body_temp.toLowerCase().contains(":false")) { 796 | stdout.println(request_data_body_temp+"跳过"); 797 | switch_para = 1; 798 | break; 799 | } 800 | 801 | 802 | if(request_data_body_temp.contains("\":")){ 803 | 804 | if(para.getName().equals(para_name)){ 805 | //处理json嵌套列表,这种情况只跑一次 806 | stdout.println("json嵌套列表,这个参数处理过了,跳过"); 807 | json_count -= 1; 808 | switch_para = 1; 809 | break; 810 | } 811 | 812 | //判断字符串中是否有":,如果有则为正常json内容 813 | Pattern p = Pattern.compile(".*:\\s?\\[?\\s?(.*?$)"); 814 | Matcher m = p.matcher(request_data_body_temp); 815 | if(m.find()){ 816 | request_data_body_temp = m.group(1);//获取:后面的内容 817 | } 818 | if(request_data_body_temp.contains("\"")){//判断内容是否为字符串 819 | request_data_body_temp = request_data_temp[i]; 820 | //修改内容,添加payload 821 | request_data_body_temp = request_data_body_temp.replaceAll("^(.*:.*?\")(.*?)(\"[^\"]*)$","$1$2"+payload+"$3"); 822 | stdout.println(request_data_body_temp); 823 | request_data_body+= "\""+request_data_body_temp +","; 824 | }else { 825 | request_data_body_temp = request_data_temp[i]; 826 | //修改内容,添加payload 纯数字 827 | request_data_body_temp = request_data_body_temp.replaceAll("^(.*:.*?)(\\d*)([^\"\\d]*)$","$1\"$2"+payload+"\"$3"); 828 | stdout.println(request_data_body_temp); 829 | request_data_body+= "\""+request_data_body_temp +","; 830 | } 831 | 832 | }else { 833 | stdout.println("处理过,无需处理"); 834 | switch_para = 1; 835 | if(para.getName().equals(para_name)){ 836 | //处理json嵌套列表,这种情况只跑一次 837 | stdout.println("json嵌套列表,已经处理过第一个值"); 838 | } 839 | break; 840 | 841 | /* 842 | //字符串中没有":,表示json格式中嵌套的列表 843 | 844 | if(request_data_body_temp.contains("\"")) {//判断内容是否为字符串 845 | //修改内容,添加payload 846 | request_data_body_temp = request_data_body_temp.replaceAll("^(\")(.*?)(\".*?)$","$1$2"+payload+"$3"); 847 | request_data_body+= "\""+request_data_body_temp +","; 848 | }else { 849 | //不是字符串,则为纯数字 850 | request_data_body_temp = request_data_body_temp.replaceAll("^(\\d*)(.*?)$","\"$1"+payload+"\"$2"); 851 | request_data_body+= "\""+request_data_body_temp +","; 852 | } 853 | */ 854 | } 855 | //stdout.println(request_data_body_temp); 856 | 857 | 858 | }else { 859 | request_data_body += "\""+request_data_temp[i]+","; 860 | } 861 | } 862 | 863 | if(switch_para == 1){ 864 | //跳过这个参数 865 | break; 866 | } 867 | if(para.getName().equals(para_name)){ 868 | //处理json嵌套列表,这种情况只跑一次 869 | stdout.println("json嵌套列表,已经处理过第一个值!!!!"); 870 | } 871 | 872 | 873 | request_data_body = request_data_body.substring(0, request_data_body.length() - 1); //去除最后一个, 874 | request_data_body = request_data_body.substring(1,request_data_body.length()); //去除第一个" 875 | 876 | byte[] bodyByte = request_data_body.getBytes(); 877 | byte[] new_Requests = helpers.buildHttpMessage(headers, bodyByte); //关键方法 878 | time_1 = (int) System.currentTimeMillis(); 879 | requestResponse = callbacks.makeHttpRequest(iHttpService, new_Requests);//发送请求 880 | time_2 = (int) System.currentTimeMillis(); 881 | 882 | } 883 | }else { 884 | stdout.println("普通格式"); 885 | //不是json格式 886 | IParameter newPara = helpers.buildParameter(key,value + payload, para.getType()); //构造新的参数 887 | byte[] newRequest = helpers.updateParameter(new_Request, newPara);//更新请求包的参数 888 | 889 | time_1 = (int) System.currentTimeMillis(); 890 | requestResponse = callbacks.makeHttpRequest(iHttpService, newRequest);//发送请求 891 | time_2 = (int) System.currentTimeMillis(); 892 | 893 | } 894 | 895 | //判断数据长度是否会变化 896 | String change_sign;//第二个表格中 变化 的内容 897 | if(payload == "'" || payload == "-1" || change == 0){ 898 | change = requestResponse.getResponse().length;//保存第一次请求响应的长度 899 | change_sign = ""; 900 | }else{ 901 | if(payload == "''" || payload == "-0" ){ 902 | if(change != requestResponse.getResponse().length){//判断第一次的长度和现在的是否不同 903 | if(payload == "''" && requestResponse.getResponse().length == original_data_len || payload == "-0" && requestResponse.getResponse().length == original_data_len){//判断两个单引号的长度和第一次的不一样且和原始包的长度一致 904 | //原始包的长度和两个双引号的长度相同且和一个单引号的长度不同 905 | change_sign = "✔ ==> ?"; 906 | change_sign_1 = " ✔"; 907 | }else{ 908 | //第一次的包和第二次包的长度不同 909 | change_sign = "✔ "+ (change-requestResponse.getResponse().length); 910 | change_sign_1 = " ✔"; 911 | } 912 | }else { 913 | //第一次包和第二次包的长度一样 914 | change_sign = ""; 915 | } 916 | }else { 917 | //自定义payload 918 | if(time_2-time_1 >= 3000){ 919 | //响应时间大于3秒 920 | change_sign = "time > 3"; 921 | change_sign_1 = " ✔"; 922 | }else { 923 | change_sign = "diy payload"; 924 | } 925 | } 926 | 927 | } 928 | //把响应内容保存在log2中 929 | log2.add(new LogEntry(conut,toolFlag, callbacks.saveBuffersToTempFiles(requestResponse),helpers.analyzeRequest(requestResponse).getUrl(),key,value+payload,change_sign,temp_data,time_2-time_1,"end",helpers.analyzeResponse(requestResponse.getResponse()).getStatusCode())); 930 | 931 | } 932 | } 933 | para_name = para.getName();//用于判断json嵌套里面有列表,列表中带值只跑一次 934 | stdout.println(json_count); 935 | 936 | } 937 | 938 | //用于更新是否已经跑完所有payload的状态 939 | for(int i = 0; i < log.size(); i++){ 940 | if(temp_data.equals(log.get(i).data_md5)){ 941 | log.get(i).setState("end!"+change_sign_1); 942 | //stdout.println("ok"); 943 | } 944 | } 945 | 946 | //刷新第一个列表框 947 | //BurpExtender.this.fireTableRowsInserted(log.size(), log.size()); 948 | BurpExtender.this.fireTableDataChanged(); 949 | //第一个表格 继续选中之前选中的值 950 | BurpExtender.this.logTable.setRowSelectionInterval(BurpExtender.this.select_row,BurpExtender.this.select_row); 951 | 952 | 953 | 954 | } 955 | 956 | @Override 957 | public List doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { 958 | return null; 959 | } 960 | 961 | @Override 962 | public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) { 963 | if (existingIssue.getIssueName().equals(newIssue.getIssueName())) 964 | return -1; 965 | else return 0; 966 | } 967 | // 968 | // extend AbstractTableModel 969 | // 970 | 971 | @Override 972 | public int getRowCount() 973 | { 974 | return log.size(); 975 | 976 | } 977 | 978 | @Override 979 | public int getColumnCount() 980 | { 981 | return 5; 982 | } 983 | 984 | @Override 985 | public String getColumnName(int columnIndex) 986 | { 987 | switch (columnIndex) 988 | { 989 | case 0: 990 | return "#"; 991 | case 1: 992 | return "来源"; 993 | case 2: 994 | return "URL"; 995 | case 3: 996 | return "返回包长度"; 997 | case 4: 998 | return "状态"; 999 | default: 1000 | return ""; 1001 | } 1002 | } 1003 | 1004 | @Override 1005 | public Class getColumnClass(int columnIndex) 1006 | { 1007 | return String.class; 1008 | } 1009 | 1010 | @Override 1011 | public Object getValueAt(int rowIndex, int columnIndex) 1012 | { 1013 | LogEntry logEntry = log.get(rowIndex); 1014 | 1015 | switch (columnIndex) 1016 | { 1017 | case 0: 1018 | return logEntry.id; 1019 | case 1: 1020 | return callbacks.getToolName(logEntry.tool); 1021 | case 2: 1022 | return logEntry.url.toString(); 1023 | case 3: 1024 | return logEntry.requestResponse.getResponse().length;//返回响应包的长度 1025 | case 4: 1026 | return logEntry.state; 1027 | default: 1028 | return ""; 1029 | } 1030 | } 1031 | 1032 | 1033 | //model2 1034 | class MyModel extends AbstractTableModel { 1035 | 1036 | @Override 1037 | public int getRowCount() 1038 | { 1039 | return log3.size(); 1040 | } 1041 | 1042 | @Override 1043 | public int getColumnCount() 1044 | { 1045 | return 6; 1046 | } 1047 | 1048 | @Override 1049 | public String getColumnName(int columnIndex) 1050 | { 1051 | switch (columnIndex) 1052 | { 1053 | case 0: 1054 | return "参数"; 1055 | case 1: 1056 | return "payload"; 1057 | case 2: 1058 | return "返回包长度"; 1059 | case 3: 1060 | return "变化"; 1061 | case 4: 1062 | return "用时"; 1063 | case 5: 1064 | return "响应码"; 1065 | default: 1066 | return ""; 1067 | } 1068 | } 1069 | 1070 | @Override 1071 | public Class getColumnClass(int columnIndex) 1072 | { 1073 | return String.class; 1074 | } 1075 | 1076 | @Override 1077 | public Object getValueAt(int rowIndex, int columnIndex) 1078 | { 1079 | LogEntry logEntry2 = log3.get(rowIndex); 1080 | 1081 | switch (columnIndex) 1082 | { 1083 | case 0: 1084 | return logEntry2.parameter; 1085 | case 1: 1086 | return logEntry2.value; 1087 | case 2: 1088 | return logEntry2.requestResponse.getResponse().length;//返回响应包的长度 1089 | case 3: 1090 | return logEntry2.change; 1091 | case 4: 1092 | return logEntry2.times; 1093 | case 5: 1094 | return logEntry2.response_code; 1095 | default: 1096 | return ""; 1097 | } 1098 | } 1099 | } 1100 | 1101 | 1102 | 1103 | 1104 | // 1105 | // implement IMessageEditorController 1106 | // this allows our request/response viewers to obtain details about the messages being displayed 1107 | // 1108 | 1109 | @Override 1110 | public byte[] getRequest() 1111 | { 1112 | return currentlyDisplayedItem.getRequest(); 1113 | } 1114 | 1115 | @Override 1116 | public byte[] getResponse() 1117 | { 1118 | return currentlyDisplayedItem.getResponse(); 1119 | } 1120 | 1121 | @Override 1122 | public IHttpService getHttpService() 1123 | { 1124 | return currentlyDisplayedItem.getHttpService(); 1125 | } 1126 | 1127 | // 1128 | // extend JTable to handle cell selection 1129 | // 1130 | 1131 | private class Table extends JTable 1132 | { 1133 | public Table(TableModel tableModel) 1134 | { 1135 | super(tableModel); 1136 | } 1137 | 1138 | @Override 1139 | public void changeSelection(int row, int col, boolean toggle, boolean extend) 1140 | { 1141 | // show the log entry for the selected row 1142 | LogEntry logEntry = log.get(row); 1143 | data_md5_id = logEntry.data_md5; 1144 | //stdout.println(log_id);//输出目前选中的行数 1145 | select_row = logEntry.id; 1146 | 1147 | log3.clear(); 1148 | for (int i = 0; i < log2.size(); i++) {//筛选出目前选中的原始数据包--》衍生出的带有payload的数据包 1149 | if(log2.get(i).data_md5==data_md5_id){ 1150 | log3.add(log2.get(i)); 1151 | } 1152 | } 1153 | //刷新列表界面 1154 | model.fireTableRowsInserted(log3.size(), log3.size()); 1155 | model.fireTableDataChanged(); 1156 | 1157 | requestViewer.setMessage(logEntry.requestResponse.getRequest(), true); 1158 | responseViewer.setMessage(logEntry.requestResponse.getResponse(), false); 1159 | currentlyDisplayedItem = logEntry.requestResponse; 1160 | 1161 | super.changeSelection(row, col, toggle, extend); 1162 | } 1163 | } 1164 | 1165 | private class Table_log2 extends JTable 1166 | { 1167 | public Table_log2(TableModel tableModel) 1168 | { 1169 | super(tableModel); 1170 | } 1171 | 1172 | @Override 1173 | public void changeSelection(int row, int col, boolean toggle, boolean extend) 1174 | { 1175 | 1176 | // show the log entry for the selected row 1177 | LogEntry logEntry = log3.get(row); 1178 | requestViewer.setMessage(logEntry.requestResponse.getRequest(), true); 1179 | responseViewer.setMessage(logEntry.requestResponse.getResponse(), false); 1180 | currentlyDisplayedItem = logEntry.requestResponse; 1181 | 1182 | super.changeSelection(row, col, toggle, extend); 1183 | } 1184 | } 1185 | 1186 | //存放数据包的md5值,用于匹配该数据包已请求过 1187 | private static class Request_md5 1188 | { 1189 | final String md5_data; 1190 | 1191 | Request_md5(String md5_data) 1192 | { 1193 | this.md5_data = md5_data; 1194 | } 1195 | } 1196 | // 1197 | // class to hold details of each log entry 1198 | // 1199 | private static class LogEntry 1200 | { 1201 | final int id; 1202 | final int tool; 1203 | final IHttpRequestResponsePersisted requestResponse; 1204 | final URL url; 1205 | final String parameter; 1206 | final String value; 1207 | final String change; 1208 | final String data_md5; 1209 | final int times; 1210 | final int response_code; 1211 | String state; 1212 | 1213 | 1214 | LogEntry(int id,int tool, IHttpRequestResponsePersisted requestResponse, URL url,String parameter,String value,String change,String data_md5,int times,String state,int response_code) 1215 | { 1216 | this.id = id; 1217 | this.tool = tool; 1218 | this.requestResponse = requestResponse; 1219 | this.url = url; 1220 | this.parameter = parameter; 1221 | this.value = value; 1222 | this.change = change; 1223 | this.data_md5 = data_md5; 1224 | this.times = times; 1225 | this.state = state; 1226 | this.response_code = response_code; 1227 | } 1228 | 1229 | public String setState(String state){ 1230 | this.state = state; 1231 | return this.state; 1232 | } 1233 | } 1234 | 1235 | public static String MD5(String key) { 1236 | char hexDigits[] = { 1237 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 1238 | }; 1239 | try { 1240 | byte[] btInput = key.getBytes(); 1241 | // 获得MD5摘要算法的 MessageDigest 对象 1242 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 1243 | // 使用指定的字节更新摘要 1244 | mdInst.update(btInput); 1245 | // 获得密文 1246 | byte[] md = mdInst.digest(); 1247 | // 把密文转换成十六进制的字符串形式 1248 | int j = md.length; 1249 | char str[] = new char[j * 2]; 1250 | int k = 0; 1251 | for (int i = 0; i < j; i++) { 1252 | byte byte0 = md[i]; 1253 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 1254 | str[k++] = hexDigits[byte0 & 0xf]; 1255 | } 1256 | return new String(str); 1257 | } catch (Exception e) { 1258 | return null; 1259 | } 1260 | } 1261 | 1262 | 1263 | } 1264 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 声明 2 | 代码是根据算命瞎子大佬的[xia_sql](https://github.com/smxiazi/xia_sql/tree/main)瞎注插件修改
3 | 因为目前代码在github的只有2.9版本,~~所以是根据2.9进行的新增~~,release中放了3.3版本的修改版,有jdk11 17 21三个版本
4 | 5 | # 功能 6 | 新增了如下功能:
7 | - 参数黑名单(可以禁止跑pageNum这种参数) 8 | - 返回包长度这种结果的排序 9 | - 数据包用时的排序 10 | - 自动匹配并替换数据包中的内容 11 | 12 | --------------------------------------------------------------------------------