当前位置: 首页 > news >正文

内网渗透瑞士军刀-impacket工具解析(二)

impacket工具解析之Kerberos认证协议

上一期我们介绍了impacket中ntlm协议的实现,在Windows认证中除了使用ntlm认证,还支持Kerberos认证协议,Kerberos认证也是Windows 活动目录中占比最高的认证方式。
什么是Kerberos协议?

Kerberos协议是一种网络身份验证协议,用于在计算机网络环境中进行安全的身份验证和授权,最初由麻省理工学院(MIT)开发。微软在Windows 操作系统中实现了 Kerberos 协议,作为Windows Active Directory(AD)默认的身份验证协议。

ASN.1

我们在Kerberos协议RFC文档可以看到使用类似于以下格式的语句来描述Kerberos的消息结构。


PrincipalName::= SEQUENCE {name-type       [0] Int32,name-string     [1] SEQUENCE OF KerberosString}

这种表示方法和ntlm协议直接使用字节排列的方式来描述有所不同,该描述方式被称作ASN.1。

Kerberos 协议使用 ASN.1(Abstract Syntax Notation One)来定义和描述其消息格式和数据结构。ASN.1 是一种通用的数据表示和编码规范,用于描述结构化数据和交换格式。

在 Kerberos 中,ASN.1 用于定义各种消息类型、字段和数据结构。每个消息类型都有其自己的 ASN.1 定义,包括消息的字段、类型、长度和顺序等信息。这些 ASN.1 定义规定了 Kerberos 消息的结构和编码规则。

01类型表示

ASN.1 定义了一套抽象的数据类型和结构,包括简单类型(如整数、字符串)和复合类型(如序列、集合)。这些抽象数据类型提供了一种独立于具体实现的方式来描述数据结构。

简单类型

ASN.1定义了多种简单类型,用于描述基本的数据类型。

  1. INTEGER:INTEGER 类型用于表示整数。它可以表示正整数、负整数或零。根据需要,可以指定整数的取值范围和约束条件。
  2. BOOLEAN:BOOLEAN 类型用于表示布尔值,即真或假。它只有两个取值:TRUE 和 FALSE。
  3. ENUMERATED:ENUMERATED 类型用于表示枚举类型,其中每个枚举值都有一个对应的整数值。ENUMERATED
    类型可以定义一组具体的枚举值,并为每个值分配一个整数。
  4. NULL:NULL 类型用于表示一个空值,不包含任何数据。它通常用于表示缺少值或占位符。
  5. OCTET STRING:OCTET STRING
    类型用于表示二进制数据,通常是字节序列。它可以表示任意长度的字节流,用于传输和存储二进制数据。
  6. BIT STRING:BIT STRING 类型用于表示位串,即位的序列。它可以表示定长或变长的位序列,用于表示比特字段和位标志。
  7. OBJECT IDENTIFIER:OBJECT IDENTIFIER
    类型用于表示对象标识符(OID),它是一个全局唯一的标识符,用于标识实体、算法、属性等。
  8. UTF8String:UTF8String 类型用于表示以 UTF-8 编码的字符串。它可以包含任意 Unicode
    字符,并支持国际化字符集。

这些简单类型提供了一种通用的方式来表示和传输基本数据类型。ASN.1 还支持其他一些简单类型,如实数、日期时间等,以满足更具体的数据需求。

复合类型

除了简单类型,ASN.1还提供了多种复合类型,用于描述和组织结构化数据。以下是一些常见的 ASN.1 复合类型:

  1. SEQUENCE:SEQUENCE
    是最常用的复合类型之一,它定义了一组按顺序排列的成员。每个成员可以是简单类型或其他复合类型。成员的顺序在序列化和解析数据时必须保持一致。
  2. SET:SET 类型与 SEQUENCE 类似,但是它不要求成员的顺序,可以无序地存储和表示。在序列化和解析数据时,SET
    类型会根据成员的标签进行匹配。
  3. CHOICE:CHOICE 类型允许在一组成员中选择一个进行存储和表示。每个成员都有一个唯一的标签,用于标识所选择的成员。CHOICE
    类型只能存储和表示选择的成员,而其他成员则被忽略。
  4. SEQUENCE OF 和 SET OF:SEQUENCE OF 和 SET OF
    类型允许定义一个成员的序列或集合。它们表示成员的重复出现,可以包含零个或多个相同类型的成员。
  5. ARRAY:ARRAY 类型定义了一个固定长度的数组,其中每个元素可以是简单类型或其他复合类型。ARRAY 类型在某些编程语言中可能与
    SEQUENCE OF 或 SET OF 类型实现相似。

这些 ASN.1 复合类型提供了组织和描述结构化数据的灵活性和可扩展性。通过组合和嵌套这些复合类型,可以构建复杂的数据结构,以满足特定应用或协议的需求。

02编码

ASN.1 定义了不同的编码规则,用于将抽象的数据类型转换为二进制格式进行传输和存储。常见的编码规则包括基于长度的编码(BER,Basic Encoding Rules)、基于标记的编码(DER,Distinguished Encoding Rules)、基于CER的编码(CER,Canonical Encoding Rules)等。

其中Kerberos协议规定使用DER编码方式。

示例

我们可以通过impacket中使用的asn.1开源实现pyasn1来演示一些基本的asn1数据类型表示及数据编码。首先使用asn.1定义一个复合类型。

Record ::= SEQUENCE {  id        INTEGER,room  [0] INTEGER OPTIONAL,house [1] INTEGER DEFAULT 0}

根据pyasn1提供的类描述该类型

from pyasn1.type.univ import *
from pyasn1.type.tag import *
from pyasn1.type.namedtype import *class Record(Sequence):componentType = NamedTypes(NamedType('id', Integer()),OptionalNamedType('room', Integer().subtype(implicitTag=Tag(tagClassContext, tagFormatSimple, 0))),DefaultedNamedType('house', Integer(0).subtype(implicitTag=Tag(tagClassContext, tagFormatSimple, 1))))

直接输出


record = Record()
record['id'] = 123
record['room'] = 321
print(record)-----------------------------------
Record:
id=123
room=321

pyasn1也实现了ber、der、cer编码方式,例如使用der对该消息进行编码。


from pyasn1.codec.der import encoderencodedRecord = encoder.encode(record)
print(encodedRecord.hex())----------------------------------------
300702017b80020141

Kerberos数据类型

kerberos大部分的数据类型定义位于impacket/krb5/asn1.py中,文件中实现了Kerberos协议中定义的简单类型如Int32、UInt32、Microseconds、KerberosString

class Int32(univ.Integer):subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(-2147483648, 2147483647)class UInt32(univ.Integer):pass
subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, 4294967295)class Microseconds(univ.Integer):subtypeSpec = univ.Integer.subtypeSpec + constraint.ValueRangeConstraint(0, 999999)class KerberosString(char.GeneralString):# TODO marc: I'm not sure how to express this constraint in the API.# For now, we will be liberal in what we accept.# subtypeSpec = constraint.PermittedAlphabetConstraint(char.IA5String())pass

在简单类型的基础上通过序列组合形成多个复合类型如PrincipalName、HostAddress、AuthorizationData、PA_DATA等。

class PrincipalName(univ.Sequence):componentType = namedtype.NamedTypes(_sequence_component("name-type", 0, Int32()),_sequence_component("name-string", 1,univ.SequenceOf(componentType=KerberosString())))class HostAddress(univ.Sequence):componentType = namedtype.NamedTypes(_sequence_component("addr-type", 0, Int32()),_sequence_component("address", 1, univ.OctetString()))class AuthorizationData(univ.SequenceOf):componentType = univ.Sequence(componentType=namedtype.NamedTypes(_sequence_component('ad-type', 0, Int32()),_sequence_component('ad-data', 1, univ.OctetString())))class PA_DATA(univ.Sequence):componentType = namedtype.NamedTypes(_sequence_component('padata-type', 1, Int32()),_sequence_component('padata-value', 2, univ.OctetString()))

01KDC_REQ

KDC_REQ用于客户端向KDC发送请求,impacket中用于认证的请求AS_REQ和票据请求的TGS_REQ都通过继承KDC_REQ来实现自身结构,该结构定义如下:


KDC-REQ        ::= SEQUENCE {pvno         [0] INTEGER (5),msg-type     [1] INTEGER (10 -- AS --),padata       [2] SEQUENCE OF PA-DATA OPTIONAL,req-body     [3] KDC-REQ-BODY
}

KDC-REQ中的字段有4种:

  • pvno:协议版本号,表示 Kerberos 协议的版本。
  • msg-type:消息类型,表示消息的类型,对于 AS_REQ 结构,它的值为 10,表示 AS 请求。
  • padata:可选字段,表示附加的认证数据(Pre-Authentication Data)。
  • req-body:KDC-REQ-BODY 结构,包含了请求的主体信息,如客户端的身份信息、请求的服务等。
KDC-REQ-BODY   ::= SEQUENCE {kdc-options             [0] KDCOptions,cname                   [1] PrincipalName OPTIONAL,realm                   [2] Realm,sname                   [3] PrincipalName OPTIONAL,from                    [4] KerberosTime OPTIONAL,till                    [5] KerberosTime,rtime                   [6] KerberosTime OPTIONAL,nonce                   [7] UInt32,etype                   [8] SEQUENCE OF Int32 -- EncryptionTypeaddresses               [9] HostAddresses OPTIONAL,enc-authorization-data  [10] EncryptedData OPTIONAL,additional-tickets      [11] SEQUENCE OF Ticket OPTIONAL
}

KDC-REQ-BODY 结构中的字段包括

  • kdc-options:KDC 选项,表示请求的选项,如是否要求可续期票据、是否要求使用预认证等。
  • cname:客户端名称,表示客户端的主体名称。
  • realm:域,表示域的名称。
  • sname:服务名称,表示请求的服务的主体名称。
  • from:可选字段,表示票据的有效起始时间。
  • till:票据的有效截止时间。
  • rtime:可选字段,表示票据的可续期时间。
  • nonce:随机数,用于防止重放攻击。
  • etype:加密类型,表示请求的票据的加密类型。
  • addresses:可选字段,表示客户端的网络地址。
  • enc-authorization-data:可选字段,表示加密的授权数据。
  • additional-tickets:可选字段,表示附加的票据。

02 KDC_REP

KDC_REP用于表示KDC向客户端发送的响应,impacket中用于认证的请求AS_REP和票据请求的TGS_REP通过继承KDC_REP来实现自身结构,该结构定义如下:

KDC-REP        ::= SEQUENCE {pvno         [0] INTEGER (5),msg-type     [1] INTEGER (11 -- AS -- | 13 -- TGS --),padata       [2] SEQUENCE OF PA-DATA OPTIONAL,crealm       [3] Realm,cname        [4] PrincipalName,ticket       [5] Ticket,enc-part     [6] EncryptedData
}

KDC_REP 结构中的字段包括

  • pvno:协议版本号,表示 Kerberos 协议的版本。
  • msg-type:消息类型,表示消息的类型。对于 KDC_REP 结构,它的值可以是 11(AS 响应)或 13(TGS 响应),取决于是
    AS 请求还是 TGS 请求的响应。
  • padata:可选字段,表示附加的认证数据(Pre-Authentication Data)。
  • crealm:域(realm),表示响应的域的名称。
  • cname:客户端名称,表示客户端的主体名称。
  • ticket:票据,表示请求的票据(Ticket Granting Ticket,TGT)或服务票据(Service Ticket)。
  • enc-part:加密的部分,表示加密的票据部分或认证数据。

Kerberos函数

在impacket库中,用于Kerberos认证最常用的一些顶层函数位于impacket/krb5/kerberosv5.py中,在文件中主要通过以下3个函数来实现Kerberos认证。

01 sendReceive

sendReceive是一个Kerberos消息发送和接收函数,该函数除了与KDC的88端口建立通信连接外,还对KDC的消息进行了一些处理,我们可以看到在25行,对接收到的数据包进行了解码,在39行的判断中,如果出现KDC_ERR_PREAUTH_REQUIRED以外的错误,都会抛出异常。同时我们也可以看到,这个函数会优先使用kdcHost参数作为连接目标,只有kdcHost为None的情况下才会使用host作为连接目标,kdcHost和host分别代表了目标ip和目标主机名。
在impacket中,通常会将域名设置为host,kdcHost作为一个可选参数,通过Kerberos认证时如果没有指定kdc地址,会尝试通过解析域名来获取kdc地址,所以如果在一台无法解析域名的机器上在没有指定kdcHost(一般是-dc-ip参数)的话就会导致连接失败,这也是使用impacket一个经常出现的问题。

def sendReceive(data, host, kdcHost):if kdcHost is None:targetHost = hostelse:targetHost = kdcHostmessageLen = struct.pack('!i', len(data))LOG.debug('Trying to connect to KDC at %s' % targetHost)try:af, socktype, proto, canonname, sa = socket.getaddrinfo(targetHost, 88, 0, socket.SOCK_STREAM)[0]s = socket.socket(af, socktype, proto)s.connect(sa)except socket.error as e:raise socket.error("Connection error (%s:%s)" % (targetHost, 88), e)s.sendall(messageLen + data)recvDataLen = struct.unpack('!i', s.recv(4))[0]r = s.recv(recvDataLen)while len(r) < recvDataLen:r += s.recv(recvDataLen-len(r))try:krbError = KerberosError(packet = decoder.decode(r, asn1Spec = KRB_ERROR())[0])except:return rif krbError.getErrorCode() != constants.ErrorCodes.KDC_ERR_PREAUTH_REQUIRED.value:try:for i in decoder.decode(r):if type(i) == Sequence:for k in vars(i)["_componentValues"]:if type(k) == GeneralizedTime:server_time = datetime.datetime.strptime(k.asOctets().decode("utf-8"), "%Y%m%d%H%M%SZ")LOG.debug("Server time (UTC): %s" % server_time)except:# Couldn't get server time for some reasonpassraise krbErrorreturn r

02 getKerberosTGT

getKerberosTGT实现的部分比较长,可以从其名称可以看出来是用于获取TGT。


def getKerberosTGT(clientName, password, domain, lmhash, nthash, aesKey='', kdcHost=None, requestPAC=True):# Convert to binary form, just in case we're receiving stringsif isinstance(lmhash, str):try:lmhash = unhexlify(lmhash)except TypeError:passif isinstance(nthash, str):try:nthash = unhexlify(nthash)except TypeError:passif isinstance(aesKey, str):try:aesKey = unhexlify(aesKey)except TypeError:passasReq = AS_REQ()...

从这个函数里面我们也能看到一些重要的信息,首先通过参数我们可以看到支持的凭据包括password、lmhash、nthash、aesKey(lmhash实际没有参与运算)。
在这里插入图片描述
在156行至174行,这里是预认证过程发送的第一个AS_REQ加密方式的初始化,可以看出来客户端支持的加密方式是由提供的凭据类型决定的,输入的凭据对应的加密方式如下,优先级从到下逐渐降低。
在这里插入图片描述
从加密方式的设置上也能看出来,不管提供的是什么凭据,AS_REQ中的加密方式始终只有一种,但是在实际的Windows客户端一般都支持多种加密方式,这也是一个比较明显的特征。

在这里插入图片描述
244行至268行是预身份验证中的第二个AS_REQ进行初始化,在impacket中只实现了加密时间戳的认证方式,这里也是对时间戳进行加密的核心部分,可以看到使用的凭据优先级与上一个AS_REQ相同,根据不同的凭据类型转换成对应的加密key,加密时间戳使用的也是经过编码后的KerberosTime结构。
在这里插入图片描述
311至320行实现了加密方式的回滚,在前面的代码中,我们可以知道当指定了password也就是明文密码时会使用aes256加密方式,而这里捕获了KDC_ERR_ETYPE_NOSUPP异常,也就是KDC不支持aes256,在这里的操作是将明文密码转换为hash,再进行请求。
在这里插入图片描述

332-352行是对AS_REP的enc-part进行解密,这里的enc-part是KDC使用客户端的密钥进行加密的,这里所说的客户端就是AS_REQ中设置的cname,在cname对应的用户UAC设置了DONT_REQ_PREAUTH的情况下,没有设置预认证信息,kdc也会返回使用该用户凭据加密的enc-part,这时候就可以通过离线破解enc-part来获取用户的密钥,这也就是aesreproating攻击的原理。在这个部分的代码,作用主要就是获取sessionKey, sessionKey作为下阶段(TGS_REQ)的认证加密密钥。最后返回的tgt实际上并不是协议描述的TGT,而是整个AS_REP的数据包。

03 getKerberosTGS

getKerberosTGS函数用于获取服务票据,也就是Kerberos认证的第二个阶段,我们从函数的参数可以看到,参数中一些名称正好是和getKerberosTGT的返回值相吻合的,getKerberosTGT通过传参的设计实现了pth(Pass-the-Hash),而在getKerberosTGS参数中的tgt实现ptt(Pass-the-Ticket)。


def getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey):# Decode the TGTtry:decodedTGT = decoder.decode(tgt, asn1Spec = AS_REP())[0]except:decodedTGT = decoder.decode(tgt, asn1Spec = TGS_REP())[0]domain = domain.upper()# Extract the ticket from the TGTticket = Ticket()ticket.from_asn1(decodedTGT['ticket'])apReq = AP_REQ()apReq['pvno'] = 5apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value)

在函数的开头部分对tgt进行了解码,注意这里使用的结构并不是TGT而是AS_REP或者TGS_REP,这是因为两种数据类型虽然不一样,但是结构是完全相同的,并且在AS_REP中的ticket与请求服务为krbtgt返回的TGS_REP中的ticket都可以当作TGT来使用。

367-400行涉及到两个重要结构的初始化,AP_REQ和Authenticator,在AP_REQ的ticket设置的是AS_REQ中获取的tgt,而在Authenticator中设置了客户端主体、请求的spn、域名、时间戳等信息,整个Authenticator使用上一步的sessionKey进行加密。
在这里插入图片描述
在这里插入图片描述
402-438行对TGS_REQ进行了初始化,设置好票据选项、认证数据、域名、时间戳等信息后发送到KDC
在这里插入图片描述
442-468行中,处理与getKerberosTGT类似,首先是对TGS_REP进行解码,在利用sessionKey对enc-part进行解密,获取下一阶段的sessionKey以及服务票据等信息。在这里还进行了返回票据的判断,如果返回票据的spn和请求中设置的spn不一致的话再进行递归调用。请求服务票据。
在这里插入图片描述
服务端根据请求的spn来确定服务主体,如果spn存在的话就会返回TGS票据,并且TGS票据中的ticket部分使用该服务主体的密钥进行加密,绝大部分情况下服务主体都是计算机账户,如果一个用户账户存在spn,就可以利用TGS请求用户的服务票据,这时候返回的TGS票据就会包含使用该用户的密钥进行加密的ticket部分,此时就可以通过离线破解获取用户的密钥,这种攻击手法就是kerberoasting攻击

  以上就是impacket中kerberos实现部分,主要包含了Kerberos消息编码、基础数据结构、消息类型及两个常用的助手函数。在Windows实际的认证中smb、rpc、ldap、http等服务都支持使用ntlm协议和Kerberos协议,两种协议的认证信息如何嵌入到上述协议的数据包中,以及认证数据的交互,我们将在后续的应用层协议解析中再进行具体介绍。

本文转自 公众号 网星安全 https://mp.weixin.qq.com/s/9biFHMHnw37xFG3fryFBZA

相关文章:

内网渗透瑞士军刀-impacket工具解析(二)

impacket工具解析之Kerberos认证协议 上一期我们介绍了impacket中ntlm协议的实现&#xff0c;在Windows认证中除了使用ntlm认证&#xff0c;还支持Kerberos认证协议&#xff0c;Kerberos认证也是Windows 活动目录中占比最高的认证方式。 什么是Kerberos协议&#xff1f; Kerb…...

huggingface 笔记:pipeline

1 介绍 pipeline() 是使用预训练模型进行推理的最简单和最快速的方式。可以针对不同模态的许多任务直接使用 pipeline() 2 举例&#xff1a;情感分析 2.1 创建pipeline实例 from transformers import pipelineclassifier pipeline("sentiment-analysis") #首先创…...

玩转Matlab-Simscape(初级)-01-从一个简单模型开始学习之旅

** 玩转Matlab-Simscape&#xff08;初级&#xff09;- 01 - 从一个简单模型开始学习之旅 ** 目录 玩转Matlab-Simscape&#xff08;初级&#xff09;- 01 - 从一个简单模型开始学习之旅 前言一、从模板开始建模二、建模一个简单的连杆2.1 建模2.2 生成子系统 总结 前言 在产…...

电脑录屏软件有哪些?这3款神器必须要知道

在当今现代社会&#xff0c;电脑录屏软件已经成为人们日常生活中不可或缺的一部分。无论是录制游戏精彩瞬间、制作教程、还是在线会议记录&#xff0c;一款好用的电脑录屏软件都能帮助我们更高效地完成任务。可是电脑录屏软件有哪些呢&#xff1f;接下来&#xff0c;我们将介绍…...

如何在华企盾DSC防泄密系统中设置文件自动加密?

在华企盾DSC系统中设置文件自动加密的过程&#xff0c;简单且用户友好&#xff0c;确保了企业数据的安全&#xff0c;同时不干扰日常工作流程。以下是设置文件自动加密的步骤&#xff1a; 系统安装与配置&#xff1a;确保华企盾DSC数据防泄密系统已经在企业的网络中正确安装和配…...

【DevOps】Dockerfile详解,做自己的docker镜像

学会使用DockerHub找自己想要的镜像以后&#xff0c;我们会很方便的使用一些公用镜像仓库的Docker镜像。但是开发和部署的过程中&#xff0c;能找到的镜像可能并不能满足我们需要&#xff0c;这样我们就需要自己制作Docker镜像。我们通过需要编写一个 Dockerfile&#xff0c;然…...

CSRF 攻击实验:Token 不存在绕过验证

前言 CSRF&#xff08;Cross-Site Request Forgery&#xff09;&#xff0c;也称为XSRF&#xff0c;是一种安全漏洞&#xff0c;攻击者通过欺骗用户在受信任网站上执行非自愿的操作&#xff0c;以实现未经授权的请求。 CSRF攻击利用了网站对用户提交的请求缺乏充分验证和防范…...

c#教程——索引器

前言&#xff1a; 索引器&#xff08;Indexer&#xff09;可以像操作数组一样来访问对象的元素。它允许你使用索引来访问对象中的元素&#xff0c;就像使用数组索引一样。在C#中&#xff0c;索引器的定义方式类似于属性&#xff0c;但具有类似数组的访问方式。 索引器&#x…...

麒麟服务器上执行可执行脚本报错:bash: ./xx: Permission denied(完整版)

前情提要 本来都好好的&#xff0c;我重启了服务器以后就开始报这个错了&#xff0c;而我的麒麟服务器目前是这个情况&#xff1a; 已经在服务器上配置好了 ssh 免密登录&#xff0c;在命令行里执行 ssh -o StrictHostKeyCheckingno -p 22 usernamexxx.xxx.xxx.xxx 可以正常登…...

触觉美学:移动端UI设计的视觉盛宴

...

前端起dev从110秒减少到7秒, 开发体验大幅提升

[webpack由浅入深]系列的内容 第一层: 了解一个小功能的完整流程. 看完可以满足好奇心和应付原理级别面试.第二层: 源码陪读, webpack源码比较灵活, 自己看容易陷入迷惑. 文章里会贴出关键流程的代码来辅助阅读源码. 如果你正在自己调试, 在这些方法上下断点会节约你宝贵的时间…...

Flink CDC 原理

简介 Flink CDC&#xff08;Change Data Capture&#xff09;是 Apache Flink 提供的一个变更数据捕获工具集。它可以监控数据库的变更&#xff0c;并将这些变更实时地以流的形式提供给下游系统&#xff0c;这些变更包括插入、更新和删除操作。 Flink CDC 适用于需要实时数据…...

Axure网上超市用户端APP原型 (O2O生鲜电商/买菜到家/数字零售/京东到家/抖音超市领域)

作品概况 页面数量&#xff1a;共 100 页 源文件格式&#xff1a;rp格式&#xff0c;兼容 Axure RP 9/10&#xff0c;非程序软件无源代码 适用领域&#xff1a;O2O生鲜电商、网上超市、买菜到家、数字零售 作品特色 本作品为网上超市用户消费端Axure交互原型&#xff0c;属于…...

外包公司中能学到技术的都是那些人?

在外包公司能够有效学习并提升技术的人&#xff0c;通常具备以下特点和行为模式&#xff1a; 自我驱动力强&#xff1a;这类人有强烈的学习欲望和提升自我的动机&#xff0c;不依赖公司安排的培训&#xff0c;而是主动寻找学习资源&#xff0c;如在线课程、技术书籍、开源项目等…...

JavaEE初阶-多线程进阶2

文章目录 前言一、CAS1.1 CAS的概念1.2 原子类1.3 CAS的ABA问题 二、JUC中常用类2.1 Callable接口2.2 ReentrantLock&#xff08;可重入&#xff09;2.3 Semaphore信号量2.4 CountDownLatch类2.5 CopyOnWriteArrayList类2.6 ConcurrentHashMap 前言 对于多线程进阶的部分&…...

B/S和C/S框架

一、B/S框架 B/S框架是指Browser/Server框架&#xff0c;即基于浏览器和服务器的应用程序开发框架。在B/S架构中&#xff0c;用户通过浏览器&#xff08;Browser&#xff09;访问服务器&#xff08;Server&#xff09;上的应用程序或网站&#xff0c;而无需在用户端安装额外的客…...

机器学习中常用的几种距离——欧式、余弦等

目录 一、欧式距离&#xff08;L2距离&#xff09;二、曼哈顿距离&#xff08;L1距离&#xff09;三、汉明距离四、余弦相似度 一、欧式距离&#xff08;L2距离&#xff09; &#xff08;1&#xff09;二维空间的距离公式&#xff08;三维空间的在这个基础上类推&#xff09;&…...

2024 Google I/O Android 相关内容汇总

2024 Google I/O Android 相关内容汇总 本次 Google I/O 的核心虽然是 AI &#xff0c;但是 Android 也是作为主要议题出现&#xff0c; Android 部分可以简单分为产品和开发相关内容&#xff0c;接下来主要介绍这两部分的相关更新。 重点开始开发相关&#xff0c;内容不少 产…...

# 从浅入深 学习 SpringCloud 微服务架构(十八)

从浅入深 学习 SpringCloud 微服务架构&#xff08;十八&#xff09; 一、开源配置中心 Apollo&#xff1a;概述 1、开源配置中心 Apollo Apollo -A reliable configuration management system Apollo(阿波罗)是携程框架部门研发的分布式配置中心&#xff0c;能够集中化管理…...

在SQL Server中使用临时表与普通表的性能差异分析

在SQL Server中&#xff0c;临时表和普通表的性能确实存在差异&#xff0c;具体表现和影响因素如下&#xff1a; 临时表和普通表的区别 存储位置&#xff1a; 临时表&#xff1a;存储在tempdb数据库中&#xff0c;生命周期仅限于当前会话或批处理。当会话结束或批处理完成时&a…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...