└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # burpDevNote 2 | burp插件开发笔记,简单记一下方便查阅。刚入门最好的建议就是模仿,多看别人写的,尝试着修改,尝试着自己写一个。 3 | 4 | 5 | 6 | 7 | 8 | ## 基础知识 9 | 10 | burp suite支持三种编程语言开发的插件: 11 | 12 | - Java 13 | - python 14 | - ruby 15 | 16 | 我选java 17 | 18 | 官方各种示例代码:https://portswigger.net/burp/extender 19 | 20 | 官方API文档:https://portswigger.net/burp/extender/api/ 21 | 22 | 23 | 24 | maven依赖 25 | 26 | ```xml 27 | 28 | net.portswigger.burp.extender 29 | burp-extender-api 30 | 1.7.22 31 | 32 | ``` 33 | 34 | 35 | 36 | - 所有的burp插件都必须实现IBurpExtender这个接口 37 | - 实现类的包名称必须是burp 38 | - 实现类的名称必须是BurpExtender,burp插件入口 39 | - 实现类比较是public的 40 | - 实现类必须有默认构造函数(public,无参),如果没有定义构造函数就是默认构造函数 41 | 42 | 43 | 44 | ### callbacks对象的作用 45 | 46 | 通过 callbacks 这个实例对象,传递给插件一系列burp的原生方法。我们需要实现的很多功能都需要调用这些方法。当前拓展用来和burp进行交互,如各种注册,设置拓展名字,获取helper,添加菜单等等。 47 | 48 | 49 | 50 | ### 需要主动注册的对象 51 | 52 | 53 | 54 | 也就是需要写在registerExtenderCallbacks方法里面的 55 | 56 | 他们的共通特定是:会被burp主程序主动调用或者主动通知,burp主程序必须知道它们的存在,才能完成对应的功能。 57 | 58 | #### 各种事件监听器 59 | 60 | ExtensionStateListener 61 | 62 | HttpListener 63 | 64 | ProxyListener 65 | 66 | ScannerListener 67 | 68 | ScopeChangeListener 69 | 70 | #### 各种对象构造工厂 71 | 72 | ContextMenuFactory 73 | 74 | MessageEditorTabFactory 75 | 76 | IntruderPayloadGeneratorFactory 77 | 78 | #### 其他 79 | 80 | ScannerInsertionPointProvider 81 | 82 | ScannerCheck 83 | 84 | IntruderPayloadProcessor 85 | 86 | SessionHandlingAction 87 | 88 | MenuItem 89 | 90 | 91 | 92 | ## 关键对象 93 | 94 | 95 | 96 | ### IExtensionHelpers 97 | 98 | 用途:主要用来处理数据包 99 | 100 | 初始化,一般写在registerExtenderCallbacks方法里面 101 | 102 | ```java 103 | IExtensionHelpers helpers = callbacks.getHelpers(); 104 | ``` 105 | 106 | Request和Response获取 107 | 108 | ``` 109 | IRequestInfo analyzeRequest = helpers.analyzeRequest(requestOrResponse); 110 | IResponseInfo analyzeResponse = helpers.analyzeResponse(requestOrResponse); 111 | ``` 112 | 113 | 获取header 114 | 115 | ``` 116 | IRequestInfo analyzeRequest = helpers.analyzeRequest(requestOrResponse); 117 | List headers = analyzeRequest.getHeaders(); 118 | ``` 119 | 120 | 获取body 121 | 122 | ```java 123 | int bodyOffset = -1; 124 | if(isRequest) { 125 | IRequestInfo analyzeRequest = helpers.analyzeRequest(requestOrResponse); 126 | bodyOffset = analyzeRequest.getBodyOffset(); 127 | }else { 128 | IResponseInfo analyzeResponse = helpers.analyzeResponse(requestOrResponse); 129 | bodyOffset = analyzeResponse.getBodyOffset(); 130 | } 131 | byte[] byte_body = Arrays.copyOfRange(requestOrResponse, bodyOffset, requestOrResponse.length); 132 | //not length-1 133 | //String body = new String(byte_body); //byte[] to String 134 | return byte_body; 135 | ``` 136 | 137 | 138 | 139 | 修改http包 140 | 141 | ``` 142 | byte[] RequestOrResponse = helpers.buildHttpMessage(headers, body); 143 | ``` 144 | 145 | 146 | 147 | 具体看大佬封装的工具类https://github.com/bit4woo/burp-api-common/blob/master/src/main/java/burp/HelperPlus.java 148 | 149 | 150 | 151 | 152 | 153 | ### IHttpListener 154 | 155 | 用途:任何组件产生的请求和响应都会触发http监听器,有点被动扫描的味道。 156 | 157 | 必须实现processHttpMessage方法 158 | 159 | ```java 160 | processHttpMessage(int toolFlag,boolean messageIsRequest,IHttpRequestResponse messageInfo) 161 | ``` 162 | 163 | toolFlag 164 | 165 | 不同的toolFlag代表了不同的burp组件,一共如下 166 | 167 | https://portswigger.net/burp/extender/api/constant-values.html#burp.IBurpExtenderCallbacks 168 | 169 | ![image-20211220212403938](https://gitee.com/safe6/img/raw/master/image-20211220212403938.png) 170 | 171 | messageIsRequest,判断当前是不是request 172 | 173 | IHttpRequestResponse,具体的消息体对象。可用`helpers#analyzeRequest`对消息体进行解析,messageInfo是整个HTTP请求和响应消息体的总和,各种HTTP相关信息的获取都来自于它,HTTP流量的修改都是围绕它进行的。 174 | 175 | 176 | 177 | 178 | 179 | ```java 180 | package burp; 181 | 182 | import java.io.PrintWriter; 183 | import java.util.Arrays; 184 | import java.util.List; 185 | 186 | public class BurpExtender implements IBurpExtender, IHttpListener 187 | {//所有burp插件都必须实现IBurpExtender接口,而且实现的类必须叫做BurpExtender 188 | private IBurpExtenderCallbacks callbacks; 189 | private IExtensionHelpers helpers; 190 | 191 | private PrintWriter stdout; 192 | private PrintWriter stderr; 193 | private String ExtenderName = "burp extender api drops by bit4woo"; 194 | 195 | @Override 196 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) 197 | {//IBurpExtender必须实现的方法 198 | stdout = new PrintWriter(callbacks.getStdout(), true); 199 | stderr = new PrintWriter(callbacks.getStderr(), true); 200 | callbacks.printOutput(ExtenderName); 201 | //stdout.println(ExtenderName); 202 | this.callbacks = callbacks; 203 | helpers = callbacks.getHelpers(); 204 | callbacks.setExtensionName(ExtenderName); 205 | callbacks.registerHttpListener(this); //如果没有注册,下面的processHttpMessage方法是不会生效的。处理请求和响应包的插件,这个应该是必要的 206 | } 207 | 208 | @Override 209 | public void processHttpMessage(int toolFlag,boolean messageIsRequest,IHttpRequestResponse messageInfo) 210 | { 211 | if (toolFlag == IBurpExtenderCallbacks.TOOL_PROXY){ 212 | //不同的toolFlag代表了不同的burp组件 https://portswigger.net/burp/extender/api/constant-values.html#burp.IBurpExtenderCallbacks 213 | if (messageIsRequest){ //对请求包进行处理 214 | IRequestInfo analyzeRequest = helpers.analyzeRequest(messageInfo); 215 | //对消息体进行解析,messageInfo是整个HTTP请求和响应消息体的总和,各种HTTP相关信息的获取都来自于它,HTTP流量的修改都是围绕它进行的。 216 | 217 | /*****************获取参数**********************/ 218 | List paraList = analyzeRequest.getParameters(); 219 | //获取参数的方法 220 | //当body是json格式的时候,这个方法也可以正常获取到键值对;但是PARAM_JSON等格式不能通过updateParameter方法来更新。 221 | //如果在url中的参数的值是 key=json格式的字符串 这种形式的时候,getParameters应该是无法获取到最底层的键值对的。 222 | 223 | for (IParameter para : paraList){// 循环获取参数,判断类型,进行加密处理后,再构造新的参数,合并到新的请求包中。 224 | String key = para.getName(); //获取参数的名称 225 | String value = para.getValue(); //获取参数的值 226 | int type = para.getType(); 227 | stdout.println("参数 key value type: "+key+" "+value+" "+type); 228 | } 229 | 230 | /*****************修改并更新参数**********************/ 231 | IParameter newPara = helpers.buildParameter("testKey", "testValue", IParameter.PARAM_BODY); //构造新的参数 232 | byte[] new_Request = messageInfo.getRequest(); 233 | new_Request = helpers.updateParameter(new_Request, newPara); //构造新的请求包 234 | messageInfo.setRequest(new_Request);//设置最终新的请求包 235 | 236 | /*****************删除参数**********************/ 237 | for (IParameter para : paraList){// 循环获取参数,判断类型,进行加密处理后,再构造新的参数,合并到新的请求包中。 238 | String key = para.getName(); //获取参数的名称 239 | if (key.equals("aaa")) { 240 | new_Request = helpers.removeParameter(new_Request, para); //构造新的请求包 241 | } 242 | } 243 | 244 | 245 | /*****************获取header**********************/ 246 | List headers = analyzeRequest.getHeaders(); 247 | 248 | for (String header : headers){// 循环获取参数,判断类型,进行加密处理后,再构造新的参数,合并到新的请求包中。 249 | stdout.println("header "+header); 250 | if (header.startsWith("referer")) { 251 | /*****************删除header**********************/ 252 | headers.remove(header); 253 | } 254 | } 255 | 256 | /*****************新增header**********************/ 257 | headers.add("myheader: balalbala"); 258 | 259 | 260 | /*****************获取body 方法一**********************/ 261 | int bodyOffset = analyzeRequest.getBodyOffset(); 262 | byte[] byte_Request = messageInfo.getRequest(); 263 | 264 | String request = new String(byte_Request); //byte[] to String 265 | String body = request.substring(bodyOffset); 266 | byte[] byte_body = body.getBytes(); //String to byte[] 267 | 268 | /*****************获取body 方法二**********************/ 269 | 270 | int len = byte_Request.length; 271 | byte[] byte_body1 = Arrays.copyOfRange(byte_Request, bodyOffset, len); 272 | 273 | new_Request = helpers.buildHttpMessage(headers, byte_body); 274 | //如果修改了header或者数修改了body,不能通过updateParameter,使用这个方法。 275 | messageInfo.setRequest(new_Request);//设置最终新的请求包 276 | } 277 | } 278 | else{//处理响应包 279 | IResponseInfo analyzedResponse = helpers.analyzeResponse(messageInfo.getResponse()); //getResponse获得的是字节序列 280 | short statusCode = analyzedResponse.getStatusCode(); 281 | List headers = analyzedResponse.getHeaders(); 282 | String resp = new String(messageInfo.getResponse()); 283 | int bodyOffset = analyzedResponse.getBodyOffset();//响应包是没有参数的概念的,大多需要修改的内容都在body中 284 | String body = resp.substring(bodyOffset); 285 | 286 | if (statusCode==200){ 287 | String newBody= body+"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"; 288 | byte[] bodybyte = newBody.getBytes(); 289 | messageInfo.setResponse(helpers.buildHttpMessage(headers, bodybyte)); 290 | } 291 | } 292 | } 293 | } 294 | ``` 295 | 296 | 297 | 298 | ### IContextMenuFactory 299 | 300 | ![image-20211220215113980](https://gitee.com/safe6/img/raw/master/image-20211220215113980.png) 301 | 302 | 用途:注册右键菜单,必须实现createMenuItems方法。 303 | 304 | 如下创建菜单,添加点击事件 305 | 306 | ```java 307 | @Override 308 | public List createMenuItems(IContextMenuInvocation invocation) { 309 | 310 | ArrayList menu_item_list = new ArrayList(); 311 | 312 | //常用 313 | JMenuItem printEmails = new JMenuItem("Print Emails"); 314 | printEmails.addActionListener(new printEmails(invocation)); 315 | menu_item_list.add(printEmails); 316 | 317 | JMenuItem printCookie = new JMenuItem("find last cookie of Url"); 318 | printCookie.addActionListener(new printCookies(invocation)); 319 | menu_item_list.add(printCookie); 320 | 321 | JMenuItem scan = new JMenuItem("scan this url"); 322 | scan.addActionListener(new printCookies(invocation)); 323 | menu_item_list.add(scan); 324 | 325 | return menu_item_list; 326 | 327 | } 328 | ``` 329 | 330 | 331 | 332 | - 鼠标右键的创建 333 | - 从Scanner issues中收集邮箱地址 334 | - 从Proxy history中查找最新cookie 335 | - 发起扫描任务、发起爬行任务 336 | - 查询和更新scope 337 | 338 | ```java 339 | package burp; 340 | 341 | import java.awt.MenuItem; 342 | import java.awt.event.ActionEvent; 343 | import java.awt.event.ActionListener; 344 | import java.io.PrintWriter; 345 | import java.lang.reflect.Array; 346 | import java.net.URL; 347 | import java.net.URLDecoder; 348 | import java.util.ArrayList; 349 | import java.util.Arrays; 350 | import java.util.List; 351 | import java.util.regex.Matcher; 352 | import java.util.regex.Pattern; 353 | 354 | import javax.swing.JMenuItem; 355 | 356 | 357 | public class BurpExtender implements IBurpExtender, IContextMenuFactory 358 | {//所有burp插件都必须实现IBurpExtender接口,而且实现的类必须叫做BurpExtender 359 | private IBurpExtenderCallbacks callbacks; 360 | private IExtensionHelpers helpers; 361 | 362 | private PrintWriter stdout; 363 | private PrintWriter stderr; 364 | private String ExtenderName = "burp extender api drops by bit4woo"; 365 | 366 | @Override 367 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) 368 | {//IBurpExtender必须实现的方法 369 | stdout = new PrintWriter(callbacks.getStdout(), true); 370 | stderr = new PrintWriter(callbacks.getStderr(), true); 371 | callbacks.printOutput(ExtenderName); 372 | //stdout.println(ExtenderName); 373 | this.callbacks = callbacks; 374 | helpers = callbacks.getHelpers(); 375 | callbacks.setExtensionName(ExtenderName); 376 | callbacks.registerContextMenuFactory(this); 377 | } 378 | 379 | @Override 380 | public List createMenuItems(IContextMenuInvocation invocation) { 381 | 382 | ArrayList menu_item_list = new ArrayList(); 383 | 384 | //常用 385 | JMenuItem printEmails = new JMenuItem("Print Emails"); 386 | printEmails.addActionListener(new printEmails(invocation)); 387 | menu_item_list.add(printEmails); 388 | 389 | JMenuItem printCookie = new JMenuItem("find last cookie of Url"); 390 | printCookie.addActionListener(new printCookies(invocation)); 391 | menu_item_list.add(printCookie); 392 | 393 | JMenuItem scan = new JMenuItem("scan this url"); 394 | scan.addActionListener(new printCookies(invocation)); 395 | menu_item_list.add(scan); 396 | 397 | return menu_item_list; 398 | 399 | } 400 | 401 | public class printEmails implements ActionListener{ 402 | private IContextMenuInvocation invocation; 403 | 404 | public printEmails(IContextMenuInvocation invocation) { 405 | this.invocation = invocation; 406 | } 407 | 408 | @Override 409 | public void actionPerformed(ActionEvent event) { 410 | IScanIssue[] issues = callbacks.getScanIssues(null); 411 | 412 | final String REGEX_EMAIL = "[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+"; 413 | Pattern pDomainNameOnly = Pattern.compile(REGEX_EMAIL); 414 | 415 | for (IScanIssue issue:issues) { 416 | if (issue.getIssueName().equalsIgnoreCase("Email addresses disclosed")) { 417 | String detail = issue.getIssueDetail(); 418 | Matcher matcher = pDomainNameOnly.matcher(detail); 419 | while (matcher.find()) {//多次查找 420 | String email = matcher.group(); 421 | System.out.println(matcher.group()); 422 | } 423 | } 424 | } 425 | } 426 | } 427 | 428 | public class printCookies implements ActionListener{ 429 | private IContextMenuInvocation invocation; 430 | 431 | public printCookies(IContextMenuInvocation invocation) { 432 | this.invocation = invocation; 433 | } 434 | 435 | @Override 436 | public void actionPerformed(ActionEvent event) { 437 | try { 438 | IHttpRequestResponse[] messages = invocation.getSelectedMessages(); 439 | byte[] req = messages[0].getRequest(); 440 | String currentShortUrl = messages[0].getHttpService().toString(); 441 | stdout.println(currentShortUrl); 442 | 443 | /*******************从Proxy history中查找最新cookie***************************/ 444 | IHttpRequestResponse[] historyMessages = callbacks.getProxyHistory(); 445 | int len = historyMessages.length; 446 | for (int index=len; index >=0; index--) { 447 | IHttpRequestResponse item = historyMessages[index]; 448 | 449 | String hisShortUrl = item.getHttpService().toString(); 450 | if (currentShortUrl.equals(hisShortUrl)) { 451 | IRequestInfo hisanalyzedRequest = helpers.analyzeRequest(item); 452 | List headers = hisanalyzedRequest.getHeaders(); 453 | 454 | for (String header:headers) { 455 | if (header.startsWith("Cookie:")) { 456 | stdout.println("找到cookie---"+header); 457 | } 458 | } 459 | } 460 | } 461 | } catch (Exception e) { 462 | callbacks.printError(e.getMessage()); 463 | } 464 | } 465 | } 466 | 467 | public class scan implements ActionListener{ 468 | private IContextMenuInvocation invocation; 469 | 470 | public scan(IContextMenuInvocation invocation) { 471 | this.invocation = invocation; 472 | } 473 | 474 | @Override 475 | public void actionPerformed(ActionEvent event) { 476 | try { 477 | IHttpRequestResponse[] messages = invocation.getSelectedMessages(); 478 | for (IHttpRequestResponse message:messages) { 479 | byte[] req = message.getRequest(); 480 | IRequestInfo analyzedRequest = helpers.analyzeRequest(req); 481 | URL url = analyzedRequest.getUrl(); 482 | IHttpService service = message.getHttpService(); 483 | boolean useHttps = service.getProtocol().equalsIgnoreCase("https"); 484 | /******************发起扫描任务************************/ 485 | callbacks.doActiveScan(service.getHost(), service.getPort(), useHttps, req); 486 | stdout.println(url.toString()+"被加入了扫描队列"); 487 | /******************发起爬行任务************************/ 488 | callbacks.sendToSpider(url); 489 | 490 | /******************查询URL是否在scope中************************/ 491 | if (callbacks.isInScope(url)) { 492 | /******************从scope中移除************************/ 493 | callbacks.excludeFromScope(url); 494 | } 495 | URL shortUrl = new URL(service.toString()); 496 | /******************加入scope中************************/ 497 | callbacks.includeInScope(shortUrl); 498 | } 499 | } catch (Exception e) { 500 | callbacks.printError(e.getMessage()); 501 | } 502 | } 503 | } 504 | } 505 | ``` 506 | 507 | ### IMessageEditorTab 508 | 509 | 用途:有点像repeater模块,主要就是用来展示和编辑request和response。 510 | 511 | 512 | 513 | 514 | 515 | ```java 516 | //添加一个editor,用于显示HTTP数据包 517 | IMessageEditor editor = BurpExtender.getCallbacks().createMessageEditor(this, false); 518 | contentPane.add(editor.getComponent(), BorderLayout.CENTER); 519 | 520 | JButton btnNewButton = new JButton("displayRequest"); 521 | btnNewButton.addActionListener(new ActionListener() { 522 | public void actionPerformed(ActionEvent e) { 523 | editor.setMessage(getRequest(), true);//调用IMessageEditorController的函数来显示请求包 524 | } 525 | }); 526 | ``` 527 | 528 | 529 | 530 | ```java 531 | public Tags(final IBurpExtenderCallbacks callbacks, String name) { 532 | this.callbacks = callbacks; 533 | this.tagName = name; 534 | 535 | SwingUtilities.invokeLater(new Runnable() { 536 | 537 | 538 | @Override 539 | public void run() { 540 | 541 | 542 | jPanel = new JPanel(); 543 | 544 | splitPanel = new JSplitPane(0); 545 | splitPanel.setDividerLocation(0.5D); 546 | jTabbedPane = new JTabbedPane(); 547 | jTabbedPane1 = new JTabbedPane(); 548 | request = callbacks.createMessageEditor(Tags.this, false); 549 | response = callbacks.createMessageEditor(Tags.this,false); 550 | jTabbedPane.addTab("Request",request.getComponent()); 551 | jTabbedPane.addTab("Response",response.getComponent()); 552 | splitPanel.add(jTabbedPane); 553 | splitPanel.setTopComponent(jTabbedPane1); 554 | splitPanel.setBottomComponent(jTabbedPane); 555 | jPanel.add(splitPanel); 556 | 557 | // // 设置自定义组件并添加标签 558 | callbacks.customizeUiComponent(jPanel);//根据Burp的UI样式自定义UI组件,包括字体大小、颜色、表格行距等。 559 | callbacks.addSuiteTab(Tags.this); 560 | 561 | } 562 | }); 563 | } 564 | ``` 565 | 566 | 567 | 568 | ### IBurpCollaboratorClientContext 569 | 570 | 如何与burp自生DNSlog进行交互 571 | 572 | ```java 573 | IBurpCollaboratorClientContext ccc = callbacks.createBurpCollaboratorClientContext(); 574 | 575 | //返回结果类似:053bsqoev8gezev8oq59zylgv71xpm, 053bsqoev8gezev8oq59zylgv71xpm.burpcollaborator.net 576 | public static String[] getFullDnsDomain(){ 577 | String subdomain = ccc.generatePayload(false); 578 | String interactionID = subdomain; 579 | String server = ccc.getCollaboratorServerLocation(); 580 | String fullPayload = subdomain+"."+server; 581 | String[] result = {interactionID,fullPayload}; 582 | return result; 583 | } 584 | ``` 585 | 586 | 587 | 588 | 589 | 590 | ## 插件解析 591 | 592 | 解析P喵呜大佬写的,shiro被动扫描插件。 593 | 594 | 前提:了解shiro反序列化漏洞原理,了解burp插件开发。 595 | 596 | 597 | 598 | https://github.com/pmiaowu/BurpShiroPassiveScan.git 599 | 600 | 601 | 602 | 找到入口类开始看,发现继承了IScannerCheck。 603 | 604 | IScannerCheck和IHttpListener有点相似,简单说下我理解的区别,如有不对欢迎指出。 605 | 606 | IHttpListener有点像proxy抓包拦截,能在收到某某request或者response就马上进行处理。而IScannerCheck则是发现你请求了某某url之后,单独对这个url进行漏洞扫描。 607 | 608 | ![image-20211226144135012](https://gitee.com/safe6/img/raw/master/image-20211226144135012.png) 609 | 610 | 611 | 612 | 先看关键注册方法,主要是一些初始化操作 613 | 614 | ![image-20211226144243446](https://gitee.com/safe6/img/raw/master/image-20211226144243446.png) 615 | 616 | 617 | 618 | 初始化关键对象 619 | 620 | ![image-20211226144619862](https://gitee.com/safe6/img/raw/master/image-20211226144619862.png) 621 | 622 | 初始化两个用于存放扫描url和domain的对象 623 | 624 | ![image-20211226144729787](https://gitee.com/safe6/img/raw/master/image-20211226144729787.png) 625 | 626 | 这两个对象主要是用了单例各种维护一个了map 627 | 628 | ![](https://gitee.com/safe6/img/raw/master/image-20211226145014584.png) 629 | 630 | 631 | 632 | 初始化插件界面,设置插件名称,注册扫描,打印一些作者信息。 633 | 634 | ![image-20211226145255622](https://gitee.com/safe6/img/raw/master/image-20211226145255622.png) 635 | 636 | 637 | 638 | 看看插件界面代码,就是表格加req和res 639 | 640 | ![](https://gitee.com/safe6/img/raw/master/image-20211226151549825.png) 641 | 642 | 643 | 644 | 接下来看,被动扫描。核心代码都在这。 645 | 646 | ![image-20211226152831719](https://gitee.com/safe6/img/raw/master/image-20211226152831719.png) 647 | 648 | 先判断域名有没有被扫描过 649 | 650 | ![image-20211226153017814](https://gitee.com/safe6/img/raw/master/image-20211226153017814.png) 651 | 652 | 再检测url有没有被扫描过(此处有重复代码的感觉,离谱) 653 | 654 | ![image-20211226153117727](https://gitee.com/safe6/img/raw/master/image-20211226153117727.png) 655 | 656 | 657 | 658 | 都没有扫描过,则加到前面初始化的map里面去。(大佬居然管这个叫数组,有点离谱,问题不大) 659 | 660 | ![image-20211226153559483](https://gitee.com/safe6/img/raw/master/image-20211226153559483.png) 661 | 662 | 663 | 664 | 开始核心的各种检测 665 | 666 | ![image-20211226155021186](https://gitee.com/safe6/img/raw/master/image-20211226155021186.png) 667 | 668 | 669 | 670 | 后面就是一些添加issues,爆破key什么的,不想看了。 671 | 672 | 突然发现写这种东西,对我完全没任何好处。而且还及其浪费时间,疯狂截图,各种写。 673 | 674 | 675 | 676 | ## 致谢 677 | 678 | 感谢大佬开源,向大佬致敬。 679 | 680 | - https://github.com/bit4woo/burp-api-drops 681 | - https://xz.aliyun.com/t/7065 682 | --------------------------------------------------------------------------------