diff --git a/BurpFastJsonScan.iml b/BurpFastJsonScan.iml new file mode 100644 index 0000000..1559b52 --- /dev/null +++ b/BurpFastJsonScan.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 925fa63..262162a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.pmiaowu BurpFastJsonScan - 2.1.3 + 2.2.0 diff --git a/src/main/java/burp/Application/CmdEchoExtension/CmdEcho.java b/src/main/java/burp/Application/CmdEchoExtension/CmdEcho.java index 9f584a4..42456c3 100644 --- a/src/main/java/burp/Application/CmdEchoExtension/CmdEcho.java +++ b/src/main/java/burp/Application/CmdEchoExtension/CmdEcho.java @@ -5,6 +5,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import burp.Bootstrap.GlobalVariableReader; import burp.IBurpExtenderCallbacks; import burp.Bootstrap.YamlReader; @@ -12,6 +13,8 @@ import burp.Application.ExtensionInterface.IAppExtension; public class CmdEcho { + private GlobalVariableReader globalVariableReader; + private IBurpExtenderCallbacks callbacks; private BurpAnalyzedRequest analyzedRequest; @@ -24,10 +27,13 @@ public class CmdEcho { private Date startDate = new Date(); public CmdEcho( + GlobalVariableReader globalVariableReader, IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, YamlReader yamlReader, String callClassName) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + this.globalVariableReader = globalVariableReader; + this.callbacks = callbacks; this.analyzedRequest = analyzedRequest; @@ -47,6 +53,7 @@ private void init(String callClassName) throws ClassNotFoundException, NoSuchMet Class c = Class.forName("burp.Application.CmdEchoExtension.ExtensionMethod." + callClassName); Constructor cConstructor = c.getConstructor( + GlobalVariableReader.class, IBurpExtenderCallbacks.class, BurpAnalyzedRequest.class, YamlReader.class, @@ -54,6 +61,7 @@ private void init(String callClassName) throws ClassNotFoundException, NoSuchMet Date.class, Integer.class); this.cmdEcho = (IAppExtension) cConstructor.newInstance( + this.globalVariableReader, this.callbacks, this.analyzedRequest, this.yamlReader, diff --git a/src/main/java/burp/Application/CmdEchoExtension/ExtensionMethod/CmdEchoScan.java b/src/main/java/burp/Application/CmdEchoExtension/ExtensionMethod/CmdEchoScan.java index 61fa3c8..d638281 100644 --- a/src/main/java/burp/Application/CmdEchoExtension/ExtensionMethod/CmdEchoScan.java +++ b/src/main/java/burp/Application/CmdEchoExtension/ExtensionMethod/CmdEchoScan.java @@ -8,15 +8,14 @@ import burp.*; -import burp.Bootstrap.CustomBurpHelpers; -import burp.Bootstrap.YamlReader; -import burp.Bootstrap.CustomHelpers; -import burp.Bootstrap.BurpAnalyzedRequest; +import burp.Bootstrap.*; import burp.Application.ExtensionInterface.AAppExtension; import burp.CustomErrorException.TaskTimeoutException; public class CmdEchoScan extends AAppExtension { + private GlobalVariableReader globalVariableReader; + private IBurpExtenderCallbacks callbacks; private IExtensionHelpers helpers; @@ -34,9 +33,12 @@ public class CmdEchoScan extends AAppExtension { // 命令输出点 private String commandOutputPoint; - public CmdEchoScan(IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, + public CmdEchoScan(GlobalVariableReader globalVariableReader, + IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, YamlReader yamlReader, List payloads, Date startDate, Integer maxExecutionTime) { + this.globalVariableReader = globalVariableReader; + this.callbacks = callbacks; this.helpers = callbacks.getHelpers(); @@ -57,6 +59,11 @@ public CmdEchoScan(IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyze private void runExtension() { for (String payload : this.payloads) { + // 这个参数为true说明插件已经被卸载,退出所有任务,避免继续扫描 + if (this.globalVariableReader.getBooleanData("isExtensionUnload")) { + return; + } + if (this.isIssue()) { return; } diff --git a/src/main/java/burp/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java b/src/main/java/burp/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java index 4f24e09..5809f47 100644 --- a/src/main/java/burp/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java +++ b/src/main/java/burp/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java @@ -8,6 +8,7 @@ import burp.*; +import burp.Bootstrap.GlobalVariableReader; import burp.CustomScanIssue; import burp.DnsLogModule.DnsLog; import burp.Bootstrap.YamlReader; @@ -17,6 +18,8 @@ import burp.CustomErrorException.TaskTimeoutException; public class RemoteCmdScan extends AAppExtension { + private GlobalVariableReader globalVariableReader; + private IBurpExtenderCallbacks callbacks; private IExtensionHelpers helpers; @@ -37,9 +40,12 @@ public class RemoteCmdScan extends AAppExtension { private ArrayList dnsLogUrlArrayList = new ArrayList<>(); private ArrayList httpRequestResponseArrayList = new ArrayList<>(); - public RemoteCmdScan(IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, + public RemoteCmdScan(GlobalVariableReader globalVariableReader, + IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, DnsLog dnsLog, YamlReader yamlReader, List payloads, Date startDate, Integer maxExecutionTime) { + this.globalVariableReader = globalVariableReader; + this.callbacks = callbacks; this.helpers = callbacks.getHelpers(); @@ -62,6 +68,11 @@ public RemoteCmdScan(IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analy private void runExtension() { for (String payload : this.payloads) { + // 这个参数为true说明插件已经被卸载,退出所有任务,避免继续扫描 + if (this.globalVariableReader.getBooleanData("isExtensionUnload")) { + return; + } + // 说明接收到了dnslog请求确定是FastJson if (this.isIssue()) { return; diff --git a/src/main/java/burp/Application/RemoteCmdExtension/RemoteCmd.java b/src/main/java/burp/Application/RemoteCmdExtension/RemoteCmd.java index b2e4442..45c7855 100644 --- a/src/main/java/burp/Application/RemoteCmdExtension/RemoteCmd.java +++ b/src/main/java/burp/Application/RemoteCmdExtension/RemoteCmd.java @@ -5,6 +5,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import burp.Bootstrap.GlobalVariableReader; import burp.IBurpExtenderCallbacks; import burp.DnsLogModule.DnsLog; @@ -13,6 +14,8 @@ import burp.Application.ExtensionInterface.IAppExtension; public class RemoteCmd { + private GlobalVariableReader globalVariableReader; + private IBurpExtenderCallbacks callbacks; private BurpAnalyzedRequest analyzedRequest; @@ -27,11 +30,14 @@ public class RemoteCmd { private Date startDate = new Date(); public RemoteCmd( + GlobalVariableReader globalVariableReader, IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, DnsLog dnsLog, YamlReader yamlReader, String callClassName) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + this.globalVariableReader = globalVariableReader; + this.callbacks = callbacks; this.analyzedRequest = analyzedRequest; @@ -53,6 +59,7 @@ private void init(String callClassName) throws ClassNotFoundException, NoSuchMet Class c = Class.forName("burp.Application.RemoteCmdExtension.ExtensionMethod." + callClassName); Constructor cConstructor = c.getConstructor( + GlobalVariableReader.class, IBurpExtenderCallbacks.class, BurpAnalyzedRequest.class, DnsLog.class, @@ -61,6 +68,7 @@ private void init(String callClassName) throws ClassNotFoundException, NoSuchMet Date.class, Integer.class); this.remoteCmd = (IAppExtension) cConstructor.newInstance( + this.globalVariableReader, this.callbacks, this.analyzedRequest, this.dnsLog, diff --git a/src/main/java/burp/Bootstrap/GlobalVariableReader.java b/src/main/java/burp/Bootstrap/GlobalVariableReader.java new file mode 100644 index 0000000..f847ad2 --- /dev/null +++ b/src/main/java/burp/Bootstrap/GlobalVariableReader.java @@ -0,0 +1,36 @@ +package burp.Bootstrap; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class GlobalVariableReader { + private ConcurrentHashMap booleanMap; + + public GlobalVariableReader() { + this.booleanMap = new ConcurrentHashMap(); + } + + public Map getBooleanMap() { + return this.booleanMap; + } + + public Boolean getBooleanData(String key) { + return this.getBooleanMap().get(key); + } + + public void putBooleanData(String key, Boolean b) { + if (key == null || key.length() <= 0) { + throw new IllegalArgumentException("key不能为空"); + } + + synchronized (this.getBooleanMap()) { + this.getBooleanMap().put(key, b); + } + } + + public void delBooleanData(String key) { + if (this.getBooleanMap().get(key) != null) { + this.getBooleanMap().remove(key); + } + } +} diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 0584e64..ef8808b 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -1,6 +1,7 @@ package burp; import java.util.List; +import java.util.Arrays; import java.util.ArrayList; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; @@ -11,12 +12,15 @@ import burp.Bootstrap.YamlReader; import burp.Bootstrap.CustomBurpUrl; import burp.Bootstrap.BurpAnalyzedRequest; +import burp.Bootstrap.GlobalVariableReader; import burp.CustomErrorException.TaskTimeoutException; import burp.Application.RemoteCmdExtension.RemoteCmd; -public class BurpExtender implements IBurpExtender, IScannerCheck { +public class BurpExtender implements IBurpExtender, IScannerCheck, IExtensionStateListener { public static String NAME = "FastJsonScan"; - public static String VERSION = "2.1.3"; + public static String VERSION = "2.2.0"; + + private GlobalVariableReader globalVariableReader; private IBurpExtenderCallbacks callbacks; private IExtensionHelpers helpers; @@ -36,6 +40,15 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { this.stdout = new PrintWriter(callbacks.getStdout(), true); this.stderr = new PrintWriter(callbacks.getStderr(), true); + // 全局变量的数据保存地址 + // 用于在程序执行的过程中能够实时的修改变量数据使用 + this.globalVariableReader = new GlobalVariableReader(); + + // 是否卸载扩展 + // 用于卸载插件以后,把程序快速退出去,避免卡顿 + // true = 已被卸载, false = 未卸载 + this.globalVariableReader.putBooleanData("isExtensionUnload", false); + // 标签界面 this.tags = new Tags(callbacks, NAME); @@ -44,6 +57,7 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { callbacks.setExtensionName(NAME); callbacks.registerScannerCheck(this); + callbacks.registerExtensionStateListener(this); // 基本信息输出 // 作者拿来臭美用的 ╰(*°▽°*)╯ @@ -72,6 +86,9 @@ private static String basicInformationOutput() { public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { List issues = new ArrayList<>(); + List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist"); + List domainNameWhitelist = this.yamlReader.getStringList("scan.domainName.whitelist"); + // 基础url解析 CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, baseRequestResponse); @@ -86,6 +103,25 @@ public List doPassiveScan(IHttpRequestResponse baseRequestResponse) return null; } + // 判断域名黑名单 + if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) { + if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) { + return null; + } + } + + // 判断域名白名单 + if (domainNameWhitelist != null && domainNameWhitelist.size() >= 1) { + if (!isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameWhitelist)) { + return null; + } + } + + // 判断当前请求后缀,是否为url黑名单后缀 + if (this.isUrlBlackListSuffix(baseBurpUrl)) { + return null; + } + // 判断是否有允许扫描的JSON类型 if (this.tags.getBaseSettingTagClass().getScanTypeList().size() == 0) { return null; @@ -271,7 +307,7 @@ private IScanIssue cmdEchoExtension(int tagId, BurpAnalyzedRequest analyzedReque return null; } - CmdEcho cmdEcho = new CmdEcho(this.callbacks, analyzedRequest, this.yamlReader, provider); + CmdEcho cmdEcho = new CmdEcho(this.globalVariableReader, this.callbacks, analyzedRequest, this.yamlReader, provider); if (!cmdEcho.run().isIssue()) { return null; } @@ -312,7 +348,7 @@ private IScanIssue remoteCmdExtension(int tagId, BurpAnalyzedRequest analyzedReq } DnsLog dnsLog = new DnsLog(this.callbacks, this.yamlReader.getString("dnsLogModule.provider")); - RemoteCmd remoteCmd = new RemoteCmd(this.callbacks, analyzedRequest, dnsLog, this.yamlReader, provider); + RemoteCmd remoteCmd = new RemoteCmd(this.globalVariableReader, this.callbacks, analyzedRequest, dnsLog, this.yamlReader, provider); if (!remoteCmd.run().isIssue()) { return null; } @@ -370,4 +406,118 @@ private Integer getSiteJsonNumber(String domainName) { } return number; } + + /** + * 判断是否查找的到指定的域名 + * + * @param domainName 需匹配的域名 + * @param domainNameList 待匹配的域名列表 + * @return + */ + private static Boolean isMatchDomainName(String domainName, List domainNameList) { + domainName = domainName.trim(); + + if (domainName.length() <= 0) { + return false; + } + + if (domainNameList == null || domainNameList.size() <= 0) { + return false; + } + + if (domainName.contains(":")) { + domainName = domainName.substring(0, domainName.indexOf(":")); + } + + String reverseDomainName = new StringBuffer(domainName).reverse().toString(); + + for (String domainName2 : domainNameList) { + domainName2 = domainName2.trim(); + + if (domainName2.length() <= 0) { + continue; + } + + if (domainName2.contains(":")) { + domainName2 = domainName2.substring(0, domainName2.indexOf(":")); + } + + String reverseDomainName2 = new StringBuffer(domainName2).reverse().toString(); + + if (domainName.equals(domainName2)) { + return true; + } + + if (reverseDomainName.contains(".") && reverseDomainName2.contains(".")) { + List splitDomainName = new ArrayList(Arrays.asList(reverseDomainName.split("[.]"))); + + List splitDomainName2 = new ArrayList(Arrays.asList(reverseDomainName2.split("[.]"))); + + if (splitDomainName.size() <= 0 || splitDomainName2.size() <= 0) { + continue; + } + + if (splitDomainName.size() < splitDomainName2.size()) { + for (int i = splitDomainName.size(); i < splitDomainName2.size(); i++) { + splitDomainName.add("*"); + } + } + + if (splitDomainName.size() > splitDomainName2.size()) { + for (int i = splitDomainName2.size(); i < splitDomainName.size(); i++) { + splitDomainName2.add("*"); + } + } + + int ii = 0; + for (int i = 0; i < splitDomainName.size(); i++) { + if (splitDomainName2.get(i).equals("*")) { + ii = ii + 1; + } else if (splitDomainName.get(i).equals(splitDomainName2.get(i))) { + ii = ii + 1; + } + } + + if (ii == splitDomainName.size()) { + return true; + } + } + } + return false; + } + + /** + * 判断是否url黑名单后缀 + * 大小写不区分 + * 是 = true, 否 = false + * + * @param burpUrl + * @return + */ + private boolean isUrlBlackListSuffix(CustomBurpUrl burpUrl) { + if (!this.yamlReader.getBoolean("urlBlackListSuffix.config.isStart")) { + return false; + } + + String noParameterUrl = burpUrl.getHttpRequestUrl().toString().split("\\?")[0]; + String urlSuffix = noParameterUrl.substring(noParameterUrl.lastIndexOf(".") + 1); + + List suffixList = this.yamlReader.getStringList("urlBlackListSuffix.suffixList"); + if (suffixList == null || suffixList.size() == 0) { + return false; + } + + for (String s : suffixList) { + if (s.toLowerCase().equals(urlSuffix.toLowerCase())) { + return true; + } + } + + return false; + } + + @Override + public void extensionUnloaded() { + this.globalVariableReader.putBooleanData("isExtensionUnload", true); + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 80c2d03..460fd14 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -20,6 +20,35 @@ scan: # 超过次数以后就不在对该站点进行扫描了 # 0 表示无限次扫描 siteScanNumber: 0 + # 域名扫描规则 + domainName: + # 域名黑名单 + # 注: 黑名单优先级最高 + # 注: 为空表示关闭该功能 + # 使用规则: + # 1. 过滤某个域名: www.domain1.com + # 2. 过滤某个域名的全部子域名: *.domain2.com + # 3. 过滤某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com + # 使用方法: + # blacklist: + # - "www.domain1.com" + # - "*.domain2.com" + blacklist: + - "*.dnslog.cn" + - "*.ceye.io" + - "*.fofa.so" + # 域名白名单 + # 注: 黑名单优先级最高 + # 注: 为空表示关闭该功能 + # 使用规则: + # 1. 只扫描某个域名: www.domain1.com + # 2. 只扫描某个域名的全部子域名: *.domain2.com + # 3. 只扫描某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com + # 使用方法: + # whitelist: + # - "www.domain1.com" + # - "*.domain2.com" + whitelist: # 扫描类型 type: # 用于判断是否将 Get参数的Json 作为扫描参数 @@ -33,6 +62,120 @@ scan: # 用于判断是否将 HTTP请求正文的Json 作为扫描参数 isScanBodyJson: true +# url黑名单后缀 +# url的后缀出现这些字段的都不进行测试 +urlBlackListSuffix: + config: + isStart: true + suffixList: + - "3g2" + - "3gp" + - "7z" + - "aac" + - "abw" + - "aif" + - "aifc" + - "aiff" + - "arc" + - "au" + - "avi" + - "azw" + - "bin" + - "bmp" + - "bz" + - "bz2" + - "cmx" + - "cod" + - "csh" + - "css" + - "csv" + - "doc" + - "docx" + - "eot" + - "epub" + - "gif" + - "gz" + - "ico" + - "ics" + - "ief" + - "jar" + - "jfif" + - "jpe" + - "jpeg" + - "jpg" + - "m3u" + - "mid" + - "midi" + - "mjs" + - "mp2" + - "mp3" + - "mpa" + - "mpe" + - "mpeg" + - "mpg" + - "mpkg" + - "mpp" + - "mpv2" + - "odp" + - "ods" + - "odt" + - "oga" + - "ogv" + - "ogx" + - "otf" + - "pbm" + - "pdf" + - "pgm" + - "png" + - "pnm" + - "ppm" + - "ppt" + - "pptx" + - "ra" + - "ram" + - "rar" + - "ras" + - "rgb" + - "rmi" + - "rtf" + - "snd" + - "svg" + - "swf" + - "tar" + - "tif" + - "tiff" + - "ttf" + - "vsd" + - "wav" + - "weba" + - "webm" + - "webp" + - "woff" + - "woff2" + - "xbm" + - "xls" + - "xlsx" + - "xpm" + - "xul" + - "xwd" + - "zip" + - "js" + - "wmv" + - "asf" + - "asx" + - "rm" + - "rmvb" + - "mp4" + - "mov" + - "m4v" + - "dat" + - "mkv" + - "flv" + - "vob" + - "txt" + - "php" + - "asp" + # 应用程序配置 application: # 命令回显扩展