Java反序列化—Fastjson基础

news2024/11/25 20:32:22

0x01 前言

最近摆烂了很久,来学习一下fastjson

0x02 Fastjson 简介

Fastjson 是 Alibaba 开发的 Java 语言编写的高性能 JSON 库,用于将数据在 JSON 和 Java Object 之间互相转换。

提供两个主要接口来分别实现序列化和反序列化操作。

JSON.toJSONString 将 Java 对象转换为 json 对象,序列化的过程。
JSON.parseObject/JSON.parse 将 json 对象重新变回 Java 对象;反序列化的过程
  • 所以可以简单的把 json 理解成是一个字符串。

0x03 代码 demo

1. 序列化代码实现

这里通过 Demo 了解下如何使用 Fastjson 进行序列化和反序列化,以及其中的一些特性之间的区别等等。

首先,pom.xml 里面导入 Fastjson 的依赖,这里先导入 1.2.24 的。

<dependency>  
 <groupId>com.alibaba</groupId>  
 <artifactId>fastjson</artifactId>  
 <version>1.2.24</version>  
</dependency>

定义了一个Student类

public class Student {  
    private String name;  
    private int age;  
  
 public Student() {  
        System.out.println("构造函数");  
 }  
  
    public String getName() {  
        System.out.println("getName");  
        return name;  
 }  
  
    public void setName(String name) {  
        System.out.println("setName");  
        this.name = name;  
 }  
  
    public int getAge() {  
        System.out.println("getAge");  
        return age;  
 }  
  
    public void setAge(int age) {  
        System.out.println("setAge");  
        this.age = age;  
 }  
}

然后写序列化的代码,调用 JSON.toJsonString() 来序列化 Student 类对象 :

import com.alibaba.fastjson.JSON;  
import com.alibaba.fastjson.serializer.SerializerFeature;  
  
// 最开始的序列化 demopublic class StudentSerialize {  
    public static void main(String[] args) {  
        Student student = new Student();  
 student.setName("Drunkbaby");  
//        student.setAge(6);  
 String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);  
 System.out.println(jsonString);  
 }  
}

这个地方,序列化的逻辑我们可以稍微调试看一下。

首先会进到 JSON 这个类,然后进到它的 toJSONString() 的函数里面,new 了一个 SerializeWriter 对象。我们的序列化这一步在这里就已经是完成了。

在进到 JSON 这个类里面的时候多出了个 static 的变量,写着 “members of JSON”,这里要特别注意一个值 DEFAULT_TYPE_KEY 为 “@type”,这个挺重要的。

里面定义了一些初值,赋值给 out 变量,这个 out 变量后续作为 JSONSerializer 类构造的参数。

继续往下面走,就是显示的部分了,toString() 方法,最后的运行结果。

很明显这句语句是关键的。

String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);

我们关注于它的参数

第一个参数是 student,是一个对象,就不多说了;
第二个参数是 SerializerFeature.WriteClassName,是 JSON.toJSONString() 中的一个设置属性值,设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名,type 可以指定反序列化的类,并且调用其 getter/setter/is 方法。
  • Fastjson 接受的 JSON 可以通过@type字段来指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作。

输出如下:

// 设置了SerializerFeature.WriteClassName
构造函数
setName
setAge
getAge
getName
{"@type":"org.example.Student","age":6,"name":"John"}
 
// 未设置SerializerFeature.WriteClassName
构造函数
setName
setAge
getAge
getName
{"age":6,"name":"John"}

2. 反序列化代码实现

调用 JSON.parseObject(),代码如下

FastjsonEzPoc.java

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;


public class FastjsonEasyPoc {
    public static void main(String[] args){
        String jsonString ="{\"@type\":\"Student\",\"age\":18,\"name\":\"ttt\"}";

        JSONObject obj = JSON.parseObject(jsonString);
        System.out.println(obj);
    }
}

运行结果如图

至此,代码 demo 结束

3.调试分析

在JSON.parseObjct(jsontoString)打个断点,我们看看这些方法是怎么调用的

parse分析

getDeserialize分析

进入parseObject,首先通过parse去解析text,返回一个Object的obj,然后返回JSONObject类型的JSON.toJSON(obj)。

这个JSONObject实际上是一个Map

进入parse(text),来到DefaultJSONParser这里,会采用默认的JSONParser解析器来解析text

得到parser后继续通过parse.parse来解析,核心逻辑全在这里

跟进parse.parse,首先会进行lexer的赋值,然后通过switch来判断lexer.token的值

当前token值为12,对应左大括号

所以会进入到case LBRACE这里,new JSONObject首先新建了一个Map赋值为object,然后作为参数进入parseObject

跟进parseObejct,先判断lexer.token的值,都不满足

进入for这里是个死循环,继续走到ParseContext context = this.context这里,进行简单的赋值。AllowArbitraryCommas表示遇到多个逗号会跳过,进行往下走,会判断ch为,或者:之类的

我们的ch为冒号,所以会走到这里。首先通过"为标志取出key为@type,lexer.skipWhitespace()是跳过空格,然后继续取出ch进行判断

接着判断!isObjectKey后进入,寻找下一个元素跳过空格,然后继续取出当前元素。

重点在loadClass这里,先判断key是否等于@type,然后取出要加载的类名typename,接着使用loadClass进行加载

跟进loadClass,先判断className是否为空,然后mappings.get(className)会先从缓存中寻找该类

addBaseClassMappings会预先放一堆类到mappings里面,当然这里肯定是加载不到的

继续往下走,className.charAt(0)从类名中取第一个字符,如果是[的话就使用数组的方式来加载,这里肯定不是了。

第二个if也是进行判断,如果是L字母开头并且是;结尾的,会把L和;去掉然后加载,后面的绕过中有个地方就用到这个特性

走到contextClassLoader处,通过Thread.currentThread().getContextClassLoader()获取AppClassLoader。

接着使用AppClassLoader来加载Student类,将它放到缓存里面,然后返回clazz。

退出loadclass后往下走到,先判断token这类的东西,没有什么影响。走到object.size()这里,每加载完一轮key:value之后都会往object里面放,现在还没有放所以size为0。

接下来这个就比较重要了,上面的过程还是在json字符解析的操作阶段,接下来就要安装java的方法进行反序列化(其实和java那个原生的反序列化也不一样)。通过config.getDeserializer(clazz)获取反序列化器,然后使用这个反序列化器来反序列化

跟进getDeserializer,也是先从缓存中寻找反序列化器,构造方法在构造时会先把系统的一些类放入缓存中,当然这里肯定也是找不到的

继续往下,判断Student类是否为Class的实例

跟进getDeserializer,前面还是从缓存中寻找Student类

走到这里,clazz.getAnnotation(JSONType.class)会clazz中获取注解,类似于自己写个反序列化器,Student类也是没有

走到for这里,有个黑名单java.lang.Thread,设计的目的也许时线程会影响性能,所以className不能为这个

接着如果className是java.awt开头的话,就使用下面的反序列化器

走到这里判断clazz是否是数字、数组之类的,会进行很多类似的判断,我们都不符合

最后系统会默认把你当成一个JavaBean来创建反序列化器

跟进这个createJavaBeanDeserializer,这里有个字段asmEnable,是java底层动态创建类、动态加载的一个记录,默认值为true

前面会经过一些无关紧要的判断就不说了,asmEnable这个开关在某些时候也是会关闭的。比如下面Student的标识符不是public的话就会关闭,也就是asmEnable为flase

如果泛型的长度不为0,也是会关闭的,不过这里是0

直接走到这里,这个函数很重要。在创建对应的反序列化器时,它要把你这个类的东西进行了解,比如setter、getter、filed、构造函数之类的,通过这个build函数组成一个javaBeaninfo

我们看一下这个函数怎么实现的,首先它获取Student的所有字段和所有方法,获取默认的构造方法,实际上就是我们的无参构造

然后进行一些判断,如果没有无参构造函数.........就直接跳过

走到这里,它把这个构造函数设置为能访问

走到三个for这里,比较重要。第一个for是遍历setter、第三个for是遍历getter

第一个methodname是getname,如果长度大于4就跳过,如果getname是修饰符是静态的话也跳过

如果返回类型不是void.type也跳过,setter一般返回类型都是void,我们当前是getname返回类型肯定不是void,所以直接跳过到下一个

下一个是setName,前面说的条件都满足

往下走到这里,如果不是set开头的话也会跳过

上面都满足后就会来到这里,不管你的方法是大写还是小写,都会将它转为小写

接着获取当前field的所有信息,然后一些不重要的判断

一路走到最后add这里

跟进这个FieldInfo,前面是一些赋值、然后进行判断、设置method与field允许访问,重点在getonly这里,默认值是flase

首先判断你的参数类型是否为1,为1则进入if。我们的目的是让它进入else,将getOnly改成true,这个后面再说原因。当然这里也是没成功,进入了if

后面则是一些泛型的判断,也是进不去的,直接返回。这里主要的是这个getOnly,后面会有用

回到外面add会将其放入fieldList表单里面,继续进行for (Method method : methods)的循环,都差不多就不看了,直接进入到下一个for

clazz.getFields()会获取所有public字段,实际上都是private,所以直接进入下一个for遍历getter

它跟前面遍历setter的逻辑有点不一样,前面还是一样的。看看不一样的地方,这个if是要求你的返回值为Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong几种才会进入里面的add

同时要求fieldList这个表单里面没有setter,不然会跳过。也就是只能有getter,不能有setter,而且getter返回值还有符合类型,才能进入add

当前肯定是不满足条件的,直接出来了。最后就是到这进入JavaBeanInfo,可以跟进去看看,没什么特殊的逻辑,就是把该传的传进去

完成JavaBeanInfo.build之后得到beanInfo,在后面还有一些机会把asmEnable这个开关给关了,我们来看看

第一个if如果beanInfo的字段长度大于200,开关会关闭

第二个if如果默认构造函数为空,并且类不是接口,开关会关闭

接着会遍历你的字段,第一个if如果字段中有人是getOnly的话,开关会关闭,后面几个if也是可以关闭开关,不管都进不去了

那么这个开关有什么用呢?一直走到这里看看,如果开关说关闭的,就会new一个系统内置的JavaBeanDeserializer

当前我们是true肯定进入不了,那么就会进入try通过asmFactory创建一个临时的JavaBeanDeserializer

这里已经获取到了,叫做FastjsonASMDerializer

那么这个有什么危害呢?我们上面已经获取到反序列化器了,接下面应该通过该反序列化器进行反序列化

但是这个反序列化器是个临时的,代码不在我们这里面。所以当我们一直F7进入deserializer.deserialze时,代码代码是没有变化的,但下面的值是会改变,已经是调试不了了。所以这就是为什么要关闭开关的原因

那我们要怎么修改呢?我们肯定是要在这里修改,修改某成员的getOnly为true,在ParserConfig.java时就会把开关关闭

那就要进入else。但因为setter的参数值是1,setter肯定进不了的。

而且前面第一个for那里判断时如果把setter参数设为0,也进不来add这一步

所以只能在getter改,但getter返回类型需要满足条件,为其中四种才能进入add

所以直接在Student类那里新建一个getmap就好了,这样就能使用系统默认的反序列化器

我们再来调试一下,当前是getMap

跟进new FieldInfo()

顺利进入else将getOnly设置为true

一直回到ParserConfig这里,当遍历到map的时候,就关掉了开关

后面就能使用javaBeanDeserialize,也就能调试了

一路F8,获取到反序列化器后,就使用该反序列化器来调deserialize方法

deserialize方法

在上面F7一直跟进,前面都是简单的赋值之类的操作,这段代码是遍历Field

后面的一些判断就比较复杂,是根据json字符串走的,我们按照默认的分支看看会发生什么就行了

跟进createInstance,如果是接口的话就先获取默认加载器,然后创建动态代理,这里肯定不是跳过

走到这里,获取默认构造方法

最后在下面的else进行调用,很容易忽略

一路走出来回到这里

上面调用完构造函数,后面就是给它赋值了。赋值的话一般是通过反射或者setter赋值,实际上这里是setter赋值,这里跟进看一下

实际上是通过上面获取setAge方法,然后在这里通过invoke调用

setName也是一样,这里就不细看了,setter方法就是在这里调用的。那么getter方法又在哪里调用呢?

tojson调用

一路F8出来到tojson那里跟进

前面都是一些赋值和对Field的操作,可以自己看看,走到这里

跟进getFieldValuesMap,首先获取第一个getter,就是getAge,然后把它放到map里面

getter方法就是在getPropertyValue调用的

在fieldInfo.get(object)完成调用

还有一种如果符合特殊形式的话,也会调用。可以看到调用了两次getMap,map、properties之类的都行

触发点在这,代码可以自己跟一跟

那么如果某个类的setter或者getter里面有危险方法,不就可以直接完成攻击了吗,类似于我这里改一改

getmap里面有危险方法

0x04 另外一些基础

Java反序列化Fastjson篇01-FastJson基础 | 芜风

0x05 fastjson 反序列化漏洞原理

fastjson 在反序列化的时候会去找我们在 @type 中规定的类是哪个类,然后在反序列化的时候会自动调用这些 setter 与 getter 方法的调用,注意!并不是所有的 setter 和 getter 方法。

下面直接引用结论,Fastjson会对满足下列要求的setter/getter方法进行调用:

满足条件的setter:

非静态函数
返回类型为void或当前类
参数个数为1个

满足条件的getter:

非静态方法
无参数
返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

1. 漏洞原理

由前面知道,Fastjson是自己实现的一套序列化和反序列化机制,不是用的Java原生的序列化和反序列化机制。无论是哪个版本,Fastjson反序列化漏洞的原理都是一样的,只不过不同版本是针对不同的黑名单或者利用不同利用链来进行绕过利用而已。

通过Fastjson反序列化漏洞,攻击者可以传入一个恶意构造的JSON内容,程序对其进行反序列化后得到恶意类并执行了恶意类中的恶意函数,进而导致代码执行。

那么如何才能够反序列化出恶意类呢?

由前面demo知道,Fastjson使用parseObject()/parse()进行反序列化的时候可以指定类型。如果指定的类型太大,包含太多子类,就有利用空间了。例如,如果指定类型为Object或JSONObject,则可以反序列化出来任意类。例如代码写Object o = JSON.parseObject(poc,Object.class)就可以反序列化出Object类或其任意子类,而Object又是任意类的父类,所以就可以反序列化出所有类。

接着,如何才能触发反序列化得到的恶意类中的恶意函数呢?

由前面知道,在某些情况下进行反序列化时会将反序列化得到的类的构造函数、getter方法、setter方法执行一遍,如果这三种方法中存在危险操作,则可能导致反序列化漏洞的存在。换句话说,就是攻击者传入要进行反序列化的类中的构造函数、getter方法、setter方法中要存在漏洞才能触发。

我们到DefaultJSONParser.parseObject(Map object, Object fieldName)中看下,JSON中以@type形式传入的类的时候,调用deserializer.deserialize()处理该类,并去调用这个类的setter和getter方法:

public final Object parseObject(final Map object, Object fieldName) {
    ...
    // JSON.DEFAULT_TYPE_KEY即@type
    if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
        ...
        ObjectDeserializer deserializer = config.getDeserializer(clazz);
        return deserializer.deserialze(this, clazz, fieldName);

分析在上面调试中了

小结一下

若反序列化指定类型的类如Student obj = JSON.parseObject(text, Student.class);,该类本身的构造函数、setter方法、getter方法存在危险操作,则存在Fastjson反序列化漏洞;

若反序列化未指定类型的类如Object obj = JSON.parseObject(text, Object.class);,该若该类的子类的构造方法、setter方法、getter方法存在危险操作,则存在Fastjson反序列化漏洞;

2. PoC 写法

一般的,Fastjson反序列化漏洞的PoC写法如下,@type指定了反序列化得到的类

{
"@type":"xxx.xxx.xxx",
"xxx":"xxx",
...
}

关键是要找出一个特殊的在目标环境中已存在的类,满足如下两个条件:

1. 该类的构造函数、setter方法、getter方法中的某一个存在危险操作,比如造成命令执行;
2. 可以控制该漏洞函数的变量(一般就是该类的属性);

0x06 小结

总结一下漏洞发生在反序列化的点,也就是 Obj.parse 和 Obj.parseObject 这里。必须的是传参要带入 class 的参数,最好带上 Feature.SupportNonPublicField

PoC 是通过 String 传进去的,要以 @type 打头。

漏洞的原因是反序列化的时候去调用了 getter 和 setter 的方法。其余就没什么了,比较简单。

参考文章

Java反序列化Fastjson篇01-FastJson基础 | 芜风 (drun1baby.github.io)

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

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

相关文章

socket应用之从电脑发送图片到手机(1)之通信过程建立

本人曾经做了一个基于MPVd的C#开发的播放器&#xff0c;用于自娱自乐&#xff0c;后来又用websocket 写了个简单的远程控制器。由于websocket 要依赖于浏览器&#xff0c;因此有诸多不便&#xff0c;后来又用flutter写了一个&#xff0c;方便多了。 下面介绍具体实现。 1、通信…

RabbitMQ 消息持久化

RabbitMQ 消息持久化 持久化是为提高rabbitmq消息的可靠性&#xff0c;防止在异常情况(重启&#xff0c;关闭&#xff0c;宕机)下数据的丢失。设置完队列和消息的持久化&#xff0c;并不能完全保证消息不会丢失。尽管它告诉 RabbitMQ 将消息保存到磁盘&#xff0c;但当 Rabbit…

mapbox-gl添加threejs飞线

文章目录前言飞线实现1 初始化地图并加载three图层2 绘制飞线几何体将几何体正确定位在mapbox上正确操作BufferGeometry几何体3 tween实现动画全部代码总结待改进之处参考前言 mapbox-gl是一个基于webgl开发的三维地图渲染引擎&#xff0c;但是很多三维特效只用mapbox并不容易…

【CSDN 年终总结】CSDN的进阶之路—— “1+1=王”的2022总结

正文之前打个广告&#xff0c;我正在参加年度博客之星评选&#xff0c;请大家帮我投票打分&#xff0c;您的每一分都是对我的支持与鼓励。⭐ ⭐ ⭐ ⭐ ⭐https://bbs.csdn.net/topics/611386885?spm1001.2014.3001.6953 2022我在CSDN 2022 在CSDN是持续输出&#xff0c;持续…

TinyPng图片压缩的正确打开方式

https://tinypng.com/ TinyPNG使用智能的「有损压缩技术」来减少WEBP、JPEG和PNG文件的文件大小。通过选择性地减少图像中的「颜色数量」&#xff0c;使用更少的字节来存储数据。这种效果几乎是看不见的&#xff0c;但在文件大小上有非常大的差别。 使用过TinyPNG的都知道&…

MyBatis 万字长文:从入门到动态SQL超详细

文章目录1. 前言2. 创建项目3. 添加框架支持4. 建库5. 配置数据库连接信息和 XML 文件路径5.1 创建 Java 类5.2 Java 接口5.3 XML 文件6. 查询6.1 不带参数的查询6.2 单元测试6.3 带参数的查询7. 修改8. 增加8.1 将对象插入表中8.2 获取自增主键9. 删除10. 数据库字段和类属性名…

Video2StyleGAN: Disentangling Local and Global Variations in a Video翻译

点击下载论文 代码地址 摘要 使用预训练的StyleGAN生成器进行图像编辑已成为面部编辑的强大范例&#xff0c;它提供了对年龄、表情、照明度等的解纠缠控制。然而&#xff0c;该方法不能直接用于视频操作。我们认为主要因素是缺乏对面部位置、面部姿势和局部面部表情的精细和清…

腾讯云-云服务器购买流程-Java项目部署(详细的一批)

文章目录云服务器购买云服务搭建部署环境宝塔面板使用&#xff08;安装所需环境&#xff09;部署SpringBoot项目出现Error: Unable to access jarfile /www/wwwroot/xxxx.jar--server.port6066 问题解决腾讯云COS有什么用&#xff1f;如果感觉有用就一键三连吧&#xff0c;创作…

Electron 实现切换暗_亮模式与主题

文章末尾附上仓库地址&#xff01;&#xff01;&#xff01;&#xff01; 清单 模板基于 electron-vite-vue vue3 ts vite组件库 element-plushooks库 vueuse 、useElementPlusTheme 初始化工程 使用 electron-vite 作为模板&#xff0c;方便大家尽快吧项目跑起来 # 创建模…

Java面试之数据库篇

一、基础 1.数据库事务的特征ACID 原子性&#xff08;Atomicity&#xff09;&#xff1a;原子性是指事务包含的所有操作要么全部成功&#xff0c;要么全部失败回滚&#xff0c;这和前面两篇博客介绍事务的功能是一样的概念&#xff0c;因此事务的操作如果成功就必须要完全应用…

UOS服务器操作系统多版本Java切换

一、修改java的环境变量和软链接来实现版本切换 1、配置环境变量 sudo vim &#xff5e;/.bashrc 2、创建java运行程序软连接 3、使配置生效&#xff0c;并检查java版本 source /etc/profile 二、使用update-alternatives 进行版本的切换 1、同时安装了openjdk-8-jdk 和…

shell第七天作业——awk

题目 1、获取根分区剩余大小 2、获取当前机器ip地址 3、统计出apache的/var/log/httpd/access_log文件中访问量最多的前3个IP 4、打印/etc/passwd中UID大于500的用户名和uid 5、/etc/passwd 中匹配包含root或sys或tcp的任意行 6、请打印出/etc/passwd 第一个域&#xff0…

指针进阶之数组参数和指针参数

文章目录一、回顾1.字符指针2.指针数组和数组指针&#xff08;1&#xff09;指针数组&#xff08;2&#xff09;数组指针二、数组参数1.一维数组传参&#xff08;1&#xff09;整型数组&#xff08;2&#xff09;指针数组&#xff08;3&#xff09;总结2.二维数组传参&#xff…

基于Python tensorflow2.3实现的水果识别系统源码+模型+数据集,卷积神经网络的入门案例

水果识别-基于tensorflow2.3实现 水果识别是卷积神经网络的入门案例&#xff0c;这里我将模型的训练、测试、保存以及使用整合在了一起&#xff0c;至于原理部分&#xff0c;大家可以参考知乎或者B站上的回答&#xff0c;在这里我就不赘述了 完整代码下载地址&#xff1a;基于…

计算机网络实验---验证性实验

实验一/ipconfig 实作一 实作二 实验二/ping 实作一 实作二 实验三/tracert 实作一 实作二 实验四/ARP 实作一 实作二 实作二 实验五/DHCP 实作一 实验六/netstat 实作一 实作二 实验七/DNS 实作一 实作二 实作二 实验八/cache 实作一 实作二 总结 实验一/ipconfig 实…

[Leetcode] 二叉树的遍历

转载自&#xff08;有删减和少量改动&#xff09; 图解二叉树的四种遍历 https://leetcode.cn/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/1. 相关题目144.二叉树的前序遍历 https://leetcode.cn/problems/binary-tree-p…

【SpringMVC 入门教程】

SpringMVC_day02 &#x1f308;博客主页&#xff1a;屠一乐的博客 &#x1f4c5; 发文时间&#xff1a;2023.1.5 &#x1f388; 一定存在只有你才能做成的事 &#x1f339; 博主水平有限&#xff0c;如有错误&#xff0c;欢迎指正 欢迎各位&#x1f44d;收藏&#x1f48e;评论✉…

MacBookPro安装mysql遇到的几个问题

用Mac的好处是不用开关机&#xff0c;无弹窗无广告&#xff0c;坏处是在安装某些第三方的软件时&#xff0c;总是和视频教程上的winows版不一致&#xff0c;需要自己上网找资料尝试怎么安装。今天学python&#xff0c;需要安装mysql&#xff0c;幸好网上有一些文章&#xff0c;…

Vulnhub靶机:MISDIRECTION_ 1

目录介绍信息收集主机发现主机信息探测网站探测反弹shell方式1&#xff1a;使用nc方式2&#xff1a;使用bash方式3&#xff1a;使用MSF提权sudo提权passwd提权docker提权参考介绍 系列&#xff1a;Misdirection&#xff08;此系列共1台&#xff09; 发布日期&#xff1a;2019 …

【ClickHouse】从Mysql迁移到ClickHouse大全

从关系型的数据库(Mysql)升级到列式管理的联机分析型数据库(ClickHouse)&#xff0c;这不亚于是小米加步枪升级为加特林机关枪的性能提升了&#xff0c;查询能力等确实是大大的提升了&#xff0c;这出现了一个问题我们之前存储在Mysql里的历史数据怎么往ClickHouse里面迁移呢&a…