freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

JSP型内存马的原理学习与实现
2023-09-08 21:43:08

前言

在前面的文章中,系统性的分析了tomcat中间件下的Listener / Filter / Servlet / Executor / Upgrade / Valve等等类型的内存马的实现

这里我们继续接着之前的内容继续总结内存马相关的内容,这里我们一起来看看JSP型的内存马的实现原理和方式

前置

想要成功实现一个JSP类型的内存马,详细了解在tomcat容器下的JSP的加载流程是不可避免的

JSP大致的执行过程如下

  1. 当用户请求一个JSP页面,将会向tomcat中发送请求

  2. jsp容器将会将对应的JSP页面转化成Servlet源码

  3. 将转化而来的java源码编译成.class字节码

  4. 加载编译的.class并执行逻辑

  5. 将执行结果返回给用户端

正文

JSP加载流程

首先是在经过一系列的filter之后将会把JSP请求传递给JspServlet#service进行处理

image-20230906211906751.png

image-20230906212028278.png

前面都是一些jsp请求的url信息的获取和debug模式的日志打印等等,通过调用preCompile方法来判断是否对请求资源进行了预编译

image-20230906212450851.png

这里的常量PRECOMPILEjsp_precompile,只有在请求jsp页面是附带有查询参数为jsp_precompile才会进行预编译

之后就是JSP的关键方法serviceJspFile的调用

image-20230906212935220.png

首先就是调用JspRuntimeContext#getWrapper来获取请求jsp对应的wrapper,如果首次访问该jsp资源将会返回null值,并且将会创建对应jsp资源的一个JspServletWrapper对象,并将其添加进入JspServletWrapper类的jsps属性中,在这之前,这里将会对jsp资源是否存在进行判断,若不存在将会出现异常

JspServletWrapper是Servlet的一个包装类,所有被注册了的jsp servlet都会存放在rctxt中

在创建了对应的JspServletWrapper之后,将会通过调用它的service方法对请求进行处理

快进到JspServletWrapper#serive方法中的关键功能——编译环节

image-20230906214452030.png

在经过前面一系列的判断语句之后,在满足了条件this.options.getDevelopment() || this.mustCompile环节之后可以进入编译的环节

image-20230906214638024.png

默认的编译器是org.apache.jasper.compiler.JDTCompiler

image-20230906214753303.png

在创建好并成功初始化编译器之后通过调用编译器的isOutDated方法判断是否需要进行编译

image-20230906215202630.png

image-20230906215427929.png

之后编译过程就是删除掉原来已经生成的java和class文件

image-20230906215550327.png

这里因为第一次访问,本身就没有进行编译,更不可能存在

之后就是调用JDTCompiler#compile进行编译的过程

image-20230906215928585.png

image-20230906215941798.png

在这里调用generateJava方法生成了请求资源的java代码

image-20230906220034522.png

在目标目录已经生成了java代码

image-20230906220334263.png

类似的,之后通过调用generateClass方法来进行java代码的编译

就这样结束了JspServletWrapper#service中的生成java代码和编译的一部分功能,在编译完成之后也会将mustCompile属性置为false

紧接着就是调用JspServletWrapper#getServlet方法进行jsp servlet的注册功能

image-20230906220926578.png

首先将会判断this.getReloadInternal() || this.theServlet == null,其中theServlet是用来判断是否存在有servelt,这里是第一次访问,是不存在的,所以为null

其中destroy方法是用来销毁该servlet的

image-20230906221259510.png

紧接着就是通过下面的代码创建了一个servlet的实例

InstanceManager instanceManager = InstanceManagerFactory.getInstanceManager(this.config);
servlet = (Servlet)instanceManager.newInstance(this.ctxt.getFQCN(), this.ctxt.getJspLoader());

并进行jsp Servlet的初始化

最后将创建好的servlet保存在theServlet属性中

最后的最后就是将调用创建好的servlet#service方法进行请求的处理

内存马实现

想要实现一个内存马,必须能够满足条件

    # web安全
    本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
    被以下专辑收录,发现更多精彩内容
    + 收入我的专辑
    + 加入我的收藏
    相关推荐
    • 0 文章数
    • 0 关注者
    文章目录