内存码学习笔记(一)
什么是内存马?他不是像文件存储再硬盘中,而是存储到内存中,不能永久储存,但更隐蔽
filter内存马
最开始调项目
看了很多教程,最后还是用springboot起的项目,
controller随便写,filter中
1 | import org.springframework.core.annotation.Order; |
application中
1 | import org.springframework.boot.SpringApplication; |
先下断电,然后访问对应接口,然后调试就可以了
多种方法建项目,但底层都是走代码的流程
@WebFilter注解: 不用写XML配置文件
web.xml配置:
1
2
3
4
5
6 ><filter> <filter-name>filter</filter-name>
><filter-class>filter</filter-class>
></filter>
><filter-mapping> <filter-name>filter</filter-name>
><url-pattern>/filter</url-pattern>
></filter-mapping></web-app>
- Spring框架过滤器注册: Spring框架提供了自己的方式来注册过滤器,通常结合Spring的IoC容器来管理过滤器对象。在Spring框架中,可以将过滤器作为一个Spring组件(Bean)注册,并通过配置类来进行过滤器的注册。
背景
Servlet、Listener、Filter 由 javax.servlet.ServletContext
去加载
Servlet 3.0 API 允许使 ServletContext 用动态进行注册
在web容器初始化的时候,也就是建立ServletContext 对象的时候,可以使用
add/create
方法进行动态注册
Filter 是 Java Web 应用程序中的一种组件,用于在请求到达 Servlet 之前或响应离开 Servlet 之后对请求或响应进行处理。 可以通过实现 javax.servlet.Filter
接口来定义自己的过滤器逻辑。在 Servlet 容器中,Filter 的工作原理是基于回调函数,在请求到达 Servlet 之前和响应离开 Servlet 之后执行相应的方法。Filter 可以读取请求的信息、修改请求的参数、处理请求的内容,并且可以对响应进行相应的处理,但这些操作都是在内存中进行的
分析filter前奏
tomcat
tomcat先由连接器( Connector )从客户端接收请求,然后通过网络接收器( Acceptor )创建对应的Socket对象,再由网络处理器分配processor,最后交给 Servlet 处理(这里servelt就是和我写的controller是一个意思)
一个服务器上(server)有一个engine,有多个服务(service),一个服务有多个Connector
Connector
主要的职责就是负责接收客户端连接和客户端请求的处理加工请求Request和响应Response对象。
tomcat有两个典型connector
1,一个直接侦听来自browser的http请求,一个侦听来自其它WebServer的请求Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求。
2、另外一个是Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。
Context:
一个Context对应于一个Web Application,一个WebApplication由一个或者多个Servlet组成。
Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类,当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类。如果找到,则执行该类,获得请求的回应,并返回。
Engine:最顶层容器组件,其下可以包含多个 Host。
Host:一个 Host 代表一个虚拟主机,其下可以包含多个 Context。
Context:一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper。
Wrapper: Wrapper是它代表了一个Servlet的执行实例
分析filter流程
tomcat初始化的时候会调用startinternal然后会调用filterstart
standardcontext
类的filterstart:
1 | public boolean filterStart() { |
大概意思是:
根据
filterdef
创建ApplicationFilterConfig实例放到filterConfigs
中然后就会调用filter的init,把所有的filter都初始化
然后就结束了初始化,再次刷新就开始了web服务:
先创建线程,然后进入tomcat容器,进行 Socket通信 的操作又进行了http的操作,然后是请求处理器的实现
CoyoteAdapter类的service方法:
service就是tomcat
container是返回一个 Engine ,默认localhost
pipline,是tomcat用来管理和组织 Valve 的对象 ,getfirst是获取他的第一个value,如果没有就返回他本身的容器
进入invoke,里面判断是否接受异步请求,接受就给他设置异步请求
然后就是通过invoke获取他的第一个value,然后返回他的下一个base子容器
Engine
>Host
>Context
>Wrapper
在最后一个invoke看到了要找的filter
StandardWrapperValve类的invoke:
跟进createfilterchain
可以看到这里的逻辑是初始化一个空的filterchain然后获取req的filterchain(req是这个函数的参数,等会回去找找这个参数可不可控),
然后req又set了一个空的filterchain
给这个filterchain set 个servlet
根据tomcat子容器Wrapper
,强转了一个standardContext ,并生成一个filtermaps
在这里可以看到我写的filter在第五个
根据filtermap名字生成ApplicationFilterConfig,然后加入filterchain
第一次dofilter直接跳到internaldofilter,然后又进到OncePerRequestFilter的dofilter,在poc等于3的时候的跑到我写的dofilter这里触发了calc,然后回到了我写的controller,触发了接口(相当于severlet)
总结一下:
dofilter循环调用,最后到了我的dofilter,然后下一个调用到到service然后进入了我写的/hello接口
调代码遇到的有关filter的类
ApplicationFilterChain
javax.servlet.FilterChain的实现,用于管理特定请求的一组过滤器的执行。当定义的过滤器集全部执行完毕后,对doFilter()的下一次调用将执行servlet的service()方法本身。
OncePerRequestFilter
过滤器基类,旨在保证在任何servlet容器上每个请求调度只执行一次。它提供了一个带有HttpServletRequest和HttpServletResponse参数的doFilterInternal方法。
从Servlet 3.0开始,过滤器可以作为REQUEST或异步调度的一部分在单独的线程中调用。可以在web.xml中配置过滤器是否应该参与异步分派。然而,在某些情况下,servlet容器采用不同的默认配置。因此,子类可以覆盖shouldNotFilterAsyncDispatch()方法来静态声明
OncePerRequestFilter just supports HTTP requests
CharacterEncodingFilter
Servlet过滤器,允许为请求指定字符编码。这很有用,因为当前的浏览器通常不设置字符编码,即使在HTML页面或表单中指定了。
如果请求还没有指定编码,这个过滤器可以应用它的编码,或者在任何情况下强制这个过滤器的编码(“forceEncoding”=”true”)。在后一种情况下,编码也将作为默认响应编码应用(尽管这通常会被视图中的完整内容类型集覆盖)。
FormContentFilter
用于解析HTTP PUT、PATCH和DELETE请求的表单数据并将其公开为Servlet请求参数的过滤器。默认情况下,Servlet规范只要求对HTTP POST进行此操作。
RequestContextFilter
Servlet过滤器,通过LocaleContextHolder和RequestContextHolder向当前线程公开请求。在web.xml中注册为过滤器。
或者,Spring的org.springframework.web.context.request.RequestContextListener和Spring的org.springframework.web.servlet.DispatcherServlet也向当前线程公开相同的请求上下文。
这个过滤器主要用于第三方servlet,例如JSF的FacesServlet。在Spring自己的web支持中,DispatcherServlet的处理是完全足够的。
开始exp
我写内存马是想把恶意代码加载到内存中,上面的本地测试我是创建的filter,并且配置了filter,而比赛中我们是不可能这样加载的,所以我应该动态创建一个filter并加载到filterchain中
所以我们要获取运行服务器的Standardcontext(这个讲的很详细),我们还要写三个filterDefs
,filterConfigs
和filterMaps
来配置filter
- 先获取
filterDef
对象,进行一系列配置,利用standardcontext
的addfilter进行加载- 获取
filterMaps
对象,配置路径等信息,利用standardcontext
的addFilterMapBefore进行加载,修改 HashMap中的顺序filterConfigs
是调用StandardContext
的 filterStart方法创建ApplicationFilterConfig实例放到filterConfigs
中
ApplicationContextFacade类重写了addfilter,这个类实现了对 ApplicationContext对象的封装(封装就是你点一下context.addfilter,他就会跳转到ApplicationContext)
1 | private FilterRegistration.Dynamic addFilter(String filterName, |
大概意思是:
找不到filterdef就自己创建一个,根据名字获得filterclass然后 context.addFilterDef(filterDef),最后返回ApplicationFilterRegistration对象
1 | package demos.web.mytext; |