浅谈帆软在Windows下写文件RCE姿势

写在前面

之前上一篇文章中浅析帆软FineVis默认插件前台RCE提到jasper依赖没被加载,当时只是简单做了测试,没有具体看为什么jsp未被解析,只是疑惑了下tomcat下jspservlet配置明明正确配置页面却直接返回空(没有考虑到编译报错这一层问题),今天无意间看到星球有师傅分享了如何解析jsp的过程,写文章同时也顺带分享下如何实现RCE的两种姿势

当然至于为什么是windows,之前的两篇漏洞文章中都有提到过,因为linux的默认可以解析,这一点从官方文档就能知道(https://help.fanruan.com/finereport/doc-view-822.html),要求自行下载tomcat部署启动,因此在linux下也不存在这个jsp的解析问题

如何在Windows下完成RCE

SPI

由于这个插件写文件比较特殊,遇到不存在的文件夹会自动创建,因此我们很容易利用Java中SPI的机制完成RCE的利用,比较简单,这里不再展开,不熟悉的可以去网上了解下以前SpringBoot FatJar的一些打法

加载JSP

比较抽象直接访问jsp能访问到但是页面为空白

image-20240814192427045

之前没细细研究,想着这里不是有对应的servlet配置吗,直到看到了别的星球发了一篇文章才发现,原来启动时使用了Tomcat().start()启动

image-20240814113439923

这和Springboot整合tomcat启动时使用的方法一致,也算学到了点新东西(之前一直以为只能通过BootStrap启动),具体可以看看这篇文章了解https://blog.csdn.net/qq_33468007/article/details/107620507

接下来调试可以看到确实触发了jsp编译的过程,但是报错了

image-20240814192049879

经过最终调试发现,报错是因为javax.servlet.jsp.JspFactory#deflt为null

image-20240814193334916

因此让jsp加载就要解决这个属性为null的问题,而这个来源于JasperInitializer初始化的过程,它是Tomcat内部的一个初始化器,本就是用于处理支持JSP页面的,在静态块中设置了这个factory,而由于启动方式的原因这个类并没有被初始化

image-20240814193839453

因此要解析jsp,就需要解决这个类初始化的问题,因此我们需要找到一个前台的类帮助我们完成任意类加载

而在com.fr.web.controller.common.FileRequestService#getFile中就存在我们需要的初始化过程

简单看看下面的代码通过PlatformScaffold.getReflectionProvider().classForName(path)完成了任意类的初始化,因此也就成功解决了javax.servlet.jsp.JspFactory#deflt为null的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void getFile(HttpServletRequest req, HttpServletResponse res, @RequestParam("path") String path, @RequestParam(value = "type",required = false) String type, @RequestParam(value = "parser",required = false) String parser, @RequestParam(value = "tag",required = false) String tag) throws Exception {
xxxxxx省略部分代码xxxxxx
}
} else if (fileType == FileType.CLASS) {
String charset = PlatformScaffold.getBasicConfigProvider().getServerCharset();

// 参数path可控制初始化的类
TextGenerator generator = (TextGenerator)Reflect.on(PlatformScaffold.getReflectionProvider().classForName(path)).create().get();
((HttpServletResponse)res).setContentType(generator.mimeType() + ";charset=" + charset);
String text = generator.text(req, (HttpServletResponse)res);
PrintWriter writer = WebUtil.createPrintWriter((HttpServletResponse)res);
writer.write(text);
writer.flush();
writer.close();
}
} catch (Exception var17) {
FineLoggerFactory.getLogger().error(var17.getMessage(), var17);
} finally {
if (wrappedResponse != null) {
wrappedResponse.finishResponse();
}

}

} else {
throw new SpecialCharProhibitException();
}
}

因此只需要通过一个请求

1
http://xxxx/webroot/decision/file?path=org.apache.jasper.servlet.JasperInitializer&type=class

这一次我们的jsp成功被渲染了

image-20240814194504349