Module: Msf::Exploit::Local::WindowsKernel::HandleEnum

Defined in:
lib/msf/core/exploit/local/windows_kernel/handle_enum.rb

Constant Summary collapse

SYSTEMHANDLEINFORMATION =
64.freeze

Instance Method Summary collapse

Instance Method Details

#enum_system_handles(session, max_handles = 50000, timeout = 30) ⇒ Object

HandleEnum provides methods for enumerating Windows kernel handles via NtQuerySystemInformation for security research purposes.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/msf/core/exploit/local/windows_kernel/handle_enum.rb', line 11

def enum_system_handles(session, max_handles = 50000, timeout = 30)
  pointers = []
  max_attempts = 5
  attempt = 0
  buffer_size = 1024 * 1024

  begin
    Timeout.timeout(timeout) do
      while attempt < max_attempts
        vprint_status("HandleEnum: Attempt #{attempt + 1}: Trying buffer size #{buffer_size} bytes")

        begin
          buffer = "\x00" * buffer_size
        rescue ArgumentError
          print_error("HandleEnum: Failed to allocate buffer of size #{buffer_size}")
          return nil
        end

        result = session.railgun.ntdll.NtQuerySystemInformation(SYSTEMHANDLEINFORMATION, buffer, buffer_size, 4)

        if result.blank?
          print_error('HandleEnum: NtQuerySystemInformation returned nil/empty')
          return nil
        end

        if result['return'] == 0
          vprint_good("HandleEnum: Success with buffer size #{buffer_size}")
          data = result['SystemInformation']
          break
        elsif result['return'] == 0xC0000004
          if result['ReturnLength'] && result['ReturnLength'] > buffer_size
            buffer_size = result['ReturnLength']
            vprint_status("HandleEnum: Buffer too small, need #{buffer_size} bytes")
          else
            buffer_size *= 2
            vprint_status("HandleEnum: Doubling buffer to #{buffer_size} bytes")
          end
          attempt += 1
        else
          print_error("HandleEnum: NtQuerySystemInformation failed: 0x#{result['return'].to_s(16)}")
          return nil
        end
      end

      if attempt >= max_attempts
        print_error("HandleEnum: Failed to get valid buffer after #{max_attempts} attempts")
        return nil
      end

      if data.blank? || data.length < 16
        print_error('HandleEnum: Invalid response data')
        return nil
      end

      num_handles = data[0, 8].unpack('Q').first
      vprint_good("HandleEnum: System has #{num_handles} total handles")

      if max_handles > 0 && num_handles > max_handles
        vprint_status("HandleEnum: Limiting to #{max_handles} handles")
        num_handles = max_handles
      end

      vprint_status("HandleEnum: Processing #{num_handles} handles...")

      offset = 16
      entry_size = 48

      num_handles.times do |i|
        entry_offset = offset + (i * entry_size)
        break if entry_offset + entry_size > data.length

        entry = data[entry_offset, entry_size]

        begin
          object_ptr = entry[0, 8].unpack('Q').first
          pid = entry[8, 8].unpack('Q').first
          handle = entry[16, 8].unpack('Q').first
          access = entry[24, 4].unpack('V').first
          type_idx = entry[30, 2].unpack('v').first

          if kernel_address?(object_ptr)
            pointers << {
              address: object_ptr,
              pid: pid,
              handle: handle,
              access: access,
              type_index: type_idx
            }
          end
        rescue StandardError => e
          vprint_error("HandleEnum: Error parsing handle #{i}: #{e.message}")
        end
      end

      vprint_good("HandleEnum: Processed #{num_handles} handles, found #{pointers.size} kernel addresses")
    end
  rescue Timeout::Error
    print_error("HandleEnum: Enumeration timed out after #{timeout} seconds")
    return nil
  rescue StandardError => e
    print_error("HandleEnum: Error during enumeration: #{e.message}")
    return nil
  end

  pointers
end

#format_file_size(bytes) ⇒ Object



163
164
165
166
167
168
169
170
171
# File 'lib/msf/core/exploit/local/windows_kernel/handle_enum.rb', line 163

def format_file_size(bytes)
  if bytes < 1024
    "#{bytes} bytes"
  elsif bytes < 1024 * 1024
    "#{(bytes / 1024.0).round(2)} KB"
  else
    "#{(bytes / (1024.0 * 1024.0)).round(2)} MB"
  end
end

#get_process_name(session, pid) ⇒ Object



152
153
154
155
156
157
158
159
160
161
# File 'lib/msf/core/exploit/local/windows_kernel/handle_enum.rb', line 152

def get_process_name(session, pid)
  begin
    session.sys.process.each_process do |p|
      return p['name'] if p['pid'] == pid
    end
  rescue StandardError
    nil
  end
  "PID:#{pid}"
end

#get_type_hint(type_idx) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/msf/core/exploit/local/windows_kernel/handle_enum.rb', line 125

def get_type_hint(type_idx)
  hints = {
    7 => 'Process',
    8 => 'Thread',
    16 => 'Key',
    24 => 'File',
    32 => 'ALPC',
    33 => 'ALPC',
    34 => 'ALPC',
    35 => 'ALPC Port',
    36 => 'ALPC Port',
    37 => 'ALPC Port',
    38 => 'ALPC Port',
    39 => 'ALPC Port',
    40 => 'ALPC Port',
    41 => 'ALPC Port',
    42 => 'ALPC Section',
    43 => 'ALPC',
    44 => 'ALPC',
    45 => 'ALPC',
    46 => 'ALPC',
    47 => 'ALPC',
    48 => 'ALPC'
  }
  hints[type_idx] || 'Unknown'
end

#kernel_address?(addr) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
121
122
123
# File 'lib/msf/core/exploit/local/windows_kernel/handle_enum.rb', line 118

def kernel_address?(addr)
  return false if addr.nil? || addr == 0

  high_bits = (addr >> 48) & 0xFFFF
  high_bits == 0xFFFF
end