Module: Msf::Post::Windows::Lsa

Defined in:
lib/msf/core/post/windows/lsa.rb

Defined Under Namespace

Classes: KERB_CRYPTO_KEY_x64, KERB_CRYPTO_KEY_x86, KERB_EXTERNAL_TICKET_x64, KERB_EXTERNAL_TICKET_x86, KERB_QUERY_TKT_CACHE_REQUEST, KERB_QUERY_TKT_CACHE_RESPONSE_x64, KERB_QUERY_TKT_CACHE_RESPONSE_x86, KERB_RETRIEVE_TKT_REQUEST_x64, KERB_RETRIEVE_TKT_REQUEST_x86, KERB_RETRIEVE_TKT_RESPONSE_x64, KERB_RETRIEVE_TKT_RESPONSE_x86, KERB_TICKET_CACHE_INFO_EX_x64, KERB_TICKET_CACHE_INFO_EX_x86, LSA_LAST_INTER_LOGON_INFO, LSA_STRING_x64, LSA_STRING_x86, LSA_UNICODE_STRING_x64, LSA_UNICODE_STRING_x86, LsaPointer, SECURITY_LOGON_SESSION_DATA_x64, SECURITY_LOGON_SESSION_DATA_x86, TOKEN_STATISTICS, UNICODE_STRING_x64, UNICODE_STRING_x86

Instance Method Summary collapse

Instance Method Details

#initialize(info = {}) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/msf/core/post/windows/lsa.rb', line 9

def initialize(info = {})
  super(
    update_info(
      info,
      'Compat' => {
        'Meterpreter' => {
          'Commands' => %w[
            stdapi_railgun_api
            stdapi_railgun_memread
            stdapi_railgun_memwrite
          ]
        }
      }
    )
  )
end

#lsa_call_authentication_package(handle, auth_package, submit_buffer, submit_buffer_length: nil) ⇒ Object



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/msf/core/post/windows/lsa.rb', line 388

def lsa_call_authentication_package(handle, auth_package, submit_buffer, submit_buffer_length: nil)
  if auth_package.is_a?(String)
    auth_package = lsa_lookup_authentication_package(handle, auth_package)
    return nil if auth_package.nil?
  end

  submit_buffer = submit_buffer.to_binary_s if submit_buffer.is_a?(BinData::Struct)
  if submit_buffer_length.nil?
    submit_buffer_length = submit_buffer.length
  end

  result = session.railgun.secur32.LsaCallAuthenticationPackage(
    handle,
    auth_package,
    submit_buffer,
    submit_buffer_length,
    4,
    4,
    4
  )
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to call the authentication package. LsaCallAuthenticationPackage failed with: #{status}")
    return nil
  end
  unless result['ProtocolStatus'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = lsa_nt_status_to_win_error(result['ProtocolStatus'])
    print_error("Failed to call the authentication package. LsaCallAuthenticationPackage authentication package failed with: #{status}")
    return nil
  end
  return nil if result['ProtocolReturnBuffer'] == 0

  LsaPointer.new(result['ProtocolReturnBuffer'], session.railgun.memread(result['ProtocolReturnBuffer'], result['ReturnBufferLength']))
end

#lsa_connect_untrustedObject



423
424
425
426
427
428
429
430
431
432
# File 'lib/msf/core/post/windows/lsa.rb', line 423

def lsa_connect_untrusted
  result = session.railgun.secur32.LsaConnectUntrusted(4)
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to obtain a handle to LSA. LsaConnectUntrusted failed with: #{status.to_s}")
    return nil
  end

  result['LsaHandle']
end

#lsa_deregister_logon_process(handle) ⇒ Object



434
435
436
437
438
439
440
441
442
443
# File 'lib/msf/core/post/windows/lsa.rb', line 434

def lsa_deregister_logon_process(handle)
  result = session.railgun.secur32.LsaDeregisterLogonProcess(handle)
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to close the handle to LSA. LsaDeregisterLogonProcess failed with: #{status.to_s}")
    return nil
  end

  true
end

#lsa_enumerate_logon_sessionsObject



445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/msf/core/post/windows/lsa.rb', line 445

def lsa_enumerate_logon_sessions
  result = session.railgun.secur32.LsaEnumerateLogonSessions(4, 4)
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to enumerate logon sessions. LsaEnumerateLogonSessions failed with: #{status.to_s}")
    return nil
  end

  return [] if result['LogonSessionCount'] == 0
  luids = BinData::Array.new(type: :ms_dtyp_luid, initial_length: result['LogonSessionCount'])
  luids.read(session.railgun.memread(result['LogonSessionList'], luids.num_bytes))
  session.railgun.secur32.LsaFreeReturnBuffer(result['LogonSessionList'])
  luids
end

#lsa_get_logon_session_data(luid) ⇒ Object



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/msf/core/post/windows/lsa.rb', line 460

def lsa_get_logon_session_data(luid)
  case session.native_arch
  when ARCH_X64
    logon_session_data = SECURITY_LOGON_SESSION_DATA_x64.new
    result = session.railgun.secur32.LsaGetLogonSessionData(luid, 8)
  when ARCH_X86
    logon_session_data = SECURITY_LOGON_SESSION_DATA_x86.new
    result = session.railgun.secur32.LsaGetLogonSessionData(luid, 4)
  else
    raise NotImplementedError, "Unsupported session architecture: #{session.native_arch}"
  end

  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to obtain logon session data. LsaGetLogonSessionData failed with: #{status.to_s}")
    return nil
  end
  logon_session_data.read(session.railgun.memread(result['ppLogonSessionData'], logon_session_data.num_bytes))

  LsaPointer.new(result['ppLogonSessionData'], logon_session_data)
end

#lsa_lookup_authentication_package(handle, package_name) ⇒ Object



482
483
484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/msf/core/post/windows/lsa.rb', line 482

def lsa_lookup_authentication_package(handle, package_name)
  package_name = lsa_string(package_name)
  return nil if package_name.nil?

  result = session.railgun.secur32.LsaLookupAuthenticationPackage(handle, package_name, 4)
  session.railgun.util.free_string(package_name.buffer)
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to lookup the authentication package. LsaLookupAuthenticationPackage failed with: #{status.to_s}")
    return nil
  end

  result['AuthenticationPackage']
end

#lsa_nt_status_to_win_error(nt_status) ⇒ Object



497
498
499
# File 'lib/msf/core/post/windows/lsa.rb', line 497

def lsa_nt_status_to_win_error(nt_status)
  ::WindowsError::Win32.find_by_retval(session.railgun.advapi32.LsaNtStatusToWinError(nt_status)['return']).first
end

#lsa_register_logon_processObject



501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/msf/core/post/windows/lsa.rb', line 501

def lsa_register_logon_process
  logon_process_name = lsa_string('Winlogon')
  return nil if logon_process_name.nil?

  result = session.railgun.secur32.LsaRegisterLogonProcess(logon_process_name.to_binary_s, 4, 4)
  session.railgun.util.free_string(logon_process_name.buffer)
  unless result['return'] == ::WindowsError::NTStatus::STATUS_SUCCESS
    status = ::WindowsError::NTStatus.find_by_retval(result['return']).first
    print_error("Failed to obtain a handle to LSA. LsaRegisterLogonProcess failed with: #{status.to_s}")
    return nil
  end

  result['LsaHandle']
end

#lsa_string(string) ⇒ Object

Initialize a new LSA_STRING instance in memory.

Parameters:

  • string (String)

    The string value to place in memory.



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/msf/core/post/windows/lsa.rb', line 343

def lsa_string(string)
  case session.native_arch
  when ARCH_X64
    klass = LSA_STRING_x64
  when ARCH_X86
    klass = LSA_STRING_x86
  else
    raise NotImplementedError, "Unsupported session architecture: #{session.native_arch}"
  end

  ptr = session.railgun.util.alloc_and_write_string(string)
  return nil if ptr.nil?

  klass.new(len: string.length, maximum_len: string.length + 1, buffer: ptr)
end

#lsa_unicode_string(string) ⇒ Object

Initialize a new LSA_UNICODE_STRING instance in memory.

Parameters:

  • string (String)

    The string value to place in memory.



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/msf/core/post/windows/lsa.rb', line 362

def lsa_unicode_string(string)
  case session.native_arch
  when ARCH_X64
    klass = LSA_UNICODE_STRING_x64
  when ARCH_X86
    klass = LSA_UNICODE_STRING_x86
  else
    raise NotImplementedError, "Unsupported session architecture: #{session.native_arch}"
  end

  ptr = session.railgun.util.alloc_and_write_string(string)
  return nil if ptr.nil?

  klass.new(len: string.length, maximum_len: string.length + 2, buffer: ptr)
end

#read_lsa_unicode_string(str) ⇒ Object

Read an LSA_UNICODE_STRING from memory.

Parameters:

  • str (LSA_UNICODE_STRING)

    The LSA_UNICODE_STRING to read from memory.



381
382
383
384
385
386
# File 'lib/msf/core/post/windows/lsa.rb', line 381

def read_lsa_unicode_string(str)
  return '' if str.len == 0

  # the len field is in bytes, divide by two because #read_wstring takes chars
  session.railgun.util.read_wstring(str.buffer, str.len / 2)
end