欢迎光临
我们一直在努力

Cobalt Strike, a Defender’s Guide – Part 2(译文)

在上一篇文章中,我们介绍了Cobalt Strike最受攻击者喜欢的一些功能。在本文中,我们将重点关注它所产生的网络流量,并提供一些简单易用的方法,来帮助防御者检测beaconing活动;本文涉及的主题包括域名前置、SOCKS代理、C2流量、Sigma规则、JARM、JA3/S、RITA等。

与我们之前的文章一样,我们将重点介绍攻击者使用Cobalt Strike的常见方式。

1.png

感谢@Kostastsale帮助我们完成了本系列的第二篇文章。同时,也特别感谢@svch0st、@pigerlin和@0xtornado审阅本文。

尽管网络监控和检测能力对许多组织来说并不容易,但如果实施得当,通常可以带来很高的回报。这是因为,恶意软件要想接受进一步的指示,就必须与其C2服务器进行通信。本文将展示如何在入侵者达到其目标之前检测这种通信。我们可以通过多个方面来识别任何可疑的流量和相关的基础设施。但是,在此之前,我们首先应该讨论是什么让Cobalt Strike如此“多才多艺”。

Cobalt Strike的功能之所以如此丰富,是因为允许对payload进行灵活配置。这要归功于柔性C2配置文件。我们的前一篇文章简单介绍过柔性C2配置文件,以及入侵者是如何利用它们的;然而,这只是它们众多应用中的一部分。下面,我们将介绍攻击者经常用来提高Cobalt Strike网络流量分析难度的方法。

下面的参考资料取自Raphael Mudge的GitHub仓库。

###Global Options###
set sample_name "whatever.profile";
set sleeptime "0"; <================ # Decimal number to indicate the time the beacon will sleep for between communications in milliseconds
set jitter "25"; <================ # A number that indicates the percentage of a random sleep time that beacon will introduce to its C2 comm
set useragent "<string>"; <================ # Custom user agent of your choice
set data_jitter "35"; <================ # Represents the value bytes variable that would instruct Cobalt Strike to send a random string on http-get/post to match the bytes value.
set headers_remove "<header to remove>"; <================ # Specifying headers to be removed in a comma separated manner.

####### Not much explanation is needed here, you can change the certificate information to your heart's content.#######
https-certificate {
set C "US";
set CN "whatever.com";
set L "California";
set O "whatever LLC.";
set OU "local.org";
set ST "CA";
set validity "365";
}
###HTTP-Config Block###
http-config {
set headers "<headers to include>"; <================ # Specifying the headers that you want to include.
header "<name of the header(s)>"; <================ # Specifying the name of the header that will store the data that are transmitted to the C2 server
set trust_x_forwarded_for "<true OR false>"; <================ # If the C2 server is behind a redirector, this option would allow to forward the traffic to the correct destination
set block_useragents "<user agents>"; <================ # User agents that C2 server will block and show a 404 response
set allow_useragents "<user agents>" <================ # Opposite of the above
}
###HTTP-GET Block. This function and all of its fields could also exist and be customized for the HTTP-POST Block (Server communication)###
http-get {
set uri "/<URI string>"; <================ # Specifying the URI to reference in bidirectional communication from client and server
set verb "POST"; <================ # Setting the verb when requesting available tasks from the C2 server.
client {
header "Host" "whatever.com"; <================ # Setting the header specific to client communication with the C2.
header "Connection" "close";
### Metadata corresponds to the information that the beacon is sending to the C2 server about itself. The operators may choose to enable additional fields that will include data on the C2 communication. You can mix and match fields below:
metadata {
#base64; <================ # Base64 encoded string
base64url; <================ # URL safe Base64 encoded string
#mask; <================ # Encrypting and encoding the data with XOR mask and random key
#netbios; <================ # Encoding data as netbios in lower case
#netbiosu; <================ # Another variation of netbios encoding
#prepend "TEST123"; <================ # Choosing a string to prepend to the transmitted data
append ".php"; <================ # Choosing a string to append
### Termination statements: This statement tells Beacon and its server wherein the transaction to store the transformed data. You may choose one of these termination statement methods.
parameter "file"; <================ # Adding a parameter to the URI.
#header "Cookie"; <================ # Adding a specific string within a specific header.
#uri-append; <================ # Adding a specific string in the URI.
#print;
}
parameter "test1" "t

我们在上面的配置文件中添加了注释,指出了攻击者可以修改的字段,他们可以根据自己的需要对这些字段进行定制。所有这些不同的字段为C2通信方式带来了极大的灵活性。当然,也有许多免费的、开源的randomizer脚本可以创建独特的配置文件,例如@Joevest的Random C2 Profile Generator、@BlusCreenofJeff的Malleable-C2-Randomizer和@FortyNorthSec的C2Covesaler。

下面是我们在入侵响应过程中观察到的一些Cobalt Strike C2服务器。在右列中,显示了通过配置让Cobalt Strike的payload去查询的URL。眼尖的读者可能已经发现了一些存在于免费资源上的柔性配置文件,比如Raphael Mudge在其GitHub页面上提供的列表。另一个例子是“jquery-3.3.1.min.js”,我们曾经在四个入侵响应案例中都观察到了这种柔性C2配置文件。

+----------------------+-----------------------+
| C2 Server | URI queried |
+----------------------+-----------------------+
| gawocag.com | /nd |
| 190.114.254.116 | /push |
| 190.114.254.116 | /__utm.gif |
| kaslose.com | /jquery-3.3.1.min.js |
| yawero.com | /skin.js |
| sazoya.com | /skin.js |
| 192.198.86.130 | /skin.js |
| 162.244.83.216 | /jquery-3.3.1.min.js |
| sammitng.com | /jquery-3.3.1.min.js |
| 23.19.227.147 | /styles.html |
| securityupdateav.com | /tab_shop_active.html |
| 108.62.118.247 | /as |
| windowsupdatesc.com | /as |
| 212.114.52.180 | /copyright.css |
| defenderupdateav.com | /default.css |
| onlineworkercz[.]com | /kj |
| checkauj.com | /jquery-3.3.1.min.js |
+----------------------+-----------------------+

另外,读者也可以在@ZephrFish的这篇文章中找到对所有可用字段的深入介绍。实际上,这篇文章还介绍了后渗透过程中,与beacon配置有关的其他字段,以及与网络通信有关的字段。这方面的另一篇优秀文章是SpecterOps撰写的,具体地址为https://posts.specterops.io/a-deep-dive-into-cobalt-strike-malleable-c2-6660e33b0e0b。

域名前置

域名前置是另一种隐藏端点与C2服务器之间通信的方法。域名前置的主要目的是连接受限制的主机,同时伪装成与所允许的主机之间的通信。它本质上是通过将某个网站伪装成不同的域,以掩饰访问某个网站的流量。

这种技术之所以能够实现,主要是拜Content Delivery Networks(CDN)所赐。在一些限制流量的国家,Web服务主要使用域名前置来绕过审查。近年来,攻击者开始使用这种技术将恶意基础设施隐藏在合法域后面。因为域名前置是一个非常复杂的主题,所以我们直接截取了Cobalt Strike官方页面的图片,来概述这项技术。

1.png

Cobalt Strike允许攻击者通过柔性C2配置文件来配置相关选项,从而使域名前置成为可能。当然,必须满足以下先决条件才能实现域名前置:

  1. 已经拥有一个域名(例如,infosecppl.store)
  2. 选择一个提供CDN功能的Web服务(例如cloudfront.net)
  3. 设置CDN服务,以创建新的CDN端点并将流量重定向到您的域(例如,l33th4x0r.cloudfront.net)。
  4. 通过配置文件实现域名前置
  5. 指定使用相同CDN的域,以确保通信流量将被转发到正确的资源。

这里最有趣的是第5步:攻击者可以使用在同一CDN供应商下注册的合法域名。如上面的截图所示,他们所要做的就是在请求的host头部中包含自己的CDN端点域(在第3步中创建)。这样,合法网站就会根据host头部中的域名,将流量通过CDN转发到原始目的地。

在下面的截图中,展示了如何配置柔性C2配置文件,通过Fastly和AzureEdge CDN实现域名前置。

1.png

这篇由加州大学伯克利分校的学者们发布的研究论文是对域名前置的一个很好的介绍。这篇论文启发了许多研究人员,以拓展通过Web流量来隐藏最终目标服务器的独特方法的可能性。其中一位研究人员是Vincent,他写了一篇关于域名前置的优秀文章。他用通俗的笔触解释了域名前置是如何工作的。此外,他还公布了一个Python脚本,以识别可以实现域名前置的潜在域名。

根据我们的经验,域名前置的应用还不是很广泛。这很可能是由于建立必要的基础设施的过程比较复杂所致。尽管如此,根据我们收集的有关恶意基础设施的数据,域名前置似乎正在逐步流行。根据我们从2021年初至今的数据,在入侵者的首选CDN方面,Amazon Cloudfront遥遥领先。

1.png

使用Cobalt Strike Beacon的反向代理

我们经常遇到的一种技术是反向代理。我们看到的情况是,入侵者利用他们的beacon会话,通过反向代理建立RDP访问。Cobalt Strike能够在服务器上运行一个SOCKS代理服务器。这使得攻击者能够设置一个监听端口,并利用它来中继开放beacon会话的流量。下面的截图展示了这种实现方式。

1.png

图片来源:cobaltstrike.com

我们观察到的入侵者使用反向代理的其他案例:

Diavol Ransomware
BazarLoader and the Conti Leaks
Snatch Ransomware

在上述大多数案例中,攻击者的目的都是建立一个远程桌面会话。建立RDP会话有许多好处,例如能够使用图形环境进行导航,因此,只要获得必要的访问权,就可以轻松地进行横向移动。

下面,我们将展示攻击者是如何通过kali Linux主机中的proxychains来利用此技术的。在第一张图片中,攻击者在Cobalt Strike团队的服务器上打开了一个socks监听端口,具体为8888端口。

1.png

创建监听端口(TCP 8888端口)

在第二张图片中,使用从攻击者的Kali Linux主机到RDP的proxychains,通过SOCKS服务器进入目标环境。这个过程非常简单,只需把团队服务器的IP地址添加到proxychains的配置中,然后用xfreerdp连接即可。

1.png
使用反向代理通过RDP进入目标主机

查看生成的工件,我们可以看到在目标主机上创建了一个ID为4624的事件。在我们报告的类似案例中,我们也提到了一个有趣的事情,那就是受害者的主机名在这个登录事件中被捕获了,而且源地址是127.0.0.1。

1.png
安全事件ID 4624显示了攻击者的主机名

再一次,运行中的Cobalt Strike beacon作为中转站,通过反向代理创建远程桌面会话。

深入分析Cobalt Strike的C2流量

本节将试图说明柔性C2配置文件是如何影响网络通信的。

在下面的一些例子中,我们模拟了恶意的C2通道,以显示不同的柔性配置文件配置是如何改变观察到的流量的。之后,我们将考察与横向移动相关的网络数据,以及使用Cobalt Strike的攻击者所采用的各种方法。

HTTP/HTTPS C2流量

我们将使用略有修改的jquery配置文件来说明如何设置C2连接的各个字段。在我们之前的文章中说过,这个jquery配置文件是我们遇到的入侵案例中最常用的配置文件之一。

1.png

如上所示,借助于柔性C2配置文件提供的配置,攻击者可以生成独特的网络通信流量。其中,该柔性C2配置文件显示在截图的下半部分。在截图的上半部分,我们显示了Beacon和Cobalt Strike服务器之间的HTTP通信。

柔性配置文件确定了GET和POST请求中使用的所有参数的值。由于更改这些参数非常简单,这使得创建用于主动防御的网络签名变得极为困难。不过,防御者可以为公开可用的配置文件(见下面的Sigma部分)或通过从开源情报中提取和提供的配置文件创建签名。此外,防御者也可以搜索匹配已知模式(如jquery或amazon)但目标IP/域与预期底层基础设施不匹配的流量。

DNS C2流量

Cobalt Strike可以使用DNS作为C2。攻击者可以将其服务器配置为响应A、AAAA或TXT记录中的beacon请求。这个策略对于更隐蔽的操作非常有用,因为目标主机可能是良性DNS服务器。防御者将不得不检查所有流量数据,以从中寻找可疑的DNS记录。

下面的截图来自Cobalt Strike的官方文档,显示了被攻击的主机和C2服务器之间的DNS通信是如何进行的。

1.png

在下面的示例中,我们模拟了这种技术,并将beacon配置为通过DNS进行通信,并使用A记录来请求新任务。同样,我们可以将beacon配置为使用TXT或AAAA记录来请求任务,或向服务器发送信息。值得注意的是,默认方法是使用DNS TXT记录数据通道。下面是我们为演示目的而搭建的基础设施:

目标主机地址: 192.168.88.179
内部DNS服务器地址 : 192.168.88.2
Cobalt Strike C2 域名: infosecppl.store

我们命令beacon在被攻击的主机上执行systeminfo命令。从下面的截图可以看出,它用了148个包含DNS请求和响应的数据包来完成该任务,并将数据发回给Cobalt Strike服务器。需要注意的是,这个过程只需要5秒钟即可。

1.png

与HTTP/HTTPS流量一样,DNS流量也可以利用柔性C2配置文件实现随机化。下面是攻击者可以使用的一些选项:

1.png

上表摘自Cobalt Strike的官方文件

SMB Beacon

攻击者的另一个选择是,一旦他们获得了对网络的访问权限,就开始使用SMB beacon。SMB beacon会在目标主机上打开一个本地端口,监听来自父beacon的流量。两个beacon之间的通信,是通过命名管道实现的。

攻击者可以在客户端配置管道名称;但是,SMB beacon的默认管道名称都是以“msagent_#”开头的。关于其他服务的默认管道名称的列表,请参考@svch0st的文章,其中还包括一些自定义配置文件。

1.png

SMB beacon主要用于增加网络检测的难度,以及访问禁止与互联网通信的隔离系统。此外,由于SMB协议可以在大多数内部网络中访问,因此,它是一种可靠的C2通信方法。同时,攻击者还可以通过链式beacon在网络内横向移动。

根据我们的经验,SMB beacon使用的频率并不高。然而,在老道的攻击者手中,它们仍然是一种强大的武器。由于SMB beacon在现实案例中非常少见,因此,我们从实验室中选取了一个示例案例来演示该方法的有效性。

我们在目标主机上运行了一个PowerShell加载器,它将在内存中加载一个stageless的SMB beacon。在我们的示例中,SMB beacon通过网络使用命名管道与父beacon进行通信。对于本例来说,我们选择的命名管道为“my_pipes”。

1.png

从下面的截图中可以看到,4688号windows事件中包含PowerShell命令执行事件。

1.png

正如我们之前的Cobalt Strike文章中所解释的,17和18号Sysmon事件可以记录命名管道。但是,前提是显式地将Sysmon配置为记录命名管道事件。Olaf的Sysmon Moduler是一个很棒的通用Sysmon配置,其中就涉及命名管道等内容。

下面,您可以看到创建的命名管道,它是我们在创建SMB侦听器时在Cobalt Strike接口上指定的。

1.png

此外,SMB beacon将通过端口445与主beacon进行通信,如上所述,主beacon将把结果发送到C2服务器。这被称为链式beacon。下面的截图演示了beachhead主机上的beacon和链式beacon之间的SMB通信。另一种描述通信方式的方法是使用父/子关系。

1.png

网络通信流量显示目标主机是通过SMB与运行父HTTP beacon的其他受损主机进行通信的。命名管道用于简化数据的传输。

192.168.38.102 = SMB Beacon

192.168.38.104 = HTTP Parent Beacon

1.png

C2通信的检测与分析

得益于免费的开源工具,网络流量的调查工作已经变得容易多了。当我们进行入侵响应时,我们会使用特定的工具来考察可疑的网络通信流量。我们坚信,虽然没有哪个工具能够提供全面的检测功能,但是我们可以通过组合多种工具,来接近这一目标。在下一节中,我们将研究这些可以帮助防御者提高分析速度的工具。

Sigma规则

此外,我们也可以借助于Sigma规则来检测Cobalt Strike的网络活动。

Cobalt Strike DNS Beaconing是Florian Roth创建的一个规则,它会检查DNS日志,根据dns_stager_subhost、put_output和dns_stager_subhost来检测默认的DNS C2行为,具体如上图所示。

1.png

下面是@bareiss_patrick创建的一个更通用的规则,它是基于对单个域名的大量查询,来检测可疑DNS通信量的一个很好的示例。

1.png

由Daniil Yugoslavskiy创建的另一个更通用的规则,这个规则使用dns日志,查找单个源在一分钟内发送50个或更多的TXT记录的行为:

1.png

Default Cobalt Strike Certificate是Bhabesh Raj编写的规则,使用Zeek日志来检测缺省Cobalt Strike证书。

1.png

RDP over Reverse SSH Tunnel WFP是由Samir Bousseaden WFP编写的一个规则,使用反向隧道寻找可疑RDP活动。

1.png

CobaltStrike Malleable Amazon Browsing Traffic Profile是由Markus Neis提供的,用于查找亚马逊柔性配置文件的代理日志。

1.png

其他柔性配置文件规则包括 CobaltStrike Malformed UAs in Malleable Profiles、CobaltStrike Malleable (OCSP) Profile和CobaltStrike Malleable OneDrive Browsing Traffic Profile。

这里介绍的所有Sigma规则都可以在第1篇文章的底部找到。

Rita

Rita是Real Intelligence Threat Analytics(RITA)的缩写,由Active Countermeasures公司开发。Rita实际上就是一个检测C2通信的框架,它采用了Zeek日志数据,根据我们的经验,它可以准确检测beacon活动。

Rita的一大特点是易于使用,并能够以不同的格式输出信息,包括CSV和HTML格式。人们只需将Rita指向Zeek的日志,然后静待结果即可。当然,可用的数据越多,结果就越准确。而Zeek日志可以通过PCAP(s)生成。

下面的屏幕截图示例显示了Rita基于上文中使用的流量创建的结果,以演示jquery柔性C2配置文件产生的流量。

1.png

我们让beacon运行了一个小时,以模拟实际入侵情况,同时,还在后台运行其他几个与网络无关的进程。在这一小时内,我们还让beacon执行了几个命令。Rita的输出表明,一小时的网络数据足以识别beacon活动,并给出了非常高的分数。当然,数据越多,结果就越准确。
下面,可以看到最近的一个案例(BazarLoader和Conti泄密案)的检测结果:前三个IP地址跟beacon与之通信CS服务器有关。

1.png

Rita准确地识别了与Cobalt Strike C2通信有关的beacon活动。使用Rita,我们可以根据多个特征来识别恶意的C2通信,包括通信频率、平均发送/接收的字节数、连接数等。因此,我们在检测Cobalt Strike的beacon活动时,不必担心柔性C2配置文件或额外抖动所带来的困扰。

JA3/JA3S

JA3是由John Althouse、Jeff Atkinson和Josh Atkins创建的一个开源项目。JA3/JA3S可以为客户和服务器之间的通信创建SSL指纹。这些独特的签名可以识别从客户端Hello数据包中的字段收集的几个值:

  • SSL版本
  • 接受的密码
  • 扩展列表
  • 椭圆曲线密码
  • 椭圆曲线密码格式

关于JA3工作原理的更多信息,可以访问其GitHub官方存储库:https://github.com/salesforce/ja3。

JA3工具用于为客户端与服务器的beacon连接生成签名。同时,JA3S还能够生成服务器指纹。两者的结合可以产生最准确的结果。JA3S能够捕捉到完整的加密通信数据,并结合JA3的发现来生成签名。

这种方法的缺点是,如果Cobalt Strike位于重定向器后面,则可能产生不准确的结果。

我们可以找到许多相关报告,其中包含与Cobalt Strike指纹相对应的JA3值。当涉及到Cobalt Strike基础设施时,我们可以寻找的已知JA3和JA3s签名包括:

JA3

72a589da586844d7f0818ce684948eea
a0e9f5d64349fb13191bc781f81f42e1

JA3s

b742b407517bac9536a77a7b0fee28e9
ae4edc6faf64d08308082ad26be60767

通过使用JA3/S签名,我们甚至可以发现各种恶意软件C2服务器,而不仅仅是Cobalt Strike。Salesforce在这里提供了属于许多不同应用程序的签名的完整集合。下面给出部分具有众所周知的JA3指纹的示例签名:

Trickbot: 6734f37431670b3ab4292b8f60f29984
AsyncRat: fc54e0d16d9764783542f0146a98b300
Dridex: 51c64c77e60f3980eea90869b68c58a8
JA3 of Python usually hosting Empire or PoshC2: db42e3017c8b6d160751ef3a04f695e7
TOR client: e7d705a3286e19ea42f587b344ee6865

另一个关于大型数据库测试JA3签名的网站是JA3ER,地址为https://ja3er.com/。

JARM

与JA3/JA3S类似,JARM也能对远程服务器的TLS值进行指纹识别。它通过与目标服务器交互,发送10个TLS Client Hello数据包,并记录应答中的特定属性来实现这一点。然后,它将计算结果值的哈希值,并创建最终的JARM指纹。

与JA3/S不同,JARM对远程服务器应用程序进行指纹识别采取的是主动方式。关于JA3/S和JARM之间的区别,可以参考John Althouse撰写的相关文章,具体地址为https://medium.com/@jalthouse/great-question-11aa555f6b28。这篇文章指出:

“JARM会主动扫描服务器,并创建服务器应用程序的指纹。JA3/S是被动的,只是被动侦听,而不主动接触;而JARM是主动的,会积极探测目标。并且,JARM能够在JA3S鞭长莫及的情况下创建服务器应用程序的指纹”

根据下面提到的研究和对JAVA TLS版本的进一步修改,与Cobalt Strike的默认配置相对应的JARM指纹为:

07d14d16d21d21d00042d41d00041de5fb3038104f457d92ba02e9311512c2

Cobalt Strike依赖于Java来运行客户端图形用户界面(GUI)和团队服务器。当我们使用JARM扫描Cobalt Strike服务器时,得到的结果与所使用的Java版本紧密相关。根据Cobalt Strike的文档,OpenJDK 11是攻击者的首选安装版本。这使得识别潜在的Cobalt Strike服务器更加容易,然而,防御者应该意识到,仅凭这一点就得出结论的话,就容易出现误报。这是因为互联网上许多其他合法的服务器也使用这个版本的Java来运行网络应用程序。

2021年4月20日,Java禁用了TLS 1.0和TLS 1.1,转而使用TLS 1.2或以上版本。在这一变化之后,Cobalt Strike服务器的JARM指纹也发生了相应的变化:

From: 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

To: 07d14d16d21d21d00042d41d00041de5fb3038104f457d92ba02e9311512c2

1.png

@bodziurity和@wlesicki在合作中强调了这一变化:

1.png

Cobalt Strike有一篇专门针对JARM的文章,详细介绍了JARM是如何工作的,以及如何基于Java版本创建特定的哈希值。

在我们的报告中查找这个哈希值将返回我们的四个案例。所有这些案例都将Cobalt Strike用作后渗透工具。

要为服务器生成JARM指纹,可以借助于Python工具JARM ,具体用法如下所示:

python3 jarm.py [target] -p [port]

1.png

虽然JARM提供了另一个工具来帮助暴露攻击者的基础设施,但它们不能作为单独使用的指标。因为JARM签名可以被伪造,Dagmawi Mulugeta于2021年在阿姆斯特丹举行的HiTB大会上展示了一种工具,可以供红队队员用于伪造其基础设施的JARM签名。该工具名为JARM Randomizer,可以配置为Cobalt Strike服务器的前置代理,向潜在的互联网扫描器提供虚假数据。

其他JARM,请访问https://github.com/cedowens/C2-JARM。

Arkime (Moloch)与JA3/S

我们之所以介绍Arkime,说因为它可以与JA3/JA3S和其他插件结合使用,以提高我们的网络分析效率。工作中,我们经常借助Arkime来调查网络活动并收集相关指标。它可以索引网络流量,以及轻松搜索相关事件。

Arkime设置简单,非常适合审查流量。Arkime可以集成额外的分析工具,以进一步提高其分析能力,我们将在后续的文章中进行进一步的介绍。

1.png

小结

以上就是本文的全部内容。您是否对本系列的第3篇的内容非常感兴趣呢?欢迎这里或推特上联系我们,并提出您的宝贵建议。感谢阅读,希望对您有所帮助!

此外,要想了解更多的检测和规则,可以访问我们第一篇文章的末尾部分。

原文地址:https://thedfirreport.com/2022/01/24/cobalt-strike-a-defenders-guide-part-2/

赞(0) 打赏
未经允许不得转载:黑客技术网 » Cobalt Strike, a Defender’s Guide – Part 2(译文)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏