Repository: whwlsfb/SpringSpider
Branch: master
Commit: 26494ac0fc30
Files: 18
Total size: 49.8 KB
Directory structure:
gitextract_ctj4vjj7/
├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src/
└── main/
└── java/
└── burp/
├── BurpExtender.java
├── Issue.java
├── scanner/
│ ├── IResponseChecker.java
│ ├── ISubScanner.java
│ ├── Payload.java
│ ├── SpringScanner.java
│ └── sub/
│ ├── APIDoc.java
│ └── SpringActuator.java
├── ui/
│ └── UIHandler.java
└── utils/
├── BypassPayloadUtils.java
├── ConfigUtils.java
├── HttpHeader.java
├── UIUtil.java
└── Utils.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/out/
/target
/.idea
/*.iml
dependency-reduced-pom.xml
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# SpringSpider
该工具为被动扫描Spring Actuator端点的BurpSuite插件,用于解决多层级目录下隐藏的Actuator端点、或端点需要Bypass才能访问的情况下的漏报问题。
## 安装方法
导航至BurpSuite的`Extender->Extensions`界面,点击`Add`按钮,在弹出的窗口中点击`Select file ...`按钮,在文件打开页面中找到插件的jar文件,安装即可。
## 使用
该插件安装完成后,将无需特殊设置,自动启用被动扫描,扫描发现的端点将会生成漏洞条目出现在BurpSuite首页的`Issue activity`中。另外,若要优化扫描过程中的参数,则需要根据需要,修改插件设置,插件设置位于BurpSuite的SpringSpider选项卡。
本插件具有如下设置项:
#### Enable
该复选框为修改该插件的启用状态,当该复选框选中时插件才会执行被动扫描。当取消选中时,插件将不会再接受新的扫描任务,在当前正在执行的扫描任务结束后将会停止扫描。
#### Dir Scan Deeper
该设置项为修改插件的目录扫描深度,设置范围为`1~∞`,默认建议值为`3`,假设当前目录扫描深度设置为`3`,在用户访问目标「`http://test.com/backend/api/admin/user/`」时,将会拆分为「`http://test.com/`」、「`http://test.com/backend/`」、「`http://test.com/backend/api/`」分别扫描,该参数请尽量控制在1~5以内,以避免产生过大的请求流量。
#### Use Bypass
该设置项为修改启用的Bypass字符列表,默认启用`;`、`.`,当正常请求无果后,将会尝试在路径中插入Bypass字符尝试进行绕过,例如在启用`;`字符后,对「`http://test.com/api/actuator/env`」的绕过URL则是「`http://test.com/api/;/actuator/;/env`」
#### Scan Point
该设置项为修改启动扫描的端点,为了避免请求频率过大,目前支持启用的端点有「/actuator/env」、「/actuator」、「/env」,建议全部启用。
# 鸣谢
插件中部分代码借鉴于以下项目
https://github.com/sting8k/BurpSuite_403Bypasser
================================================
FILE: pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.wanghw</groupId>
<artifactId>SpringSpider</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/net.portswigger.burp.extender/burp-extender-api -->
<dependency>
<groupId>net.portswigger.burp.extender</groupId>
<artifactId>burp-extender-api</artifactId>
<version>1.7.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.jodah/expiringmap -->
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.10</version>
</dependency>
</dependencies>
</project>
================================================
FILE: src/main/java/burp/BurpExtender.java
================================================
package burp;
import burp.scanner.SpringScanner;
import burp.ui.UIHandler;
import burp.utils.Utils;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IExtensionStateListener {
public IExtensionHelpers helpers;
public IBurpExtenderCallbacks callbacks;
public PrintWriter stdout;
public PrintWriter stderr;
public String version = "1.0";
public UIHandler uiHandler;
public SpringScanner scanner;
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
Utils.Callback = this.callbacks = callbacks;
Utils.Helpers = this.helpers = callbacks.getHelpers();
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.stderr = new PrintWriter(callbacks.getStderr(), true);
callbacks.setExtensionName("SpringSpider");
this.stdout.println("SpringSpider v" + version);
this.stdout.println("Author: whwlsfb");
this.stdout.println("Github: https://github.com/whwlsfb/SpringSpider");
this.uiHandler = new UIHandler(this);
callbacks.addSuiteTab(this.uiHandler);
scanner = new SpringScanner();
callbacks.registerScannerCheck(scanner);
callbacks.registerExtensionStateListener(this);
}
@Override
public void extensionUnloaded() {
}
}
================================================
FILE: src/main/java/burp/Issue.java
================================================
package burp;
import java.net.URL;
public class Issue implements IScanIssue {
private IHttpService httpService;
private URL url;
private IHttpRequestResponse[] httpMessages;
private String name;
private String detail;
private String severity;
private boolean isCertain;
public Issue(
IHttpService httpService,
URL url,
IHttpRequestResponse[] httpMessages,
String name,
String detail,
String severity) {
this.httpService = httpService;
this.url = url;
this.httpMessages = httpMessages;
this.name = name;
this.detail = detail;
this.severity = severity;
this.isCertain = false;
}
public Issue(
IHttpService httpService,
URL url,
IHttpRequestResponse[] httpMessages,
String name,
String detail,
String severity, boolean isCertain) {
this.httpService = httpService;
this.url = url;
this.httpMessages = httpMessages;
this.name = name;
this.detail = detail;
this.severity = severity;
this.isCertain = isCertain;
}
@Override
public URL getUrl() {
return url;
}
@Override
public String getIssueName() {
return name;
}
@Override
public int getIssueType() {
return 0;
}
@Override
public String getSeverity() {
return severity;
}
@Override
public String getConfidence() {
return isCertain ? "Certain" : "Firm";
}
@Override
public String getIssueBackground() {
return null;
}
@Override
public String getRemediationBackground() {
return null;
}
@Override
public String getIssueDetail() {
return detail;
}
@Override
public String getRemediationDetail() {
return null;
}
@Override
public IHttpRequestResponse[] getHttpMessages() {
return httpMessages;
}
@Override
public IHttpService getHttpService() {
return httpService;
}
}
================================================
FILE: src/main/java/burp/scanner/IResponseChecker.java
================================================
package burp.scanner;
import burp.*;
import java.net.URL;
public interface IResponseChecker {
Issue checkResponse(IHttpRequestResponse baseRequestResponse, IHttpRequestResponse checkRequest, URL newUrl);
}
================================================
FILE: src/main/java/burp/scanner/ISubScanner.java
================================================
package burp.scanner;
import burp.IHttpRequestResponse;
import burp.Issue;
import java.net.URL;
import java.util.List;
public interface ISubScanner {
String getName();
List<Issue> check(URL url, IHttpRequestResponse originRequestResponse);
}
================================================
FILE: src/main/java/burp/scanner/Payload.java
================================================
package burp.scanner;
import java.util.List;
public class Payload {
public List<String[]> resources = null;
public IResponseChecker responseChecker = null;
public Payload(List<String[]> resources, IResponseChecker responseChecker) {
this.resources = resources;
this.responseChecker = responseChecker;
}
}
================================================
FILE: src/main/java/burp/scanner/SpringScanner.java
================================================
package burp.scanner;
import burp.*;
import burp.scanner.sub.SpringActuator;
import burp.utils.BypassPayloadUtils;
import burp.utils.ConfigUtils;
import burp.utils.Utils;
import net.jodah.expiringmap.ExpiringMap;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class SpringScanner implements IScannerCheck {
private final String[] STATIC_FILE_EXT = new String[]{
"png",
"jpg",
"jpeg",
"gif",
"pdf",
"bmp",
"js",
"css",
"ico",
"woff",
"woff2",
"ttf",
"otf",
"ttc",
"svg",
"psd",
"exe",
"zip",
"rar",
"7z",
"msi",
"tar",
"gz",
"mp3",
"mp4",
"mkv",
"swf",
"xls",
"xlsx",
"doc",
"docx",
"ppt",
"pptx",
"iso",
"map",
"php",
"aspx",
"ashx",
"asp"
};
List<String> scannedUrls = new ArrayList<>();
Map<String, Object> scannedNewUrls = ExpiringMap.builder().expiration(1, TimeUnit.HOURS).build();
List<ISubScanner> subScanners = new ArrayList<ISubScanner>() {{
// add(new APIDoc());
add(new SpringActuator(SpringScanner.this));
}};
@Override
public List<IScanIssue> doPassiveScan(IHttpRequestResponse baseRequestResponse) {
if (ConfigUtils.getBoolean(ConfigUtils.ENABLE, true)) {
URL originUrl = cleanURL(Utils.Helpers.analyzeRequest(baseRequestResponse).getUrl());
List<IScanIssue> result = new ArrayList<>();
URL[] urls = Utils.splitUrls(originUrl);
for (URL url : urls) {
if (!isChecked(url.toString()))
for (ISubScanner subScanner : subScanners) {
result.addAll(subScanner.check(url, baseRequestResponse));
}
}
return result;
} else {
return null;
}
}
public synchronized IHttpRequestResponse doRequest(List<String> originHeaders, IHttpRequestResponse originRequestResponse, URL newUrl) {
String urlMd5 = Utils.MD5(newUrl.toString());
if (!scannedNewUrls.containsKey(urlMd5)) {
scannedNewUrls.put(urlMd5, newUrl);
byte[] newRequest = BypassPayloadUtils.makeNewGETRequest(originHeaders, newUrl);
return Utils.Callback.makeHttpRequest(originRequestResponse.getHttpService(), newRequest);
} else {
return null;
}
}
public URL cleanURL(URL originUrl) {
String baseUrl = originUrl.getProtocol() + "://" + originUrl.getAuthority();
String path = originUrl.getPath();
if (isStaticFile(originUrl)) {
path = path.substring(0, path.lastIndexOf("/"));
}
try {
return new URL(baseUrl + (path.isEmpty() ? "/" : path));
} catch (Exception ex) {
return originUrl;
}
}
public boolean isChecked(String url) {
String urlMd5 = Utils.MD5(url);
synchronized (scannedUrls) {
if (scannedUrls.contains(urlMd5)) {
return true;
} else {
scannedUrls.add(urlMd5);
return false;
}
}
}
private boolean isStaticFile(URL url) {
return Arrays.stream(STATIC_FILE_EXT).anyMatch(s -> s.equalsIgnoreCase(Utils.getUrlFileExt(url.toString())));
}
@Override
public List<IScanIssue> doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) {
return null;
}
@Override
public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) {
return 0;
}
}
================================================
FILE: src/main/java/burp/scanner/sub/APIDoc.java
================================================
package burp.scanner.sub;
import burp.*;
import burp.scanner.IResponseChecker;
import burp.scanner.ISubScanner;
import burp.scanner.Payload;
import burp.utils.BypassPayloadUtils;
import burp.utils.ConfigUtils;
import burp.utils.Utils;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class APIDoc implements ISubScanner {
private final List<Payload> payloads = new ArrayList<Payload>() {{
add(new Payload(new ArrayList<String[]>() {{
add(new String[]{"swagger-ui.html"});
}}, (baseRequestResponse, checkRequest, newUrl) -> {
IResponseKeywords founds = Utils.Helpers.analyzeResponseKeywords(new ArrayList<String>() {{
add("Swagger UI");
add("swagger-ui/lib");
}}, checkRequest.getResponse());
if (BypassPayloadUtils.hasFound(founds, 0) && Utils.Helpers.analyzeResponse(checkRequest.getResponse()).getStatusCode() == 200) {
Utils.Callback.printOutput("found " + newUrl + ".\r\n");
return new Issue(
baseRequestResponse.getHttpService(),
newUrl,
new IHttpRequestResponse[]{checkRequest},
"Swagger UI found.",
"URL: " + newUrl,
"Medium", true);
} else {
return null;
}
}));
add(new Payload(new ArrayList<String[]>() {{
add(new String[]{"api-docs"});
add(new String[]{"v2", "api-docs"});
add(new String[]{"v2", "api-docs-ext"});
add(new String[]{"swagger", "v1", "swagger.json"});
}}, (baseRequestResponse, checkRequest, newUrl) -> {
IResponseKeywords founds = Utils.Helpers.analyzeResponseKeywords(new ArrayList<String>() {{
add("\"swagger\":");
}}, checkRequest.getResponse());
if (BypassPayloadUtils.hasFound(founds, 0) && Utils.Helpers.analyzeResponse(checkRequest.getResponse()).getStatusCode() == 200) {
Utils.Callback.printOutput("found " + newUrl + ".\r\n");
return new Issue(
baseRequestResponse.getHttpService(), newUrl,
new IHttpRequestResponse[]{checkRequest},
"API-Docs found.",
"URL: " + newUrl,
"Medium", false);
} else {
return null;
}
}));
add(new Payload(new ArrayList<String[]>() {{
add(new String[]{"doc.html"});
}}, (baseRequestResponse, checkRequest, newUrl) -> null));
}};
@Override
public String getName() {
return "API Doc";
}
@Override
public List<Issue> check(URL url, IHttpRequestResponse originRequestResponse) {
IRequestInfo originRequest = Utils.Helpers.analyzeRequest(originRequestResponse);
List<String> originHeaders = originRequest.getHeaders();
List<Issue> result = new ArrayList<>();
for (Payload payload : payloads) {
List<Issue> issues = new ArrayList<>();
for (String[] resParts : payload.resources) {
for (URL newUrl : BypassPayloadUtils.getBypassPayloads(url, resParts, ConfigUtils.getDict(ConfigUtils.DIR_BYPASS))) {
byte[] newRequest = BypassPayloadUtils.makeNewGETRequest(originHeaders, newUrl);
IHttpRequestResponse resp = Utils.Callback.makeHttpRequest(originRequestResponse.getHttpService(), newRequest);
Issue issue = payload.responseChecker.checkResponse(originRequestResponse, resp, newUrl);
if (issue != null) {
issues.add(issue);
break;
}
}
if (issues.size() > 0) {
break;
}
}
result.addAll(issues);
}
return result;
}
}
================================================
FILE: src/main/java/burp/scanner/sub/SpringActuator.java
================================================
package burp.scanner.sub;
import burp.*;
import burp.scanner.IResponseChecker;
import burp.scanner.ISubScanner;
import burp.scanner.Payload;
import burp.scanner.SpringScanner;
import burp.utils.BypassPayloadUtils;
import burp.utils.ConfigUtils;
import burp.utils.Utils;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class SpringActuator implements ISubScanner {
private SpringScanner scanner;
public SpringActuator(SpringScanner scanner) {
this.scanner = scanner;
}
private final List<Payload> payloads = new ArrayList<Payload>() {{
add(new Payload(new ArrayList<String[]>() {{
add(new String[]{"env"});
add(new String[]{"actuator", "env"});
}}, (baseRequestResponse, checkRequest, newUrl) -> {
IResponseKeywords founds = Utils.Helpers.analyzeResponseKeywords(new ArrayList<String>() {{
add("java.version");
add("os.arch");
}}, checkRequest.getResponse());
if (BypassPayloadUtils.hasFound(founds, 0) && Utils.Helpers.analyzeResponse(checkRequest.getResponse()).getStatusCode() == 200) {
Utils.Callback.printOutput("found " + newUrl + ".\r\n");
return new Issue(
baseRequestResponse.getHttpService(),
newUrl,
new IHttpRequestResponse[]{checkRequest},
"Spring Actuator-Env found.",
"URL: " + newUrl,
"Medium", true);
} else {
return null;
}
}));
add(new Payload(new ArrayList<String[]>() {{
add(new String[]{"actuator"});
}}, (baseRequestResponse, checkRequest, newUrl) -> {
IResponseKeywords founds = Utils.Helpers.analyzeResponseKeywords(new ArrayList<String>() {{
add("health");
add("{\"self\":{");
add("{\"_links\":{");
}}, checkRequest.getResponse());
if (BypassPayloadUtils.hasFound(founds, 0) && Utils.Helpers.analyzeResponse(checkRequest.getResponse()).getStatusCode() == 200) {
Utils.Callback.printOutput("found " + newUrl + ".\r\n");
return new Issue(
baseRequestResponse.getHttpService(),
newUrl,
new IHttpRequestResponse[]{checkRequest},
"Spring Actuator found.",
"URL: " + newUrl,
"Medium", false);
} else {
return null;
}
}));
}};
@Override
public String getName() {
return "Spring Actuator";
}
@Override
public List<Issue> check(URL url, IHttpRequestResponse originRequestResponse) {
IRequestInfo originRequest = Utils.Helpers.analyzeRequest(originRequestResponse);
List<String> originHeaders = originRequest.getHeaders();
List<Issue> result = new ArrayList<>();
for (Payload payload : payloads) {
List<Issue> issues = new ArrayList<>();
for (String[] resParts : payload.resources) {
if (Utils.urlAllowScan(resParts)) {
for (URL newUrl : BypassPayloadUtils.getBypassPayloads(url, resParts, ConfigUtils.getDict(ConfigUtils.DIR_BYPASS))) {
IHttpRequestResponse resp = scanner.doRequest(originHeaders, originRequestResponse, newUrl);
if (resp != null) {
Issue issue = payload.responseChecker.checkResponse(originRequestResponse, resp, newUrl);
if (issue != null) {
issues.add(issue);
break;
}
}
}
}
if (issues.size() > 0) {
break;
}
}
result.addAll(issues);
}
return result;
}
}
================================================
FILE: src/main/java/burp/ui/UIHandler.java
================================================
package burp.ui;
import burp.BurpExtender;
import burp.ITab;
import burp.utils.ConfigUtils;
import burp.utils.UIUtil;
import burp.utils.Utils;
import jdk.nashorn.internal.runtime.regexp.joni.Config;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class UIHandler implements ITab {
public JPanel mainPanel;
public BurpExtender parent;
public JTextField dirScanDeeper;
public static final List<String> DefaultBypass = new ArrayList<String>() {{
add(".");
add(";");
}};
public static final List<String> DefaultScanPoint = new ArrayList<String>() {{
add("/env");
add("/actuator");
add("/actuator/env");
}};
public UIHandler(BurpExtender parent) {
this.parent = parent;
this.initUI();
}
private void applyDefaultBypassIfNotSet() {
String val = ConfigUtils.get(ConfigUtils.DIR_BYPASS);
if (val == null || val.isEmpty()) {
for (String str : DefaultBypass) {
ConfigUtils.setStrToDict(ConfigUtils.DIR_BYPASS, str, true);
}
}
}
private void applyDefaultScanPointIfNotSet() {
String val = ConfigUtils.get(ConfigUtils.SCAN_POINT);
if (val == null || val.isEmpty()) {
for (String str : DefaultScanPoint) {
ConfigUtils.setStrToDict(ConfigUtils.SCAN_POINT, str, true);
}
}
}
private void initUI() {
applyDefaultBypassIfNotSet();
applyDefaultScanPointIfNotSet();
Utils.SplitDeep = ConfigUtils.getInt(ConfigUtils.DIR_SCAN_DEEPER, 3);
this.mainPanel = new JPanel();
mainPanel.setAlignmentX(0.0f);
mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
mainPanel.setLayout(new BoxLayout(mainPanel, 1));
EmptyBorder border = new EmptyBorder(5, 5, 6, 6);
JPanel panel1 = UIUtil.GetXJPanel();
JLabel savedTip0 = new JLabel("Saved!");
savedTip0.setVisible(false);
savedTip0.setBorder(border);
savedTip0.setForeground(Color.GREEN);
JCheckBox enableBox = new JCheckBox();
enableBox.addActionListener(a -> {
ConfigUtils.setBoolean(ConfigUtils.ENABLE, enableBox.isSelected());
startTimerHide(savedTip0);
});
enableBox.setSelected(ConfigUtils.getBoolean(ConfigUtils.ENABLE, true));
panel1.add(new JLabel("Enable: "));
panel1.add(enableBox);
panel1.add(savedTip0);
mainPanel.add(panel1);
panel1 = UIUtil.GetXJPanel();
dirScanDeeper = new JTextField(10);
dirScanDeeper.setText(String.valueOf(ConfigUtils.getInt(ConfigUtils.DIR_SCAN_DEEPER, 3)));
dirScanDeeper.setMaximumSize(dirScanDeeper.getPreferredSize());
panel1.add(new JLabel("Dir Scan Deeper: "));
panel1.add(dirScanDeeper);
panel1.add(new JButton("Save") {{
addActionListener(l -> {
try {
int val = Integer.parseInt(dirScanDeeper.getText());
Utils.SplitDeep = val;
ConfigUtils.setInt(ConfigUtils.DIR_SCAN_DEEPER, val);
JOptionPane.showMessageDialog(mainPanel, "OK!");
} catch (Exception ex) {
JOptionPane.showMessageDialog(mainPanel, "Must be number!");
}
});
}});
mainPanel.add(panel1);
panel1 = UIUtil.GetXJPanel();
panel1.add(new JLabel("Use Bypass: "));
JLabel savedTip1 = new JLabel("Saved!");
savedTip1.setVisible(false);
savedTip1.setBorder(border);
savedTip1.setForeground(Color.GREEN);
for (String str : new String[]{
".",
";",
"..;",
";%09..;",
";%09..",
";%2f..",
"*",
"%09",
"%20",
"%23",
"%2e",
"%2f"
}) {
JCheckBox checkBox = new JCheckBox();
checkBox.setText(str);
checkBox.addActionListener(a -> {
ConfigUtils.setStrToDict(ConfigUtils.DIR_BYPASS, str, checkBox.isSelected());
startTimerHide(savedTip1);
});
checkBox.setSelected(ConfigUtils.getStrInDict(ConfigUtils.DIR_BYPASS, str, false));
panel1.add(checkBox);
}
panel1.add(savedTip1);
mainPanel.add(panel1);
panel1 = UIUtil.GetXJPanel();
panel1.add(new JLabel("Scan Point: "));
JLabel savedTip2 = new JLabel("Saved!");
savedTip2.setVisible(false);
savedTip2.setBorder(border);
savedTip2.setForeground(Color.GREEN);
for (String str : new String[]{
"/env",
"/actuator",
"/actuator/env"
}) {
JCheckBox checkBox = new JCheckBox();
checkBox.setText(str);
checkBox.addActionListener(a -> {
ConfigUtils.setStrToDict(ConfigUtils.SCAN_POINT, str, checkBox.isSelected());
startTimerHide(savedTip2);
});
checkBox.setSelected(ConfigUtils.getStrInDict(ConfigUtils.SCAN_POINT, str, false));
panel1.add(checkBox);
}
panel1.add(savedTip2);
mainPanel.add(panel1);
// BackendUIHandler bui = new BackendUIHandler(parent);
// POCUIHandler pui = new POCUIHandler(parent);
// FuzzUIHandler fui = new FuzzUIHandler(parent);
// this.mainPanel.addTab("Backend", bui.getPanel());
// this.mainPanel.addTab("POC", pui.getPanel());
// this.mainPanel.addTab("Fuzz", fui.getPanel());
}
public void startTimerHide(JComponent component) {
component.setVisible(true);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(4000);
component.setVisible(false);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.setDaemon(true);
thread.start();
}
@Override
public String getTabCaption() {
return "SpringSpider";
}
@Override
public Component getUiComponent() {
return mainPanel;
}
}
================================================
FILE: src/main/java/burp/utils/BypassPayloadUtils.java
================================================
package burp.utils;
import burp.IResponseKeywords;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class BypassPayloadUtils {
public static final String[] URL_BYPASS = new String[]{
".",
";",
// "..;",
/* ";%09..;",
";%09..",
";%2f..",
"*",
"%09",
"%20",
"%23",
"%2e",
"%2f"*/
};
public static final String[] HEADER_BYPASS = new String[]{
"Client-IP",
"X-Real-IP",
"Redirect",
"Referer",
"X-Client-IP",
"X-Custom-IP-Authorization",
"X-Forwarded-By",
"X-Forwarded-For",
"X-Forwarded-Host",
"X-Forwarded-Port",
"X-True-IP"
};
public static final String[] GET_SKIPED_HEADERS = new String[]{"content-type", "content-length"};
public static URL[] getBypassPayloads(URL baseUrl, String[] resParts, String[] bypass) {
List<URL> result = new ArrayList<>();
String originUrl = baseUrl.toString();
originUrl = originUrl.endsWith("/") ? originUrl : originUrl + "/";
try {
result.add(new URL(originUrl + String.join("/", resParts)));
for (String bypassPayload : bypass) {
result.add(new URL(originUrl + bypassPayload + "/" + String.join("/" + bypassPayload + "/", resParts)));
}
} catch (Exception ex) {
System.out.println(ex);
}
return result.toArray(new URL[0]);
}
public static byte[] makeNewGETRequest(List<String> originHeaders, URL url) {
List<String> headers = new ArrayList<String>() {{
add(
"GET " + url.getPath() + " HTTP/1.1"
);
}};
List<String> headerBypass = new ArrayList(Arrays.asList(HEADER_BYPASS));
for (int i = 1; i < originHeaders.size(); i++) { //skip url line.
HttpHeader header = new HttpHeader(originHeaders.get(i));
List<String> needSkipheader = headerBypass.stream().filter(h -> h.equalsIgnoreCase(header.Name)).collect(Collectors.toList());
needSkipheader.forEach(headerBypass::remove);
if (Arrays.stream(GET_SKIPED_HEADERS).anyMatch(e -> e.equalsIgnoreCase(header.Name))) {
continue;
} else {
if (header.Name.equalsIgnoreCase("accept")) {
headers.add("Accept: */*");
} else {
headers.add(header.toString());
}
}
}
for (String headerName : headerBypass) {
switch (headerName) {
case "X-Forwarded-Port":
headers.add(String.format("%s: %s", headerName, url.getPort()));
break;
default:
headers.add(String.format("%s: %s", headerName, "127.0.0.1"));
}
}
return Utils.Helpers.buildHttpMessage(headers, null);
}
public static boolean hasFound(IResponseKeywords keywords, int responseIndex) {
for (String keyword : keywords.getInvariantKeywords()) {
if (keywords.getKeywordCount(keyword, responseIndex) > 0) {
return true;
}
}
return false;
}
}
================================================
FILE: src/main/java/burp/utils/ConfigUtils.java
================================================
package burp.utils;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
public class ConfigUtils {
public static final String DIR_SCAN_DEEPER = "dir_scan_deeper";
public static final String DIR_BYPASS = "dir_bypass";
public static final String SCAN_POINT = "scan_point";
public static final String ENABLE = "enable";
public static String get(String name) {
return Utils.Callback.loadExtensionSetting(name);
}
public static String get(String name, String defaultValue) {
String val = get(name);
return val == null || val.isEmpty() ? defaultValue : val;
}
public static int getInt(String name, int defaultValue) {
String val = get(name);
return val == null || val.isEmpty() ? defaultValue : Integer.parseInt(val);
}
public static boolean getBoolean(String name, boolean defaultValue) {
String val = get(name);
return val == null || val.isEmpty() ? defaultValue : val.equals("1");
}
public static boolean getStrInDict(String name, String str, boolean defaultValue) {
String val = get(name);
if (val == null || val.isEmpty())
return defaultValue;
try {
DocumentContext array = JsonPath.parse(val);
if (array.json() instanceof JSONArray) {
return ((JSONArray) array.json()).contains(str);
} else {
return defaultValue;
}
} catch (Exception ex) {
return defaultValue;
}
}
public static void setStrToDict(String name, String str, boolean value) {
String val = get(name);
if (val == null || val.isEmpty())
val = "[]";
DocumentContext array = null;
try {
array = JsonPath.parse(val);
} catch (Exception ex) {
array = JsonPath.parse("[]");
}
JSONArray arr = array.json();
if (value && !arr.contains(str)) {
arr.add(str);
} else if (!value && arr.contains(str)) {
arr.remove(str);
}
set(name, arr.toJSONString());
}
public static String[] getDict(String name) {
String val = get(name);
if (val == null || val.isEmpty())
return new String[0];
DocumentContext array = null;
try {
array = JsonPath.parse(val);
} catch (Exception ex) {
return new String[0];
}
JSONArray arr = array.json();
return arr.toArray(new String[0]);
}
public static void set(String name, String value) {
Utils.Callback.saveExtensionSetting(name, value);
}
public static void setBoolean(String name, boolean value) {
set(name, value ? "1" : "0");
}
public static void setInt(String name, int value) {
set(name, String.valueOf(value));
}
public static void main(String[] args) {
}
}
================================================
FILE: src/main/java/burp/utils/HttpHeader.java
================================================
package burp.utils;
public class HttpHeader {
public String Name;
public String Value = "";
public HttpHeader(String src) {
int headerLength = src.indexOf(':');
if (headerLength > -1) {
Name = src.substring(0, headerLength);
Value = src.substring(headerLength + 1).trim();
} else {
Name = src;
}
}
@Override
public String toString() {
return String.format("%s: %s", Name, Value);
}
}
================================================
FILE: src/main/java/burp/utils/UIUtil.java
================================================
package burp.utils;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
public class UIUtil {
public static JPanel GetXJPanel() {
JPanel panel1 = new JPanel();
panel1.setAlignmentX(0.0f);
panel1.setLayout(new BoxLayout(panel1, 0));
panel1.setForeground(new Color(249, 130, 11));
panel1.setBorder(new EmptyBorder(5, 0, 5, 0));
return panel1;
}
public static JPanel GetYJPanel() {
JPanel panel1 = new JPanel();
panel1.setAlignmentX(0.0f);
panel1.setLayout(new BoxLayout(panel1, 1));
panel1.setForeground(new Color(249, 130, 11));
panel1.setBorder(new EmptyBorder(5, 0, 5, 0));
return panel1;
}
}
================================================
FILE: src/main/java/burp/utils/Utils.java
================================================
package burp.utils;
import burp.IBurpExtenderCallbacks;
import burp.IExtensionHelpers;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class Utils {
public static IBurpExtenderCallbacks Callback;
public static IExtensionHelpers Helpers;
private static MessageDigest md;
private static SecureRandom rand = new SecureRandom();
public static int SplitDeep = 3;
public static long getRandomLong() {
return rand.nextLong();
}
public static int GetRandomNumber(int min, int max) {
return rand.nextInt(max - min + 1) + min;
}
public static Boolean GetRandomBoolean() {
return rand.nextInt(100) > 50;
}
public static String GetRandomString(int length) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = rand.nextInt(str.length() - 1);
sb.append(str.charAt(number));
}
return sb.toString();
}
public static int[] getRandomIndex(int size, int max) {
if (size > max) size = max;
return ThreadLocalRandom.current().ints(0, max).distinct().limit(size).toArray();
}
public static String confusionChars(String[] _chars) {
int confusionCount = Utils.GetRandomNumber(1, _chars.length);
return confusionChars(_chars, confusionCount);
}
public static String confusionChars(String[] _chars, int confusionCount) {
StringBuilder result = new StringBuilder();
int[] confustionCharIndexs = Utils.getRandomIndex(confusionCount, _chars.length);
for (int i = 0; i < _chars.length; i++) {
int finalI = i;
if (Arrays.stream(confustionCharIndexs).anyMatch(c -> c == finalI)) {
result.append(confusionChar(_chars[i]));
} else {
result.append(_chars[i]);
}
}
return result.toString();
}
public static String confusionChar(String _char) {
int garbageCount = Utils.GetRandomNumber(2, 5);
StringBuilder garbage = new StringBuilder();
for (int i = 0; i < garbageCount; i++) {
int garbageLength = Utils.GetRandomNumber(3, 6);
String garbageWord = Utils.GetRandomString(garbageLength);
garbage.append(garbageWord).append(":");
}
return String.format("${%s-%s}", garbage, _char);
}
public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
byte[] bt3 = new byte[bt1.length + bt2.length];
System.arraycopy(bt1, 0, bt3, 0, bt1.length);
System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
return bt3;
}
public static String getUrlFileExt(String url) {
String pureUrl = url.substring(0, url.contains("?") ? url.indexOf("?") : url.length());
return (pureUrl.lastIndexOf(".") > -1 ? pureUrl.substring(pureUrl.lastIndexOf(".") + 1) : "").toLowerCase();
}
public static URL[] splitUrls(URL url) {
List<URL> urls = new ArrayList<>();
try {
String baseUrl = url.getProtocol() + "://" + url.getAuthority() + "/";
String[] paths = url.getPath().split("/");
for (String path : paths) {
if (urls.size() >= SplitDeep) break;
String tmpUrl = baseUrl + path;
urls.add(new URL(tmpUrl));
//urls.add(new URL(tmpUrl + (tmpUrl.endsWith("/") ? ".." : "/..")));
baseUrl += path + (path.isEmpty() ? "" : "/");
}
} catch (Exception ex) {
System.out.println(ex);
}
return urls.toArray(new URL[0]);
}
public static boolean urlAllowScan(String[] urlParts) {
String url = "/" + String.join("/", urlParts);
return ConfigUtils.getStrInDict(ConfigUtils.SCAN_POINT, url, false);
}
public static String getCurrentTimeMillis() {
return String.valueOf(System.currentTimeMillis());
}
public static byte[] Replace(byte[] request, int[] selectedIndexRange, byte[] targetBytes) {
byte[] result = new byte[request.length - (selectedIndexRange[1] - selectedIndexRange[0]) + targetBytes.length];
System.arraycopy(request, 0, result, 0, selectedIndexRange[0]);
System.arraycopy(targetBytes, 0, result, selectedIndexRange[0], targetBytes.length);
System.arraycopy(request, selectedIndexRange[1], result, selectedIndexRange[0] + targetBytes.length, request.length - selectedIndexRange[1]);
return result;
}
public static String MD5(String src) {
return Base64.getEncoder().encodeToString(MD5(src.getBytes(StandardCharsets.UTF_8)));
}
public static byte[] MD5(byte[] src) {
if (md == null) {
try {
md = MessageDigest.getInstance("md5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 not found!");
}
}
byte[] secretBytes = null;
secretBytes = md.digest(src);
return secretBytes;
}
public static String[] splitString(String str) {
String[] result = new String[str.length()];
for (int i = 0; i < str.length(); i++) {
result[i] = String.valueOf(str.charAt(i));
}
return result;
}
}
gitextract_ctj4vjj7/
├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src/
└── main/
└── java/
└── burp/
├── BurpExtender.java
├── Issue.java
├── scanner/
│ ├── IResponseChecker.java
│ ├── ISubScanner.java
│ ├── Payload.java
│ ├── SpringScanner.java
│ └── sub/
│ ├── APIDoc.java
│ └── SpringActuator.java
├── ui/
│ └── UIHandler.java
└── utils/
├── BypassPayloadUtils.java
├── ConfigUtils.java
├── HttpHeader.java
├── UIUtil.java
└── Utils.java
SYMBOL INDEX (87 symbols across 14 files)
FILE: src/main/java/burp/BurpExtender.java
class BurpExtender (line 11) | public class BurpExtender implements IBurpExtender, IExtensionStateListe...
method registerExtenderCallbacks (line 21) | @Override
method extensionUnloaded (line 38) | @Override
FILE: src/main/java/burp/Issue.java
class Issue (line 5) | public class Issue implements IScanIssue {
method Issue (line 16) | public Issue(
method Issue (line 32) | public Issue(
method getUrl (line 48) | @Override
method getIssueName (line 53) | @Override
method getIssueType (line 58) | @Override
method getSeverity (line 63) | @Override
method getConfidence (line 68) | @Override
method getIssueBackground (line 73) | @Override
method getRemediationBackground (line 78) | @Override
method getIssueDetail (line 83) | @Override
method getRemediationDetail (line 88) | @Override
method getHttpMessages (line 93) | @Override
method getHttpService (line 98) | @Override
FILE: src/main/java/burp/scanner/IResponseChecker.java
type IResponseChecker (line 7) | public interface IResponseChecker {
method checkResponse (line 8) | Issue checkResponse(IHttpRequestResponse baseRequestResponse, IHttpReq...
FILE: src/main/java/burp/scanner/ISubScanner.java
type ISubScanner (line 9) | public interface ISubScanner {
method getName (line 10) | String getName();
method check (line 12) | List<Issue> check(URL url, IHttpRequestResponse originRequestResponse);
FILE: src/main/java/burp/scanner/Payload.java
class Payload (line 5) | public class Payload {
method Payload (line 9) | public Payload(List<String[]> resources, IResponseChecker responseChec...
FILE: src/main/java/burp/scanner/SpringScanner.java
class SpringScanner (line 18) | public class SpringScanner implements IScannerCheck {
method doPassiveScan (line 70) | @Override
method doRequest (line 88) | public synchronized IHttpRequestResponse doRequest(List<String> origin...
method cleanURL (line 99) | public URL cleanURL(URL originUrl) {
method isChecked (line 112) | public boolean isChecked(String url) {
method isStaticFile (line 124) | private boolean isStaticFile(URL url) {
method doActiveScan (line 128) | @Override
method consolidateDuplicateIssues (line 133) | @Override
FILE: src/main/java/burp/scanner/sub/APIDoc.java
class APIDoc (line 15) | public class APIDoc implements ISubScanner {
method getName (line 63) | @Override
method check (line 68) | @Override
FILE: src/main/java/burp/scanner/sub/SpringActuator.java
class SpringActuator (line 16) | public class SpringActuator implements ISubScanner {
method SpringActuator (line 19) | public SpringActuator(SpringScanner scanner) {
method getName (line 68) | @Override
method check (line 74) | @Override
FILE: src/main/java/burp/ui/UIHandler.java
class UIHandler (line 16) | public class UIHandler implements ITab {
method UIHandler (line 30) | public UIHandler(BurpExtender parent) {
method applyDefaultBypassIfNotSet (line 35) | private void applyDefaultBypassIfNotSet() {
method applyDefaultScanPointIfNotSet (line 44) | private void applyDefaultScanPointIfNotSet() {
method initUI (line 53) | private void initUI() {
method startTimerHide (line 165) | public void startTimerHide(JComponent component) {
method getTabCaption (line 182) | @Override
method getUiComponent (line 187) | @Override
FILE: src/main/java/burp/utils/BypassPayloadUtils.java
class BypassPayloadUtils (line 11) | public class BypassPayloadUtils {
method getBypassPayloads (line 41) | public static URL[] getBypassPayloads(URL baseUrl, String[] resParts, ...
method makeNewGETRequest (line 56) | public static byte[] makeNewGETRequest(List<String> originHeaders, URL...
method hasFound (line 89) | public static boolean hasFound(IResponseKeywords keywords, int respons...
FILE: src/main/java/burp/utils/ConfigUtils.java
class ConfigUtils (line 8) | public class ConfigUtils {
method get (line 14) | public static String get(String name) {
method get (line 18) | public static String get(String name, String defaultValue) {
method getInt (line 23) | public static int getInt(String name, int defaultValue) {
method getBoolean (line 28) | public static boolean getBoolean(String name, boolean defaultValue) {
method getStrInDict (line 33) | public static boolean getStrInDict(String name, String str, boolean de...
method setStrToDict (line 49) | public static void setStrToDict(String name, String str, boolean value) {
method getDict (line 68) | public static String[] getDict(String name) {
method set (line 82) | public static void set(String name, String value) {
method setBoolean (line 86) | public static void setBoolean(String name, boolean value) {
method setInt (line 90) | public static void setInt(String name, int value) {
method main (line 94) | public static void main(String[] args) {
FILE: src/main/java/burp/utils/HttpHeader.java
class HttpHeader (line 3) | public class HttpHeader {
method HttpHeader (line 7) | public HttpHeader(String src) {
method toString (line 17) | @Override
FILE: src/main/java/burp/utils/UIUtil.java
class UIUtil (line 7) | public class UIUtil {
method GetXJPanel (line 8) | public static JPanel GetXJPanel() {
method GetYJPanel (line 17) | public static JPanel GetYJPanel() {
FILE: src/main/java/burp/utils/Utils.java
class Utils (line 17) | public class Utils {
method getRandomLong (line 24) | public static long getRandomLong() {
method GetRandomNumber (line 28) | public static int GetRandomNumber(int min, int max) {
method GetRandomBoolean (line 32) | public static Boolean GetRandomBoolean() {
method GetRandomString (line 36) | public static String GetRandomString(int length) {
method getRandomIndex (line 46) | public static int[] getRandomIndex(int size, int max) {
method confusionChars (line 51) | public static String confusionChars(String[] _chars) {
method confusionChars (line 56) | public static String confusionChars(String[] _chars, int confusionCoun...
method confusionChar (line 70) | public static String confusionChar(String _char) {
method byteMerger (line 81) | public static byte[] byteMerger(byte[] bt1, byte[] bt2) {
method getUrlFileExt (line 89) | public static String getUrlFileExt(String url) {
method splitUrls (line 94) | public static URL[] splitUrls(URL url) {
method urlAllowScan (line 112) | public static boolean urlAllowScan(String[] urlParts) {
method getCurrentTimeMillis (line 117) | public static String getCurrentTimeMillis() {
method Replace (line 121) | public static byte[] Replace(byte[] request, int[] selectedIndexRange,...
method MD5 (line 129) | public static String MD5(String src) {
method MD5 (line 133) | public static byte[] MD5(byte[] src) {
method splitString (line 146) | public static String[] splitString(String str) {
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (55K chars).
[
{
"path": ".gitignore",
"chars": 54,
"preview": "/out/\n/target\n/.idea\n/*.iml\ndependency-reduced-pom.xml"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 1071,
"preview": "# SpringSpider\n\n该工具为被动扫描Spring Actuator端点的BurpSuite插件,用于解决多层级目录下隐藏的Actuator端点、或端点需要Bypass才能访问的情况下的漏报问题。\n\n## 安装方法\n\n导航至Bur"
},
{
"path": "pom.xml",
"chars": 2082,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "src/main/java/burp/BurpExtender.java",
"chars": 1408,
"preview": "package burp;\n\nimport burp.scanner.SpringScanner;\nimport burp.ui.UIHandler;\nimport burp.utils.Utils;\n\nimport java.io.Fil"
},
{
"path": "src/main/java/burp/Issue.java",
"chars": 2148,
"preview": "package burp;\n\nimport java.net.URL;\n\npublic class Issue implements IScanIssue {\n\n private IHttpService httpService;\n "
},
{
"path": "src/main/java/burp/scanner/IResponseChecker.java",
"chars": 213,
"preview": "package burp.scanner;\n\nimport burp.*;\n\nimport java.net.URL;\n\npublic interface IResponseChecker {\n Issue checkResponse"
},
{
"path": "src/main/java/burp/scanner/ISubScanner.java",
"chars": 254,
"preview": "package burp.scanner;\n\nimport burp.IHttpRequestResponse;\nimport burp.Issue;\n\nimport java.net.URL;\nimport java.util.List;"
},
{
"path": "src/main/java/burp/scanner/Payload.java",
"chars": 340,
"preview": "package burp.scanner;\n\nimport java.util.List;\n\npublic class Payload {\n public List<String[]> resources = null;\n pu"
},
{
"path": "src/main/java/burp/scanner/SpringScanner.java",
"chars": 4087,
"preview": "package burp.scanner;\n\nimport burp.*;\nimport burp.scanner.sub.SpringActuator;\nimport burp.utils.BypassPayloadUtils;\nimpo"
},
{
"path": "src/main/java/burp/scanner/sub/APIDoc.java",
"chars": 4036,
"preview": "package burp.scanner.sub;\n\nimport burp.*;\nimport burp.scanner.IResponseChecker;\nimport burp.scanner.ISubScanner;\nimport "
},
{
"path": "src/main/java/burp/scanner/sub/SpringActuator.java",
"chars": 4098,
"preview": "package burp.scanner.sub;\n\nimport burp.*;\nimport burp.scanner.IResponseChecker;\nimport burp.scanner.ISubScanner;\nimport "
},
{
"path": "src/main/java/burp/ui/UIHandler.java",
"chars": 6486,
"preview": "package burp.ui;\n\nimport burp.BurpExtender;\nimport burp.ITab;\nimport burp.utils.ConfigUtils;\nimport burp.utils.UIUtil;\ni"
},
{
"path": "src/main/java/burp/utils/BypassPayloadUtils.java",
"chars": 3454,
"preview": "package burp.utils;\n\nimport burp.IResponseKeywords;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.A"
},
{
"path": "src/main/java/burp/utils/ConfigUtils.java",
"chars": 2996,
"preview": "package burp.utils;\n\nimport com.jayway.jsonpath.DocumentContext;\nimport com.jayway.jsonpath.JsonPath;\nimport net.minidev"
},
{
"path": "src/main/java/burp/utils/HttpHeader.java",
"chars": 491,
"preview": "package burp.utils;\n\npublic class HttpHeader {\n public String Name;\n public String Value = \"\";\n\n public HttpHea"
},
{
"path": "src/main/java/burp/utils/UIUtil.java",
"chars": 737,
"preview": "package burp.utils;\n\nimport javax.swing.*;\nimport javax.swing.border.EmptyBorder;\nimport java.awt.*;\n\npublic class UIUti"
},
{
"path": "src/main/java/burp/utils/Utils.java",
"chars": 5650,
"preview": "package burp.utils;\n\n\nimport burp.IBurpExtenderCallbacks;\nimport burp.IExtensionHelpers;\n\nimport java.lang.reflect.Field"
}
]
About this extraction
This page contains the full source code of the whwlsfb/SpringSpider GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (49.8 KB), approximately 11.7k tokens, and a symbol index with 87 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.