├── BurpExtender.java ├── README.md └── xia_jie_demo.py /BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | 4 | import java.io.*; 5 | import java.net.URL; 6 | import java.net.URLConnection; 7 | import java.nio.charset.StandardCharsets; 8 | import java.security.MessageDigest; 9 | import java.awt.Component; 10 | import java.awt.event.ActionEvent; 11 | import java.awt.event.ActionListener; 12 | import java.awt.event.ItemEvent; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import javax.swing.*; 16 | import javax.swing.table.AbstractTableModel; 17 | import javax.swing.table.TableModel; 18 | import java.awt.*; 19 | import java.awt.event.ItemListener; 20 | import java.util.regex.Matcher; 21 | import java.util.regex.Pattern; 22 | import java.util.Base64; 23 | 24 | 25 | public class BurpExtender extends AbstractTableModel implements IBurpExtender, ITab, IHttpListener,IScannerCheck, IMessageEditorController,IContextMenuFactory 26 | { 27 | private IBurpExtenderCallbacks callbacks; 28 | private IExtensionHelpers helpers; 29 | private JSplitPane splitPane; 30 | private IMessageEditor requestViewer; 31 | private IMessageEditor responseViewer; 32 | private IMessageEditor requestViewer_proxy; 33 | private IMessageEditor responseViewer_proxy; 34 | private final List log = new ArrayList();//记录原始流量 35 | private IHttpRequestResponse currentlyDisplayedItem; 36 | private IHttpRequestResponse currentlyDisplayedItem_proxy; 37 | public PrintWriter stdout; 38 | JTabbedPane tabs;//数据包显示框 39 | JTabbedPane tabs_1;//数据包的proxy模块开关 40 | int switchs = 0; //开关 0关 1开 41 | int conut = 0; //记录条数 42 | int original_data_len;//记录原始数据包的长度 43 | int select_row = 0;//选中表格的行数 44 | Table logTable; //第一个表格框 45 | String white_URL = ""; 46 | int white_switchs = 0;//白名单开关 47 | int debug = 0;//调试模式 0关 1开 48 | 49 | JTextArea log_ta;//日志 50 | JTextField connect_ip; 51 | JTextArea proxy_decode_data_request; 52 | JTextArea proxy_decode_data_response; 53 | 54 | //复选框 55 | //proxy 56 | JCheckBox p_chkbox1; 57 | JCheckBox p_chkbox2; 58 | JCheckBox p_chkbox3; 59 | //Repeater 60 | JCheckBox r_chkbox1; 61 | JCheckBox r_chkbox2; 62 | //Intruder 63 | JCheckBox i_chkbox1; 64 | JCheckBox i_chkbox2; 65 | 66 | 67 | 68 | 69 | @Override 70 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) 71 | { 72 | //输出 73 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 74 | this.stdout.println("hello xia Jie!"); 75 | this.stdout.println("你好 欢迎使用 瞎解!"); 76 | this.stdout.println("version:1.0"); 77 | 78 | 79 | 80 | // keep a reference to our callbacks object 81 | this.callbacks = callbacks; 82 | 83 | // obtain an extension helpers object 84 | helpers = callbacks.getHelpers(); 85 | 86 | // set our extension name 87 | callbacks.setExtensionName("xia Jie V1.0"); 88 | 89 | // create our UI 90 | SwingUtilities.invokeLater(new Runnable() 91 | { 92 | @Override 93 | public void run() 94 | { 95 | 96 | // main split pane 97 | splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 98 | JSplitPane splitPanes = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 99 | JSplitPane splitPanes_2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 100 | 101 | //表格 102 | logTable = new Table(BurpExtender.this); 103 | logTable.getColumnModel().getColumn(3).setPreferredWidth(500); 104 | JScrollPane scrollPane = new JScrollPane(logTable); //给列表添加滚动条 105 | 106 | JPanel jp=new JPanel(); 107 | jp.setLayout(new GridLayout(1, 1)); 108 | jp.add(scrollPane); //将表格加到面板 109 | 110 | //侧边复选框 111 | JPanel jps=new JPanel(); 112 | jps.setLayout(new GridLayout(11, 1)); //六行一列 113 | JLabel jls=new JLabel("插件名:瞎解 author:算命縖子"); //创建一个标签 114 | JLabel jls_1=new JLabel("blog:www.nmd5.com"); //创建一个标签 115 | JLabel jls_2=new JLabel("版本:xia Jie V1.0"); //创建一个标签 116 | JLabel jls_3=new JLabel("感谢名单:Moonlit"); //创建一个标签 117 | 118 | JCheckBox chkbox1=new JCheckBox("启动插件"); //创建指定文本和状态的复选框 119 | connect_ip = new JTextField("127.0.0.1:23002");//白名单文本框 120 | JCheckBox chkbox2=new JCheckBox("启动调试模式(抓取最终的数据包)"); //创建指定文本和状态的复选框 121 | JLabel jls_5=new JLabel("如果需要多个域名加白请用,隔开"); //创建一个标签 122 | JTextField textField = new JTextField("填写白名单域名,强烈建议启动");//白名单文本框 123 | JButton btn1=new JButton("清空列表与日志"); //创建JButton对象 124 | JButton btn3=new JButton("启动白名单"); //处理白名单 125 | 126 | 127 | JPanel jps_2=new JPanel(); 128 | //proxy模块 129 | JLabel p_lb=new JLabel("proxy:"); //创建一个标签 130 | JLabel p_lb_1=new JLabel("加密会修改原始数据包,解密不会修改原始数据包"); //创建一个标签 131 | p_chkbox1=new JCheckBox("加密proxy请求包流量"); //创建指定文本和状态的复选框 132 | p_chkbox2=new JCheckBox("解密proxy请求包流量"); //创建指定文本和状态的复选框 133 | p_chkbox3=new JCheckBox("解密proxy响应包流量"); //创建指定文本和状态的复选框 134 | 135 | //Repeater模块 136 | JLabel r_lb=new JLabel("Repeater:"); //创建一个标签 137 | JLabel r_lb_2=new JLabel("解密请求包请到Repeater界面右键解密"); //创建一个标签 138 | r_chkbox1=new JCheckBox("加密Repeater请求包流量"); //创建指定文本和状态的复选框 139 | r_chkbox2=new JCheckBox("解密Repeater响应包流量"); //创建指定文本和状态的复选框 140 | 141 | //Intruder模块 142 | JLabel i_lb=new JLabel("Intruder:"); //创建一个标签 143 | i_chkbox1=new JCheckBox("加密Intruder请求包流量"); //创建指定文本和状态的复选框 144 | i_chkbox2=new JCheckBox("解密Intruder响应包流量"); //创建指定文本和状态的复选框、 145 | 146 | 147 | 148 | //指定面板的布局为GridLayout,1行1列,间隙为0 149 | jps_2.setLayout(new GridLayout(16,1,0,0)); 150 | jps_2.add(p_lb); 151 | jps_2.add(p_lb_1); 152 | jps_2.add(p_chkbox1); 153 | jps_2.add(p_chkbox2); 154 | jps_2.add(p_chkbox3); 155 | jps_2.add(r_lb); 156 | jps_2.add(r_lb_2); 157 | jps_2.add(r_chkbox1); 158 | jps_2.add(r_chkbox2); 159 | jps_2.add(i_lb); 160 | jps_2.add(i_chkbox1); 161 | jps_2.add(i_chkbox2); 162 | 163 | 164 | //添加复选框监听事件 开关 165 | chkbox1.addItemListener(new ItemListener() { 166 | @Override 167 | public void itemStateChanged(ItemEvent e) { 168 | if(chkbox1.isSelected()){ 169 | switchs = 1; 170 | connect_ip.setEditable(false); 171 | connect_ip.setForeground(Color.GRAY); 172 | }else { 173 | switchs = 0; 174 | connect_ip.setEditable(true); 175 | connect_ip.setForeground(Color.BLACK); 176 | } 177 | } 178 | }); 179 | //添加复选框监听事件 调试模式 180 | chkbox2.addItemListener(new ItemListener() { 181 | @Override 182 | public void itemStateChanged(ItemEvent e) { 183 | if(chkbox2.isSelected()){ 184 | debug = 1; 185 | }else { 186 | debug = 0; 187 | } 188 | 189 | } 190 | }); 191 | 192 | btn1.addActionListener(new ActionListener() {//清空列表 193 | @Override 194 | public void actionPerformed(ActionEvent e) { 195 | log.clear(); 196 | log_ta.setText("");//清除log的内容 197 | conut = 0; 198 | fireTableRowsInserted(log.size(), log.size());//刷新列表中的展示 199 | } 200 | }); 201 | btn3.addActionListener(new ActionListener() {//白名单 202 | @Override 203 | public void actionPerformed(ActionEvent e) { 204 | if(btn3.getText().equals("启动白名单")){ 205 | btn3.setText("关闭白名单"); 206 | white_URL = textField.getText(); 207 | white_switchs = 1; 208 | textField.setEditable(false); 209 | textField.setForeground(Color.GRAY);//设置组件的背景色 210 | }else { 211 | btn3.setText("启动白名单"); 212 | white_switchs = 0; 213 | textField.setEditable(true); 214 | textField.setForeground(Color.BLACK); 215 | } 216 | } 217 | }); 218 | 219 | 220 | jps.add(jls); 221 | jps.add(jls_1); 222 | jps.add(jls_2); 223 | jps.add(jls_3); 224 | jps.add(chkbox1); 225 | jps.add(connect_ip); 226 | jps.add(chkbox2); 227 | jps.add(btn1); 228 | jps.add(jls_5); 229 | jps.add(textField); 230 | jps.add(btn3); 231 | 232 | // tabs with request/response viewers 233 | tabs = new JTabbedPane(); 234 | requestViewer = callbacks.createMessageEditor(BurpExtender.this, false); 235 | responseViewer = callbacks.createMessageEditor(BurpExtender.this, false); 236 | requestViewer_proxy = callbacks.createMessageEditor(BurpExtender.this, false); 237 | responseViewer_proxy = callbacks.createMessageEditor(BurpExtender.this, false); 238 | 239 | //日志 240 | JPanel log_jp=new JPanel(); 241 | log_jp.setLayout(new GridLayout(1, 1)); //一行一列 242 | log_ta=new JTextArea(""); 243 | log_ta.setForeground(Color.BLACK); //设置组件的背景色 244 | log_ta.setFont(new Font("楷体",Font.BOLD,16)); //修改字体样式 245 | log_ta.setEditable(false);//不可编辑状态 246 | JScrollPane jsp=new JScrollPane(log_ta); //将文本域放入滚动窗口 247 | log_jp.add(jsp); //将JScrollPane添加到JPanel容器中 248 | 249 | //数据包 250 | JSplitPane d_jp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);//原始数据 251 | d_jp.setDividerLocation(500);//左右两边的距离 252 | d_jp.setLeftComponent(requestViewer.getComponent());//添加在左面 253 | d_jp.setRightComponent(responseViewer.getComponent());//添加在右面 254 | 255 | //proxy解密数据包 256 | JSplitPane j_jp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);//原始数据 257 | j_jp.setDividerLocation(500);//左右两边的距离 258 | proxy_decode_data_request = new JTextArea(""); 259 | proxy_decode_data_request.setEditable(false);//不可编辑状态 260 | proxy_decode_data_request.setLineWrap(true);//自动换行 261 | JScrollPane proxy_decode_data_request_sp=new JScrollPane(proxy_decode_data_request); //将文本域放入滚动窗口 262 | proxy_decode_data_response = new JTextArea(""); 263 | proxy_decode_data_response.setEditable(false);//不可编辑状态 264 | proxy_decode_data_response.setLineWrap(true);//自动换行 265 | JScrollPane proxy_decode_data_response_sp=new JScrollPane(proxy_decode_data_response); //将文本域放入滚动窗口 266 | j_jp.setLeftComponent(proxy_decode_data_request_sp);//添加在左面 267 | j_jp.setRightComponent(proxy_decode_data_response_sp);//添加在右面 268 | 269 | //如果是proxy的流量 270 | tabs_1 = new JTabbedPane(); 271 | tabs_1.addTab("最终数据包",d_jp); 272 | tabs_1.addTab("Proxy流量解密后的数据包",j_jp); 273 | 274 | tabs.addTab("日志",log_jp); 275 | tabs.addTab("数据包",tabs_1); 276 | 277 | 278 | //右边 279 | splitPanes_2.setLeftComponent(jps);//上面 280 | splitPanes_2.setRightComponent(jps_2);//下面 281 | 282 | //左边 283 | splitPanes.setLeftComponent(jp);//上面 284 | splitPanes.setRightComponent(tabs);//下面 285 | 286 | //整体分布 287 | splitPane.setLeftComponent(splitPanes);//添加在左面 288 | splitPane.setRightComponent(splitPanes_2);//添加在右面 289 | splitPane.setDividerLocation(1000);//设置分割的大小 290 | 291 | // customize our UI components 292 | callbacks.customizeUiComponent(splitPane); 293 | callbacks.customizeUiComponent(logTable); 294 | callbacks.customizeUiComponent(scrollPane); 295 | callbacks.customizeUiComponent(jps); 296 | callbacks.customizeUiComponent(jp); 297 | callbacks.customizeUiComponent(tabs); 298 | 299 | // add the custom tab to Burp's UI 300 | callbacks.addSuiteTab(BurpExtender.this); 301 | 302 | // register ourselves as an HTTP listener 303 | callbacks.registerHttpListener(BurpExtender.this); 304 | callbacks.registerScannerCheck(BurpExtender.this); 305 | callbacks.registerContextMenuFactory(BurpExtender.this); 306 | 307 | } 308 | }); 309 | } 310 | 311 | 312 | @Override 313 | public String getTabCaption() 314 | { 315 | return "xia Jie"; 316 | } 317 | 318 | @Override 319 | public Component getUiComponent() 320 | { 321 | return splitPane; 322 | } 323 | 324 | 325 | @Override 326 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) 327 | { 328 | 329 | if(switchs == 1){//插件开关 330 | if(toolFlag == 4 || toolFlag==32 || toolFlag ==64){//监听Proxy/Intruder/Repeater 331 | // only process responses 332 | if (!messageIsRequest) 333 | {//响应包 334 | if((i_chkbox2.isSelected() && toolFlag ==32) || (r_chkbox2.isSelected() && toolFlag ==64)){ 335 | //Intruder/Repeater 解密-单线程处理 336 | BurpExtender.this.response_Vul(messageInfo, toolFlag,false); 337 | } 338 | 339 | //proxy解密 340 | if((p_chkbox2.isSelected() && toolFlag==4)||(p_chkbox3.isSelected() && toolFlag==4)) { 341 | //Proxy流量多线程处理 342 | Thread thread = new Thread(new Runnable() { 343 | public void run() { 344 | try { 345 | BurpExtender.this.response_Vul(messageInfo,toolFlag,true); 346 | } catch (Exception ex) { 347 | ex.printStackTrace(); 348 | BurpExtender.this.stdout.println(ex); 349 | } 350 | } 351 | }); 352 | thread.start(); 353 | } 354 | 355 | //开启调试模式,proxy、request、intruder 加密 356 | if(debug == 1) { 357 | if ((p_chkbox1.isSelected() && !p_chkbox2.isSelected() && !p_chkbox3.isSelected() && toolFlag==4) || (r_chkbox1.isSelected() && !r_chkbox2.isSelected() && toolFlag==64) || (i_chkbox1.isSelected() && !i_chkbox2.isSelected() && toolFlag==32)) { 358 | if(white_switchs_boolean(messageInfo,toolFlag)) {//白名单处理 359 | conut += 1; 360 | int id = conut; 361 | log.add(new LogEntry(id, helpers.analyzeRequest(messageInfo).getMethod(), callbacks.saveBuffersToTempFiles(messageInfo), "", "", String.valueOf(helpers.analyzeRequest(messageInfo).getUrl()), messageInfo.getResponse().length - helpers.analyzeResponse(messageInfo.getResponse()).getBodyOffset(), toolFlag)); 362 | 363 | //刷新表格 364 | BurpExtender.this.fireTableDataChanged(); 365 | BurpExtender.this.logTable.setRowSelectionInterval(BurpExtender.this.select_row, BurpExtender.this.select_row); 366 | } 367 | } 368 | } 369 | 370 | 371 | }else {//请求包 372 | if((p_chkbox1.isSelected() && toolFlag ==4) || (i_chkbox1.isSelected() && toolFlag==32) || (r_chkbox1.isSelected() && toolFlag==64)){ 373 | BurpExtender.this.request_Vul(messageInfo,toolFlag); 374 | } 375 | 376 | } 377 | } 378 | 379 | } 380 | 381 | } 382 | 383 | @Override 384 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { 385 | return null; 386 | } 387 | 388 | 389 | @Override 390 | public List createMenuItems(final IContextMenuInvocation invocation) { 391 | //右键发送按钮功能 392 | 393 | List listMenuItems = new ArrayList(); 394 | if(invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER || invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_PROXY){ 395 | //父级菜单 396 | IHttpRequestResponse[] responses = invocation.getSelectedMessages(); 397 | JMenuItem jMenu_decode = new JMenuItem("Send to xia Jie decode"); 398 | JMenuItem jMenu_encode = new JMenuItem("Send to xia Jie encode"); 399 | 400 | jMenu_decode.addActionListener(new ActionListener() { 401 | @Override 402 | public void actionPerformed(ActionEvent e) { 403 | if(switchs == 1) { 404 | //不应在Swing事件调度线程中发出HTTP请求,所以需要创建一个Runnable并在 run() 方法中完成工作,后调用 new Thread(runnable).start() 来启动线程 405 | Thread thread = new Thread(new Runnable() { 406 | public void run() { 407 | try { 408 | data_return encode_data = BurpExtender.this.xj_decode(responses[0],true); 409 | 410 | byte[] body = encode_data.body.getBytes(); 411 | byte[] newRequest = helpers.buildHttpMessage(encode_data.header,body); 412 | responses[0].setRequest(newRequest);//设置最终新的请求包 413 | 414 | } catch (Exception ex) { 415 | ex.printStackTrace(); 416 | BurpExtender.this.stdout.println(ex); 417 | } 418 | } 419 | }); 420 | thread.start(); 421 | }else { 422 | BurpExtender.this.stdout.println("插件xia Jie关闭状态!"); 423 | } 424 | 425 | } 426 | }); 427 | 428 | jMenu_encode.addActionListener(new ActionListener() { 429 | @Override 430 | public void actionPerformed(ActionEvent e) { 431 | if(switchs == 1) { 432 | //不应在Swing事件调度线程中发出HTTP请求,所以需要创建一个Runnable并在 run() 方法中完成工作,后调用 new Thread(runnable).start() 来启动线程 433 | Thread thread = new Thread(new Runnable() { 434 | public void run() { 435 | try { 436 | data_return encode_data = BurpExtender.this.xj_encode(responses[0]); 437 | 438 | byte[] body = encode_data.body.getBytes(); 439 | byte[] newRequest = helpers.buildHttpMessage(encode_data.header,body); 440 | responses[0].setRequest(newRequest);//设置最终新的请求包 441 | 442 | } catch (Exception ex) { 443 | ex.printStackTrace(); 444 | BurpExtender.this.stdout.println(ex); 445 | } 446 | } 447 | }); 448 | thread.start(); 449 | }else { 450 | BurpExtender.this.stdout.println("插件xia Jie关闭状态!"); 451 | } 452 | 453 | } 454 | }); 455 | listMenuItems.add(jMenu_encode); 456 | listMenuItems.add(jMenu_decode); 457 | } 458 | 459 | return listMenuItems; 460 | } 461 | 462 | private void request_Vul(IHttpRequestResponse baseRequestResponse, int toolFlag){ 463 | //log_ta.insert("请求包\n",0); 464 | String temp_data = String.valueOf(helpers.analyzeRequest(baseRequestResponse).getUrl());//url 465 | String[] temp_data_strarray=temp_data.split("\\?"); 466 | temp_data =temp_data_strarray[0];//获取问号前面的字符串 467 | 468 | //检测白名单 469 | String[] white_URL_list = white_URL.split(","); 470 | int white_swith = 0; 471 | if(white_switchs == 1){ 472 | white_swith = 0; 473 | for(int i=0;i doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { 632 | return null; 633 | } 634 | 635 | @Override 636 | public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) { 637 | if (existingIssue.getIssueName().equals(newIssue.getIssueName())) 638 | return -1; 639 | else return 0; 640 | } 641 | 642 | @Override 643 | public int getRowCount() 644 | { 645 | return log.size(); 646 | } 647 | 648 | @Override 649 | public int getColumnCount() 650 | { 651 | return 5; 652 | } 653 | 654 | @Override 655 | public String getColumnName(int columnIndex) 656 | { 657 | switch (columnIndex) 658 | { 659 | case 0: 660 | return "#"; 661 | case 1: 662 | return "来源"; 663 | case 2: 664 | return "类型"; 665 | case 3: 666 | return "URL"; 667 | case 4: 668 | return "响应包长度"; 669 | default: 670 | return ""; 671 | } 672 | } 673 | 674 | @Override 675 | public Class getColumnClass(int columnIndex) 676 | { 677 | return String.class; 678 | } 679 | 680 | @Override 681 | public Object getValueAt(int rowIndex, int columnIndex) 682 | { 683 | LogEntry logEntry = log.get(rowIndex); 684 | 685 | switch (columnIndex) 686 | { 687 | case 0: 688 | return logEntry.id; 689 | case 1: 690 | return callbacks.getToolName(logEntry.tool); 691 | case 2: 692 | return logEntry.Method; 693 | case 3: 694 | return logEntry.url; 695 | case 4: 696 | return logEntry.original_len;//返回响应包的长度 697 | default: 698 | return ""; 699 | } 700 | } 701 | 702 | 703 | 704 | @Override 705 | public byte[] getRequest() 706 | { 707 | return currentlyDisplayedItem.getRequest(); 708 | } 709 | 710 | @Override 711 | public byte[] getResponse() 712 | { 713 | return currentlyDisplayedItem.getResponse(); 714 | } 715 | 716 | @Override 717 | public IHttpService getHttpService() 718 | { 719 | return currentlyDisplayedItem.getHttpService(); 720 | } 721 | 722 | //表格选中设置 723 | private class Table extends JTable 724 | { 725 | public Table(TableModel tableModel) 726 | { 727 | super(tableModel); 728 | } 729 | 730 | @Override 731 | public void changeSelection(int row, int col, boolean toggle, boolean extend) 732 | { 733 | // show the log entry for the selected row 734 | LogEntry logEntry = log.get(row); 735 | select_row = row;//记录选中的行数 736 | 737 | //设置点击表格,打开对应数据包的界面 738 | tabs.setSelectedIndex(1); 739 | if(logEntry.tool == 4) { 740 | tabs_1.setEnabledAt(1, true); 741 | }else { 742 | tabs_1.setSelectedIndex(0); 743 | tabs_1.setEnabledAt(1, false);//标签不可用 744 | } 745 | 746 | 747 | requestViewer.setMessage(logEntry.requestResponse.getRequest(), true); 748 | responseViewer.setMessage(logEntry.requestResponse.getResponse(), false); 749 | proxy_decode_data_request.setText(logEntry.request_data); 750 | proxy_decode_data_response.setText(logEntry.response_data); 751 | currentlyDisplayedItem = logEntry.requestResponse; 752 | 753 | super.changeSelection(row, col, toggle, extend); 754 | } 755 | } 756 | 757 | 758 | private static class LogEntry 759 | { 760 | final int id; 761 | final String Method; 762 | final IHttpRequestResponsePersisted requestResponse; 763 | final String request_data; 764 | final String response_data; 765 | final String url; 766 | final int original_len; 767 | final int tool; 768 | 769 | 770 | LogEntry(int id,String Method, IHttpRequestResponsePersisted requestResponse,String request_data,String response_data, String url,int original_len,int tool) 771 | { 772 | this.id = id; 773 | this.Method = Method; 774 | this.requestResponse = requestResponse; 775 | this.request_data = request_data; 776 | this.response_data = response_data; 777 | this.url = url; 778 | this.original_len = original_len; 779 | this.tool = tool; 780 | } 781 | 782 | } 783 | 784 | //数据处理,用来返回多个值 785 | final class data_return 786 | { 787 | public List header; 788 | public String body; 789 | 790 | public data_return(List header, String body) 791 | { 792 | this.header = header; 793 | this.body = body; 794 | } 795 | } 796 | 797 | public data_return xj_encode(IHttpRequestResponse baseRequestResponse){ 798 | // 使用 `Base64` 编码器对字符串进行编码 799 | Base64.Encoder encoder = Base64.getEncoder(); 800 | // 解码编码数据 801 | Base64.Decoder decoder = Base64.getDecoder(); 802 | 803 | //加密 804 | List headers = helpers.analyzeRequest(baseRequestResponse).getHeaders(); 805 | String headers_data ="";//head头部信息 806 | for(int i=0;i New_headers= new ArrayList<>(); 822 | String header_pattern="header=(.*?)[^&]*";//正则匹配字母,数字,特殊字符 823 | Pattern header_Pattern = Pattern.compile(header_pattern);// 创建 Pattern 对象 824 | Matcher header_matcher = header_Pattern.matcher(post_data);// 现在创建 matcher 对象 825 | if (header_matcher.find()) { 826 | //String[] headers_response_data = helpers.bytesToString(helpers.base64Decode(header_matcher.group().substring(7))).split("\n"); 827 | String[] headers_response_data = new String(decoder.decode(header_matcher.group().substring(7))).split("\n"); 828 | for(String head : headers_response_data){ 829 | New_headers.add(head); 830 | } 831 | } 832 | //body 833 | String body_response_data=""; 834 | String body_pattern="body=(.*?)[^&]*";//正则匹配字母,数字,特殊字符 835 | Pattern body_Pattern = Pattern.compile(body_pattern);// 创建 Pattern 对象 836 | Matcher body_matcher = body_Pattern.matcher(post_data);// 现在创建 matcher 对象 837 | if (body_matcher.find()) { 838 | //body_response_data = helpers.bytesToString(helpers.base64Decode(body_matcher.group().substring(5))); 839 | body_response_data = new String(decoder.decode(body_matcher.group().substring(5))); 840 | } 841 | 842 | return new data_return(New_headers,body_response_data); 843 | } 844 | 845 | public data_return xj_decode(IHttpRequestResponse baseRequestResponse,boolean messageIsRequest){ 846 | // 使用 `Base64` 编码器对字符串进行编码 847 | Base64.Encoder encoder = Base64.getEncoder(); 848 | // 解码编码数据 849 | Base64.Decoder decoder = Base64.getDecoder(); 850 | 851 | List New_headers= new ArrayList<>();//header 852 | String body_response_data="";//body 853 | 854 | if(messageIsRequest){//请求包 855 | List headers = helpers.analyzeRequest(baseRequestResponse).getHeaders(); 856 | String headers_data ="";//head头部信息 857 | for(int i=0;i headers = analyzedResponse.getHeaders(); 896 | String headers_data ="";//head头部信息 897 | for(int i=0;i 19 | 20 | ## 0x02 使用教程 21 | 22 | 1、启动插件 23 | 2、自定义修改好python脚本后运行,如下:我在头部添加了(abcd:1234)和 body体添加了 (&abcd=654321) 24 | 25 | image 26 | 27 | 点击发送 28 | 29 | image 30 | 31 | 32 | image 33 | 34 | 很多网站不是全部加密的,所以有些数据包需要解密or加密,需要多写几个if判断,哪些需要解密or解密 哪些不用 35 | 36 | 比如: 37 | 38 | image 39 | 40 | image 41 | 42 | image 43 | 44 | 当然也支持右键加解密 45 | 46 | image 47 | 48 | 点击后会 加密 49 | 50 | image 51 | 52 | 正常使用的话,先拿一段 待加密or解密 的数据测试 53 | 54 | image 55 | 56 | 测试通过在注释掉,在运行run方法 57 | 58 | 59 | -------------------------------------------------------------------------------- /xia_jie_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | from http.server import HTTPServer, BaseHTTPRequestHandler 4 | import base64 5 | import re 6 | 7 | #************⬇不要动这里⬇**************** 8 | class Resquest(BaseHTTPRequestHandler): 9 | def do_GET(self): 10 | self.send_response(200) 11 | self.send_header('Content-type', 'text/html; charset=UTF-8') 12 | self.end_headers() 13 | self.wfile.write("xia_jie".encode()) 14 | 15 | def do_POST(self): 16 | req_datas = self.rfile.read(int(self.headers['content-length'])) 17 | post_data = req_datas.decode() 18 | try: 19 | header = base64.b64decode(re.search('header=(.*?)[^&]*', post_data).group()[7:]).decode().split("\n") 20 | header.pop()#删除列表中最后一个元素 21 | body = base64.b64decode(re.search('body=(.*?)[^&]*', post_data).group()[5:]).decode() 22 | 23 | def data_handle(data): 24 | #对内容进行base64编码 25 | head_data = "" 26 | for i in data[0]: 27 | head_data+=i+"\n" 28 | ba64_header = base64.b64encode(head_data.encode()).decode() 29 | ba64_body = base64.b64encode(data[1].encode()).decode() 30 | return "header="+ba64_header+"&body="+ba64_body 31 | 32 | if self.path == "/xj_encode": 33 | data = data_handle(xia_jie.xj_encode(self,header,body)) 34 | elif self.path == "/xj_decode": 35 | data = data_handle(xia_jie.xj_decode(self,header,body)) 36 | else: 37 | data = "xia_jie error:api error" 38 | except Exception as e: 39 | print(e) 40 | data = "xia_jie:"+str(e) 41 | self.send_response(200) 42 | self.send_header('Content-type', 'text/html;') 43 | self.end_headers() 44 | self.wfile.write(data.encode()) 45 | #************⬆不要动这里⬆**************** 46 | 47 | 48 | class xia_jie: 49 | def __init__(self): 50 | pass 51 | 52 | #加密 53 | def xj_encode(self, header, body): 54 | return header, body 55 | #解密 56 | def xj_decode(self,header,body): 57 | return header, body 58 | 59 | 60 | def run(): 61 | host = ('0.0.0.0', 23002) 62 | server = HTTPServer(host, Resquest) 63 | print("run:http://"+host[0]+":"+str(host[1])) 64 | server.serve_forever() 65 | 66 | #启动 67 | run() 68 | 69 | #调试 70 | #header = ["POST / HTTP/1.1","host: 127.0.0.1"] 71 | #body = "1111" 72 | #print(xia_jie.xj_encode(0,header,body)) 73 | --------------------------------------------------------------------------------