diff --git a/images/1.png b/images/1.png
new file mode 100644
index 0000000..7d31cd3
Binary files /dev/null and b/images/1.png differ
diff --git a/images/2.png b/images/2.png
new file mode 100644
index 0000000..7c265af
Binary files /dev/null and b/images/2.png differ
diff --git a/images/3.png b/images/3.png
new file mode 100644
index 0000000..23d8f08
Binary files /dev/null and b/images/3.png differ
diff --git a/images/4.png b/images/4.png
new file mode 100644
index 0000000..a7cda34
Binary files /dev/null and b/images/4.png differ
diff --git a/images/5.png b/images/5.png
new file mode 100644
index 0000000..97d8974
Binary files /dev/null and b/images/5.png differ
diff --git a/images/6.png b/images/6.png
new file mode 100644
index 0000000..6bfb28c
Binary files /dev/null and b/images/6.png differ
diff --git a/images/7.png b/images/7.png
new file mode 100644
index 0000000..6cb4ef4
Binary files /dev/null and b/images/7.png differ
diff --git a/images/8.png b/images/8.png
new file mode 100644
index 0000000..568b031
Binary files /dev/null and b/images/8.png differ
diff --git a/images/9.png b/images/9.png
new file mode 100644
index 0000000..73dd5e3
Binary files /dev/null and b/images/9.png differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..8b1e1f4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,115 @@
+
+
+ 4.0.0
+
+ com.github.pmiaowu
+ BurpShiroPassiveScan
+ 2.0.0
+
+
+
+
+ net.portswigger.burp.extender
+ burp-extender-api
+ 2.3
+
+
+
+
+ org.yaml
+ snakeyaml
+ 1.29
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
+
+
+
+ org.apache.shiro
+ shiro-core
+ 1.2.4
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.3.0
+
+
+ BurpShiroPassiveScan
+ false
+
+
+ burp.BurpExtender
+
+
+
+ jar-with-dependencies
+
+
+ ${project.build.directory}/BurpShiroPassiveScan
+
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.2.0
+
+
+ copy-resources
+ package
+
+ copy-resources
+
+
+ ${project.build.directory}/BurpShiroPassiveScan/resources
+
+
+ src/main/resources
+
+ **/*
+
+ true
+
+
+ UTF-8
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/AShiroCipherKeyExtension.java b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/AShiroCipherKeyExtension.java
new file mode 100644
index 0000000..b2d79c1
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/AShiroCipherKeyExtension.java
@@ -0,0 +1,131 @@
+package burp.Application.ShiroCipherKeyExtension.ExtensionInterface;
+
+import burp.IHttpRequestResponse;
+
+public abstract class AShiroCipherKeyExtension implements IShiroCipherKeyExtension {
+ private String extensionName = "";
+
+ private String cipherKey = "";
+
+ private String encryptMethod = "";
+
+ private Boolean isShiroCipherKeyExists = false;
+
+ private IHttpRequestResponse newHttpRequestResponse;
+
+ /**
+ * 设置扩展名称 (必须的)
+ *
+ * @param value
+ */
+ protected void setExtensionName(String value) {
+ if (value == null || value.isEmpty()) {
+ throw new IllegalArgumentException("shiro加密key检测扩展-扩展名称不能为空");
+ }
+ this.extensionName = value;
+ }
+
+ /**
+ * 扩展名称检查
+ * 作用: 让所有不设置扩展名称的扩展无法正常使用, 防止直接调用本类的其他方法, 保证扩展的正常
+ */
+ private void extensionNameCheck() {
+ if (this.extensionName == null || this.extensionName.isEmpty()) {
+ throw new IllegalArgumentException("请为该shiro加密key检测扩展-设置扩展名称");
+ }
+ }
+
+ /**
+ * 获取扩展名称
+ *
+ * @return String
+ */
+ @Override
+ public String getExtensionName() {
+ this.extensionNameCheck();
+ return this.extensionName;
+ }
+
+ /**
+ * 设置为扫描出了shiro加密的密钥key
+ */
+ protected void setShiroCipherKeyExists() {
+ this.extensionNameCheck();
+ this.isShiroCipherKeyExists = true;
+ }
+
+ /**
+ * 是否存在 shiro加密的密钥key
+ * true 表示 成功扫描出key
+ * false 表示 未能成功扫描出key
+ *
+ * @return Boolean
+ */
+ @Override
+ public Boolean isShiroCipherKeyExists() {
+ this.extensionNameCheck();
+ return this.isShiroCipherKeyExists;
+ }
+
+ /**
+ * 设置程序使用的加密方法
+ */
+ protected void setEncryptMethod(String value) {
+ this.extensionNameCheck();
+ this.encryptMethod = value;
+ }
+
+ /**
+ * 获取加密的方法
+ * 例如返回: cbc, gcm 加密算法
+ *
+ * @return String
+ */
+ @Override
+ public String getEncryptMethod() {
+ this.extensionNameCheck();
+ return this.encryptMethod;
+ }
+
+ /**
+ * 设置加密的密钥key
+ *
+ * @param value
+ */
+ public void setCipherKey(String value) {
+ this.extensionNameCheck();
+ this.cipherKey = value;
+ }
+
+ /**
+ * 获取加密的密钥key
+ *
+ * @return String
+ */
+ @Override
+ public String getCipherKey() {
+ this.extensionNameCheck();
+ return this.cipherKey;
+ }
+
+ /**
+ * 设置http请求与响应对象
+ *
+ * @param httpRequestResponse
+ */
+ protected void setHttpRequestResponse(IHttpRequestResponse httpRequestResponse) {
+ this.extensionNameCheck();
+ this.newHttpRequestResponse = httpRequestResponse;
+ }
+
+ /**
+ * 获取http请求与响应对象
+ *
+ * @return IHttpRequestResponse
+ */
+ @Override
+ public IHttpRequestResponse getHttpRequestResponse() {
+ this.extensionNameCheck();
+ return this.newHttpRequestResponse;
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/IShiroCipherKeyExtension.java b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/IShiroCipherKeyExtension.java
new file mode 100644
index 0000000..0dfdbbe
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionInterface/IShiroCipherKeyExtension.java
@@ -0,0 +1,24 @@
+package burp.Application.ShiroCipherKeyExtension.ExtensionInterface;
+
+import burp.IScanIssue;
+import burp.IHttpRequestResponse;
+
+/**
+ * shiro加密key扩展的公共接口
+ * 所有的抽象类都要继承它并实现所有的接口
+ */
+public interface IShiroCipherKeyExtension {
+ String getExtensionName();
+
+ Boolean isShiroCipherKeyExists();
+
+ String getEncryptMethod();
+
+ String getCipherKey();
+
+ IHttpRequestResponse getHttpRequestResponse();
+
+ IScanIssue export();
+
+ void consoleExport();
+}
diff --git a/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionMethod/ShiroCipherKeyScan.java b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionMethod/ShiroCipherKeyScan.java
new file mode 100644
index 0000000..2ef7b51
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroCipherKeyExtension/ExtensionMethod/ShiroCipherKeyScan.java
@@ -0,0 +1,335 @@
+package burp.Application.ShiroCipherKeyExtension.ExtensionMethod;
+
+import java.net.URL;
+import java.util.Date;
+import java.util.List;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.shiro.subject.SimplePrincipalCollection;
+
+import burp.*;
+
+import burp.Bootstrap.*;
+import burp.Bootstrap.Encrypt.EncryptInterface;
+
+import burp.Application.ShiroCipherKeyExtension.ExtensionInterface.AShiroCipherKeyExtension;
+import burp.Application.ShiroFingerprintExtension.ShiroFingerprint;
+
+import burp.CustomErrorException.DiffPageException;
+import burp.CustomErrorException.TaskTimeoutException;
+
+public class ShiroCipherKeyScan extends AShiroCipherKeyExtension {
+ private GlobalVariableReader globalVariableReader;
+ private GlobalPassiveScanVariableReader globalPassiveScanVariableReader;
+
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+ private PrintWriter stdout;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private ShiroFingerprint shiroFingerprint;
+
+ private List payloads;
+
+ private EncryptInterface encryptClass;
+
+ private Date startDate;
+
+ private Integer maxExecutionTime;
+
+ private CustomBurpHelpers customBurpHelpers;
+
+ private double similarityRatio;
+
+ // 相似度匹配算法,匹配失败的次数
+ private int errorNumber = 0;
+ private int endErrorNumber = 10;
+
+ private IHttpRequestResponse shiroFingerprintHttpRequestResponse;
+
+ private String rememberMeCookieName;
+
+ private String responseRememberMeCookieValue;
+
+ private String newRequestRememberMeCookieValue;
+
+ public ShiroCipherKeyScan(GlobalVariableReader globalVariableReader,
+ GlobalPassiveScanVariableReader globalPassiveScanVariableReader,
+ IBurpExtenderCallbacks callbacks,
+ YamlReader yamlReader,
+ IHttpRequestResponse baseRequestResponse,
+ ShiroFingerprint shiroFingerprint,
+ List payloads,
+ EncryptInterface encryptClass,
+ Date startDate,
+ Integer maxExecutionTime) throws IOException {
+ this.globalVariableReader = globalVariableReader;
+ this.globalPassiveScanVariableReader = globalPassiveScanVariableReader;
+
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+ this.stdout = new PrintWriter(callbacks.getStdout(), true);
+
+ this.yamlReader = yamlReader;
+ this.baseRequestResponse = baseRequestResponse;
+ this.shiroFingerprint = shiroFingerprint;
+ this.payloads = payloads;
+ this.encryptClass = encryptClass;
+ this.startDate = startDate;
+ this.maxExecutionTime = maxExecutionTime;
+
+ this.customBurpHelpers = new CustomBurpHelpers(this.callbacks);
+
+ this.similarityRatio = yamlReader.getDouble("application.shiroCipherKeyExtension.config.similarityRatio");
+
+ this.shiroFingerprintHttpRequestResponse = this.shiroFingerprint.run().getHttpRequestResponse();
+
+ this.rememberMeCookieName = this.shiroFingerprint.run().getResponseDefaultRememberMeCookieName();
+ this.responseRememberMeCookieValue = this.shiroFingerprint.run().getResponseDefaultRememberMeCookieValue();
+ this.newRequestRememberMeCookieValue = "";
+
+ this.setExtensionName("ShiroCipherKeyScan");
+
+ this.runExtension();
+ }
+
+ private void runExtension() throws IOException {
+ if (this.payloads.size() <= 0) {
+ throw new IllegalArgumentException("shiro加密key检测扩展-要进行爆破的payloads不能为空, 请检查");
+ }
+
+ byte[] exp = this.encryptClass.getBytes(new SimplePrincipalCollection());
+
+ // 加密key检测
+ for (String key : this.payloads) {
+ // 这个参数为true说明插件已经被卸载,退出所有任务,避免继续扫描
+ if (this.globalVariableReader.getBooleanData("isExtensionUnload")) {
+ return;
+ }
+
+ // 说明别的线程已经扫描到shiro key了,可以退出这个线程了
+ if (this.globalPassiveScanVariableReader.getBooleanData("isEndShiroCipherKeyTask")) {
+ return;
+ }
+
+ // 说明检测到shiro key了
+ if (this.isShiroCipherKeyExists()) {
+ return;
+ }
+
+ // 如果 相似度匹配算法,匹配失败的次数,超过10次,那么就可以退出了
+ // 因为这种情况下,大概率触发waf规则了, 那么就没必要跑剩下的了
+ if (this.errorNumber >= this.endErrorNumber) {
+ // 抛异常结束任务
+ throw new DiffPageException("shiro key scan too many errors");
+ }
+
+ // 判断程序是否运行超时
+ int startTime = CustomHelpers.getSecondTimestamp(this.startDate);
+ int currentTime = CustomHelpers.getSecondTimestamp(new Date());
+ int runTime = currentTime - startTime;
+ if (runTime >= this.maxExecutionTime) {
+ throw new TaskTimeoutException("shiro key scan task timeout");
+ }
+
+ this.cipherKeyDetection(key, exp);
+ }
+ }
+
+ /**
+ * 加密key检测
+ *
+ * @param key 要爆破的key
+ * @param exp 加密的算法类byte
+ */
+ private void cipherKeyDetection(String key, byte[] exp) {
+ int shiroFingerprintCookieRememberMeNumber = this.getHttpCookieRememberMeNumber(this.shiroFingerprintHttpRequestResponse);
+ String shiroFingerprintHttpBody = this.customBurpHelpers.getHttpResponseBody(this.shiroFingerprintHttpRequestResponse.getResponse());
+
+ // 使用当前可能正确的key-发送可能被此shiro框架成功解密的请求
+ String correctRememberMe = this.encryptClass.encrypt(key, exp);
+ IHttpRequestResponse newHttpRequestResponse1 = this.getNewHttpRequestResponse(correctRememberMe, 3);
+
+ // 判断shiro指纹的请求与当前可能正确key的请求相似度是否差不多一致
+ String newHttpBody1 = this.customBurpHelpers.getHttpResponseBody(newHttpRequestResponse1.getResponse());
+ double htmlSimilarityRatio1 = DiffPage.getRatio(shiroFingerprintHttpBody, newHttpBody1);
+ if (this.similarityRatio > htmlSimilarityRatio1) {
+ this.errorNumber++;
+ return;
+ }
+
+ // 判断当前可能正确的请求-是否被此shiro框架解密
+ int newHttpCookieRememberMeNumber1 = this.getHttpCookieRememberMeNumber(newHttpRequestResponse1);
+ if (newHttpCookieRememberMeNumber1 >= shiroFingerprintCookieRememberMeNumber) {
+ return;
+ }
+
+ // 二次验证-这样可以减少因为waf造成的大量误报
+ // 使用一个必定错误的key-发送一个肯定不会被此shiro框架成功解密的请求
+ // 密钥 errorKey 然后 aes 加密 == U2FsdGVkX19xgIigFNCsuy2aXwtskOnJV8rQkrT9D5Y=
+ String errorKey = "U2FsdGVkX19xgIigFNCsuy2aXwtskOnJV8rQkrT9D5Y=";
+ String errorRememberMe = this.encryptClass.encrypt(errorKey, exp);
+ IHttpRequestResponse newHttpRequestResponse2 = this.getNewHttpRequestResponse(errorRememberMe, 3);
+
+ // 判断shiro指纹的请求与当前必定错误的请求相似度是否差不多一致
+ String newHttpBody2 = this.customBurpHelpers.getHttpResponseBody(newHttpRequestResponse2.getResponse());
+ double htmlSimilarityRatio2 = DiffPage.getRatio(shiroFingerprintHttpBody, newHttpBody2);
+ if (this.similarityRatio > htmlSimilarityRatio2) {
+ this.errorNumber++;
+ return;
+ }
+
+ // 判断当前必定错误的请求-是否被此shiro框架解密
+ int newHttpCookieRememberMeNumber2 = this.getHttpCookieRememberMeNumber(newHttpRequestResponse2);
+ if (newHttpCookieRememberMeNumber2 < shiroFingerprintCookieRememberMeNumber) {
+ return;
+ }
+
+ // 设置问题详情
+ this.setIssuesDetail(newHttpRequestResponse1, key, this.encryptClass.getName(), correctRememberMe);
+ }
+
+ /**
+ * 获取http cookie 记住我出现的次数
+ *
+ * @param httpRequestResponse
+ * @return
+ */
+ private int getHttpCookieRememberMeNumber(IHttpRequestResponse httpRequestResponse) {
+ int number = 0;
+ for (ICookie c : this.helpers.analyzeResponse(httpRequestResponse.getResponse()).getCookies()) {
+ if (c.getName().equals(this.rememberMeCookieName)) {
+ if (c.getValue().equals(this.responseRememberMeCookieValue) || c.getValue().equals("deleteMe")) {
+ number++;
+ }
+ }
+ }
+ return number;
+ }
+
+ /**
+ * 获取新的http请求响应
+ *
+ * @param rememberMe
+ * @param remainingRunNumber 剩余运行次数
+ * @return IHttpRequestResponse
+ */
+ private IHttpRequestResponse getNewHttpRequestResponse(String rememberMe, int remainingRunNumber) {
+ IHttpService httpService = this.baseRequestResponse.getHttpService();
+ IParameter newParameter = this.helpers.buildParameter(
+ this.rememberMeCookieName,
+ rememberMe,
+ (byte) 2);
+ byte[] newRequest = this.helpers.updateParameter(this.baseRequestResponse.getRequest(), newParameter);
+ IHttpRequestResponse newHttpRequestResponse = this.callbacks.makeHttpRequest(httpService, newRequest);
+
+ if (remainingRunNumber <= 1) {
+ return newHttpRequestResponse;
+ }
+ remainingRunNumber--;
+
+ String shiroFingerprintHttpBody = this.customBurpHelpers.getHttpResponseBody(this.shiroFingerprintHttpRequestResponse.getResponse());
+ String newHttpBody = this.customBurpHelpers.getHttpResponseBody(newHttpRequestResponse.getResponse());
+
+ double htmlSimilarityRatio = DiffPage.getRatio(shiroFingerprintHttpBody, newHttpBody);
+ if (this.similarityRatio > htmlSimilarityRatio) {
+ return this.getNewHttpRequestResponse(rememberMe, remainingRunNumber);
+ }
+
+ return newHttpRequestResponse;
+ }
+
+ /**
+ * 设置问题详情
+ */
+ private void setIssuesDetail(
+ IHttpRequestResponse httpRequestResponse,
+ String key,
+ String encryptMethod,
+ String correctRememberMe) {
+ this.setShiroCipherKeyExists();
+ this.setCipherKey(key);
+ this.setEncryptMethod(encryptMethod);
+ this.setHttpRequestResponse(httpRequestResponse);
+ this.setNewRequestRememberMeCookieValue(correctRememberMe);
+ }
+
+ private void setNewRequestRememberMeCookieValue(String value) {
+ this.newRequestRememberMeCookieValue = value;
+ }
+
+ private String getNewRequestRememberMeCookieValue() {
+ return this.newRequestRememberMeCookieValue;
+ }
+
+ @Override
+ public IScanIssue export() {
+ if (!this.isShiroCipherKeyExists()) {
+ return null;
+ }
+
+ IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl();
+
+ String str1 = String.format("
=============ShiroCipherKeyDetail============
");
+ String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName());
+ String str3 = String.format("EncryptMethod: %s
", this.encryptClass.getName());
+ String str4 = String.format("CookieName: %s
", this.rememberMeCookieName);
+ String str5 = String.format("CookieValue: %s
", this.getNewRequestRememberMeCookieValue());
+ String str6 = String.format("ShiroCipherKey: %s
", this.getCipherKey());
+ String str7 = String.format("=====================================
");
+
+ String detail = str1 + str2 + str3 + str4 + str5 + str6 + str7;
+
+ String shiroCipherKeyIssueName = this.yamlReader.getString("application.shiroCipherKeyExtension.config.issueName");
+
+ return new CustomScanIssue(
+ newHttpRequestUrl,
+ shiroCipherKeyIssueName,
+ 0,
+ "High",
+ "Certain",
+ null,
+ null,
+ detail,
+ null,
+ new IHttpRequestResponse[]{newHttpRequestResponse},
+ newHttpRequestResponse.getHttpService()
+ );
+ }
+
+ @Override
+ public void consoleExport() {
+ if (!this.isShiroCipherKeyExists()) {
+ return;
+ }
+
+ IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl();
+ String newHttpRequestMethod = this.helpers.analyzeRequest(newHttpRequestResponse.getRequest()).getMethod();
+ int newHttpResponseStatusCode = this.helpers.analyzeResponse(newHttpRequestResponse.getResponse()).getStatusCode();
+
+ this.stdout.println("");
+ this.stdout.println("===========shiro加密key详情============");
+ this.stdout.println("你好呀~ (≧ω≦*)喵~");
+ this.stdout.println("这边检测到有一个站点使用了 shiro框架 喵~");
+ this.stdout.println(String.format(
+ "注意: 该检测方法, 正确的时候响应包的 %s 会消失, 这表示当前key是正确的",
+ this.rememberMeCookieName));
+ this.stdout.println(String.format("负责检测的插件: %s", this.getExtensionName()));
+ this.stdout.println(String.format("使用的加密方法: %s", this.encryptClass.getName()));
+ this.stdout.println(String.format("url: %s", newHttpRequestUrl));
+ this.stdout.println(String.format("请求方法: %s", newHttpRequestMethod));
+ this.stdout.println(String.format("页面http状态: %d", newHttpResponseStatusCode));
+ this.stdout.println(String.format("对应的Cookie键: %s", this.rememberMeCookieName));
+ this.stdout.println(String.format("对应的Cookie值: %s", this.getNewRequestRememberMeCookieValue()));
+ this.stdout.println(String.format("Shiro加密key: %s", this.getCipherKey()));
+ this.stdout.println("详情请查看-Burp Scanner模块-Issue activity界面");
+ this.stdout.println("===================================");
+ this.stdout.println("");
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKey.java b/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKey.java
new file mode 100644
index 0000000..c6f56c8
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKey.java
@@ -0,0 +1,161 @@
+package burp.Application.ShiroCipherKeyExtension;
+
+import java.util.Date;
+import java.util.List;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import burp.Bootstrap.GlobalPassiveScanVariableReader;
+import burp.IHttpRequestResponse;
+import burp.IBurpExtenderCallbacks;
+
+import burp.Bootstrap.YamlReader;
+import burp.Bootstrap.GlobalVariableReader;
+import burp.Bootstrap.Encrypt.CbcEncrypt;
+import burp.Bootstrap.Encrypt.GcmEncrypt;
+import burp.Bootstrap.Encrypt.EncryptInterface;
+
+import burp.Application.ShiroFingerprintExtension.ShiroFingerprint;
+
+import burp.Application.ShiroCipherKeyExtension.ExtensionInterface.IShiroCipherKeyExtension;
+
+public class ShiroCipherKey implements Runnable {
+ private GlobalVariableReader globalVariableReader;
+ private GlobalPassiveScanVariableReader globalPassiveScanVariableReader;
+
+ private IBurpExtenderCallbacks callbacks;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private ShiroFingerprint shiroFingerprint;
+
+ private String callClassName;
+
+ private List payloadList;
+
+ /**
+ * 该模块启动日期
+ */
+ private final Date startDate = new Date();
+
+ /**
+ * 程序最大执行时间,单位为秒
+ * 注意: 会根据payload的添加而添加
+ */
+ private final int maxExecutionTime = 60;
+
+ public ShiroCipherKey(GlobalVariableReader globalVariableReader,
+ GlobalPassiveScanVariableReader globalPassiveScanVariableReader,
+ IBurpExtenderCallbacks callbacks,
+ YamlReader yamlReader,
+ IHttpRequestResponse baseRequestResponse,
+ ShiroFingerprint shiroFingerprint,
+ String callClassName,
+ List payloadList) {
+ this.globalVariableReader = globalVariableReader;
+ this.globalPassiveScanVariableReader = globalPassiveScanVariableReader;
+
+ this.callbacks = callbacks;
+
+ this.yamlReader = yamlReader;
+
+ this.baseRequestResponse = baseRequestResponse;
+
+ this.shiroFingerprint = shiroFingerprint;
+
+ this.callClassName = callClassName;
+
+ this.payloadList = payloadList;
+ }
+
+ @Override
+ public void run() {
+ if (callClassName == null || callClassName.length() <= 0) {
+ throw new IllegalArgumentException("Application.ShiroCipherKeyExtension-请输入要调用的插件名称");
+ }
+
+ if (this.payloadList.size() == 0) {
+ throw new IllegalArgumentException("Application.ShiroCipherKeyExtension-获取的payloads为空,无法正常运行");
+ }
+
+ try {
+ Class c = Class.forName("burp.Application.ShiroCipherKeyExtension.ExtensionMethod." + callClassName);
+ Constructor cConstructor = c.getConstructor(
+ GlobalVariableReader.class,
+ GlobalPassiveScanVariableReader.class,
+ IBurpExtenderCallbacks.class,
+ YamlReader.class,
+ IHttpRequestResponse.class,
+ ShiroFingerprint.class,
+ List.class,
+ EncryptInterface.class,
+ Date.class,
+ Integer.class);
+
+ Boolean isScanCbcEncrypt = this.yamlReader.getBoolean("application.shiroCipherKeyExtension.config.isScanCbcEncrypt");
+ if (isScanCbcEncrypt) {
+ if (this.globalPassiveScanVariableReader.getBooleanData("isEndShiroCipherKeyTask")) {
+ return;
+ }
+
+ IShiroCipherKeyExtension shiroCipherKey1 = (IShiroCipherKeyExtension) cConstructor.newInstance(
+ this.globalVariableReader,
+ this.globalPassiveScanVariableReader,
+ this.callbacks,
+ this.yamlReader,
+ this.baseRequestResponse,
+ this.shiroFingerprint,
+ this.payloadList,
+ new CbcEncrypt(),
+ this.startDate,
+ this.getMaxExecutionTime());
+
+ if (shiroCipherKey1.isShiroCipherKeyExists()) {
+ this.globalPassiveScanVariableReader.putBooleanData("isEndShiroCipherKeyTask", true);
+ this.globalPassiveScanVariableReader.putShiroCipherKeyExtensionData("shiroCipherKey", shiroCipherKey1);
+ }
+ }
+
+ Boolean isScanGcmEncrypt = this.yamlReader.getBoolean("application.shiroCipherKeyExtension.config.isScanGcmEncrypt");
+ if (isScanGcmEncrypt) {
+ if (this.globalPassiveScanVariableReader.getBooleanData("isEndShiroCipherKeyTask")) {
+ return;
+ }
+
+ IShiroCipherKeyExtension shiroCipherKey2 = (IShiroCipherKeyExtension) cConstructor.newInstance(
+ this.globalVariableReader,
+ this.globalPassiveScanVariableReader,
+ this.callbacks,
+ this.yamlReader,
+ this.baseRequestResponse,
+ this.shiroFingerprint,
+ this.payloadList,
+ new GcmEncrypt(),
+ this.startDate,
+ this.getMaxExecutionTime());
+
+ if (shiroCipherKey2.isShiroCipherKeyExists()) {
+ this.globalPassiveScanVariableReader.putBooleanData("isEndShiroCipherKeyTask", true);
+ this.globalPassiveScanVariableReader.putShiroCipherKeyExtensionData("shiroCipherKey", shiroCipherKey2);
+ }
+ }
+ } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace(new PrintWriter(this.callbacks.getStderr(), true));
+ }
+ }
+
+ /**
+ * 程序最大执行时间,单位为秒
+ * 会根据payload的添加而添加
+ *
+ * @return
+ */
+ private Integer getMaxExecutionTime() {
+ Integer maxExecutionTime = this.maxExecutionTime;
+ maxExecutionTime += this.payloadList.size() * 6;
+ return maxExecutionTime;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKeyThread.java b/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKeyThread.java
new file mode 100644
index 0000000..faad2ef
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroCipherKeyExtension/ShiroCipherKeyThread.java
@@ -0,0 +1,84 @@
+package burp.Application.ShiroCipherKeyExtension;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import burp.IHttpRequestResponse;
+import burp.IBurpExtenderCallbacks;
+
+import burp.Bootstrap.YamlReader;
+import burp.Bootstrap.CustomHelpers;
+import burp.Bootstrap.GlobalVariableReader;
+import burp.Bootstrap.GlobalPassiveScanVariableReader;
+
+import burp.Application.ShiroFingerprintExtension.ShiroFingerprint;
+
+public class ShiroCipherKeyThread {
+ private List threadPool = new ArrayList<>();
+
+ public ShiroCipherKeyThread(GlobalVariableReader globalVariableReader,
+ GlobalPassiveScanVariableReader globalPassiveScanVariableReader,
+ IBurpExtenderCallbacks callbacks,
+ YamlReader yamlReader,
+ IHttpRequestResponse baseRequestResponse,
+ ShiroFingerprint shiroFingerprint,
+ String callClassName) {
+ // 是否结束shiro加密key扩展任务
+ // 用于多线程,跑到key,把程序快速退出去,避免资源浪费与卡顿
+ // true = 结束, false = 不结束
+ globalPassiveScanVariableReader.putBooleanData("isEndShiroCipherKeyTask", false);
+
+ if (callClassName == null || callClassName.length() <= 0) {
+ throw new IllegalArgumentException("Application.ShiroCipherKeyExtension-请输入要调用的插件名称");
+ }
+
+ List payloads = yamlReader.getStringList("application.shiroCipherKeyExtension.config.payloads");
+ if (payloads.size() == 0) {
+ throw new IllegalArgumentException("Application.ShiroCipherKeyExtension-获取的payloads为空,无法正常运行");
+ }
+
+ // payload按照配置线程数分块
+ Integer shiroCipherKeyThreadTotal = yamlReader.getInteger("application.shiroCipherKeyExtension.config.threadTotal");
+ List> payloadChunk = CustomHelpers.listChunkSplit(payloads, shiroCipherKeyThreadTotal);
+
+ // 建立线程池
+ for (List payloadList : payloadChunk) {
+ this.threadPool.add(new Thread(
+ new ShiroCipherKey(
+ globalVariableReader, globalPassiveScanVariableReader, callbacks,
+ yamlReader, baseRequestResponse, shiroFingerprint,
+ callClassName, payloadList)
+ ));
+ }
+
+ // 线程启动
+ for (int i = 0; i < this.threadPool.size(); i++) {
+ this.threadPool.get(i).start();
+ }
+ }
+
+ /**
+ * 判断线程任务是否执行完毕
+ *
+ * @return
+ */
+ public Boolean isTaskComplete() {
+ // 开启的线程总数
+ Integer threadCcount = this.threadPool.size();
+
+ // 线程完成数量
+ Integer threadNum = 0;
+
+ for (Thread t : this.threadPool) {
+ if (!t.isAlive()) {
+ threadNum++;
+ }
+ }
+
+ if (threadNum.equals(threadCcount)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/AShiroFingerprintExtension.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/AShiroFingerprintExtension.java
new file mode 100644
index 0000000..f81b2dc
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/AShiroFingerprintExtension.java
@@ -0,0 +1,211 @@
+package burp.Application.ShiroFingerprintExtension.ExtensionInterface;
+
+import burp.IHttpRequestResponse;
+
+/**
+ * shiro指纹扩展的抽象类
+ * 所有的shiro指纹检测的方法都要继承它并实现所有的接口
+ */
+public abstract class AShiroFingerprintExtension implements IShiroFingerprintExtension {
+ private String extensionName = "";
+
+ private Boolean isRunExtension = false;
+
+ private Boolean isShiroFingerprint = false;
+
+ private String requestRememberMeCookieName = "";
+ private String requestRememberMeCookieValue = "";
+
+ private String responseRememberMeCookieName = "";
+ private String responseRememberMeCookieValue = "";
+
+ private IHttpRequestResponse newHttpRequestResponse;
+
+ /**
+ * 设置扩展名称 (必须的)
+ *
+ * @param value
+ */
+ protected void setExtensionName(String value) {
+ if (value == null || value.isEmpty()) {
+ throw new IllegalArgumentException("shiro指纹扫描扩展-扩展名称不能为空");
+ }
+ this.extensionName = value;
+ }
+
+ /**
+ * 扩展名称检查
+ * 作用: 让所有不设置扩展名称的扩展无法正常使用, 防止直接调用本类的其他方法, 保证扩展的正常
+ */
+ private void extensionNameCheck() {
+ if (this.extensionName == null || this.extensionName.isEmpty()) {
+ throw new IllegalArgumentException("请为该shiro指纹扫描扩展-设置扩展名称");
+ }
+ }
+
+ /**
+ * 获取扩展名称
+ *
+ * @return String
+ */
+ @Override
+ public String getExtensionName() {
+ this.extensionNameCheck();
+ return this.extensionName;
+ }
+
+ /**
+ * 注册插件 (必须的)
+ * 扩展在运行之前必须调用该接口注册, 否则将无法调用本类的其他方法
+ */
+ protected void registerExtension() {
+ this.extensionNameCheck();
+ this.isRunExtension = true;
+ }
+
+ /**
+ * 注册扩展检查
+ * 作用: 让所有未调用方法 registerExtension() 的接口, 无法使用本类的其他方法, 保证扩展的正常
+ */
+ private void registerExtensionCheck() {
+ if (!this.isRunExtension) {
+ throw new IllegalArgumentException("注意: 该指纹模块未注册,无法使用");
+ }
+ }
+
+ /**
+ * 是否运行扩展
+ * true 运行
+ * false 不运行
+ *
+ * @return Boolean
+ */
+ @Override
+ public Boolean isRunExtension() {
+ return this.isRunExtension;
+ }
+
+ /**
+ * 设置为shiro指纹
+ */
+ protected void setShiroFingerprint() {
+ this.registerExtensionCheck();
+ this.isShiroFingerprint = true;
+ }
+
+ /**
+ * 是否shiro框架
+ *
+ * @return Boolean
+ */
+ @Override
+ public Boolean isShiroFingerprint() {
+ this.registerExtensionCheck();
+ return this.isShiroFingerprint;
+ }
+
+ /**
+ * 设置请求默认“记住我”的Cookie名
+ *
+ * @param value
+ */
+ protected void setRequestDefaultRememberMeCookieName(String value) {
+ this.registerExtensionCheck();
+ this.requestRememberMeCookieName = value;
+ }
+
+ /**
+ * 获取请求默认“记住我”的Cookie名
+ *
+ * @return String
+ */
+ @Override
+ public String getRequestDefaultRememberMeCookieName() {
+ this.registerExtensionCheck();
+ return this.requestRememberMeCookieName;
+ }
+
+ /**
+ * 设置请求默认“记住我”的Cookie值
+ *
+ * @param value
+ */
+ protected void setRequestDefaultRememberMeCookieValue(String value) {
+ this.registerExtensionCheck();
+ this.requestRememberMeCookieValue = value;
+ }
+
+ /**
+ * 获取请求默认“记住我”的Cookie值
+ *
+ * @return String
+ */
+ @Override
+ public String getRequestDefaultRememberMeCookieValue() {
+ this.registerExtensionCheck();
+ return this.requestRememberMeCookieValue;
+ }
+
+ /**
+ * 设置响应默认“记住我”的Cookie名称
+ *
+ * @param value
+ */
+ protected void setResponseDefaultRememberMeCookieName(String value) {
+ this.registerExtensionCheck();
+ this.responseRememberMeCookieName = value;
+ }
+
+ /**
+ * 获取响应默认“记住我”的Cookie名称
+ *
+ * @return String
+ */
+ @Override
+ public String getResponseDefaultRememberMeCookieName() {
+ this.registerExtensionCheck();
+ return this.responseRememberMeCookieName;
+ }
+
+ /**
+ * 设置响应默认的“记住我”Cookie值
+ *
+ * @param value
+ */
+ protected void setResponseDefaultRememberMeCookieValue(String value) {
+ this.registerExtensionCheck();
+ this.responseRememberMeCookieValue = value;
+ }
+
+ /**
+ * 获取设置响应默认的“记住我”Cookie值
+ *
+ * @return
+ */
+ @Override
+ public String getResponseDefaultRememberMeCookieValue() {
+ this.registerExtensionCheck();
+ return this.responseRememberMeCookieValue;
+ }
+
+ /**
+ * 设置http请求与响应对象
+ *
+ * @param httpRequestResponse
+ */
+ protected void setHttpRequestResponse(IHttpRequestResponse httpRequestResponse) {
+ this.registerExtensionCheck();
+ this.newHttpRequestResponse = httpRequestResponse;
+ }
+
+ /**
+ * 获取http请求与响应对象
+ *
+ * @return IHttpRequestResponse
+ */
+ @Override
+ public IHttpRequestResponse getHttpRequestResponse() {
+ this.registerExtensionCheck();
+ return this.newHttpRequestResponse;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/IShiroFingerprintExtension.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/IShiroFingerprintExtension.java
new file mode 100644
index 0000000..1ec2c92
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionInterface/IShiroFingerprintExtension.java
@@ -0,0 +1,30 @@
+package burp.Application.ShiroFingerprintExtension.ExtensionInterface;
+
+import burp.IScanIssue;
+import burp.IHttpRequestResponse;
+
+/**
+ * shiro指纹扩展的公共接口
+ * 所有的抽象类都要继承它并实现所有的接口
+ */
+public interface IShiroFingerprintExtension {
+ String getExtensionName();
+
+ Boolean isRunExtension();
+
+ Boolean isShiroFingerprint();
+
+ String getRequestDefaultRememberMeCookieName();
+
+ String getRequestDefaultRememberMeCookieValue();
+
+ String getResponseDefaultRememberMeCookieName();
+
+ String getResponseDefaultRememberMeCookieValue();
+
+ IHttpRequestResponse getHttpRequestResponse();
+
+ IScanIssue export();
+
+ void consoleExport();
+}
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint1.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint1.java
new file mode 100644
index 0000000..3b254bc
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint1.java
@@ -0,0 +1,142 @@
+package burp.Application.ShiroFingerprintExtension.ExtensionMethod;
+
+import burp.*;
+import burp.Application.ShiroFingerprintExtension.ExtensionInterface.AShiroFingerprintExtension;
+import burp.Bootstrap.YamlReader;
+
+import java.io.PrintWriter;
+import java.net.URL;
+
+public class ShiroFingerprint1 extends AShiroFingerprintExtension {
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private String rememberMeCookieName = "rememberMe";
+ private String rememberMeCookieValue = "1";
+
+ public ShiroFingerprint1(IBurpExtenderCallbacks callbacks, YamlReader yamlReader, IHttpRequestResponse baseRequestResponse) {
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+
+ this.yamlReader = yamlReader;
+
+ this.baseRequestResponse = baseRequestResponse;
+
+ this.setExtensionName("ShiroFingerprint1");
+
+ this.runConditionCheck();
+ }
+
+ private void runConditionCheck() {
+ this.registerExtension();
+ }
+
+ public void runExtension() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ IHttpService httpService = this.baseRequestResponse.getHttpService();
+
+ IParameter newParameter = this.helpers.buildParameter(this.rememberMeCookieName, this.rememberMeCookieValue, (byte) 2);
+ byte[] newRequest = this.helpers.updateParameter(this.baseRequestResponse.getRequest(), newParameter);
+ IHttpRequestResponse newHttpRequestResponse = this.callbacks.makeHttpRequest(httpService, newRequest);
+
+ this.setHttpRequestResponse(newHttpRequestResponse);
+
+ for (ICookie c : this.helpers.analyzeResponse(newHttpRequestResponse.getResponse()).getCookies()) {
+ if (c.getName().equals(this.rememberMeCookieName)) {
+ this.setShiroFingerprint();
+
+ this.setRequestDefaultRememberMeCookieName(this.rememberMeCookieName);
+ this.setRequestDefaultRememberMeCookieValue(this.rememberMeCookieValue);
+
+ this.setResponseDefaultRememberMeCookieName(c.getName());
+ this.setResponseDefaultRememberMeCookieValue(c.getValue());
+ break;
+ }
+ }
+ }
+
+ @Override
+ public IScanIssue export() {
+ if (!this.isRunExtension()) {
+ return null;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return null;
+ }
+
+ IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl();
+
+ String str1 = String.format("
============ShiroFingerprintDetail============
");
+ String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName());
+ String str3 = String.format("RequestCookiePayload: %s=%s
",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue());
+ String str4 = String.format("ResponseReturnCookie: %s=%s
",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue());
+ String str5 = String.format("=====================================
");
+
+ String detail = str1 + str2 + str3 + str4 + str5;
+
+ String shiroFingerprintIssueName = this.yamlReader.getString("application.shiroFingerprintExtension.config.issueName");
+
+ return new CustomScanIssue(
+ newHttpRequestUrl,
+ shiroFingerprintIssueName,
+ 0,
+ "Information",
+ "Certain",
+ null,
+ null,
+ detail,
+ null,
+ new IHttpRequestResponse[]{newHttpRequestResponse},
+ newHttpRequestResponse.getHttpService()
+ );
+ }
+
+ @Override
+ public void consoleExport() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return;
+ }
+
+ IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl();
+ String newHttpRequestMethod = this.helpers.analyzeRequest(newHttpRequestResponse.getRequest()).getMethod();
+ int newHttpResponseStatusCode = this.helpers.analyzeResponse(newHttpRequestResponse.getResponse()).getStatusCode();
+
+ PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true);
+
+ stdout.println("");
+ stdout.println("==============shiro指纹详情============");
+ stdout.println("你好呀~ (≧ω≦*)喵~");
+ stdout.println("这边检测到有一个站点使用了 shiro框架 喵~");
+ stdout.println(String.format("负责检测的插件: %s", this.getExtensionName()));
+ stdout.println(String.format("url: %s", newHttpRequestUrl));
+ stdout.println(String.format("请求方法: %s", newHttpRequestMethod));
+ stdout.println(String.format("页面http状态: %d", newHttpResponseStatusCode));
+ stdout.println(String.format("请求对应的cookie: %s=%s",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue()));
+ stdout.println(String.format("响应返回的cookie: %s=%s",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue()));
+ stdout.println("详情请查看-Burp Scanner模块-Issue activity界面");
+ stdout.println("===================================");
+ stdout.println("");
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint2.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint2.java
new file mode 100644
index 0000000..59d35bb
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint2.java
@@ -0,0 +1,173 @@
+package burp.Application.ShiroFingerprintExtension.ExtensionMethod;
+
+import burp.*;
+import burp.Application.ShiroFingerprintExtension.ExtensionInterface.AShiroFingerprintExtension;
+import burp.Bootstrap.YamlReader;
+
+import java.io.PrintWriter;
+import java.net.URL;
+
+public class ShiroFingerprint2 extends AShiroFingerprintExtension {
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private String rememberMeCookieValue = "2";
+
+ public ShiroFingerprint2(IBurpExtenderCallbacks callbacks, YamlReader yamlReader, IHttpRequestResponse baseRequestResponse) {
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+
+ this.yamlReader = yamlReader;
+
+ this.baseRequestResponse = baseRequestResponse;
+
+ this.setExtensionName("ShiroFingerprint2");
+
+ this.runConditionCheck();
+ }
+
+ /**
+ * 原始请求响应返回 cookie 的 value 带了 deleteMe 则进入该流程
+ */
+ private void runConditionCheck() {
+ for (ICookie c : this.helpers.analyzeResponse(this.baseRequestResponse.getResponse()).getCookies()) {
+ if (c.getValue().equals("deleteMe")) {
+ this.registerExtension();
+ break;
+ }
+ }
+ }
+
+ public void runExtension() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ // 先保存一个基础的请求响应
+ this.setHttpRequestResponse(this.baseRequestResponse);
+
+ for (ICookie c : this.helpers.analyzeResponse(this.baseRequestResponse.getResponse()).getCookies()) {
+ if (c.getValue().equals("deleteMe")) {
+ this.setShiroFingerprint();
+
+ // 通过返回包的key重新构造一个请求发过去
+ // 这样二次确认过的请求响应, 可以获得最真实的结果
+ IHttpRequestResponse newHttpRequestResponse = this.getNewHttpRequestResponse(
+ c.getName(),
+ this.rememberMeCookieValue);
+
+ // 二次确认的请求确定是shiro框架了
+ // 保存这个最真实的结果, 覆盖上面那个基础的请求响应
+ this.setHttpRequestResponse(newHttpRequestResponse);
+
+ this.setRequestDefaultRememberMeCookieName(c.getName());
+ this.setRequestDefaultRememberMeCookieValue(this.rememberMeCookieValue);
+
+ this.setResponseDefaultRememberMeCookieName(c.getName());
+ this.setResponseDefaultRememberMeCookieValue(c.getValue());
+ break;
+ }
+ }
+ }
+
+ /**
+ * 获取新的http请求响应
+ *
+ * @param rememberMeCookieName
+ * @param rememberMeCookieValue
+ * @return IHttpRequestResponse
+ */
+ private IHttpRequestResponse getNewHttpRequestResponse(String rememberMeCookieName, String rememberMeCookieValue) {
+ IHttpService httpService = this.baseRequestResponse.getHttpService();
+ IParameter newParameter = this.helpers.buildParameter(
+ rememberMeCookieName,
+ rememberMeCookieValue,
+ (byte) 2);
+ byte[] newRequest = this.helpers.updateParameter(this.baseRequestResponse.getRequest(), newParameter);
+ IHttpRequestResponse newHttpRequestResponse = this.callbacks.makeHttpRequest(httpService, newRequest);
+ return newHttpRequestResponse;
+ }
+
+ @Override
+ public IScanIssue export() {
+ if (!this.isRunExtension()) {
+ return null;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return null;
+ }
+
+ IHttpRequestResponse baseHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(baseHttpRequestResponse).getUrl();
+
+ String str1 = String.format("
============ShiroFingerprintDetail============
");
+ String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName());
+ String str3 = String.format("RequestCookiePayload: %s=%s
",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue());
+ String str4 = String.format("ResponseReturnCookie: %s=%s
",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue());
+ String str5 = String.format("=====================================
");
+
+ String detail = str1 + str2 + str3 + str4 + str5;
+
+ String shiroFingerprintIssueName = this.yamlReader.getString("application.shiroFingerprintExtension.config.issueName");
+
+ return new CustomScanIssue(
+ newHttpRequestUrl,
+ shiroFingerprintIssueName,
+ 0,
+ "Information",
+ "Certain",
+ null,
+ null,
+ detail,
+ null,
+ new IHttpRequestResponse[]{baseHttpRequestResponse},
+ baseHttpRequestResponse.getHttpService()
+ );
+ }
+
+ @Override
+ public void consoleExport() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return;
+ }
+
+ IHttpRequestResponse baseHttpRequestResponse = this.getHttpRequestResponse();
+ URL baseHttpRequestUrl = this.helpers.analyzeRequest(baseHttpRequestResponse).getUrl();
+ String baseHttpRequestMethod = this.helpers.analyzeRequest(baseHttpRequestResponse.getRequest()).getMethod();
+ int baseHttpResponseStatusCode = this.helpers.analyzeResponse(baseHttpRequestResponse.getResponse()).getStatusCode();
+
+ PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true);
+
+ stdout.println("");
+ stdout.println("=============shiro指纹详情============");
+ stdout.println("你好呀~ (≧ω≦*)喵~");
+ stdout.println("这边检测到有一个站点使用了 shiro框架 喵~");
+ stdout.println(String.format("负责检测的插件: %s", this.getExtensionName()));
+ stdout.println(String.format("url: %s", baseHttpRequestUrl));
+ stdout.println(String.format("请求方法: %s", baseHttpRequestMethod));
+ stdout.println(String.format("页面http状态: %d", baseHttpResponseStatusCode));
+ stdout.println("注意: 原始请求响应返回了 shiro 关键字所以没有发送新请求");
+ stdout.println(String.format("请求对应的cookie: %s=%s",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue()));
+ stdout.println(String.format("响应返回的cookie: %s=%s",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue()));
+ stdout.println("详情请查看-Burp Scanner模块-Issue activity界面");
+ stdout.println("===================================");
+ stdout.println("");
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint3.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint3.java
new file mode 100644
index 0000000..60a8c95
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ExtensionMethod/ShiroFingerprint3.java
@@ -0,0 +1,161 @@
+package burp.Application.ShiroFingerprintExtension.ExtensionMethod;
+
+import burp.*;
+import burp.Application.ShiroFingerprintExtension.ExtensionInterface.AShiroFingerprintExtension;
+import burp.Bootstrap.YamlReader;
+
+import java.io.PrintWriter;
+import java.net.URL;
+
+public class ShiroFingerprint3 extends AShiroFingerprintExtension {
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private String rememberMeCookieName = "rememberMe";
+ private String rememberMeCookieValue = "3";
+
+ public ShiroFingerprint3(IBurpExtenderCallbacks callbacks, YamlReader yamlReader, IHttpRequestResponse baseRequestResponse) {
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+
+ this.yamlReader = yamlReader;
+
+ this.baseRequestResponse = baseRequestResponse;
+
+ this.setExtensionName("ShiroFingerprint3");
+
+ this.runConditionCheck();
+ }
+
+ /**
+ * 原始请求 cookie 的 key 带了 rememberMe 则进入该流程
+ */
+ private void runConditionCheck() {
+ for (IParameter p : this.helpers.analyzeRequest(this.baseRequestResponse.getRequest()).getParameters()) {
+ if (p.getType() != 2) {
+ continue;
+ }
+ if (!p.getName().equals(this.rememberMeCookieName)) {
+ continue;
+ }
+ if (p.getValue() == null || p.getValue().length() <= 0) {
+ continue;
+ }
+
+ for (ICookie c : this.helpers.analyzeResponse(this.baseRequestResponse.getResponse()).getCookies()) {
+ if (c.getName().equals(this.rememberMeCookieName)) {
+ if (c.getValue().equals("deleteMe")) {
+ this.registerExtension();
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public void runExtension() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ this.setHttpRequestResponse(this.baseRequestResponse);
+
+ for (ICookie c : this.helpers.analyzeResponse(this.baseRequestResponse.getResponse()).getCookies()) {
+ if (c.getName().equals(this.rememberMeCookieName)) {
+ if (c.getValue().equals("deleteMe")) {
+ this.setShiroFingerprint();
+
+ this.setRequestDefaultRememberMeCookieName(this.rememberMeCookieName);
+ this.setRequestDefaultRememberMeCookieValue(this.rememberMeCookieValue);
+
+ this.setResponseDefaultRememberMeCookieName(c.getName());
+ this.setResponseDefaultRememberMeCookieValue(c.getValue());
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public IScanIssue export() {
+ if (!this.isRunExtension()) {
+ return null;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return null;
+ }
+
+ IHttpRequestResponse baseHttpRequestResponse = this.getHttpRequestResponse();
+ URL newHttpRequestUrl = this.helpers.analyzeRequest(baseHttpRequestResponse).getUrl();
+
+ String str1 = String.format("
============ShiroFingerprintDetail============
");
+ String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName());
+ String str3 = String.format("RequestCookiePayload: %s=%s
",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue());
+ String str4 = String.format("ResponseReturnCookie: %s=%s
",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue());
+ String str5 = String.format("=====================================
");
+
+ String detail = str1 + str2 + str3 + str4 + str5;
+
+ String shiroFingerprintIssueName = this.yamlReader.getString("application.shiroFingerprintExtension.config.issueName");
+
+ return new CustomScanIssue(
+ newHttpRequestUrl,
+ shiroFingerprintIssueName,
+ 0,
+ "Information",
+ "Certain",
+ null,
+ null,
+ detail,
+ null,
+ new IHttpRequestResponse[]{baseHttpRequestResponse},
+ baseHttpRequestResponse.getHttpService()
+ );
+ }
+
+ @Override
+ public void consoleExport() {
+ if (!this.isRunExtension()) {
+ return;
+ }
+
+ if (!this.isShiroFingerprint()) {
+ return;
+ }
+
+ IHttpRequestResponse baseHttpRequestResponse = this.getHttpRequestResponse();
+ URL baseHttpRequestUrl = this.helpers.analyzeRequest(baseHttpRequestResponse).getUrl();
+ String baseHttpRequestMethod = this.helpers.analyzeRequest(baseHttpRequestResponse.getRequest()).getMethod();
+ int baseHttpResponseStatusCode = this.helpers.analyzeResponse(baseHttpRequestResponse.getResponse()).getStatusCode();
+
+ PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true);
+
+ stdout.println("");
+ stdout.println("==============shiro指纹详情============");
+ stdout.println("你好呀~ (≧ω≦*)喵~");
+ stdout.println("这边检测到有一个站点使用了 shiro框架 喵~");
+ stdout.println(String.format("负责检测的插件: %s", this.getExtensionName()));
+ stdout.println(String.format("url: %s", baseHttpRequestUrl));
+ stdout.println(String.format("请求方法: %s", baseHttpRequestMethod));
+ stdout.println(String.format("页面http状态: %d", baseHttpResponseStatusCode));
+ stdout.println("注意: 原始请求自己添加了 shiro 关键字所以没有发送新请求");
+ stdout.println(String.format("请求对应的cookie: %s=%s",
+ this.getRequestDefaultRememberMeCookieName(),
+ this.getRequestDefaultRememberMeCookieValue()));
+ stdout.println(String.format("响应返回的cookie: %s=%s",
+ this.getResponseDefaultRememberMeCookieName(),
+ this.getResponseDefaultRememberMeCookieValue()));
+ stdout.println("详情请查看-Burp Scanner模块-Issue activity界面");
+ stdout.println("===================================");
+ stdout.println("");
+ }
+}
diff --git a/src/main/java/burp/Application/ShiroFingerprintExtension/ShiroFingerprint.java b/src/main/java/burp/Application/ShiroFingerprintExtension/ShiroFingerprint.java
new file mode 100644
index 0000000..c5b2d58
--- /dev/null
+++ b/src/main/java/burp/Application/ShiroFingerprintExtension/ShiroFingerprint.java
@@ -0,0 +1,57 @@
+package burp.Application.ShiroFingerprintExtension;
+
+import burp.IHttpRequestResponse;
+import burp.IBurpExtenderCallbacks;
+
+import burp.Bootstrap.YamlReader;
+
+import burp.Application.ShiroFingerprintExtension.ExtensionMethod.ShiroFingerprint1;
+import burp.Application.ShiroFingerprintExtension.ExtensionMethod.ShiroFingerprint2;
+import burp.Application.ShiroFingerprintExtension.ExtensionMethod.ShiroFingerprint3;
+
+import burp.Application.ShiroFingerprintExtension.ExtensionInterface.IShiroFingerprintExtension;
+
+public class ShiroFingerprint {
+ private IBurpExtenderCallbacks callbacks;
+
+ private YamlReader yamlReader;
+
+ private IHttpRequestResponse baseRequestResponse;
+
+ private IShiroFingerprintExtension shiroFingerprint;
+
+ public ShiroFingerprint(IBurpExtenderCallbacks callbacks, YamlReader yamlReader, IHttpRequestResponse baseRequestResponse) {
+ this.callbacks = callbacks;
+
+ this.yamlReader = yamlReader;
+
+ this.baseRequestResponse = baseRequestResponse;
+
+ this.shiroFingerprint = setShiroFingerprint();
+ }
+
+ private IShiroFingerprintExtension setShiroFingerprint() {
+ // 原始请求 cookie 的 key 带了 rememberMe 则进入该流程
+ ShiroFingerprint3 shiroFingerprint3 = new ShiroFingerprint3(this.callbacks, this.yamlReader, this.baseRequestResponse);
+ if (shiroFingerprint3.isRunExtension()) {
+ shiroFingerprint3.runExtension();
+ return shiroFingerprint3;
+ }
+
+ // 原始请求响应返回 cookie 的 value 带了 deleteMe 则进入该流程
+ ShiroFingerprint2 shiroFingerprint2 = new ShiroFingerprint2(this.callbacks, this.yamlReader, this.baseRequestResponse);
+ if (shiroFingerprint2.isRunExtension()) {
+ shiroFingerprint2.runExtension();
+ return shiroFingerprint2;
+ }
+
+ // 上面的条件都不满足时,进入该流程
+ ShiroFingerprint1 shiroFingerprint1 = new ShiroFingerprint1(this.callbacks, this.yamlReader, this.baseRequestResponse);
+ shiroFingerprint1.runExtension();
+ return shiroFingerprint1;
+ }
+
+ public IShiroFingerprintExtension run() {
+ return this.shiroFingerprint;
+ }
+}
diff --git a/src/main/java/burp/Bootstrap/CustomBurpHelpers.java b/src/main/java/burp/Bootstrap/CustomBurpHelpers.java
new file mode 100644
index 0000000..3e4bf91
--- /dev/null
+++ b/src/main/java/burp/Bootstrap/CustomBurpHelpers.java
@@ -0,0 +1,68 @@
+package burp.Bootstrap;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+import burp.*;
+
+public class CustomBurpHelpers {
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+
+ public CustomBurpHelpers(IBurpExtenderCallbacks callbacks) {
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+ }
+
+ /**
+ * 获取-插件运行路径
+ *
+ * @return
+ */
+ public String getExtensionFilePath() {
+ String path = "";
+ Integer lastIndex = this.callbacks.getExtensionFilename().lastIndexOf(File.separator);
+ path = this.callbacks.getExtensionFilename().substring(0, lastIndex) + File.separator;
+ return path;
+ }
+
+ /**
+ * 获取请求的Body内容
+ *
+ * @return String
+ */
+ public String getHttpRequestBody(byte[] request) {
+ IRequestInfo requestInfo = this.helpers.analyzeRequest(request);
+
+ int httpRequestBodyOffset = requestInfo.getBodyOffset();
+ int httpRequestBodyLength = request.length - httpRequestBodyOffset;
+
+ String httpRequestBody = null;
+ try {
+ httpRequestBody = new String(request, httpRequestBodyOffset, httpRequestBodyLength, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ return httpRequestBody;
+ }
+
+ /**
+ * 获取响应的Body内容
+ *
+ * @return String
+ */
+ public String getHttpResponseBody(byte[] response) {
+ IResponseInfo responseInfo = this.helpers.analyzeResponse(response);
+
+ int httpResponseBodyOffset = responseInfo.getBodyOffset();
+ int httpResponseBodyLength = response.length - httpResponseBodyOffset;
+
+ String httpResponseBody = null;
+ try {
+ httpResponseBody = new String(response, httpResponseBodyOffset, httpResponseBodyLength, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ return httpResponseBody;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/burp/Bootstrap/CustomBurpUrl.java b/src/main/java/burp/Bootstrap/CustomBurpUrl.java
new file mode 100644
index 0000000..d22f48f
--- /dev/null
+++ b/src/main/java/burp/Bootstrap/CustomBurpUrl.java
@@ -0,0 +1,106 @@
+package burp.Bootstrap;
+
+import java.net.URL;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+
+import burp.IExtensionHelpers;
+import burp.IHttpRequestResponse;
+import burp.IBurpExtenderCallbacks;
+
+public class CustomBurpUrl {
+ private IBurpExtenderCallbacks callbacks;
+ private IExtensionHelpers helpers;
+
+ public PrintWriter stderr;
+
+ private IHttpRequestResponse requestResponse;
+
+ public CustomBurpUrl(IBurpExtenderCallbacks callbacks, IHttpRequestResponse requestResponse) {
+ this.callbacks = callbacks;
+ this.helpers = callbacks.getHelpers();
+ this.stderr = new PrintWriter(callbacks.getStderr(), true);
+
+ this.requestResponse = requestResponse;
+ }
+
+ public IHttpRequestResponse requestResponse() {
+ return this.requestResponse;
+ }
+
+ /**
+ * 获取-请求协议
+ *
+ * @return
+ */
+ public String getRequestProtocol() {
+ return this.requestResponse.getHttpService().getProtocol();
+ }
+
+ /**
+ * 获取-请求主机
+ *
+ * @return
+ */
+ public String getRequestHost() {
+ return this.requestResponse.getHttpService().getHost();
+ }
+
+ /**
+ * 获取-请求端口
+ *
+ * @return
+ */
+ public int getRequestPort() {
+ return this.requestResponse.getHttpService().getPort();
+ }
+
+ /**
+ * 获取-请求路径
+ *
+ * @return
+ */
+ public String getRequestPath() {
+ return this.helpers.analyzeRequest(this.requestResponse).getUrl().getPath();
+ }
+
+ /**
+ * 获取-请求参数
+ *
+ * @return
+ */
+ public String getRequestQuery() {
+ return this.helpers.analyzeRequest(this.requestResponse).getUrl().getQuery();
+ }
+
+ /**
+ * 获取-请求域名名称
+ *
+ * @return
+ */
+ public String getRequestDomainName() {
+ if (this.getRequestPort() == 80 || this.getRequestPort() == 443) {
+ return this.getRequestProtocol() + "://" + this.getRequestHost();
+ } else {
+ return this.getRequestProtocol() + "://" + this.getRequestHost() + ":" + this.getRequestPort();
+ }
+ }
+
+ /**
+ * 获取-获取http请求url
+ *
+ * @return
+ */
+ public URL getHttpRequestUrl() {
+ try {
+ if (this.getRequestQuery() == null) {
+ return new URL(this.getRequestDomainName() + this.getRequestPath());
+ } else {
+ return new URL(this.getRequestDomainName() + this.getRequestPath() + "?" + this.getRequestQuery());
+ }
+ } catch (MalformedURLException e) {
+ e.printStackTrace(this.stderr);
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/burp/Bootstrap/CustomHelpers.java b/src/main/java/burp/Bootstrap/CustomHelpers.java
new file mode 100644
index 0000000..46f43be
--- /dev/null
+++ b/src/main/java/burp/Bootstrap/CustomHelpers.java
@@ -0,0 +1,73 @@
+package burp.Bootstrap;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class CustomHelpers {
+ /**
+ * 获取精确到秒的时间戳
+ *
+ * @param date
+ * @return Integer
+ */
+ public static Integer getSecondTimestamp(Date date) {
+ if (null == date) {
+ return 0;
+ }
+ String timestamp = String.valueOf(date.getTime() / 1000);
+ return Integer.valueOf(timestamp);
+ }
+
+ /**
+ * 列表块分割函数
+ * 功能: 把列表按照size分割成指定的list快返回
+ * 例子1:
+ * a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ * listChunkSplit(a, 2)
+ * 返回: [[1, 2, 3, 4, 5], [6, 7, 8, 9]]
+ * 例子2:
+ * a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ * listChunkSplit(a, 10)
+ * 返回: [[1], [2], [3], [4], [5], [6], [7], [8], [9]]
+ *
+ * @param dataSource 数据源
+ * @param groupSize 一个整数, 规定最多分成几个list
+ * @return List>
+ */
+ public static List> listChunkSplit(List dataSource, Integer groupSize) {
+ List> result = new ArrayList<>();
+
+ if (dataSource.size() == 0 || groupSize == 0) {
+ return result;
+ }
+
+ // 偏移量
+ int offset = 0;
+
+ // 计算 商
+ int number = dataSource.size() / groupSize;
+
+ // 计算 余数
+ int remainder = dataSource.size() % groupSize;
+
+ for (int i = 0; i < groupSize; i++) {
+ List value = null;
+ if (remainder > 0) {
+ value = dataSource.subList(i * number + offset, (i + 1) * number + offset + 1);
+ remainder--;
+ offset++;
+ } else {
+ value = dataSource.subList(i * number + offset, (i + 1) * number + offset);
+ }
+
+ if (value.size() == 0) {
+ break;
+ }
+
+ result.add(value);
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/burp/Bootstrap/DiffPage.java b/src/main/java/burp/Bootstrap/DiffPage.java
new file mode 100644
index 0000000..0d785df
--- /dev/null
+++ b/src/main/java/burp/Bootstrap/DiffPage.java
@@ -0,0 +1,114 @@
+package burp.Bootstrap;
+
+public class DiffPage {
+ /**
+ * 返回经过过滤无用的数据以后两个字符串的相似度
+ *
+ * @param str
+ * @param target
+ * @return
+ */
+ public static double getRatio(String str, String target) {
+ str = getFilteredPageContent(str);
+ target = getFilteredPageContent(target);
+ return getSimilarityRatio(str, target);
+ }
+
+ /**
+ * 返回经过过滤的页面内容,不包含脚本、样式和/或注释
+ * 或所有HTML标签
+ * 调用 getFilteredPageContent("foobartest")
+ * 返回内容: foobartest
+ *
+ * @param htmlStr
+ * @return String
+ */
+ public static String getFilteredPageContent(String htmlStr) {
+ // 将实体字符串转义返回 如: "<"="<", ">"=">", """="\"", " "=" ", "&"="&"
+ htmlStr = htmlStr.replace("<", "<");
+ htmlStr = htmlStr.replace(">", ">");
+ htmlStr = htmlStr.replace(""", "\"");
+ htmlStr = htmlStr.replace(" ", " ");
+ htmlStr = htmlStr.replace("&", "&");
+
+ //定义script的正则表达式,去除js可以防止注入
+ String scriptRegex = "